private RuntimeResult VisitCallNode(CallNode node, Context context, Context fromCtx = null) { List <(string, Values.Value)> args = new List <(string, Values.Value)>(); for (int i = 0; i < node.Arguments.Count; i++) { RuntimeResult result = Visit(node.Arguments[i].Item2, fromCtx == null ? context : fromCtx); if (result.HasError) { return(result); } args.Add((node.Arguments[i].Item1, result.Value)); } if (node.Node.Type == NodeType.VAR_ACCESS) { VarAccessNode accessNode = (VarAccessNode)node.Node; string name = accessNode.Token.Value.ToString(); if (BuiltinMethods.BuiltinMethodList.ContainsKey(name)) { return(BuiltinMethods.Execute(name, args, node.Position, context)); } else { Values.Value method = context.GetSymbol(name); if (method == null) { return(new RuntimeResult(new RuntimeError(node.Position, "Method '" + name + "' is not defined", context))); } if (method.Type == Values.ValueType.METHOD) { return(((Values.MethodValue)method).Execute(args, this)); } else if (method.Type == Values.ValueType.CLASS) { Values.ClassValue classValue = ((Values.ClassValue)method).Clone(); //classValue.Type = Values.ValueType.OBJECT; if (classValue.BaseClass != null) { RuntimeResult baseResult = classValue.InitializeBaseClass(context, this); if (baseResult.HasError) { return(baseResult); } Context newContext = new Context(name, baseResult.Value.Context); classValue.SetPositionAndContext(accessNode.Token.Position, newContext); newContext.AddSymbol("this", classValue); newContext.AddSymbol("base", baseResult.Value); RuntimeResult runtimeResult = Visit(classValue.Body, newContext); if (runtimeResult.HasError) { return(runtimeResult); } //Constructor Values.Value ctorValue = newContext.GetSymbol("init"); if (ctorValue != null && ctorValue.Type == Values.ValueType.METHOD) { Values.MethodValue initMethod = (Values.MethodValue)ctorValue; RuntimeResult res = initMethod.Execute(args, this); if (res.HasError) { return(res); } } return(new RuntimeResult(classValue)); } else { Context newContext = new Context(name, context); classValue.SetPositionAndContext(accessNode.Token.Position, newContext); newContext.AddSymbol("this", classValue); RuntimeResult runtimeResult = Visit(classValue.Body, newContext); if (runtimeResult.HasError) { return(runtimeResult); } //Constructor Values.Value ctorValue = newContext.GetSymbol("init"); if (ctorValue != null && ctorValue.Type == Values.ValueType.METHOD) { Values.MethodValue initMethod = (Values.MethodValue)ctorValue; initMethod.Execute(args, this); } return(new RuntimeResult(classValue)); } } return(new RuntimeResult(new RuntimeError(node.Position, "'" + name + "' is not a method", context))); } } return(new RuntimeResult(new RuntimeError(node.Position, "Can't call as a method", context))); }
private RuntimeResult VisitMethodNode(MethodNode node, Context context) { string name = "anonymous"; if (node.Token != null) { switch (node.Token.Type) { case TokenType.IDENTIFIER: name = node.Token.Value.ToString(); break; case TokenType.PLUS: name = "-add-"; break; case TokenType.MINUS: name = "-sub-"; break; case TokenType.MULTIPLY: name = "-mul-"; break; case TokenType.DIVIDE: name = "-div-"; break; case TokenType.MODULUS: name = "-mod-"; break; case TokenType.EXPONENT: name = "-exp-"; break; case TokenType.STRING: name = "-str-"; break; case TokenType.LEFT_SQB: name = "-sst-"; break; case TokenType.LESS_THAN: name = "-les-"; break; case TokenType.LESS_TOE: name = "-lte-"; break; case TokenType.GREATER_THAN: name = "-gre-"; break; case TokenType.GREATER_TOE: name = "-gte-"; break; case TokenType.EQUALS_EQUALS: name = "-eeq-"; break; case TokenType.NOT_EQUALS: name = "-neq-"; break; case TokenType.BITWISE_AND: name = "-ban-"; break; case TokenType.BITWISE_OR: name = "-bor-"; break; case TokenType.BITWISE_XOR: name = "-xor-"; break; case TokenType.COMPLEMENT: name = "-com-"; break; case TokenType.EQUALS: name = "-sse-"; break; case TokenType.LEFT_SHIFT: name = "-lsh-"; break; case TokenType.RIGHT_SHIFT: name = "-rsh-"; break; case TokenType.BOOLEAN_AND: name = "-and-"; break; case TokenType.BOOLEAN_OR: name = "-orr-"; break; case TokenType.BOOLEAN_NOT: name = "-not-"; break; case TokenType.IN: name = "-inn-"; break; } } Values.Value method = new Values.MethodValue(name, node.Parameters, node.Body, node.DefaultValues).SetPositionAndContext(node.Position, context); if (node.Token != null) { context.AddSymbol(name, method); } return(new RuntimeResult(method)); }