/// <summary> /// <para>执行一个Python脚本文件,它拥有访问和修改引擎公共上下文的能力</para> /// <para>此方法使用互斥锁保证线程安全,因此同一时刻此方法只能被一个线程所执行</para> /// </summary> /// <param name="pyPath">要执行的Python命令</param> /// <param name="ctx">上下文</param> /// <returns>执行的结果</returns> public static dynamic ExecuteFile(string pyPath, EvaluatableContext ctx) { dynamic execResult = null; try { lock (YuririWorld.executionMutex) { ScriptScope scope = YuririWorld.contextEngine.CreateScope(); foreach (var kvp in ctx.GetSymbols()) { scope.SetVariable(kvp.Key, kvp.Value); } scope.SetVariable("_YuririReflector_", new YuririReflector()); ScriptSource script = YuririWorld.contextEngine.CreateScriptSourceFromFile(IOUtils.ParseURItoURL(pyPath)); execResult = script.Execute(scope); } } catch (Exception ex) { LogUtils.AsyncLogLine("Execute isolation python file failed. " + ex, "YuririWorld", YuririWorld.consoleMutex, LogLevel.Error); } return(execResult); }
/// <summary> /// <para>为Python脚本字符串创建一个与其他脚本以及游戏运行时环境隔离性的上下文并执行它</para> /// </summary> /// <param name="pyExpr">要执行的Python命令</param> /// <param name="ctx">上下文</param> /// <returns>执行的结果</returns> public static dynamic ExecuteIsolation(string pyExpr, EvaluatableContext ctx) { try { ScriptEngine engine = Python.CreateEngine(); ScriptScope scope = engine.CreateScope(); foreach (var kvp in ctx.GetSymbols()) { scope.SetVariable(kvp.Key, kvp.Value); } ScriptSource script = engine.CreateScriptSourceFromString(pyExpr); return(script.Execute(scope)); } catch (Exception ex) { LogUtils.AsyncLogLine("Execute isolation python script failed. " + ex, "YuririWorld", YuririWorld.consoleMutex, LogLevel.Error); } return(null); }
/// <summary> /// 计算表达式的真值 /// </summary> /// <param name="polish">表达式字符串</param> /// <param name="ctx">求值上下文</param> /// <returns>表达式的真值</returns> public bool EvalBoolean(string polish, EvaluatableContext ctx) { return(Convert.ToBoolean(this.Eval(polish, ctx))); }
/// <summary> /// 将逆波兰式转化为可计算的项 /// </summary> /// <param name="polish">逆波兰式字符串</param> /// <param name="vsm">关于哪个调用堆栈做动作</param> /// <returns>可计算项目向量</returns> private static List <PolishItem> GetPolishItemList(string polish, StackMachine vsm, EvaluatableContext ctx) { var resVec = new List <PolishItem>(); var polishItem = polish.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); foreach (string item in polishItem) { PolishItem poi = null; Regex floatRegEx = new Regex(@"^(\-|\+)?\d+(\.\d+)?$"); // 常数项 if (floatRegEx.IsMatch(item)) { double numitem = Convert.ToDouble(item); poi = new PolishItem() { Number = numitem, Cluster = null, ItemType = PolishItemType.CONSTANT, Reference = numitem }; } // 字符串 else if (item.StartsWith("\"") && item.EndsWith("\"")) { string trimItem = item.Substring(1, item.Length - 2); poi = new PolishItem() { Number = 0.0f, Cluster = trimItem, ItemType = PolishItemType.STRING, Reference = trimItem }; } // 变量时 else if ((item.StartsWith("&") || item.StartsWith("$") || item.StartsWith("%")) && item.Length > 1) { object varRef = ctx != null?ctx.Fetch(item.Substring(1)) : Director.RunMana.Fetch(item, vsm); if (varRef is ValueType) { poi = new PolishItem() { Number = Convert.ToDouble(varRef), Cluster = null, ItemType = PolishItemType.VAR_NUM, Reference = varRef }; } else { poi = new PolishItem() { Number = 0.0f, Cluster = Convert.ToString(varRef), ItemType = PolishItemType.VAR_STRING, Reference = varRef }; } } else { switch (item) { case "+": poi = new PolishItem() { Number = 0.0f, Cluster = null, ItemType = PolishItemType.CAL_PLUS, Reference = null }; break; case "-": poi = new PolishItem() { Number = 0.0f, Cluster = null, ItemType = PolishItemType.CAL_MINUS, Reference = null }; break; case "*": poi = new PolishItem() { Number = 0.0f, Cluster = null, ItemType = PolishItemType.CAL_MULTI, Reference = null }; break; case "/": poi = new PolishItem() { Number = 0.0f, Cluster = null, ItemType = PolishItemType.CAL_DIV, Reference = null }; break; case "!": poi = new PolishItem() { Number = 0.0f, Cluster = null, ItemType = PolishItemType.CAL_NOT, Reference = null }; break; case "&&": poi = new PolishItem() { Number = 0.0f, Cluster = null, ItemType = PolishItemType.CAL_ANDAND, Reference = null }; break; case "||": poi = new PolishItem() { Number = 0.0f, Cluster = null, ItemType = PolishItemType.CAL_OROR, Reference = null }; break; case "<>": poi = new PolishItem() { Number = 0.0f, Cluster = null, ItemType = PolishItemType.CAL_NOTEQUAL, Reference = null }; break; case "==": poi = new PolishItem() { Number = 0.0f, Cluster = null, ItemType = PolishItemType.CAL_EQUAL, Reference = null }; break; case ">": poi = new PolishItem() { Number = 0.0f, Cluster = null, ItemType = PolishItemType.CAL_BIG, Reference = null }; break; case "<": poi = new PolishItem() { Number = 0.0f, Cluster = null, ItemType = PolishItemType.CAL_SMALL, Reference = null }; break; case ">=": poi = new PolishItem() { Number = 0.0f, Cluster = null, ItemType = PolishItemType.CAL_BIGEQUAL, Reference = null }; break; case "<=": poi = new PolishItem() { Number = 0.0f, Cluster = null, ItemType = PolishItemType.CAL_SMALLEQUAL, Reference = null }; break; } } if (poi != null) { resVec.Add(poi); } } return(resVec); }
/// <summary> /// 计算表达式的值 /// </summary> /// <param name="expr">表达式字符串</param> /// <param name="ctx">求值上下文</param> /// <returns>计算结果的值(Double/字符串)</returns> public object Eval(string expr, EvaluatableContext ctx) { var calcList = PolishEvaluator.GetPolishItemList(expr, null, ctx); return(PolishEvaluator.HandleEval(expr, calcList)); }