public RTResult Execute(List <LToken> args, Context _context, TextPosition pos) { RTResult res = new RTResult(); Context ctx = parent.context.Copy(); ctx.name = name.value.text; ctx.parentEntry = pos; ctx.parent = _context; ctx.lastIn = this; ctx.varlist.parent = DeffCon.varlist; if (Predefs.ContainsKey(name.value.text) || Special.ContainsKey(name.value.text)) { for (int n = 0; n < args.Count; n++) { ctx.varlist.Add("_ARG" + n, args[n].SetContext(ctx)); } } else { for (int n = 0; n < argNames.Count; n++) { if (n < args.Count) { ctx.varlist.Add(argNames[n], args[n].SetContext(ctx)); } else { ctx.varlist.Add(argNames[n], new LToken(TokenType.VALUE, Value.NULL, pos).SetContext(ctx)); } } } LToken t; if (Predefs.ContainsKey(name.value.text)) { t = res.Register(Predefs[name.value.text](ctx, args.Count)); } else if (Special.ContainsKey(name.value.text)) { t = res.Register(Special[name.value.text](ctx, args.Count)); } else { t = res.Register(Interpreter.Visit(body, ctx)); } if (res.error != null) { return(res); } return(res.Succes(t.SetContext(ctx))); }
static RTResult VisitUnarOp(PNode node, Context context) { RTResult res = new RTResult(); if ((node.val.type & (TokenType.INC | TokenType.DEC)) != 0) { LToken Out = res.Register(Visit(node.PNodes[0], context)); if (res.error != null) { return(res); } Out = new LToken(TokenType.VALUE, Out.value, Out.position); res.Register(Visit(node.PNodes[1], context)); if (res.error != null) { return(res); } return(res.Succes(Out)); } LToken n = res.Register(Visit(node.right, context)); if (res.error != null) { return(res); } if (node.val.type == TokenType.SUB) { if (n.value.isNumber) { return(res.Succes(new LToken(TokenType.VALUE, new Value(-n.value.number), n.position).SetContext(n.value.context))); } } if (node.val.type == TokenType.NOT) { if (n.value.type == "BOOLEAN") { return(res.Succes(new LToken(TokenType.VALUE, new Value(!n.value.boolean), n.position).SetContext(n.value.context))); } else { return(res.Failure(new RuntimeError(n.position, "Expected boolean", context))); } } return(res.Succes(n)); }
static RTResult VisitBody(PNode node, Context context) { RTResult res = new RTResult(); LToken Ot; List <PNode> PNodes = new List <PNode>(node.PNodes); foreach (PNode n in PNodes.FindAll(x => x.TYPE == "FuncDef" || x.TYPE == "PublicPrototype" || x.TYPE == "PublicFuncDeff" || x.TYPE == "SUPER" || x.TYPE == "RUN" || x.TYPE == "Prototype" || x.isMakeValid())) { Ot = res.Register(Visit(n, context)); if (res.error != null) { return(res); } if ((Ot.type & (TokenType.BREAK | TokenType.CONTINUE | TokenType.RETURN)) != 0) { return(res.Succes(Ot)); } PNodes.Remove(n); } foreach (PNode n in PNodes) { Ot = res.Register(Visit(n, context)); if (res.error != null) { return(res); } if ((Ot.type & (TokenType.BREAK | TokenType.CONTINUE | TokenType.RETURN)) != 0) { return(res.Succes(Ot)); } } return(res.Succes(new LToken(TokenType.VALUE, Value.NULL, node.val.position))); }
static public RTResult Visit(PNode node, Context context) { RTResult res = new RTResult(); LToken Ot; Function f; Value v; switch (node.TYPE) { case "VALUE": return(res.Succes(node.val.SetContext(context))); case "VarAsign": case "PublicVarMake": case "PublicPrototype": case "VarMake": Ot = res.Register(VisitVarAsign(node, context)); if (res.error != null) { return(res); } return(res.Succes(Ot)); case "VarGet": f = context.GetFunction(); if (f != null) { if (f.InnerValues.ContainsKey(node.val.value.text)) { return(res.Succes(f.InnerValues[node.val.value.text])); } } if (!context.varlist.ContainsKey(node.val.value.text)) { return(res.Failure(new RuntimeError(node.val.position, $"{node.val.value.text} is not defined", context))); } return(res.Succes(context.varlist[node.val.value.text])); case "BinOp": Ot = res.Register(VisitBinOp(node, context)); if (res.error != null) { return(res); } return(res.Succes(Ot)); case "UnarOp": Ot = res.Register(VisitUnarOp(node, context)); if (res.error != null) { return(res); } return(res.Succes(Ot)); case "PublicFuncDeff": f = new Function(node.val, node.right, node.LTokens.ConvertAll(x => x.value.text), context); Function CF = context.GetFunction(); f.InnerValues.parent = CF.InnerValues; CF.InnerValues[node.val.value.text] = new LToken(TokenType.VALUE, new Value(f), node.val.position).SetContext(context);; return(res.Succes(new LToken(TokenType.VALUE, new Value(f), node.val.position).SetContext(context))); case "FuncDef": f = new Function(node.val, node.right, node.LTokens.ConvertAll(x => x.value.text), context); if (node.val.value != null) { context.varlist[node.val.value.text] = new LToken(TokenType.VALUE, new Value(f), node.val.position).SetContext(context); } return(res.Succes(new LToken(TokenType.VALUE, new Value(f), node.val.position).SetContext(context))); case "CallFunc": Ot = res.Register(VisitCall(node, context)); if (res.error != null) { return(res); } Ot.type = TokenType.VALUE; return(res.Succes(Ot)); case "MakeList": List <Value> values = new List <Value>(); foreach (PNode n in node.PNodes) { values.Add(res.Register(Visit(n, context)).value); if (res.error != null) { return(res); } } return(res.Succes(new LToken(TokenType.VALUE, new Value(values), node.val.position).SetContext(context))); case "Prototype": Ot = res.Register(Visit(node.PNodes[0], context)); if (res.error != null) { return(res); } if (Ot.value.type != "FUNC") { return(res.Failure(new RuntimeError(Ot.position, "Value to prototype into has to be a function.", context))); } if (Compiler.forbidden.Contains(Ot.value.function.name.value.text)) { return(res.Failure(new RuntimeError(node.val.position, $"{Ot.value.function.name.value.text} is a predefined, unmutable variable", context))); } Ot.value.function.body.PNodes.Add(new PNode("PublicPrototype", node.val, node.PNodes[1])); return(res.Succes(Ot)); case "GetProperty": Ot = res.Register(Visit(node.right, context)); if (res.error != null) { return(res); } v = Ot.value.GetProperty(node.val.value.text); Ot = new LToken(TokenType.VALUE, v, Ot.position); return(res.Succes(Ot.SetContext(context))); case "PropertyAsign": Ot = res.Register(Visit(node.PNodes[1], context)); v = res.Register(Visit(node.PNodes[0].right, context)).value.SetProperty(node.PNodes[0].val.value.text, Ot); Ot = new LToken(TokenType.VALUE, v, Ot.position); return(res.Succes(Ot.SetContext(context))); case "CallProperty": LToken toCall = res.Register(Visit(node.PNodes[0], context)); if (res.error != null) { return(res); } List <LToken> args = new List <LToken>(); for (int n = 1; n < node.PNodes.Count; n++) { args.Add(res.Register(Visit(node.PNodes[n], context))); if (res.error != null) { return(res); } } LToken t = res.Register(toCall.value.CallProperty(node.val.value.text, args, context, toCall.position)); if (res.error != null) { return(res); } return(res.Succes(t.SetContext(context))); case "GetInner": Ot = res.Register(VisitGetInner(node, context)); if (res.error != null) { return(res); } return(res.Succes(Ot)); case "InnerAsign": Ot = res.Register(VisitSetInner(node, context)); if (res.error != null) { return(res); } return(res.Succes(Ot)); case "IF": { Context ctx = BracketContext(context); Ot = res.Register(Visit(node.PNodes[0], ctx)); if (res.error != null) { return(res); } if (Ot.value.boolean) { Ot = res.Register(Visit(node.PNodes[1], ctx)); if (res.error != null) { return(res); } if ((Ot.type & (TokenType.BREAK | TokenType.CONTINUE | TokenType.RETURN)) != 0) { return(res.Succes(Ot)); } } else if (node.PNodes.Count == 3) { Ot = res.Register(Visit(node.PNodes[2], ctx)); if (res.error != null) { return(res); } if ((Ot.type & (TokenType.BREAK | TokenType.CONTINUE | TokenType.RETURN)) != 0) { return(res.Succes(Ot)); } } } return(res.Succes(new LToken(TokenType.VALUE, Value.NULL, node.val.position))); case "WHILE": { Context ctx = BracketContext(context); Ot = res.Register(Visit(node.PNodes[0], ctx)); if (res.error != null) { return(res); } while (Ot.value.boolean) { Ot = res.Register(Visit(node.PNodes[1], ctx)); if (res.error != null) { return(res); } if (Ot.type == TokenType.BREAK) { break; } if (Ot.type == TokenType.RETURN) { return(res.Succes(Ot)); } ctx = BracketContext(context); Ot = res.Register(Visit(node.PNodes[0], ctx)); if (res.error != null) { return(res); } } } return(res.Succes(new LToken(TokenType.VALUE, Value.NULL, node.val.position))); case "FOR": { Context CON = BracketContext(context); res.Register(Visit(node.PNodes[0], CON)); Ot = res.Register(Visit(node.PNodes[1], CON)); if (res.error != null) { return(res); } Context ctx = BracketContext(CON); while (Ot.value.boolean) { Ot = res.Register(Visit(node.PNodes[3], ctx)); if (res.error != null) { return(res); } if (Ot.type == TokenType.BREAK) { break; } if (Ot.type == TokenType.RETURN) { return(res.Succes(Ot)); } ctx = BracketContext(CON); res.Register(Visit(node.PNodes[2], ctx)); if (res.error != null) { return(res); } Ot = res.Register(Visit(node.PNodes[1], ctx)); if (res.error != null) { return(res); } } return(res.Succes(new LToken(TokenType.VALUE, Value.NULL, node.val.position))); } case "MultExpr": return(VisitBody(node, BracketContext(context))); case "Body": return(VisitBody(node, context)); case "NEW": Ot = res.Register(Visit(node.right, context)); if (res.error != null) { return(res); } if (Ot.value.type != "FUNC") { return(res.Failure(new RuntimeError(node.val.position, "'new' copy can be only aplied to functions.", context))); } return(res.Succes(Ot.Copy(false))); case "RETURN": Ot = res.Register(Visit(node.right, context)); if (res.error != null) { return(res); } Ot.type = TokenType.RETURN; return(res.Succes(Ot)); case "BREAK": return(res.Succes(new LToken(TokenType.BREAK, Value.NULL, node.val.position))); case "CONTINUE": return(res.Succes(new LToken(TokenType.CONTINUE, Value.NULL, node.val.position))); case "SUPER": f = context.GetFunction(); if (f == null) { return(res.Failure(new RuntimeError(node.val.position, "Super can only be called inside a function.", context))); } Ot = res.Register(Visit(node.right, context)); if (res.error != null) { return(res); } if (Ot.value.type != "FUNC") { return(res.Failure(new RuntimeError(Ot.position, "Function can only accept another function as a Super.", context))); } f.InnerValues.Merge(Ot.value.function.InnerValues, f); return(res.Succes(new LToken(TokenType.VALUE, Value.NULL, node.val.position))); case "RUN": Ot = res.Register(Visit(node.right, context)); if (res.error != null) { return(res); } if (Ot.value.type != "STRING") { return(res.Failure(new RuntimeError(node.val.position, "Run statement requires a string argument.", context))); } if (!System.IO.File.Exists(Ot.value.text)) { return(res.Failure(new RuntimeError(Ot.position, $"File {Ot.value.text} does not exist.", context))); } Ot = res.Register(Compiler.Run(System.IO.File.ReadAllText(Ot.value.text), new System.IO.FileInfo(Ot.value.text).Name)); if (res.error != null) { return(res); } return(res.Succes(Ot)); default: throw new Exception("Visit not defined"); } }
static RTResult VisitBinOp(PNode node, Context context) { RTResult res = new RTResult(); LToken r = res.Register(Visit(node.right, context)); if (res.error != null) { return(res); } LToken l = res.Register(Visit(node.left, context)); if (res.error != null) { return(res); } switch (node.val.type) { case TokenType.EE: return(res.Succes(new LToken(TokenType.VALUE, new Value(l.value == r.value), l.position).SetContext(context))); case TokenType.NE: return(res.Succes(new LToken(TokenType.VALUE, new Value(l.value != r.value), l.position).SetContext(context))); } if (l.value.isNumber && r.value.isNumber) { switch (node.val.type) { case TokenType.ADD: return(res.Succes(new LToken(TokenType.VALUE, new Value(l.value.number + r.value.number), l.position).SetContext(l.value.context))); case TokenType.SUB: return(res.Succes(new LToken(TokenType.VALUE, new Value(l.value.number - r.value.number), l.position).SetContext(l.value.context))); case TokenType.MULT: return(res.Succes(new LToken(TokenType.VALUE, new Value(l.value.number * r.value.number), l.position).SetContext(l.value.context))); case TokenType.DIV: if (r.value.number == 0) { res.Failure(new RuntimeError(node.val.position, "Division by zero error", context)); } return(res.Succes(new LToken(TokenType.VALUE, new Value(l.value.number / r.value.number), l.position).SetContext(l.value.context))); case TokenType.POW: return(res.Succes(new LToken(TokenType.VALUE, new Value(Math.Pow(l.value.number, r.value.number)), l.position).SetContext(l.value.context))); case TokenType.MOD: return(res.Succes(new LToken(TokenType.VALUE, new Value(l.value.number % r.value.number), l.position).SetContext(l.value.context))); case TokenType.GT: return(res.Succes(new LToken(TokenType.VALUE, new Value(l.value.number > r.value.number), l.position).SetContext(context))); case TokenType.LT: return(res.Succes(new LToken(TokenType.VALUE, new Value(l.value.number < r.value.number), l.position).SetContext(context))); case TokenType.GTE: return(res.Succes(new LToken(TokenType.VALUE, new Value(l.value.number >= r.value.number), l.position).SetContext(context))); case TokenType.LTE: return(res.Succes(new LToken(TokenType.VALUE, new Value(l.value.number <= r.value.number), l.position).SetContext(context))); } } else if (l.value.type == "BOOLEAN" && r.value.type == "BOOLEAN") { switch (node.val.type) { case TokenType.AND: return(res.Succes(new LToken(TokenType.VALUE, new Value(l.value.boolean && r.value.boolean), l.position).SetContext(l.value.context))); case TokenType.OR: return(res.Succes(new LToken(TokenType.VALUE, new Value(l.value.boolean || r.value.boolean), l.position).SetContext(l.value.context))); } } else if (l.value.type == "LIST" && r.value.type == "LIST") { switch (node.val.type) { case TokenType.ADD: List <Value> Vs = new List <Value>(l.value.values.ToArray()); Vs.AddRange(r.value.values); return(res.Succes(new LToken(TokenType.VALUE, new Value(Vs), l.position).SetContext(l.value.context))); } } else if (l.value.type == "STRING" || r.value.type == "STRING") { switch (node.val.type) { case TokenType.ADD: return(res.Succes(new LToken(TokenType.VALUE, new Value(l.value.ToString() + r.value.ToString()), l.position).SetContext(l.value.context))); } } return(res.Failure(new RuntimeError(node.val.position, $"Invalid operation for {l.value.type} and {r.value.type}.", context))); }
static RTResult VisitVarAsign(PNode node, Context context) { RTResult res = new RTResult(); if (Compiler.forbidden.Contains(node.val.value.text)) { return(res.Failure(new RuntimeError(node.val.position, $"{node.val.value.text} is a predefined, unmutable variable", context))); } if (node.TYPE == "PublicVarMake" || node.TYPE == "PublicPrototype") { if (context.GetFunction() == null) { return(res.Failure(new RuntimeError(node.val.position, "Public variables have to be declared in an object.", context))); } } if (node.TYPE == "VarAsign") { if (context.GetFunction() == null) { if (!context.varlist.ContainsKey(node.val.value.text)) { return(res.Failure(new RuntimeError(node.val.position, $"{node.val.value.text} is not Defined", context))); } } else if (!context.varlist.ContainsKey(node.val.value.text) && !context.GetFunction().InnerValues.ContainsKey(node.val.value.text)) { return(res.Failure(new RuntimeError(node.val.position, $"{node.val.value.text} is not Defined", context))); } } else if (node.TYPE == "PublicVarMake") { if (context.GetFunction().InnerValues.ContainsKey(node.val.value.text)) { return(res.Failure(new RuntimeError(node.val.position, $"{node.val.value.text} is already Defined", context))); } } else if (node.TYPE != "PublicPrototype") { if (context.varlist.ContainsKey(node.val.value.text)) { return(res.Failure(new RuntimeError(node.val.position, $"{node.val.value.text} is already Defined", context))); } } LToken n = res.Register(Visit(node.right, context)); if (res.error != null) { return(res); } LToken Val = new LToken(TokenType.VALUE, n.value, node.val.position).SetContext(n.value.context); Function f = context.GetFunction(); if (node.TYPE == "PublicVarMake" || node.TYPE == "PublicPrototype") { if (Val.value.type == "FUNC") { Val.value.function.InnerValues.parent = f.InnerValues; } f.InnerValues[node.val.value.text] = Val; } else if (f != null) { if (f.InnerValues.ContainsKey(node.val.value.text)) { if (Val.value.type == "FUNC") { Val.value.function.InnerValues.parent = f.InnerValues; } f.InnerValues[node.val.value.text] = Val; } else { context.varlist[node.val.value.text] = Val; } } else { context.varlist[node.val.value.text] = Val; } return(res.Succes(Val.SetContext(context))); }