Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 103 was 77, checked in by swagner, 17 years ago

Fixed ticket #67

  • adapted accessing of variables in operators due to changes of variable lookup and the new name aliasing mechanism (actual/formal name translations should not be done directly anymore; instead the new method Scope.TranslateName should be used)
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      Compile();
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        throw new InvalidOperationException("No compiled code available.");
151
152      // collect parameters
153      object[] parameters = new object[VariableInfos.Count + 2];
154      parameters[0] = this;
155      parameters[1] = scope;
156      int i = 2;
157      foreach (IVariableInfo info in VariableInfos) {
158        if ((info.Kind & VariableKind.New) == VariableKind.New) {
159          parameters[i] = GetVariableValue(info.FormalName, scope, false, false);
160          if (parameters[i] == null) {
161            IItem value = (IItem)Activator.CreateInstance(info.DataType);
162            if (info.Local) {
163              AddVariable(new Variable(info.ActualName, value));
164            } else {
165              scope.AddVariable(new Variable(scope.TranslateName(info.FormalName), value));
166            }
167            parameters[i] = value;
168          }
169        } else
170          parameters[i] = GetVariableValue(info.FormalName, scope, true);
171        i++;
172      }
173
174      return (IOperation)executeMethod.Invoke(null, parameters);
175    }
176
177    public override IView CreateView() {
178      return new ProgrammableOperatorView(this);
179    }
180
181    public event EventHandler DescriptionChanged;
182    protected virtual void OnDescriptionChanged() {
183      if (DescriptionChanged != null)
184        DescriptionChanged(this, new EventArgs());
185    }
186    public event EventHandler CodeChanged;
187    protected virtual void OnCodeChanged() {
188      if (CodeChanged != null)
189        CodeChanged(this, new EventArgs());
190    }
191
192    #region Persistence Methods
193    public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary<Guid, IStorable> persistedObjects) {
194      XmlNode node = base.GetXmlNode(name, document, persistedObjects);
195      XmlNode descriptionNode = document.CreateNode(XmlNodeType.Element, "Description", null);
196      descriptionNode.InnerText = myDescription;
197      node.AppendChild(descriptionNode);
198      XmlNode codeNode = document.CreateNode(XmlNodeType.Element, "Code", null);
199      codeNode.InnerText = myCode;
200      node.AppendChild(codeNode);
201      return node;
202    }
203    public override void Populate(XmlNode node, IDictionary<Guid, IStorable> restoredObjects) {
204      base.Populate(node, restoredObjects);
205      XmlNode descriptionNode = node.SelectSingleNode("Description");
206      myDescription = descriptionNode.InnerText;
207      XmlNode codeNode = node.SelectSingleNode("Code");
208      myCode = codeNode.InnerText;
209      Compile();
210    }
211    #endregion
212  }
213}
Note: See TracBrowser for help on using the repository browser.