Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3.0/sources/HeuristicLab.Operators.Programmable/ProgrammableOperator.cs @ 8986

Last change on this file since 8986 was 117, checked in by gkronber, 17 years ago

ticket #98 also removed call to Compile() in the Populate() method since it slowed down the deserialization needed for the parallel execution horribly and it's not needed in the lazy compilation scheme anyway (also see r116)

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 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("HeuristicLab.Core"));
96      foreach (IVariableInfo variableInfo in VariableInfos)
97        ns.Imports.Add(new CodeNamespaceImport(variableInfo.DataType.Namespace));
98
99      CodeCompileUnit unit = new CodeCompileUnit();
100      unit.Namespaces.Add(ns);
101      CompilerParameters parameters = new CompilerParameters();
102      parameters.GenerateExecutable = false;
103      parameters.GenerateInMemory = true;
104      parameters.IncludeDebugInformation = false;
105      Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
106      foreach (Assembly loadedAssembly in loadedAssemblies)
107        parameters.ReferencedAssemblies.Add(loadedAssembly.Location);
108      CodeDomProvider provider = new CSharpCodeProvider();
109      CompilerResults results = provider.CompileAssemblyFromDom(parameters, unit);
110
111      executeMethod = null;
112      if (results.Errors.HasErrors) {
113        StringWriter writer = new StringWriter();
114        CodeGeneratorOptions options = new CodeGeneratorOptions();
115        options.BlankLinesBetweenMembers = false;
116        options.ElseOnClosing = true;
117        options.IndentString = "  ";
118        provider.GenerateCodeFromCompileUnit(unit, writer, options);
119        writer.Flush();
120        string[] source = writer.ToString().Split(new string[] { "\r\n" }, StringSplitOptions.None);
121        StringBuilder builder = new StringBuilder();
122        for (int i = 0; i < source.Length; i++)
123          builder.AppendLine((i + 1).ToString("###") + "     " + source[i]);
124        builder.AppendLine();
125        builder.AppendLine();
126        builder.AppendLine();
127        foreach (CompilerError error in results.Errors) {
128          builder.Append("Line " + error.Line.ToString());
129          builder.Append(", Column " + error.Column.ToString());
130          builder.AppendLine(": " + error.ErrorText);
131        }
132        throw new Exception("Compile Errors:\n\n" + builder.ToString());
133      } else {
134        Assembly assembly = results.CompiledAssembly;
135        Type[] types = assembly.GetTypes();
136        executeMethod = types[0].GetMethod("Execute");
137      }
138    }
139
140    public override object Clone(IDictionary<Guid, object> clonedObjects) {
141      ProgrammableOperator clone = (ProgrammableOperator)base.Clone(clonedObjects);
142      clone.myDescription = Description;
143      clone.myCode = Code;
144      clone.executeMethod = executeMethod;
145      return clone;
146    }
147
148    public override IOperation Apply(IScope scope) {
149      if (executeMethod == null) {
150        Compile();
151      }
152
153      // collect parameters
154      object[] parameters = new object[VariableInfos.Count + 2];
155      parameters[0] = this;
156      parameters[1] = scope;
157      int i = 2;
158      foreach (IVariableInfo info in VariableInfos) {
159        if ((info.Kind & VariableKind.New) == VariableKind.New) {
160          parameters[i] = GetVariableValue(info.FormalName, scope, false, false);
161          if (parameters[i] == null) {
162            IItem value = (IItem)Activator.CreateInstance(info.DataType);
163            if (info.Local) {
164              AddVariable(new Variable(info.ActualName, value));
165            } else {
166              scope.AddVariable(new Variable(scope.TranslateName(info.FormalName), value));
167            }
168            parameters[i] = value;
169          }
170        } else
171          parameters[i] = GetVariableValue(info.FormalName, scope, true);
172        i++;
173      }
174
175      return (IOperation)executeMethod.Invoke(null, parameters);
176    }
177
178    public override IView CreateView() {
179      return new ProgrammableOperatorView(this);
180    }
181
182    public event EventHandler DescriptionChanged;
183    protected virtual void OnDescriptionChanged() {
184      if (DescriptionChanged != null)
185        DescriptionChanged(this, new EventArgs());
186    }
187    public event EventHandler CodeChanged;
188    protected virtual void OnCodeChanged() {
189      if (CodeChanged != null)
190        CodeChanged(this, new EventArgs());
191    }
192
193    #region Persistence Methods
194    public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary<Guid, IStorable> persistedObjects) {
195      XmlNode node = base.GetXmlNode(name, document, persistedObjects);
196      XmlNode descriptionNode = document.CreateNode(XmlNodeType.Element, "Description", null);
197      descriptionNode.InnerText = myDescription;
198      node.AppendChild(descriptionNode);
199      XmlNode codeNode = document.CreateNode(XmlNodeType.Element, "Code", null);
200      codeNode.InnerText = myCode;
201      node.AppendChild(codeNode);
202      return node;
203    }
204    public override void Populate(XmlNode node, IDictionary<Guid, IStorable> restoredObjects) {
205      base.Populate(node, restoredObjects);
206      XmlNode descriptionNode = node.SelectSingleNode("Description");
207      myDescription = descriptionNode.InnerText;
208      XmlNode codeNode = node.SelectSingleNode("Code");
209      myCode = codeNode.InnerText;
210    }
211    #endregion
212  }
213}
Note: See TracBrowser for help on using the repository browser.