Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Operators.Programmable/ProgrammableOperator.cs @ 679

Last change on this file since 679 was 679, checked in by gkronber, 16 years ago

implemented #315 by adding an import statement for System.Linq.

File size: 8.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Text;
25using System.Xml;
26using System.IO;
27using System.Reflection;
28using System.CodeDom;
29using System.CodeDom.Compiler;
30using Microsoft.CSharp;
31using System.Text.RegularExpressions;
32using HeuristicLab.Core;
33using HeuristicLab.Data;
34
35namespace HeuristicLab.Operators.Programmable {
36  public class ProgrammableOperator : OperatorBase {
37    private MethodInfo executeMethod;
38
39    private string myDescription;
40    public override string Description {
41      get { return myDescription; }
42    }
43    private string myCode;
44    public string Code {
45      get { return myCode; }
46      set {
47        if (value != myCode) {
48          myCode = value;
49          executeMethod = null;
50          OnCodeChanged();
51        }
52      }
53    }
54
55    public ProgrammableOperator() {
56      myCode = "Result.Data = true;";
57      myDescription = "An operator that can be programmed for arbitrary needs.";
58
59      AddVariableInfo(new VariableInfo("Result", "A computed variable", typeof(BoolData), VariableKind.New | VariableKind.Out));
60      executeMethod = null;
61    }
62
63    public void SetDescription(string description) {
64      if (description == null)
65        throw new NullReferenceException("description must not be null");
66
67      if (description != myDescription) {
68        myDescription = description;
69        OnDescriptionChanged();
70      }
71    }
72
73    public virtual void Compile() {
74      CodeNamespace ns = new CodeNamespace("HeuristicLab.Operators.Programmable.CustomOperators");
75      CodeTypeDeclaration typeDecl = new CodeTypeDeclaration("Operator");
76      typeDecl.IsClass = true;
77      typeDecl.TypeAttributes = TypeAttributes.Public;
78
79      CodeMemberMethod method = new CodeMemberMethod();
80      method.Name = "Execute";
81      method.ReturnType = new CodeTypeReference(typeof(IOperation));
82      method.Attributes = MemberAttributes.Public | MemberAttributes.Static;
83      method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(IOperator), "op"));
84      method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(IScope), "scope"));
85      foreach (IVariableInfo info in VariableInfos)
86        method.Parameters.Add(new CodeParameterDeclarationExpression(info.DataType, info.FormalName));
87      string code = myCode + "\r\n" + "return null;";
88      method.Statements.Add(new CodeSnippetStatement(code));
89      typeDecl.Members.Add(method);
90
91      ns.Types.Add(typeDecl);
92      ns.Imports.Add(new CodeNamespaceImport("System"));
93      ns.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
94      ns.Imports.Add(new CodeNamespaceImport("System.Text"));
95      ns.Imports.Add(new CodeNamespaceImport("System.Linq"));
96      ns.Imports.Add(new CodeNamespaceImport("HeuristicLab.Core"));
97      foreach (IVariableInfo variableInfo in VariableInfos)
98        ns.Imports.Add(new CodeNamespaceImport(variableInfo.DataType.Namespace));
99
100      CodeCompileUnit unit = new CodeCompileUnit();
101      unit.Namespaces.Add(ns);
102      CompilerParameters parameters = new CompilerParameters();
103      parameters.GenerateExecutable = false;
104      parameters.GenerateInMemory = true;
105      parameters.IncludeDebugInformation = false;
106      Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
107      foreach (Assembly loadedAssembly in loadedAssemblies)
108        parameters.ReferencedAssemblies.Add(loadedAssembly.Location);
109      CodeDomProvider provider = new CSharpCodeProvider();
110      CompilerResults results = provider.CompileAssemblyFromDom(parameters, unit);
111
112      executeMethod = null;
113      if (results.Errors.HasErrors) {
114        StringWriter writer = new StringWriter();
115        CodeGeneratorOptions options = new CodeGeneratorOptions();
116        options.BlankLinesBetweenMembers = false;
117        options.ElseOnClosing = true;
118        options.IndentString = "  ";
119        provider.GenerateCodeFromCompileUnit(unit, writer, options);
120        writer.Flush();
121        string[] source = writer.ToString().Split(new string[] { "\r\n" }, StringSplitOptions.None);
122        StringBuilder builder = new StringBuilder();
123        for (int i = 0; i < source.Length; i++)
124          builder.AppendLine((i + 1).ToString("###") + "     " + source[i]);
125        builder.AppendLine();
126        builder.AppendLine();
127        builder.AppendLine();
128        foreach (CompilerError error in results.Errors) {
129          builder.Append("Line " + error.Line.ToString());
130          builder.Append(", Column " + error.Column.ToString());
131          builder.AppendLine(": " + error.ErrorText);
132        }
133        throw new Exception("Compile Errors:\n\n" + builder.ToString());
134      } else {
135        Assembly assembly = results.CompiledAssembly;
136        Type[] types = assembly.GetTypes();
137        executeMethod = types[0].GetMethod("Execute");
138      }
139    }
140
141    public override object Clone(IDictionary<Guid, object> clonedObjects) {
142      ProgrammableOperator clone = (ProgrammableOperator)base.Clone(clonedObjects);
143      clone.myDescription = Description;
144      clone.myCode = Code;
145      clone.executeMethod = executeMethod;
146      return clone;
147    }
148
149    public override IOperation Apply(IScope scope) {
150      if (executeMethod == null) {
151        Compile();
152      }
153
154      // collect parameters
155      object[] parameters = new object[VariableInfos.Count + 2];
156      parameters[0] = this;
157      parameters[1] = scope;
158      int i = 2;
159      foreach (IVariableInfo info in VariableInfos) {
160        if ((info.Kind & VariableKind.New) == VariableKind.New) {
161          parameters[i] = GetVariableValue(info.FormalName, scope, false, false);
162          if (parameters[i] == null) {
163            IItem value = (IItem)Activator.CreateInstance(info.DataType);
164            if (info.Local) {
165              AddVariable(new Variable(info.ActualName, value));
166            } else {
167              scope.AddVariable(new Variable(scope.TranslateName(info.FormalName), value));
168            }
169            parameters[i] = value;
170          }
171        } else
172          parameters[i] = GetVariableValue(info.FormalName, scope, true);
173        i++;
174      }
175
176      return (IOperation)executeMethod.Invoke(null, parameters);
177    }
178
179    public override IView CreateView() {
180      return new ProgrammableOperatorView(this);
181    }
182
183    public event EventHandler DescriptionChanged;
184    protected virtual void OnDescriptionChanged() {
185      if (DescriptionChanged != null)
186        DescriptionChanged(this, new EventArgs());
187    }
188    public event EventHandler CodeChanged;
189    protected virtual void OnCodeChanged() {
190      if (CodeChanged != null)
191        CodeChanged(this, new EventArgs());
192    }
193
194    #region Persistence Methods
195    public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary<Guid, IStorable> persistedObjects) {
196      XmlNode node = base.GetXmlNode(name, document, persistedObjects);
197      XmlNode descriptionNode = document.CreateNode(XmlNodeType.Element, "Description", null);
198      descriptionNode.InnerText = myDescription;
199      node.AppendChild(descriptionNode);
200      XmlNode codeNode = document.CreateNode(XmlNodeType.Element, "Code", null);
201      codeNode.InnerText = myCode;
202      node.AppendChild(codeNode);
203      return node;
204    }
205    public override void Populate(XmlNode node, IDictionary<Guid, IStorable> restoredObjects) {
206      base.Populate(node, restoredObjects);
207      XmlNode descriptionNode = node.SelectSingleNode("Description");
208      myDescription = descriptionNode.InnerText;
209      XmlNode codeNode = node.SelectSingleNode("Code");
210      myCode = codeNode.InnerText;
211    }
212    #endregion
213  }
214}
Note: See TracBrowser for help on using the repository browser.