public static ScriptObject MakeFunction( String name, ScriptList arguments, String help, ScriptObject body, ScriptObject declarationScope, bool copyScope = false) { if (copyScope) { var newScope = new Scope(); foreach (var prop in declarationScope.ListProperties()) { newScope.PushVariable(prop as String, declarationScope.GetLocalProperty(prop as String)); } declarationScope = newScope; } return(new GenericScriptObject( "@name", name, "@arguments", arguments, "@help", help, "@function-body", body, "@declaration-scope", declarationScope)); }
public static ScriptObject GenerateMethodBinding(System.Reflection.MethodInfo method) { ScriptList boundArguments = new ScriptList(); if (!method.IsStatic) { boundArguments.Add(Arguments.Arg("object")); } foreach (var parameter in method.GetParameters()) { if (parameter.IsOptional) { boundArguments.Add(Arguments.Optional(parameter.Name, parameter.ParameterType.Name)); } else { boundArguments.Add(Arguments.Arg(parameter.Name, parameter.ParameterType.Name)); } } return(Function.MakeSystemFunction(method.Name, boundArguments, "Auto bound function", (context, arguments) => { var parameters = method.GetParameters(); int start = method.IsStatic ? 0 : 1; var args = new object[arguments.Count - start]; for (int i = 0; i < arguments.Count - start; ++i) { args[i] = Convert.ChangeType(arguments[i + start], parameters[i].ParameterType); } return method.Invoke(method.IsStatic ? null : arguments[0], args); })); }
override public ScriptList ListProperties() { var r = new ScriptList(); r.AddRange(this.GetType().GetFields().Select((info) => info.Name)); r.AddRange(properties.Select((p) => p.Key)); return(r); }
private static ScriptList children(ScriptObject obj) { var list = obj["@children"]; if (list == null) { list = new ScriptList(); obj["@children"] = list; } return(list as ScriptList); }
public static ScriptObject MakeSystemFunction( String name, ScriptList arguments, String help, Func <Context, ScriptList, Object> func) { return(new GenericScriptObject( "@name", name, "@arguments", arguments, "@help", help, "@function-body", func)); }
public static ScriptList Args(params Object[] objs) { var r = new ScriptList(); foreach (var obj in objs) { if (obj is ScriptObject) { r.Add(obj); } else if (obj is String) { r.Add(Arg(obj.ToString())); } else { throw new InvalidProgramException(); } } return(r); }
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); }
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); } } }
private void SetupLoopFunctions() { AddFunction("map", "variable_name list code : Transform one list into another", (context, arguments) => { var vName = ArgumentType <String>(arguments[0]); var list = ArgumentType <System.Collections.IEnumerable>(arguments[1]); var code = ArgumentType <ScriptObject>(arguments[2]); var result = new ScriptList(); context.Scope.PushVariable(vName, null); foreach (var item in list) { context.Scope.ChangeVariable(vName, item); result.Add(Evaluate(context, code, true)); if (context.evaluationState == EvaluationState.UnwindingBreak) { context.Scope.PopVariable(vName); return(context.UnBreak()); } } context.Scope.PopVariable(vName); return(result); }, Arguments.Mutator(Arguments.Lazy("variable-name"), "(@identifier value)"), Arguments.Arg("in"), Arguments.Lazy("code")); AddFunction("mapi", "Like map, except the variable will hold the index.", (context, arguments) => { var vName = ArgumentType <String>(arguments[0]); var from = AutoBind.IntArgument(arguments[1]); var to = AutoBind.IntArgument(arguments[2]); var code = ArgumentType <ScriptObject>(arguments[3]); var result = new ScriptList(); context.Scope.PushVariable(vName, null); for (int i = from; i < to; ++i) { context.Scope.ChangeVariable(vName, i); result.Add(Evaluate(context, code, true)); if (context.evaluationState == EvaluationState.UnwindingBreak) { context.Scope.PopVariable(vName); return(context.UnBreak()); } } context.Scope.PopVariable(vName); return(result); }, Arguments.Mutator(Arguments.Lazy("variable-name"), "(@identifier value)"), Arguments.Arg("from"), Arguments.Arg("to"), Arguments.Lazy("code")); AddFunction("mapex", "variable_name start code next : Like map, but the next element is the result of 'next'. Stops when next = null.", (context, arguments) => { var vName = ArgumentType <String>(arguments[0]); var code = ArgumentType <ScriptObject>(arguments[2]); var next = ArgumentType <ScriptObject>(arguments[3]); var result = new ScriptList(); var item = arguments[1]; context.Scope.PushVariable(vName, null); while (item != null) { context.Scope.ChangeVariable(vName, item); result.Add(Evaluate(context, code, true)); if (context.evaluationState == EvaluationState.UnwindingBreak) { context.Scope.PopVariable(vName); return(context.UnBreak()); } item = Evaluate(context, next, true); } context.Scope.PopVariable(vName); return(result); }, Arguments.Mutator(Arguments.Lazy("variable-name"), "(@identifier value)"), Arguments.Arg("start"), Arguments.Lazy("code"), Arguments.Lazy("next")); AddFunction("for", "variable_name list code : Execute code for each item in list. Returns result of last run of code.", (context, arguments) => { var vName = ArgumentType <String>(arguments[0]); var list = ArgumentType <System.Collections.IEnumerable>(arguments[1]); var func = ArgumentType <ScriptObject>(arguments[2]); context.Scope.PushVariable(vName, null); Object result = null; foreach (var item in list) { context.Scope.ChangeVariable(vName, item); result = Evaluate(context, func, true); if (context.evaluationState == EvaluationState.UnwindingBreak) { context.Scope.PopVariable(vName); return(context.UnBreak()); } } context.Scope.PopVariable(vName); return(result); }, Arguments.Mutator(Arguments.Lazy("variable-name"), "(@identifier value)"), Arguments.Arg("list"), Arguments.Lazy("code")); AddFunction("fori", "variable_name list code : Execute code for each item in list. Returns result of last run of code.", (context, arguments) => { var vName = ArgumentType <String>(arguments[0]); var from = AutoBind.IntArgument(arguments[1]); var to = AutoBind.IntArgument(arguments[2]); var func = ArgumentType <ScriptObject>(arguments[3]); context.Scope.PushVariable(vName, null); Object result = null; for (int i = from; i < to; ++i) { context.Scope.ChangeVariable(vName, i); result = Evaluate(context, func, true); if (context.evaluationState == EvaluationState.UnwindingError) { return(result); } else if (context.evaluationState == EvaluationState.UnwindingBreak) { context.Scope.PopVariable(vName); return(context.UnBreak()); } } context.Scope.PopVariable(vName); return(result); }, Arguments.Mutator(Arguments.Lazy("variable-name"), "(@identifier value)"), Arguments.Arg("from"), Arguments.Arg("to"), Arguments.Lazy("code")); AddFunction("while", "condition code : Repeat code while condition evaluates to true.", (context, arguments) => { var cond = ArgumentType <ScriptObject>(arguments[0]); var code = ArgumentType <ScriptObject>(arguments[1]); while (context.evaluationState == EvaluationState.Normal && Evaluate(context, cond, true) != null) { if (context.evaluationState == EvaluationState.Normal) { Evaluate(context, code, true); } } if (context.evaluationState == EvaluationState.UnwindingBreak) { return(context.UnBreak()); } return(null); }, Arguments.Lazy("condition"), Arguments.Lazy("code")); }
private void SetupListFunctions() { AddFunction("length", "list : Returns length of list.", (context, arguments) => { var list = arguments[0] as ScriptList; return(list == null ? 0 : list.Count); }, Arguments.Arg("list")); AddFunction("count", "variable_name list code : Returns number of items in list for which code evaluated to true.", (context, arguments) => { var vName = ArgumentType <String>(arguments[0]); var list = ArgumentType <ScriptList>(arguments[1]); var func = ArgumentType <ScriptObject>(arguments[2]); context.Scope.PushVariable(vName, null); var result = (int)list.Count((o) => { context.Scope.ChangeVariable(vName, o); return(Evaluate(context, func, true) != null); }); context.Scope.PopVariable(vName); return(result); }, Arguments.Mutator(Arguments.Lazy("variable-name"), "(@identifier value)"), Arguments.Mutator(Arguments.Arg("in"), "(@list value)"), Arguments.Lazy("code")); AddFunction("where", "variable_name list code : Returns new list containing only the items in list for which code evaluated to true.", (context, arguments) => { var vName = ArgumentType <String>(arguments[0]); var list = ArgumentType <ScriptList>(arguments[1]); var func = ArgumentType <ScriptObject>(arguments[2]); context.Scope.PushVariable(vName, null); var result = new ScriptList(list.Where((o) => { context.Scope.ChangeVariable(vName, o); return(Evaluate(context, func, true) != null); })); context.Scope.PopVariable(vName); return(result); }, Arguments.Mutator(Arguments.Lazy("variable-name"), "(@identifier value)"), Arguments.Mutator(Arguments.Arg("in"), "(@list value)"), Arguments.Lazy("code")); AddFunction("cat", "<n> : Combine N lists into one", (context, arguments) => { var result = new ScriptList(); foreach (var arg in arguments[0] as ScriptList) { if (arg is ScriptList) { result.AddRange(arg as ScriptList); } else { result.Add(arg); } } return(result); }, Arguments.Repeat(Arguments.Optional("item"))); AddFunction("last", "list : Returns last item in list.", (context, arguments) => { return(ArgumentType <ScriptList>(arguments[0]).LastOrDefault()); }, Arguments.Mutator(Arguments.Arg("list"), "(@list value)")); AddFunction("first", "list : Returns first item in list.", (context, arguments) => { if (arguments[2] == null) { return(ArgumentType <ScriptList>(arguments[0]).FirstOrDefault()); } else { var vName = ArgumentType <String>(arguments[1]); var list = ArgumentType <ScriptList>(arguments[0]); var func = ArgumentType <ScriptObject>(arguments[2]); context.Scope.PushVariable(vName, null); var result = list.FirstOrDefault((o) => { context.Scope.ChangeVariable(vName, o); return(Evaluate(context, func, true) != null); }); context.Scope.PopVariable(vName); return(result); } }, Arguments.Mutator(Arguments.Arg("list"), "(@list value)"), Arguments.Optional(Arguments.Mutator(Arguments.Lazy("variable-name"), "(@identifier value)")), Arguments.Optional(Arguments.Lazy("code"))); AddFunction("index", "list n : Returns nth element in list.", (context, arguments) => { var index = arguments[1] as int?; if (index == null || !index.HasValue) { return(null); } if (index.Value < 0) { return(null); } var list = ArgumentType <ScriptList>(arguments[0]); if (index.Value >= list.Count) { return(null); } return(list[index.Value]); }, Arguments.Mutator(Arguments.Arg("list"), "(@list value)"), Arguments.Arg("n")); //functions.Add("sub-list", Function.MakeSystemFunction("sub-list", // Arguments.ParseArguments(this, "list list", "integer start", "integer ?length"), // "list start length: Returns a elements in list between start and start+length.", // (context, arguments) => // { // var list = ArgumentType<ScriptList>(arguments[0]); // var start = arguments[1] as int?; // if (start == null || !start.HasValue) return new ScriptList(); // int? length = arguments[2] as int?; // if (length == null || !length.HasValue) length = list.Count; // if (start.Value < 0) { length -= start; start = 0; } // if (start.Value >= list.Count) return new ScriptList(); // if (length.Value <= 0) return new ScriptList(); // if (length.Value + start.Value >= list.Count) length = list.Count - start.Value; // return new ScriptList(list.GetRange(start.Value, length.Value)); // })); //functions.Add("sort", Function.MakeSystemFunction("sort", // Arguments.ParseArguments(this, "string variable_name", "list in", "code code"), // "vname list sort_func: Sorts elements according to sort func; sort func returns integer used to order items.", // (context, arguments) => // { // var vName = ScriptObject.AsString(arguments[0]); // var list = ArgumentType<ScriptList>(arguments[1]); // var sortFunc = ArgumentType<ScriptObject>(arguments[2]); // var comparer = new ListSortComparer(this, vName, sortFunc, context); // list.Sort(comparer); // return list; // })); //functions.Add("reverse", Function.MakeSystemFunction("reverse", // Arguments.ParseArguments(this, "list list"), // "list: Reverse the list.", // (context, arguments) => // { // var list = ArgumentType<ScriptList>(arguments[0]); // list.Reverse(); // return list; // })); AddFunction("reverse", "Reverse the elements of a list", (context, arguments) => { var r = AutoBind.ListArgument(arguments[0]); if (r == null) { r = new ScriptList(); } r.Reverse(); return(r); }, Arguments.Arg("list")); AddFunction("array", "Create a list of items by running code N times", (context, arguments) => { var count = arguments[0] as int?; if (count == null || !count.HasValue) { return(null); } var result = new ScriptList(); for (int i = 0; i < count; ++i) { result.Add(Evaluate(context, arguments[1], true)); } return(result); }, Arguments.Arg("count"), Arguments.Lazy("code")); }
private void SetupStandardLibrary() { //types.Add("STRING", new TypeString()); //types.Add("INTEGER", new TypePrimitive(typeof(int), true)); //types.Add("LIST", new TypeList()); //types.Add("OBJECT", new TypePrimitive(typeof(ScriptObject), false)); //types.Add("CODE", new TypePrimitive(typeof(ScriptObject), false)); //types.Add("IDENTIFIER", new TypeString()); //types.Add("FUNCTION", new TypePrimitive(typeof(ScriptObject), false)); //types.Add("ANYTHING", Type.Anything); //types.Add("FLOAT", new TypePrimitive(typeof(float), true)); //foreach (var type in types) // type.Value.Typename = type.Key; specialVariables.Add("null", (c) => { return(null); }); specialVariables.Add("functions", (c) => { return(new ScriptList(functions.Select((pair) => { return pair.Value; }))); }); specialVariables.Add("true", (c) => { return(true); }); specialVariables.Add("false", (c) => { return(null); }); specialVariables.Add("@scope", (c) => { return(c.Scope); }); //AddFunction("net-module", "Loads a module from a .net assembly", // (context, arguments) => // { // NetModule.LoadModule(context, this, ScriptObject.AsString(arguments[0]), ScriptObject.AsString(arguments[1])); // return null; // }, "string assembly", "string module"); AddFunction("@list", "If the argument is a list, great. If not, now it is.", (context, arguments) => { if (arguments[0] == null) { return(new ScriptList()); } if (arguments[0] is ScriptList) { return(arguments[0]); } return(new ScriptList(arguments[0])); }, Arguments.Arg("value")); AddFunction("@lazy-list", "Mutates a lazy argument into a list. Effectively makes the ^ optional.", (context, arguments) => { var node = arguments[0] as ScriptObject; if (node == null) { return(new ScriptList()); } var r = new ScriptList(); foreach (var child in node._children) { r.Add(Evaluate(context, child)); } return(r); }, Arguments.Arg("arg")); AddFunction("@identifier", "Mutates a lazy argument. If it's a token, return as a string. If not, evaluate and return as a string.", (context, arguments) => { var arg = arguments[0] as ScriptObject; if (arg != null && arg.gsp("@type") == "token") { return(arg.gsp("@token")); } return(ScriptObject.AsString(Evaluate(context, arg, true))); }, Arguments.Arg("arg")); AddFunction("@identifier-if-token", "Mutates a lazy argument. If it's a token, return as a string. If not, evaluate and return.", (context, arguments) => { var arg = arguments[0] as ScriptObject; if (arg != null && arg.gsp("@type") == "token") { return(arg.gsp("@token")); } return(Evaluate(context, arg, true)); }, Arguments.Arg("arg")); AddFunction("arg", "create an argument", (context, arguments) => { if (arguments[0] is ScriptObject) { return(arguments[0]); } else { return(Arguments.Arg(ScriptObject.AsString(arguments[0]))); } }, Arguments.Mutator(Arguments.Lazy("name"), "(@identifier value)")); AddFunction("arg-lazy", "create a lazy argument", (context, arguments) => { if (arguments[0] is ScriptObject) { (arguments[0] as ScriptObject)["@lazy"] = true; return(arguments[0]); } else { return(Arguments.Lazy(Arguments.Arg(ScriptObject.AsString(arguments[0])))); } }, Arguments.Mutator(Arguments.Lazy("name"), "(@identifier-if-token value)")); AddFunction("arg-optional", "create an optional argument", (context, arguments) => { if (arguments[0] is ScriptObject) { (arguments[0] as ScriptObject)["@optional"] = true; return(arguments[0]); } else { return(Arguments.Optional(Arguments.Arg(ScriptObject.AsString(arguments[0])))); } }, Arguments.Mutator(Arguments.Lazy("name"), "(@identifier-if-token value)")); AddFunction("arg-repeat", "create a repeat argument", (context, arguments) => { if (arguments[0] is ScriptObject) { (arguments[0] as ScriptObject)["@repeat"] = true; return(arguments[0]); } else { return(Arguments.Repeat(Arguments.Arg(ScriptObject.AsString(arguments[0])))); } }, Arguments.Mutator(Arguments.Lazy("name"), "(@identifier-if-token value)")); AddFunction("arg-mutator", "Add a mutator to an argument", (context, arguments) => { if (arguments[0] is ScriptObject) { (arguments[0] as ScriptObject)["@mutator"] = arguments[1]; return(arguments[0]); } else { var r = Arguments.Arg(ScriptObject.AsString(arguments[0])); r["@mutator"] = arguments[1]; return(r); } }, Arguments.Mutator(Arguments.Lazy("name"), "(@identifier-if-token value)"), Arguments.Lazy("mutator")); AddFunction("eval", "Evaluates it's argument.", (context, arguments) => { return(Evaluate(context, arguments[0], true)); }, Arguments.Arg("arg")); AddFunction("lastarg", "Returns last argument", (context, arguments) => { return((arguments[0] as ScriptList).LastOrDefault()); }, Arguments.Repeat("child")); AddFunction("nop", "Returns null.", (context, arguments) => { return(null); }, Arguments.Optional(Arguments.Repeat("value"))); AddFunction("coalesce", "B if A is null, A otherwise.", (context, arguments) => { if (arguments[0] == null) { return(Evaluate(context, arguments[1], true, false)); } else { return(arguments[0]); } }, Arguments.Arg("A"), Arguments.Lazy("B")); AddFunction("raise-error", "Raises a new error.", (context, arguments) => { context.RaiseNewError(MISP.ScriptObject.AsString(arguments[0]), context.currentNode); return(null); }, Arguments.Arg("message")); AddFunction("catch-error", "Evaluate and return A unless error generated; if error Evaluate and return B.", (context, arguments) => { var result = Evaluate(context, arguments[0], true, false); if (context.evaluationState == EvaluationState.UnwindingError) { context.evaluationState = EvaluationState.Normal; return(Evaluate(context, arguments[1], true, false)); } return(result); }, Arguments.Lazy("good"), Arguments.Lazy("bad")); AddFunction("break", "Aborts loops and supplies a return value.", (context, arguments) => { context.evaluationState = EvaluationState.UnwindingBreak; context.breakObject = arguments[0]; return(null); }, Arguments.Arg("value")); AddFunction("reflect", "Examine an object using .net reflection.", (context, arguments) => { var stream = new System.IO.StringWriter(); if (arguments[0] == null) { stream.Write("null\n"); } else { stream.Write(arguments[0].GetType().Name + "\n"); foreach (var field in arguments[0].GetType().GetFields()) { stream.Write("field: " + field.Name + " " + field.FieldType.Name + "\n"); } foreach (var method in arguments[0].GetType().GetMethods()) { stream.Write("method: " + method.Name + " " + method.ReturnType.Name + "\n"); } } return(stream.ToString()); }, Arguments.Arg("object")); AddFunction("lazy-overloads", "Examine all possible overloads of a lazy binding.", (context, arguments) => { var binding = arguments[0] as ScriptObject; var stream = new System.IO.StringWriter(); if (binding.GetProperty("@lazy-reflection") == null) { stream.Write("Not a lazy binding object."); } else { var sourceType = binding.GetProperty("@source-type") as System.Type; var methods = sourceType.GetMethods().Where((m) => m.Name == binding.gsp("@lazy-reflection")); stream.Write("Methods found:\n"); foreach (var method in methods) { stream.Write("args: "); stream.Write(String.Join(" ", method.GetParameters().Select((p) => p.ParameterType.Name))); stream.Write("\n"); } } return(stream.ToString()); }, Arguments.Arg("object")); AddFunction("emitt", "Emit in tight-formatting style.", (context, arguments) => { return(TightFormat(arguments[0])); }, Arguments.Arg("object", "Meant for use with objects generated via AutoBind.")); AddFunction("emitf", "Emit a function", (context, arguments) => { var stream = new System.IO.StringWriter(); var obj = arguments[0] as ScriptObject; stream.Write("Name: "); stream.Write(obj.gsp("@name") + "\nHelp: " + obj.gsp("@help") + "\nArguments: \n"); foreach (var arg_ in obj["@arguments"] as ScriptList) { stream.Write(" "); var arg = arg_ as ScriptObject; //stream.Write((arg["@type"] as Type).Typename + " "); if (arg["@optional"] != null) { stream.Write("?"); } if (arg["@repeat"] != null) { stream.Write("+"); } if (arg["@lazy"] != null) { stream.Write("*"); } stream.Write(arg["@name"] + " "); if (arg["@mutator"] != null) { Engine.SerializeCode(stream, arg["@mutator"] as ScriptObject); } if (arg["@help"] != null) { stream.Write(" - " + arg["@help"].ToString()); } stream.Write("\n"); } stream.Write("\nBody: "); if (obj["@function-body"] is ScriptObject) { Engine.SerializeCode(stream, obj["@function-body"] as ScriptObject); } else { stream.Write("System"); } stream.Write("\n"); return(stream.ToString()); }, Arguments.Arg("func", "Must be a function.")); AddFunction("serialize", "Serialize an object", (context, arguments) => { var stream = new System.IO.StringWriter(); SerializeObject(stream, arguments[0] as ScriptObject); return(stream.ToString()); }, Arguments.Arg("object")); SetupVariableFunctions(); SetupObjectFunctions(); SetupMathFunctions(); SetupFunctionFunctions(); SetupBranchingFunctions(); SetupLoopFunctions(); SetupListFunctions(); SetupStringFunctions(); SetupEncryptionFunctions(); SetupFileFunctions(); SetupRegexFunctions(); }
private void SetupStringFunctions() { AddFunction("split", "Split a string into pieces", (context, arguments) => { var pieces = AutoBind.StringArgument(arguments[0]).Split( new String[] { AutoBind.StringArgument(arguments[1]) }, Int32.MaxValue, StringSplitOptions.RemoveEmptyEntries); var r = new ScriptList(pieces); return(r); }, Arguments.Arg("string"), Arguments.Arg("split-chars")); AddFunction("strlen", "string : Returns length of string.", (context, arguments) => { return(ScriptObject.AsString(arguments[0]).Length); }, Arguments.Arg("string")); AddFunction("strind", "string n : Returns nth element in string.", (context, arguments) => { var index = arguments[1] as int?; if (index == null || !index.HasValue) { return(null); } if (index.Value < 0) { return(null); } var str = ScriptObject.AsString(arguments[0]); if (index.Value >= str.Length) { return(null); } return(str[index.Value]); }, Arguments.Arg("string"), Arguments.Arg("n")); AddFunction("substr", "Returns a portion of the input string.", (context, arguments) => { var str = ScriptObject.AsString(arguments[0]); var start = AutoBind.IntArgument(arguments[1]); if (arguments[2] == null) { return(str.Substring(start)); } else { return(str.Substring(start, AutoBind.IntArgument(arguments[2]))); } }, Arguments.Arg("string"), Arguments.Arg("start"), Arguments.Optional("length")); AddFunction("strcat", "Concatenate many strings into one.", (context, arguments) => { var r = new StringBuilder(); foreach (var obj in AutoBind.ListArgument(arguments[0])) { r.Append(ScriptObject.AsString(obj)); } return(r.ToString()); }, Arguments.Repeat("item")); AddFunction("itoa", "Change a number to the string representation.", (context, arguments) => { return(arguments[0].ToString()); }, Arguments.Arg("i")); AddFunction("atoi", "", (context, arguments) => { return(Convert.ToInt32(arguments[0])); }, Arguments.Arg("i")); AddFunction("unescape", "", (context, arguments) => { return(Console.UnescapeString(ScriptObject.AsString(arguments[0]))); }, Arguments.Arg("string")); AddFunction("format", "Format a string.", (context, arguments) => { return(String.Format(AutoBind.StringArgument(arguments[0]), AutoBind.ListArgument(arguments[1]).ToArray())); }, Arguments.Arg("format-string"), Arguments.Optional(Arguments.Repeat("value"))); }
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); }
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 { var numberString = node.gsp("@token"); if (numberString.StartsWith("0x")) { result = Convert.ToInt32(numberString.Substring(2), 16); } else if (numberString.StartsWith("0b")) { var accumulator = 0; foreach (var c in numberString.Substring(2)) { accumulator <<= 1; if (c == '1') { accumulator += 1; } } result = accumulator; } else { result = Int32.Parse(numberString); } } } 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); }