protected void ResolveVarExpr(AstVarExpr expr) { var scope = Scope(); if (scope == null) { return; // TODO: Better global handling } if (expr.m_instance != null) { // Can't resolve properties (i.e., right-hand side of .), but we still want to resolve the instance (i.e., left-hand-side of .) ResolveExpr(expr.m_instance); } else { if (scope.ContainsKey(expr.m_identifier.m_identifier) && !scope[expr.m_identifier.m_identifier]) { m_error = true; Lox.Error(expr.m_startLine, "Cannot use identifier \"" + expr.m_identifier.m_identifier + "\" in it's own initialization."); return; } ResolveLocal(expr.m_identifier, expr.m_startLine); } }
protected object EvaluateVarExpr(AstVarExpr expr) { if (HadErrorOrReturn()) { return(null); } if (expr.m_instance == null) { object result = null; bool success = m_environment.Get(expr.m_identifier, out result); if (!success) { m_runtimeError = true; Lox.Error(expr.m_startLine, "Undeclared identifier \"" + expr.m_identifier.m_identifier + "\""); return(null); } return(result); } else { object instanceObj = EvaluateExpr(expr.m_instance); Instance instance = instanceObj as Instance; if (instance != null) { object value; bool success = instance.TryGetMember(expr.m_identifier.m_identifier, out value); if (success) { return(value); } m_runtimeError = true; Lox.Error(expr.m_startLine, "Undefined member \"" + expr.m_identifier + "\""); return(null); } else { m_runtimeError = true; Lox.Error(expr.m_startLine, "Only class instances can access properties with '.'"); 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); } } }
public AstAssignmentExpr(AstVarExpr lhs, AstExpr rhs) : base(EXPRK.Assignment, lhs.m_startLine) { m_lhs = lhs; m_rhs = rhs; }