秋声赋
[IronRuby]分享自己用的IronRuby脚本引擎类

本帖最后由 秋声赋 于 2012-8-8 21:57 编辑

[mw_shl_code=csharp,true]using System;

using System.Collections.Generic;

using System.IO;

using System.IO.IsolatedStorage;

using System.Text.RegularExpressions;

using System.Xml.Serialization;

using IronRuby;

using IronRuby.StandardLibrary.BigDecimal;

using Microsoft.Scripting;

using Microsoft.Scripting.Hosting;

using Runa.WPF.Content;

namespace ScriptingHost

{

public class RuntimeErrorEventArgs : EventArgs

{

public Exception Error { get; set; }

public RuntimeErrorEventArgs()

: base()

{

}

public RuntimeErrorEventArgs(Exception e)

{

this.Error = e;

}

}

public class CompilationErrorEventArgs : EventArgs

{

public ScriptSource ScriptSource { get; set; }

public string Message { get; set; }

public SourceSpan SourceSpan { get; set; }

public int ErrorCode { get; set; }

public Severity Severity { get; set; }

public CompilationErrorEventArgs(Microsoft.Scripting.Hosting.ScriptSource source, string message, Microsoft.Scripting.SourceSpan span, int errorCode, Microsoft.Scripting.Severity severity)

{

this.ScriptSource = source;

this.Message = message;

this.SourceSpan = span;

this.ErrorCode = errorCode;

this.Severity = severity;

}

}

public class CompilationErrorListener : Microsoft.Scripting.Hosting.ErrorListener

{

public EventHandler *本站禁止HTML标签噢* Handler { get; set; }

public CompilationErrorListener(EventHandler *本站禁止HTML标签噢* handler)

{

this.Handler = handler;

}

public override void ErrorReported(Microsoft.Scripting.Hosting.ScriptSource source, string message, Microsoft.Scripting.SourceSpan span, int errorCode, Microsoft.Scripting.Severity severity)

{

this.Handler.Invoke(this, new CompilationErrorEventArgs(source, message, span, errorCode, severity));

}

}

public class ScriptTask

{

public string Name { get; set; }

public DateTime CommitTime { get; set; }

public string ScriptType { get; set; }

public object Result { get; set; }

public Exception LastError { get; set; }

public string Script

{

get { return this.m_script; }

set

{

this.m_script = value;

if (string.IsNullOrEmpty(this.m_script))

{

return;

}

else

{

if (this.ScriptScope == null)

{

this.ScriptScope = ScriptTask.Engine.CreateScriptSourceFromString(this.Script);

this.CompiledCode = this.ScriptScope.Compile(new CompilationErrorListener(OnCompilationFailed));

}

}

}

}

public static ScriptEngine Engine { get; set; }

private ScriptSource ScriptScope { get; set; }

private CompiledCode CompiledCode { get; set; }

private string m_script = "";

private Dictionary<string, Tuple<ScriptSource, CompiledCode>> m_compiledCodes = new Dictionary<string, Tuple<ScriptSource, CompiledCode>>();

public event OnRuntimeErrorEventHandler OnRuntimeError;

public delegate void OnRuntimeErrorEventHandler(object sender, RuntimeErrorEventArgs e);

public event OnCompilationErrorEventHandler OnCompilationError;

public delegate void OnCompilationErrorEventHandler(object sender, CompilationErrorEventArgs e);

public ScriptTask(string code = "")

{

if (ScriptTask.Engine == null)

{

ScriptTask.Engine = Ruby.CreateEngine();

}

this.LoadAssembly(typeof(BigDecimal).Assembly);

this.Script = code;

this.GlobalVariablesName = new List *本站禁止HTML标签噢* ();

}

public void LoadAssembly(System.Reflection.Assembly assembly)

{

Engine.Runtime.LoadAssembly(assembly);

}

public void LoadScriptFromIsolatedStorage(string path, IsolatedStorageFile fileStorage)

{

try

{

using (var fs = fileStorage.OpenFile(path, FileMode.Open))

{

using (System.IO.StreamReader sr = new System.IO.StreamReader(fs))

{

this.Script = sr.ReadToEnd();

sr.Close();

}

fs.Close();

}

this.AddBasicReference(this);

}

catch (Exception ex)

{

throw ex;

}

}

public bool Execute(params WpfApplication4.Tuple<string, object>[] args)

{

try

{

if (string.IsNullOrEmpty(this.Script))

{

return false;

}

else

{

while (true)

{

if (this.ScriptScope != null)

{

if (this.ScriptScope.GetCode() == this.Script)

{

break; // TODO: might not be correct. Was : Exit While

}

}

this.ScriptScope = ScriptTask.Engine.CreateScriptSourceFromString(this.Script);

this.CompiledCode = this.ScriptScope.Compile(new CompilationErrorListener(OnCompilationFailed));

break; // TODO: might not be correct. Was : Exit While

}

}

foreach (var v in args)

{

this.CompiledCode.Engine.Runtime.Globals.SetVariable(v.Item1, v.Item2);

}

this.Result = this.CompiledCode.Execute();

return true;

}

catch (Exception ex)

{

this.LastError = ex;

if (OnRuntimeError != null)

{

OnRuntimeError(this, new RuntimeErrorEventArgs(ex));

}

return false;

}

}

public bool Execute(string expression, params WpfApplication4.Tuple<string, object>[] args)

{

try

{

if (string.IsNullOrEmpty(this.m_script))

{

throw new ArgumentException("Null or empty script to execute.");

return false;

}

else

{

if (string.IsNullOrEmpty(expression) == false)

{

var code = this.m_script + Environment.NewLine + expression;

while (true)

{

if (this.m_compiledCodes.ContainsKey(code))

{

if (this.m_compiledCodes[code].Item1.GetCode() == code)

{

this.CompiledCode = this.m_compiledCodes[code].Item2;

break; // TODO: might not be correct. Was : Exit While

}

}

this.ScriptScope = ScriptTask.Engine.CreateScriptSourceFromString(code);

this.CompiledCode = this.ScriptScope.Compile(new CompilationErrorListener(OnCompilationFailed));

this.m_compiledCodes.Add(code, new Tuple<ScriptSource, CompiledCode>(this.ScriptScope, this.CompiledCode));

break; // TODO: might not be correct. Was : Exit While

}

}

else

{

throw new ArgumentException("Null or empty expression to execute.");

return false;

}

}

foreach (var v in args)

{

this.CompiledCode.Engine.Runtime.Globals.SetVariable(v.Item1, v.Item2);

}

CheakGlobalsName(expression);

this.Result = this.CompiledCode.Execute();

return true;

}

catch (Exception ex)

{

this.LastError = ex;

if (OnRuntimeError != null)

{

OnRuntimeError(this, new RuntimeErrorEventArgs(ex));

}

return false;

}

}

private void OnCompilationFailed(object sender, CompilationErrorEventArgs e)

{

if (OnCompilationError != null)

{

OnCompilationError(sender, e);

}

}

private void AddBasicReference(ScriptTask spt)

{

var _with1 = spt;

_with1.LoadAssembly(this.GetType().Assembly);

}

//========上面是Long写好给我的,稍微修改了下,本来会判断Ruby还是Python的

//========但是目前引擎还不会使用Python,所以我就删掉了

//========下面是我自己写的,用来保存那些全局变量的

//========能保存全局变量的话,就能做存档功能了

//========SerializableDictionary是自己写的能序列化的字典

public List *本站禁止HTML标签噢* GlobalVariablesName

{ get; set; }

private void CheakGlobalsName(string code)

{

if (code.Contains("$") && code.Contains("="))

{

code = code.Replace(" ", "");

int index = code.IndexOf('$');

int endindex = code.IndexOf('=');

if (index < endindex)

{

string pattern = @"^[A-Za-z0-9$]+$";

Regex regex = new Regex(pattern);

if (regex.IsMatch(code.Substring(index, endindex)))

{

GlobalVariablesName.Add(code.Substring(index, endindex));

}

}

}

}

public System.Collections.Generic.Dictionary<string, string> GetGlobals()

{

System.Collections.Generic.Dictionary<string, string> result = new Dictionary<string, string>();

for (int i = 0; i < this.GlobalVariablesName.Count; i++)

{

var ex = "return " + this.GlobalVariablesName;

this.Execute(ex);

if (this.Result.GetType() == typeof(IronRuby.Builtins.MutableString))

{

result.Add(this.GlobalVariablesName, "\""+this.Result.ToString()+"\"");

}

else

{

result.Add(this.GlobalVariablesName, this.Result.ToString());

}

}

return result;

}

public void SaveGlobals(Stream fs)

{

SerializableDictionary<string, string> r = new SerializableDictionary<string, string>(this.GetGlobals());

XmlSerializer xs = new XmlSerializer(r.GetType());

xs.Serialize(fs, r);

fs.Close();

}

public void LoadGlobale(Stream fs)

{

XmlSerializer xs = new XmlSerializer(typeof(SerializableDictionary<string, string>));

var s= xs.Deserialize(fs) as SerializableDictionary<string, string>;

fs.Close();

foreach (var k in s.Keys)

{

this.Execute(k + "=" + s[k]);

}

}

}

}[/mw_shl_code]

如果有人需要的话,我可以解释下