public static ScriptObject ParseChar(ParseState state) { var result = new GenericScriptObject("@type", "char", "@start", state.start, "@source", state); var token = ""; state.Advance(); //skip opening ' while (!state.AtEnd()) { if (state.Next() == '\\') { state.Advance(); if (state.Next() == 'n') token += "\n"; if (state.Next() == 't') token += "\t"; if (state.Next() == 'r') token += "\r"; else token += state.Next(); } else if (state.Next() == '\'') { result["@end"] = state.start; result["@token"] = token; state.Advance(); return result; } else { token += state.Next(); state.Advance(); } } result["@end"] = state.start; result["@token"] = token; return result; }
public static GenericScriptObject BindXNAMath() { var xna = new GenericScriptObject(); xna.SetProperty("v", Function.MakeSystemFunction("Vector3", Arguments.Args("x", "y", "z", Arguments.Optional("w")), "Create a new vector.", (context, arguments) => { if (arguments[3] == null) return new Vector3(AutoBind.NumericArgument(arguments[0]), AutoBind.NumericArgument(arguments[1]), AutoBind.NumericArgument(arguments[2])); else return new Vector4(AutoBind.NumericArgument(arguments[0]), AutoBind.NumericArgument(arguments[1]), AutoBind.NumericArgument(arguments[2]), AutoBind.NumericArgument(arguments[3])); })); xna.SetProperty("helper", AutoBind.GenerateLazyBindingObjectForStaticLibrary(typeof(MathHelper))); xna.SetProperty("matrix", AutoBind.GenerateLazyBindingObjectForStaticLibrary(typeof(Matrix))); xna.SetProperty("quat", AutoBind.GenerateLazyBindingObjectForStaticLibrary(typeof(Quaternion))); xna.SetProperty("v2", AutoBind.GenerateLazyBindingObjectForStaticLibrary(typeof(Vector2), true)); xna.SetProperty("v3", AutoBind.GenerateLazyBindingObjectForStaticLibrary(typeof(Vector3), true)); xna.SetProperty("v4", AutoBind.GenerateLazyBindingObjectForStaticLibrary(typeof(Vector4), true)); xna.SetProperty("rect", AutoBind.GenerateLazyBindingObjectForStaticLibrary(typeof(Rectangle), true)); return xna; }
public static ScriptObject GenerateTypeBinding(System.Type type) { var r = new GenericScriptObject(); r.SetProperty("@construct", Function.MakeSystemFunction("@construct", Arguments.Args(Arguments.Optional(Arguments.Repeat("argument"))), "Create a new instance of " + type.Name, (context, arguments) => { return(Activator.CreateInstance(type, (arguments[0] as ScriptList).ToArray())); })); foreach (var method in type.GetMethods()) { if (method.IsPublic) { r.SetProperty(method.Name, GenerateMethodBinding(method)); } } return(r); }
public static MISP.GenericScriptObject GenerateBinding() { var gui = new MISP.GenericScriptObject(); gui["create"] = MISP.Function.MakeSystemFunction("create", MISP.Arguments.Args( MISP.Arguments.Arg("type"), Arguments.Arg("rect"), Arguments.Arg("settings"), Arguments.Optional("hover")), "Create a ui element.", (context, arguments) => { var type = ScriptObject.AsString(arguments[0]); var rect = arguments[1] as Rectangle?; if (rect == null || !rect.HasValue) throw new InvalidOperationException("Second argument must be a rect."); UIItem result = null; if (type == "item") result = new UIItem(rect.Value); else if (type == "slider") result = new VerticalSlider(rect.Value); else throw new InvalidOperationException("Unknown element type."); result.settings = arguments[2] as ScriptObject; result.hoverSettings = arguments[3] as ScriptObject; return result; }); return gui; }
public static ScriptObject GenerateLazyBindingObjectForStaticLibrary(System.Type type, bool generateConstructor = false) { var r = new GenericScriptObject(); if (generateConstructor) { r.SetProperty("@construct", Function.MakeSystemFunction("@construct", Arguments.Args(Arguments.Optional(Arguments.Repeat("argument"))), "Create a new instance of " + type.Name, (context, arguments) => { return(Activator.CreateInstance(type, (arguments[0] as ScriptList).ToArray())); })); } foreach (var method in type.GetMethods()) { if (method.IsPublic && method.IsStatic) { r.SetProperty(TransformMethodName(method.Name), LazyBindStaticMethod(type, method.Name)); } } return(r); }
public static ScriptObject ReorderMemberAccessNode(ScriptObject node) { //Convert (A (B (C D))) to (((A B) C) D) //Create an (A B C D) list. var nodeList = new LinkedList<AccessChainNode>(); for (var n = node; n != null; n = (isType(n, "memberaccess") ? child(n,1) as ScriptObject : null)) { if (isType(n, "memberaccess")) nodeList.AddLast(new AccessChainNode { node = child(n,0), token = n["@token"] }); else nodeList.AddLast(new AccessChainNode { node = n, token = "" }); } //Each iteration, take the first two nodes and combine them into a new member access node. //(A B C D) becomes ((A B) C D), etc. while (nodeList.Count > 1) { var lhs = nodeList.First(); nodeList.RemoveFirst(); var rhs = nodeList.First(); nodeList.RemoveFirst(); var newNode = new GenericScriptObject("@type", "memberaccess", "@start", (lhs.node as ScriptObject)["@start"], "@source", (lhs.node as ScriptObject)["@source"]); newNode["@token"] = lhs.token; children(newNode).Add(lhs.node); children(newNode).Add(rhs.node); nodeList.AddFirst(new AccessChainNode { node = newNode, token = rhs.token }); } return nodeList.First().node as ScriptObject; }
public static ScriptObject ParseToken(ParseState state) { var result = new GenericScriptObject("@type", "token", "@start", state.start, "@source", state); while (!state.AtEnd() && !(" \t\r\n:.)]}".Contains(state.Next()))) state.Advance(); result["@end"] = state.start; result["@token"] = state.source.Substring(asInt(result["@start"]), asInt(result["@end"]) - asInt(result["@start"])); if (String.IsNullOrEmpty(result.gsp("@token"))) throw new ParseError("Empty token", state.currentLine); return result; }
public static ScriptObject ParseStringExpression(ParseState state, bool isRoot = false) { var result = new GenericScriptObject("@type", "stringexpression", "@start", state.start, "@source", state); if (!isRoot) state.Advance(); //Skip opening quote string piece = ""; int piece_start = state.start; while (!state.AtEnd()) { if (state.Next() == '}' && piece.Length == 0) { state.Advance(1); } else if (state.Next() == '(') { if (piece.Length > 0) children(result).Add( new GenericScriptObject("@type", "string", "@start", piece_start, "@source", state, "@token", state.source.Substring(piece_start, state.start - piece_start))); children(result).Add(ParseNode(state)); piece = ""; } else if (state.Next() == '\\') { if (piece.Length == 0) piece_start = state.start; state.Advance(); //skip the slash. piece += state.Next(); state.Advance(); } else if (!isRoot && state.Next() == '"') { if (piece.Length > 0) children(result).Add( new GenericScriptObject("@type", "string", "@start", piece_start, "@source", state, "@token", state.source.Substring(piece_start, state.start - piece_start))); state.Advance(); result["@end"] = state.start; if (children(result).Count == 1 && isType(children(result)[0] as ScriptObject, "string")) return child(result, 0) as ScriptObject; return result; } else { if (piece.Length == 0) piece_start = state.start; piece += state.Next(); state.Advance(); } } if (isRoot) { if (piece.Length > 0) children(result).Add(new GenericScriptObject("@type", "string", "@start", piece_start, "@source", state, "@token", state.source.Substring(piece_start, state.start - piece_start))); if (children(result).Count == 1) return child(result, 0) as ScriptObject; return result; } throw new ParseError("Unexpected end of script inside string expression.", state.currentLine); }
public static ScriptObject ParseNumber(ParseState state) { var result = new GenericScriptObject("@type", "number", "@start", state.start, "@source", state); bool foundDot = false; while (!state.AtEnd()) { if (state.Next() == '-') { if (asInt(result["@start"]) != state.start) break; state.Advance(); continue; } if (state.Next() >= '0' && state.Next() <= '9') { state.Advance(); continue; } else if (state.Next() == '.') { if (foundDot) break; foundDot = true; state.Advance(); continue; } break; } result["@end"] = state.start; result["@token"] = state.source.Substring(asInt(result["@start"]), asInt(result["@end"]) - asInt(result["@start"])); return result; }
public static ScriptObject ParseNode(ParseState state, String start = "(", String end = ")") { var result = new GenericScriptObject("@type", "node", "@start", state.start, "@source", state); if (!state.MatchNext(start)) throw new ParseError("Expected " + start, state.currentLine); state.Advance(start.Length); while (!state.AtEnd() && !state.MatchNext(end)) { DevourWhitespace(state); if (state.Next() == '}') return result; if (!state.AtEnd() && !state.MatchNext(end)) { var expression = ParseExpression(state); if (isType(expression, "memberaccess")) expression = ReorderMemberAccessNode(expression); children(result).Add(expression); } DevourWhitespace(state); } if (end != null) state.Advance(end.Length); return result; }
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); }
private void SetupObjectFunctions() { AddFunction("members", "Lists all members of an object", (context, arguments) => { var obj = ArgumentType<ScriptObject>(arguments[0]); return obj.ListProperties(); }, Arguments.Arg("object")); AddFunction("record", "Create a new record.", (context, arguments) => { var obj = new GenericScriptObject(); var vars = AutoBind.ListArgument(arguments[0]); foreach (var item in vars) { var l = ArgumentType<ScriptObject>(item); if (l == null || l._children.Count != 2) throw new ScriptError("Record expects a list of pairs.", null); var arg = l._child(0) as ScriptObject; string mname = ""; if (arg != null && arg.gsp("@type") == "token") mname = arg.gsp("@token"); else mname = Evaluate(context, arg, true).ToString(); obj.SetProperty(mname, Evaluate(context, l._child(1))); } return obj; }, Arguments.Repeat(Arguments.Lazy("pairs"))); AddFunction("clone", "Clone a record.", (context, arguments) => { var r = new GenericScriptObject(arguments[0] as ScriptObject); foreach (var item in arguments[1] as ScriptList) { var list = item as ScriptList; if (list == null || list.Count != 2) throw new ScriptError("Record expects only pairs as arguments.", context.currentNode); r[ScriptObject.AsString(list[0])] = list[1]; } return r; }, Arguments.Arg("object"), Arguments.Mutator(Arguments.Repeat(Arguments.Optional("pairs")), "(@list value)")); AddFunction("set", "Set a member on an object.", (context, arguments) => { if (arguments[0] == null) return arguments[2]; return SetObjectProperty(context, arguments[0], ScriptObject.AsString(arguments[1]), arguments[2]); }, Arguments.Arg("object"), Arguments.Mutator(Arguments.Lazy("name"), "(@identifier-if-token value)"), Arguments.Arg("value")); AddFunction("multi-set", "Set multiple members of an object.", (context, arguments) => { var obj = ArgumentType<ScriptObject>(arguments[0]); var vars = AutoBind.ListArgument(arguments[1]); foreach (var item in vars) { var l = ArgumentType<ScriptObject>(item); if (l == null || l._children.Count != 2) throw new ScriptError("Multi-set expects a list of pairs.", null); var arg = l._child(0) as ScriptObject; string mname = ""; if (arg != null && arg.gsp("@type") == "token") mname = arg.gsp("@token"); else mname = Evaluate(context, arg, true).ToString(); SetObjectProperty(context, obj, mname, Evaluate(context, l._child(1))); } return obj; }, Arguments.Arg("object"), Arguments.Repeat(Arguments.Lazy("pairs"))); AddFunction("delete", "Deletes a property from an object.", (context, arguments) => { var value = (arguments[0] as ScriptObject)[ScriptObject.AsString(arguments[1])]; if (arguments[0] is Scope) (arguments[0] as Scope).PopVariable(ScriptObject.AsString(arguments[1])); else (arguments[0] as ScriptObject).DeleteProperty(ScriptObject.AsString(arguments[1])); return value; }, Arguments.Arg("object"), Arguments.Arg("property-name")); }
public static ScriptObject ParseExpression(ParseState state) { ScriptObject result = null; var prefix = ParsePrefix(state); if (state.Next() == '"') { if (prefix == "$") { prefix = ""; result = ParseBasicString(state); } else { result = ParseStringExpression(state); } } else if (state.Next() == '(') { result = ParseNode(state); } else if (state.Next() == '\'') { result = ParseChar(state); } else if ("-0123456789".Contains(state.Next())) { result = ParseNumber(state); if (result["@token"].ToString() == "-") //A lone - sign is not a valid number. Interpret it as a token. { result["@type"] = "token"; } } else { if (" \t\r\n:.)}".Contains(state.Next()) && !String.IsNullOrEmpty(prefix)) { //The prefix is a token. result = new GenericScriptObject("@type", "token", "@start", state.start - 1, "@source", state); result["@end"] = state.start; result["@token"] = prefix; prefix = ""; } else { result = ParseToken(state); } } if (!state.AtEnd() && (state.Next() == '.' || state.Next() == ':')) { var final_result = new GenericScriptObject("@type", "memberaccess", "@start", result["@start"], "@source", state); children(final_result).Add(result); final_result["@token"] = new String(state.Next(), 1); state.Advance(); children(final_result).Add(ParseExpression(state)); result = final_result; } result["@prefix"] = prefix; if (!PrefixCheck.CheckPrefix(result)) { throw new ParseError("Illegal prefix on expression of type " + result["@type"], state.currentLine); } return(result); }
private void SetupFileFunctions() { var file_functions = new GenericScriptObject(); file_functions.SetProperty("open", Function.MakeSystemFunction("open", Arguments.Args("file-name", "mode"), "Opens a file", (context, arguments) => { var mode = AutoBind.StringArgument(arguments[1]).ToUpperInvariant(); if (mode == "READ") return System.IO.File.OpenText(AutoBind.StringArgument(arguments[0])); else if (mode == "WRITE") return System.IO.File.CreateText(AutoBind.StringArgument(arguments[0])); else if (mode == "APPEND") return System.IO.File.AppendText(AutoBind.StringArgument(arguments[0])); else context.RaiseNewError("Invalid mode specifier", context.currentNode); return null; })); file_functions.SetProperty("close", Function.MakeSystemFunction("close", Arguments.Args("file"), "Close a file.", (context, arguments) => { if (arguments[0] is System.IO.StreamReader) (arguments[0] as System.IO.StreamReader).Close(); else if (arguments[0] is System.IO.StreamWriter) (arguments[0] as System.IO.StreamWriter).Close(); else context.RaiseNewError("Argument is not a file.", context.currentNode); return null; })); file_functions.SetProperty("read-line", Function.MakeSystemFunction("read-line", Arguments.Args("file"), "Read a line from a file.", (context, arguments) => { var file = arguments[0] as System.IO.StreamReader; if (file == null) { context.RaiseNewError("Argument is not a read file.", context.currentNode); return null; } return file.ReadLine(); })); file_functions.SetProperty("read-all", Function.MakeSystemFunction("read-all", Arguments.Args("file"), "Read all of a file.", (context, arguments) => { var file = arguments[0] as System.IO.StreamReader; if (file == null) { context.RaiseNewError("Argument is not a read file.", context.currentNode); return null; } return file.ReadToEnd(); })); file_functions.SetProperty("write", Function.MakeSystemFunction("write", Arguments.Args("file", "text"), "Write to a file.", (context, arguments) => { var file = arguments[0] as System.IO.StreamWriter; if (file == null) { context.RaiseNewError("Argument is not a write file.", context.currentNode); return null; } file.Write(ScriptObject.AsString(arguments[1])); return null; })); file_functions.SetProperty("more", Function.MakeSystemFunction("more", Arguments.Args("file"), "Is there more to read in this file?", (context, arguments) => { var file = arguments[0] as System.IO.StreamReader; if (file == null) { context.RaiseNewError("Argument is not a read file.", context.currentNode); return null; } if (file.EndOfStream) return null; return true; })); AddGlobalVariable("file", c => file_functions); }
private void SetupFileFunctions() { var file_functions = new GenericScriptObject(); file_functions.SetProperty("open", Function.MakeSystemFunction("open", Arguments.Args("file-name", "mode"), "Opens a file", (context, arguments) => { var mode = AutoBind.StringArgument(arguments[1]).ToUpperInvariant(); if (mode == "READ") { return(System.IO.File.OpenText(AutoBind.StringArgument(arguments[0]))); } else if (mode == "WRITE") { return(System.IO.File.CreateText(AutoBind.StringArgument(arguments[0]))); } else if (mode == "APPEND") { return(System.IO.File.AppendText(AutoBind.StringArgument(arguments[0]))); } else { context.RaiseNewError("Invalid mode specifier", context.currentNode); } return(null); })); file_functions.SetProperty("close", Function.MakeSystemFunction("close", Arguments.Args("file"), "Close a file.", (context, arguments) => { if (arguments[0] is System.IO.StreamReader) { (arguments[0] as System.IO.StreamReader).Close(); } else if (arguments[0] is System.IO.StreamWriter) { (arguments[0] as System.IO.StreamWriter).Close(); } else { context.RaiseNewError("Argument is not a file.", context.currentNode); } return(null); })); file_functions.SetProperty("read-line", Function.MakeSystemFunction("read-line", Arguments.Args("file"), "Read a line from a file.", (context, arguments) => { var file = arguments[0] as System.IO.StreamReader; if (file == null) { context.RaiseNewError("Argument is not a read file.", context.currentNode); return(null); } return(file.ReadLine()); })); file_functions.SetProperty("read-all", Function.MakeSystemFunction("read-all", Arguments.Args("file"), "Read all of a file.", (context, arguments) => { var file = arguments[0] as System.IO.StreamReader; if (file == null) { context.RaiseNewError("Argument is not a read file.", context.currentNode); return(null); } return(file.ReadToEnd()); })); file_functions.SetProperty("write", Function.MakeSystemFunction("write", Arguments.Args("file", "text"), "Write to a file.", (context, arguments) => { var file = arguments[0] as System.IO.StreamWriter; if (file == null) { context.RaiseNewError("Argument is not a write file.", context.currentNode); return(null); } file.Write(ScriptObject.AsString(arguments[1])); return(null); })); file_functions.SetProperty("more", Function.MakeSystemFunction("more", Arguments.Args("file"), "Is there more to read in this file?", (context, arguments) => { var file = arguments[0] as System.IO.StreamReader; if (file == null) { context.RaiseNewError("Argument is not a read file.", context.currentNode); return(null); } if (file.EndOfStream) { return(null); } return(true); })); AddGlobalVariable("file", c => file_functions); }
public static ScriptObject ParseExpression(ParseState state) { ScriptObject result = null; var prefix = ParsePrefix(state); if (state.Next() == '"') { result = ParseStringExpression(state); } else if (state.Next() == '(') { result = ParseNode(state); } else if (state.Next() == '\'') { result = ParseChar(state); } else if ("-0123456789".Contains(state.Next())) { result = ParseNumber(state); if (result["@token"].ToString() == "-") //A lone - sign is not a valid number. Interpret it as a token. result["@type"] = "token"; } else { if (" \t\r\n:.)}".Contains(state.Next()) && !String.IsNullOrEmpty(prefix)) { //The prefix is a token. result = new GenericScriptObject("@type", "token", "@start", state.start - 1, "@source", state); result["@end"] = state.start; result["@token"] = prefix; prefix = ""; } else result = ParseToken(state); } if (!state.AtEnd() && (state.Next() == '.' || state.Next() == ':')) { var final_result = new GenericScriptObject("@type", "memberaccess", "@start", result["@start"], "@source", state); children(final_result).Add(result); final_result["@token"] = new String(state.Next(), 1); state.Advance(); children(final_result).Add(ParseExpression(state)); result = final_result; } result["@prefix"] = prefix; if (!PrefixCheck.CheckPrefix(result)) throw new ParseError("Illegal prefix on expression of type " + result["@type"], state.currentLine); return result; }
public static ScriptObject ParseStringExpression(ParseState state, bool isRoot = false) { var result = new GenericScriptObject("@type", "stringexpression", "@start", state.start, "@source", state); if (!isRoot) { state.Advance(); //Skip opening quote } string piece = ""; int piece_start = state.start; while (!state.AtEnd()) { if (state.Next() == '}' && piece.Length == 0) { state.Advance(1); } else if (state.Next() == '(') { if (piece.Length > 0) { children(result).Add( new GenericScriptObject("@type", "string", "@start", piece_start, "@source", state, "@token", state.source.Substring(piece_start, state.start - piece_start))); } children(result).Add(ParseNode(state)); piece = ""; } else if (state.Next() == '\\') { if (piece.Length == 0) { piece_start = state.start; } state.Advance(); //skip the slash. piece += state.Next(); state.Advance(); } else if (!isRoot && state.Next() == '"') { if (piece.Length > 0) { children(result).Add( new GenericScriptObject("@type", "string", "@start", piece_start, "@source", state, "@token", state.source.Substring(piece_start, state.start - piece_start))); } state.Advance(); result["@end"] = state.start; if (children(result).Count == 1 && isType(children(result)[0] as ScriptObject, "string")) { return(child(result, 0) as ScriptObject); } return(result); } else { if (piece.Length == 0) { piece_start = state.start; } piece += state.Next(); state.Advance(); } } if (isRoot) { if (piece.Length > 0) { children(result).Add(new GenericScriptObject("@type", "string", "@start", piece_start, "@source", state, "@token", state.source.Substring(piece_start, state.start - piece_start))); } if (children(result).Count == 1) { return(child(result, 0) as ScriptObject); } return(result); } throw new ParseError("Unexpected end of script inside string expression.", state.currentLine); }
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 SetupObjectFunctions() { AddFunction("members", "Lists all members of an object", (context, arguments) => { var obj = ArgumentType <ScriptObject>(arguments[0]); return(obj.ListProperties()); }, Arguments.Arg("object")); AddFunction("record", "Create a new record.", (context, arguments) => { var obj = new GenericScriptObject(); var vars = AutoBind.ListArgument(arguments[0]); foreach (var item in vars) { var l = ArgumentType <ScriptObject>(item); if (l == null || l._children.Count != 2) { throw new ScriptError("Record expects a list of pairs.", null); } var arg = l._child(0) as ScriptObject; string mname = ""; if (arg != null && arg.gsp("@type") == "token") { mname = arg.gsp("@token"); } else { mname = Evaluate(context, arg, true).ToString(); } obj.SetProperty(mname, Evaluate(context, l._child(1))); } return(obj); }, Arguments.Repeat(Arguments.Lazy("pairs"))); AddFunction("clone", "Clone a record.", (context, arguments) => { var r = new GenericScriptObject(arguments[0] as ScriptObject); foreach (var item in arguments[1] as ScriptList) { var list = item as ScriptList; if (list == null || list.Count != 2) { throw new ScriptError("Record expects only pairs as arguments.", context.currentNode); } r[ScriptObject.AsString(list[0])] = list[1]; } return(r); }, Arguments.Arg("object"), Arguments.Mutator(Arguments.Repeat(Arguments.Optional("pairs")), "(@list value)")); AddFunction("set", "Set a member on an object.", (context, arguments) => { if (arguments[0] == null) { return(arguments[2]); } return(SetObjectProperty(context, arguments[0], ScriptObject.AsString(arguments[1]), arguments[2])); }, Arguments.Arg("object"), Arguments.Mutator(Arguments.Lazy("name"), "(@identifier-if-token value)"), Arguments.Arg("value")); AddFunction("multi-set", "Set multiple members of an object.", (context, arguments) => { var obj = ArgumentType <ScriptObject>(arguments[0]); var vars = AutoBind.ListArgument(arguments[1]); foreach (var item in vars) { var l = ArgumentType <ScriptObject>(item); if (l == null || l._children.Count != 2) { throw new ScriptError("Multi-set expects a list of pairs.", null); } var arg = l._child(0) as ScriptObject; string mname = ""; if (arg != null && arg.gsp("@type") == "token") { mname = arg.gsp("@token"); } else { mname = Evaluate(context, arg, true).ToString(); } SetObjectProperty(context, obj, mname, Evaluate(context, l._child(1))); } return(obj); }, Arguments.Arg("object"), Arguments.Repeat(Arguments.Lazy("pairs"))); AddFunction("delete", "Deletes a property from an object.", (context, arguments) => { var value = (arguments[0] as ScriptObject)[ScriptObject.AsString(arguments[1])]; if (arguments[0] is Scope) { (arguments[0] as Scope).PopVariable(ScriptObject.AsString(arguments[1])); } else { (arguments[0] as ScriptObject).DeleteProperty(ScriptObject.AsString(arguments[1])); } return(value); }, Arguments.Arg("object"), Arguments.Arg("property-name")); }