private static object SetObjectProperty(Context context, Object obj, String name, Object value) { if (obj is ScriptObject) { try { (obj as ScriptObject)[name] = value; } catch (Exception e) { context.RaiseNewError("System Exception: " + e.Message, context.currentNode); } } else { var field = obj.GetType().GetField(ScriptObject.AsString(name)); if (field != null) field.SetValue(obj, value); else { var prop = obj.GetType().GetProperty(ScriptObject.AsString(name)); if (prop != null) prop.SetValue(obj, value, null); } } return value; }
private Function defunImple(Context context, ScriptList arguments, bool addToScope) { var functionName = ArgumentType<String>(arguments[0]); List<ArgumentInfo> argumentInfo = null; try { argumentInfo = ArgumentInfo.ParseArguments(this, ArgumentType<ScriptList>(arguments[1])); } catch (ScriptError e) { context.RaiseNewError(e.Message, context.currentNode); return null; } var functionBody = ArgumentType<ParseNode>(arguments[2]); var newFunction = new Function( functionName, argumentInfo, "Script-defined function", functionBody, CopyScope(context.Scope)); newFunction.shortHelp = ScriptObject.AsString(arguments[3]); if (addToScope) newFunction.declarationScope.PushVariable(newFunction.name, newFunction); return newFunction; }
private ScriptObject defunImple(Context context, ScriptList arguments, bool addToScope) { var functionName = ArgumentType<String>(arguments[0]); ScriptList argumentInfo = null; try { argumentInfo = ArgumentType<ScriptList>(arguments[1]); } catch (ScriptError e) { context.RaiseNewError(e.Message, context.currentNode); return null; } var functionBody = ArgumentType<ScriptObject>(arguments[2]); var newFunction = Function.MakeFunction( functionName, argumentInfo, "Script-defined function", functionBody, CopyScope(context.Scope)); if (arguments[3] != null) newFunction["@help"] = ScriptObject.AsString(arguments[3]); if (addToScope) (newFunction["declaration-scope"] as Scope).PushVariable(functionName, newFunction); return newFunction; }
public static ScriptObject GetArgumentInfo(ScriptObject func, Context context, int index) { var arguments = func["@arguments"] as ScriptList; if (arguments == null) return null; if (index >= arguments.Count) { if (arguments.Count > 0 && (arguments[arguments.Count - 1] as ScriptObject)["@repeat"] != null) return arguments[arguments.Count - 1] as ScriptObject; else { context.RaiseNewError("Argument out of bounds", null); return null; } } else return arguments[index] as ScriptObject; }
private object LookupToken(Context context, String value) { //value = value.ToLowerInvariant(); if (specialVariables.ContainsKey(value)) return specialVariables[value](context); if (context.Scope.HasVariable(value)) return context.Scope.GetVariable(value); if (functions.ContainsKey(value)) return functions[value]; if (value.StartsWith("@") && functions.ContainsKey(value.Substring(1))) return functions[value.Substring(1)]; context.RaiseNewError("Could not find value with name " + value + " in this context.", context.currentNode); return null; }
private void evaluateNodeChild(bool callFunction, Object child, ScriptList arguments, Context context) { bool lazyArgument = false; var prefix = (child as ScriptObject).gsp("@prefix"); if (callFunction && arguments.Count > 0 && (Function.IsFunction(arguments[0] as ScriptObject))) { var argumentInfo = Function.GetArgumentInfo(arguments[0] as ScriptObject, context, arguments.Count - 1); if (context.evaluationState != EvaluationState.Normal) return; lazyArgument = argumentInfo["@lazy"] != null; } if (lazyArgument && prefix != ":" && prefix != "#") arguments.Add(child); else { var argument = Evaluate(context, child); if (context.evaluationState != EvaluationState.Normal) return; if (prefix == "$" && argument is ScriptList) arguments.AddRange(argument as ScriptList); else arguments.Add(argument); } }
public Object EvaluateString(Context context, String str, String fileName, bool discardResults = false) { try { var root = Parser.ParseRoot(str, fileName); return Evaluate(context, root, false, discardResults); } catch (Exception e) { context.RaiseNewError("System Exception: " + e.Message, null); return null; } }
public Object Evaluate( Context context, Object what, bool ignoreStar = false, bool discardResults = false) { if (context.evaluationState != EvaluationState.Normal) throw new ScriptError("Invalid Context", null); if (context.callDepth >= context.maximumCallDepth) { context.RaiseNewError("Overflow.", null); return null; } context.callDepth += 1; //All exit points must decrement depth. if (what is String) { var r = EvaluateString(context, what as String, "", discardResults); context.callDepth -= 1; return r; } else if (!(what is ScriptObject)) { context.callDepth -= 1; return what; } var node = what as ScriptObject; context.currentNode = node; if (context.limitExecutionTime && (DateTime.Now - context.executionStart > context.allowedExecutionTime)) { context.RaiseNewError("Timeout.", node); context.callDepth -= 1; return null; } if (node.gsp("@prefix") == "*" && !ignoreStar) //Object is a quoted node { context.callDepth -= 1; return node; } var type = node.gsp("@type"); if (String.IsNullOrEmpty(type)) { context.callDepth -= 1; return node; } //Object is not evaluatable code. object result = null; if (type == "string") { result = node["@token"]; } else if (type == "stringexpression") { if (discardResults) //Don't bother assembling the string expression. { foreach (var piece in node._children) { if ((piece as ScriptObject).gsp("@type") == "string") continue; else { Evaluate(context, piece); if (context.evaluationState != EvaluationState.Normal) { context.callDepth -= 1; return null; } } } result = null; } else { if (node._children.Count == 1) //If there's only a single item, the result is that item. { result = Evaluate(context, node._child(0)); if (context.evaluationState != EvaluationState.Normal) { context.callDepth -= 1; return null; } } else { var resultString = String.Empty; foreach (var piece in node._children) { resultString += ScriptObject.AsString(Evaluate(context, piece)); if (context.evaluationState != EvaluationState.Normal) { context.callDepth -= 1; return null; } } result = resultString; } } } else if (type == "token") { result = LookupToken(context, node.gsp("@token")); if (context.evaluationState != EvaluationState.Normal) { context.callDepth -= 1; return null; } } else if (type == "memberaccess") { var lhs = Evaluate(context, node._child(0)); if (context.evaluationState != EvaluationState.Normal) { context.callDepth -= 1; return null; } String rhs = ""; if ((node._child(1) as ScriptObject).gsp("@type") == "token") rhs = (node._child(1) as ScriptObject).gsp("@token"); else rhs = ScriptObject.AsString(Evaluate(context, node._child(1), false)); if (context.evaluationState != EvaluationState.Normal) { context.callDepth -= 1; return null; } if (lhs == null) result = null; else if (lhs is ScriptObject) { result = (lhs as ScriptObject).GetProperty(ScriptObject.AsString(rhs)); if (node.gsp("@token") == ":") { context.Scope.PushVariable("this", lhs); result = Evaluate(context, result, true, false); context.Scope.PopVariable("this"); if (context.evaluationState != EvaluationState.Normal) { context.callDepth -= 1; return null; } } } else { var field = lhs.GetType().GetField(ScriptObject.AsString(rhs)); if (field != null) result = field.GetValue(lhs); else { var prop = lhs.GetType().GetProperty(ScriptObject.AsString(rhs)); if (prop != null) result = prop.GetValue(lhs, null); else { var members = lhs.GetType().FindMembers(System.Reflection.MemberTypes.Method, System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance, new System.Reflection.MemberFilter((minfo, obj) => { return minfo.Name == obj.ToString(); }), ScriptObject.AsString(rhs)); if (members.Length != 0) { result = new GenericScriptObject( "@lazy-reflection", ScriptObject.AsString(rhs), "@source-object", lhs, "@source-type", lhs.GetType()); } else result = null; } } } } else if (type == "node") { if (!ignoreStar && node.gsp("@prefix") == "*") { result = node; } else { bool eval = node.gsp("@prefix") != "^"; var arguments = new ScriptList(); foreach (var child in node._children) { evaluateNodeChild(eval, child, arguments, context); if (context.evaluationState != EvaluationState.Normal) { context.callDepth -= 1; return null; } } if (node.gsp("@prefix") == "^") result = arguments; else { if (arguments.Count > 0 && Function.IsFunction(arguments[0] as ScriptObject)) { result = Function.Invoke((arguments[0] as ScriptObject), this, context, new ScriptList(arguments.GetRange(1, arguments.Count - 1))); if (context.evaluationState != EvaluationState.Normal) { if (context.evaluationState == EvaluationState.UnwindingError) context.PushStackTrace((arguments[0] as ScriptObject).gsp("@name")); context.callDepth -= 1; return null; } } else if (arguments.Count > 0 && arguments[0] is ScriptObject && (arguments[0] as ScriptObject).GetProperty("@lazy-reflection") != null) { var sObj = arguments[0] as ScriptObject; var argumentTypes = arguments.GetRange(1, arguments.Count - 1).Select( (obj) => obj.GetType()).ToArray(); var sourceObject = sObj.GetProperty("@source-object"); var method = (sObj.GetProperty("@source-type") as System.Type) .GetMethod(sObj.gsp("@lazy-reflection"), argumentTypes); if (method == null) throw new ScriptError("Could not find overload for " + sObj.gsp("@lazy-reflection") + " that takes argument types " + String.Join(", ", argumentTypes.Select((t) => t.Name)) + " on type " + sObj.GetProperty("@source-type").ToString(), what as ScriptObject); result = method.Invoke(sourceObject, arguments.GetRange(1, arguments.Count - 1).ToArray()); } else if (arguments.Count > 0) result = arguments[0]; else result = null; } } } else if (type == "root") { var results = new ScriptList(); foreach (var child in node._children) { results.Add(Evaluate(context, child, false, false)); if (context.evaluationState != EvaluationState.Normal) { context.callDepth -= 1; return null; } } return results; } else if (type == "number") { try { if (node.gsp("@token").Contains('.')) result = Convert.ToSingle(node.gsp("@token")); else result = Convert.ToInt32(node.gsp("@token")); } catch (Exception e) { context.RaiseNewError("Number format error.", node); { context.callDepth -= 1; return null; } } } else if (type == "char") { context.callDepth -= 1; return node.gsp("@token")[0]; } else { context.RaiseNewError("Internal evaluator error.", node); { context.callDepth -= 1; return null; } } if (node.gsp("@prefix") == ":" && !ignoreStar) result = Evaluate(context, result); if (context.evaluationState != EvaluationState.Normal) { context.callDepth -= 1; return null; }; if (node.gsp("@prefix") == ".") result = LookupToken(context, ScriptObject.AsString(result)); context.callDepth -= 1; return result; }
private void SetupEnvironmentFunctions(Engine mispEngine) { mispEngine.AddFunction("save-environment", "", (context, arguments) => { Engine.ReportSerializationError = (str) => Write(str + "\n"); var file = new System.IO.StreamWriter(arguments[0].ToString()); mispEngine.SerializeEnvironment(file, context.Scope); file.Close(); return true; }, Arguments.Arg("file")); mispEngine.AddFunction("load-environment", "", (context, arguments) => { var newContext = new Context(); var newEngine = new Engine(); PrepareEnvironment(newEngine); if (arguments[2] != null) { newEngine.Evaluate(newContext, arguments[2], true, true); if (newContext.evaluationState == EvaluationState.UnwindingError) { Write("Prime error:\n"); Write(MISP.Console.PrettyPrint2(newContext.errorObject, 0)); return false; } } var result = newEngine.EvaluateString(newContext, System.IO.File.ReadAllText(arguments[0].ToString()), arguments[0].ToString()) as ScriptObject; if (newContext.evaluationState != EvaluationState.UnwindingError) { var environment = AddEnvironment(arguments[1].ToString(), newEngine, newContext); if (environment.name == this.environment.name) this.environment = environment; SetupEnvironmentFunctions(newEngine); var scope = new Scope(); foreach (var prop in result.ListProperties()) scope.PushVariable(prop as String, result.GetLocalProperty(prop as String)); newContext.ReplaceScope(scope); Write("Loaded.\n"); return true; } else { Write("Error:\n"); Write(MISP.Console.PrettyPrint2(newContext.errorObject, 0)); return false; } }, Arguments.Arg("file"), Arguments.Arg("name"), Arguments.Optional(Arguments.Lazy("prime"))); }
public void SetupNewEnvironment(String name) { var mispEngine = new Engine(); var mispContext = new Context(); PrepareEnvironment(mispEngine); var environment = AddEnvironment(name, mispEngine, mispContext); mispContext.limitExecutionTime = false; }
public Environment AddEnvironment(String name, Engine engine, Context context) { environments.Upsert(name, new Environment { engine = engine, context = context, name = name }); return environments[name]; }
public static Object Invoke(ScriptObject func, Engine engine, Context context, ScriptList arguments) { var name = func.gsp("@name"); var argumentInfo = func["@arguments"] as ScriptList; if (context.trace != null) { context.trace(new String('.', context.traceDepth) + "Entering " + name +"\n"); context.traceDepth += 1; } var newArguments = new ScriptList(); //Check argument types if (argumentInfo.Count == 0 && arguments.Count != 0) { context.RaiseNewError("Function expects no arguments.", context.currentNode); return null; } int argumentIndex = 0; for (int i = 0; i < argumentInfo.Count; ++i) { var info = argumentInfo[i] as ScriptObject; if (info == null) throw new ScriptError("Invalid argument descriptor on function object", context.currentNode); if (info["@repeat"] != null) { var list = new ScriptList(); while (argumentIndex < arguments.Count) //Handy side effect: If no argument is passed for an optional repeat { //argument, it will get an empty list. list.Add(MutateArgument(arguments[argumentIndex], info, engine, context)); //list.Add((info["@type"] as Type).ProcessArgument(context, arguments[argumentIndex])); if (context.evaluationState != EvaluationState.Normal) return null; ++argumentIndex; } newArguments.Add(list); } else { if (argumentIndex < arguments.Count) { newArguments.Add(MutateArgument(arguments[argumentIndex], info, engine, context)); //newArguments.Add((info["@type"] as Type).ProcessArgument(context, arguments[argumentIndex])); if (context.evaluationState == EvaluationState.UnwindingError) return null; } else if (info["@optional"] != null) newArguments.Add(MutateArgument(null, info, engine, context)); else { context.RaiseNewError("Not enough arguments to " + name, context.currentNode); return null; } ++argumentIndex; } } if (argumentIndex < arguments.Count) { context.RaiseNewError("Too many arguments to " + name, context.currentNode); return null; } Object r = null; if (func["@function-body"] is ScriptObject) { var declarationScope = func["@declaration-scope"]; if (declarationScope is GenericScriptObject) { var newScope = new Scope(); foreach (var valueName in (declarationScope as GenericScriptObject).properties) newScope.PushVariable(valueName.Key, valueName.Value); func["@declaration-scope"] = newScope; } context.PushScope(func["@declaration-scope"] as Scope); for (int i = 0; i < argumentInfo.Count; ++i) context.Scope.PushVariable((argumentInfo[i] as ScriptObject).gsp("@name"), newArguments[i]); r = engine.Evaluate(context, func["@function-body"], true); for (int i = 0; i < argumentInfo.Count; ++i) context.Scope.PopVariable((argumentInfo[i] as ScriptObject).gsp("@name")); context.PopScope(); } else { try { r = (func["@function-body"] as Func<Context, ScriptList, Object>)(context, newArguments); } catch (Exception e) { context.RaiseNewError("System Exception: " + e.Message, context.currentNode); return null; } } if (context.trace != null) { context.traceDepth -= 1; context.trace(new String('.', context.traceDepth) + "Leaving " + name + (context.evaluationState == EvaluationState.UnwindingError ? (" -Error: " + context.errorObject.GetLocalProperty("message").ToString()) : "") + (context.evaluationState == EvaluationState.UnwindingBreak ? " -Breaking" : "") + "\n"); } return r; }
private static Object MutateArgument(Object argument, ScriptObject argumentDescripter, Engine engine, Context context) { var mutator = argumentDescripter["@mutator"]; if (mutator == null) return argument; context.Scope.PushVariable("value", argument); var result = engine.Evaluate(context, mutator, true); context.Scope.PopVariable("value"); return result; }