Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 2674 was 2526, checked in by swagner, 15 years ago

Refactored cloning (#806)

File size: 8.0 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.Linq;
28using System.Reflection;
29using System.CodeDom;
30using System.CodeDom.Compiler;
31using Microsoft.CSharp;
32using System.Text.RegularExpressions;
33using HeuristicLab.Core;
34using HeuristicLab.Data;
35using System.Data.Linq;
36using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
37
38namespace HeuristicLab.Operators.Programmable {
39  public class ProgrammableOperator : OperatorBase {
40    private MethodInfo executeMethod;
41
42    [Storable]
43    private string myDescription;
44    public override string Description {
45      get { return myDescription; }
46    }
47
48    [Storable]
49    private string myCode;   
50    public string Code {
51      get { return myCode; }
52      set {
53        if (value != myCode) {
54          myCode = value;
55          executeMethod = null;
56          OnCodeChanged();
57        }
58      }
59    }
60
61    private object syncRoot = new object();
62
63    public ProgrammableOperator() {
64      myCode = "Result.Data = true;";
65      myDescription = "An operator that can be programmed for arbitrary needs.";
66      AddVariableInfo(new VariableInfo("Result", "A computed variable", typeof(BoolData), VariableKind.New | VariableKind.Out));
67      executeMethod = null;
68    }
69
70    public void SetDescription(string description) {
71      if (description == null)
72        throw new NullReferenceException("description must not be null");
73
74      if (description != myDescription) {
75        myDescription = description;
76        OnDescriptionChanged();
77      }
78    }
79
80    public virtual void Compile() {
81      CodeNamespace ns = new CodeNamespace("HeuristicLab.Operators.Programmable.CustomOperators");
82      CodeTypeDeclaration typeDecl = new CodeTypeDeclaration("Operator");
83      typeDecl.IsClass = true;
84      typeDecl.TypeAttributes = TypeAttributes.Public;
85
86      CodeMemberMethod method = new CodeMemberMethod();
87      method.Name = "Execute";
88      method.ReturnType = new CodeTypeReference(typeof(IOperation));
89      method.Attributes = MemberAttributes.Public | MemberAttributes.Static;
90      method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(IOperator), "op"));
91      method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(IScope), "scope"));
92      foreach (IVariableInfo info in VariableInfos)
93        method.Parameters.Add(new CodeParameterDeclarationExpression(info.DataType, info.FormalName));
94      string code = myCode + "\r\n" + "return null;";
95      method.Statements.Add(new CodeSnippetStatement(code));
96      typeDecl.Members.Add(method);
97
98      ns.Types.Add(typeDecl);
99      ns.Imports.Add(new CodeNamespaceImport("System"));
100      ns.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
101      ns.Imports.Add(new CodeNamespaceImport("System.Text"));
102      ns.Imports.Add(new CodeNamespaceImport("System.Linq"));
103      ns.Imports.Add(new CodeNamespaceImport("System.Data.Linq"));
104      ns.Imports.Add(new CodeNamespaceImport("HeuristicLab.Core"));
105      foreach (IVariableInfo variableInfo in VariableInfos)
106        ns.Imports.Add(new CodeNamespaceImport(variableInfo.DataType.Namespace));
107
108      CodeCompileUnit unit = new CodeCompileUnit();
109      unit.Namespaces.Add(ns);
110      CompilerParameters parameters = new CompilerParameters();
111      parameters.GenerateExecutable = false;
112      parameters.GenerateInMemory = true;
113      parameters.IncludeDebugInformation = false;
114      Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
115      foreach (Assembly loadedAssembly in loadedAssemblies)
116        parameters.ReferencedAssemblies.Add(loadedAssembly.Location);
117      parameters.ReferencedAssemblies.Add(typeof(Enumerable).Assembly.Location); // add reference to version 3.5 of System.dll
118      parameters.ReferencedAssemblies.Add(typeof(DataContext).Assembly.Location); // add reference System.Data.Linq.Dll
119      CodeDomProvider provider = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });  // support C# 3.0 syntax
120      CompilerResults results = provider.CompileAssemblyFromDom(parameters, unit);
121
122      executeMethod = null;
123      if (results.Errors.HasErrors) {
124        StringWriter writer = new StringWriter();
125        CodeGeneratorOptions options = new CodeGeneratorOptions();
126        options.BlankLinesBetweenMembers = false;
127        options.ElseOnClosing = true;
128        options.IndentString = "  ";
129        provider.GenerateCodeFromCompileUnit(unit, writer, options);
130        writer.Flush();
131        string[] source = writer.ToString().Split(new string[] { "\r\n" }, StringSplitOptions.None);
132        StringBuilder builder = new StringBuilder();
133        for (int i = 0; i < source.Length; i++)
134          builder.AppendLine((i + 3).ToString("###") + "     " + source[i]);
135        builder.AppendLine();
136        builder.AppendLine();
137        builder.AppendLine();
138        foreach (CompilerError error in results.Errors) {
139          builder.Append("Line " + error.Line.ToString());
140          builder.Append(", Column " + error.Column.ToString());
141          builder.AppendLine(": " + error.ErrorText);
142        }
143        throw new Exception("Compile Errors:\n\n" + builder.ToString());
144      } else {
145        Assembly assembly = results.CompiledAssembly;
146        Type[] types = assembly.GetTypes();
147        executeMethod = types[0].GetMethod("Execute");
148      }
149    }
150
151    public override IItem Clone(ICloner cloner) {
152      ProgrammableOperator clone = (ProgrammableOperator)base.Clone(cloner);
153      clone.myDescription = Description;
154      clone.myCode = Code;
155      clone.executeMethod = executeMethod;
156      return clone;
157    }
158
159    public override IOperation Apply(IScope scope) {
160      lock (syncRoot) {
161        if (executeMethod == null) {
162          Compile();
163        }
164      }
165
166      // collect parameters
167      object[] parameters = new object[VariableInfos.Count + 2];
168      parameters[0] = this;
169      parameters[1] = scope;
170      int i = 2;
171      foreach (IVariableInfo info in VariableInfos) {
172        if ((info.Kind & VariableKind.New) == VariableKind.New) {
173          parameters[i] = GetVariableValue(info.FormalName, scope, false, false);
174          if (parameters[i] == null) {
175            IItem value = (IItem)Activator.CreateInstance(info.DataType);
176            if (info.Local) {
177              AddVariable(new Variable(info.ActualName, value));
178            } else {
179              scope.AddVariable(new Variable(scope.TranslateName(info.FormalName), value));
180            }
181            parameters[i] = value;
182          }
183        } else
184          parameters[i] = GetVariableValue(info.FormalName, scope, true);
185        i++;
186      }
187
188      return (IOperation)executeMethod.Invoke(null, parameters);
189    }
190
191    public event EventHandler DescriptionChanged;
192    protected virtual void OnDescriptionChanged() {
193      if (DescriptionChanged != null)
194        DescriptionChanged(this, new EventArgs());
195    }
196    public event EventHandler CodeChanged;
197    protected virtual void OnCodeChanged() {
198      if (CodeChanged != null)
199        CodeChanged(this, new EventArgs());
200    }
201  }
202}
Note: See TracBrowser for help on using the repository browser.