/// <summary> /// Loads a script from disk. /// Returns null if the script does not exist. /// </summary> /// <param name="path">The path to the script, including the filename but not the extension.</param> /// <returns></returns> public static PythonScript Load(string path) { var scriptFilename = Path.Combine(path + ".script"); var pythonFilename = Path.Combine(path + ".py"); var moduleName = Path.GetFileName(path); if (!File.Exists(pythonFilename)) { return(null); } var text = File.ReadAllText(pythonFilename); var externalScripts = new List <PythonScript>(); if (File.Exists(scriptFilename)) { foreach (var externalScriptPath in File.ReadAllLines(scriptFilename)) { var externalScript = PythonScript.Load(externalScriptPath); if (externalScript == null) { throw new ScriptException("Cannot find script file: " + Path.GetFullPath(externalScriptPath + ".py")); } externalScripts.Add(externalScript); } } return(new PythonScript(moduleName, text, externalScripts.ToArray())); }
/// <summary> /// Compiles and caches a script, or returns the cached script if it exists. /// </summary> /// <param name="source">The script to search for.</param> /// <returns>The compiled code.</returns> private static CompiledCode GetCompiledScript(PythonScript source) { if (!compiledScripts.ContainsKey(source)) { compiledScripts.Add(source, Compile(source)); } return(compiledScripts[source]); }
/// <summary> /// Calls a script function. /// </summary> /// <param name="script">The script containing the function.</param> /// <param name="function">The name of the function.</param> /// <param name="args">Arguments to pass to the function.</param> /// <returns>The return value.</returns> public static T CallFunction <T>(PythonScript script, string function, params object[] args) { var preCode = new List <string>(); preCode.Add("from FrEee.Modding import Mod;"); preCode.Add("if not galaxy is None:"); preCode.Add("\tMod.Current = galaxy.Mod;"); var arglist = new List <string>(); for (var i = 0; i < args.Length; i++) { arglist.Add("arg" + i); } var code = string.Join("\n", preCode.ToArray()) + "\n" + script.ModuleName + "." + function + "(" + string.Join(", ", arglist) + ")"; var variables = args.ToDictionary(arg => "arg" + args.IndexOf(arg)); var sc = new ScriptCode("functionCall", code, new PythonScript[] { script }.Concat(script.ExternalScripts).ToArray()); var functionCall = GetCodeScript(sc); var compiledScript = GetCompiledScript(functionCall); UpdateScope(variables); try { return(compiledScript.Execute <T>(scope)); } catch (Exception ex) { if (ex.Data.Values.Count > 0) { dynamic info = ex.Data.Values.Cast <dynamic>().First(); var debugInfo = info[0].DebugInfo; if (debugInfo != null) { int startLine = debugInfo.StartLine; int endLine = debugInfo.StartLine; throw new ScriptException(ex, string.Join("\n", functionCall.FullText.Split('\n').Skip(startLine - 1).Take(endLine - startLine + 1).ToArray())); } else { throw new ScriptException(ex, "(unknown code)"); } } else { throw new ScriptException(ex, "(unknown code)"); } } }
public ObjectFormula <T> CreateReferenceEnumerableFormula <T>(object context) where T : IReferenceEnumerable { var typename = typeof(T).Name; if (typename.Contains("`")) { typename = typename.Substring(0, typename.IndexOf('`')); } var f = new ObjectFormula <T>($"{typename}[{string.Join(", ", typeof(T).GetGenericArguments().Select(x => x.Name).ToArray())}]({Value.TrimStart('=')})", context, true); var import = $"from {typeof(T).Namespace} import {typename};"; var imports = new List <string>(); imports.Add(import); foreach (var genparm in typeof(T).GetGenericArguments()) { var typename2 = genparm.Name; if (typename2.Contains("`")) { typename2 = typename.Substring(0, typename2.IndexOf('`')); } imports.Add($"from {genparm.Namespace} import {typename2};"); } var script = new PythonScript("Import", string.Join("\n", imports)); if (f.ExternalScripts == null) { f.ExternalScripts = new PythonScript[] { script } } ; else { f.ExternalScripts = f.ExternalScripts.Append(script).ToArray(); } return(f); }
/// <summary> /// Runs a script. /// </summary> /// <param name="script">The script code to run.</param> /// <param name="variables">Read/write variables to inject into the script.</param> /// <param name="readOnlyVariables">Read-only variables to inject into the script.</param> public static void RunScript(PythonScript script, IDictionary <string, object> variables = null, IDictionary <string, object> readOnlyVariables = null) { var preCommands = new List <string>(); var postCommands = new List <string>(); preCommands.Add("import clr"); preCommands.Add("clr.AddReference('System.Core')"); preCommands.Add("import System"); preCommands.Add("clr.ImportExtensions(System.Linq)"); preCommands.Add("clr.AddReference('FrEee.Core')"); preCommands.Add("import FrEee"); preCommands.Add("import FrEee.Utility"); preCommands.Add("clr.ImportExtensions(FrEee.Utility.Extensions)"); preCommands.Add("from FrEee.Modding import Mod"); preCommands.Add("from FrEee.Game.Objects.Space import Galaxy"); preCommands.Add("from FrEee.Game.Objects.Civilization import Empire"); var code = string.Join("\n", preCommands.ToArray()) + "\n" + script.Text + "\n" + string.Join("\n", postCommands.ToArray()); var external = new List <PythonScript>(script.ExternalScripts); if (Mod.Current != null) { external.Add(Mod.Current.GlobalScript); } var sc = new ScriptCode("runner", code, external.ToArray()); var runner = GetCodeScript(sc); var compiledScript = GetCompiledScript(runner); var allVariables = new Dictionary <string, object>(); if (variables != null) { foreach (var v in variables) { allVariables.Add(v.Key, v.Value); } } if (readOnlyVariables != null) { foreach (var v in readOnlyVariables) { allVariables.Add(v.Key, v.Value); } } UpdateScope(allVariables); try { compiledScript.Execute(scope); if (variables != null) { var newvals = RetrieveVariablesFromScope(scope, variables.Keys); foreach (var kvp in variables) { newvals[kvp.Key].CopyTo(kvp.Value); } } } catch (Exception ex) { if (ex.Data.Values.Count > 0) { Array info = ex.Data.Values.Cast <dynamic>().First(); var debugInfo = info.Cast <dynamic>().FirstOrDefault(o => o.DebugInfo != null)?.DebugInfo; if (debugInfo != null) { int startLine = debugInfo.StartLine; int endLine = debugInfo.StartLine; throw new ScriptException(ex, string.Join("\n", runner.FullText.Split('\n').Skip(startLine - 1).Take(endLine - startLine + 1).ToArray())); } else { throw new ScriptException(ex, "(unknown code)"); } } else { throw new ScriptException(ex, "(unknown code)"); } } }
/// <summary> /// Evaluates a script expression. /// </summary> /// <param name="expression">The script code to run.</param> /// <param name="readOnlyVariables">Variables to inject into the script.</param> /// <returns>Any .</returns> public static T EvaluateExpression <T>(string expression, IDictionary <string, object> readOnlyVariables = null) { var script = new PythonScript("expression", expression); return(RunScript <T>(script, null, readOnlyVariables)); }
/// <summary> /// Compiles a script. /// </summary> /// <returns></returns> public static CompiledCode Compile(PythonScript script) { var compiledScript = engine.CreateScriptSourceFromString(script.FullText); return(compiledScript.Compile()); }