protected void ResolveFunCallExpr(AstFunCallExpr expr) { ResolveExpr(expr.m_callee); foreach (AstExpr arg in expr.m_args) { ResolveExpr(arg); } }
protected object EvaluateFunCallExpr(AstFunCallExpr expr) { if (HadErrorOrReturn()) { return(null); } object calleeObj = EvaluateExpr(expr.m_callee); IFunction callee = calleeObj as IFunction; if (callee != null) { if (expr.m_args.Count != callee.ArgCount()) { // TODO: print function name in the error m_runtimeError = true; Lox.Error(expr.m_startLine, "Function expected " + callee.ArgCount() + " arguments, but was passed " + expr.m_args.Count); return(null); } List <object> args = new List <object>(); foreach (AstExpr argExpr in expr.m_args) { args.Add(EvaluateExpr(argExpr)); } return(callee.Call(this, args)); } else { // TODO: Distinguish between someUnknownFunction() and (3 + 1)() ? // It would be nice to be able to print the name of the function in the former case m_runtimeError = true; Lox.Error(expr.m_startLine, "Invalid function call"); return(null); } }
protected AstExpr ParseFunCallExpr() { AstExpr expr = ParsePrimaryExpr(); if (expr == null) { return(EmptyErrorExpr()); } Token token; // NOTE (andrews) While loop handles chained function calls and member access like this: // some.member.functionThatReturnsFunction()(); while (true) { if ((token = TryMatch(TOKENK.OpenParen)) != null) { bool isFirstArg = true; List <AstExpr> args = new List <AstExpr>(); while ((token = TryMatch(TOKENK.CloseParen)) == null) { if (!isFirstArg) { AstExpr prevArg = args[args.Count - 1]; if ((token = TryMatch(TOKENK.Comma)) == null) { return(ErrorExpr(prevArg.m_startLine, "Expected ',' in argument list")); } if (args.Count == AstFunCallExpr.s_maxArgCount) { // NOTE (andrews) This isn't a parse error so we don't return ErrorExpr like we do for other parse errors. // This lets us report it while continuing the parse in case we find other errors. Lox.Error(prevArg.m_startLine, "Cannot exceed " + AstFunCallExpr.s_maxArgCount + " arguments"); } } AstExpr arg = ParseExpr(); if (arg == null) { return(EmptyErrorExpr()); } args.Add(arg); isFirstArg = false; } expr = new AstFunCallExpr(expr, args); } else if ((token = TryMatch(TOKENK.Dot)) != null) { if ((token = TryMatch(TOKENK.Identifier)) != null) { expr = new AstVarExpr(expr, token); } } else { return(expr); } } }