Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 553 was 164, checked in by gkronber, 17 years ago

changed Compile() to virtual in preparation for the ProgrammableFunction which extends ProgrammableOperator (ticket #106)

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("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.