protected void ExecuteVarDeclStmt(AstVarDeclStmt stmt) { if (HadErrorOrReturn()) { return; } object value = null; if (stmt.m_initExpr != null) { value = EvaluateExpr(stmt.m_initExpr); } bool success = m_environment.Define(stmt.m_identifier.m_identifier, value); if (!success) { // TODO: Print the line that the first definition was on? To do that we would have to store // line numbers in the environment. Also, it wouldn't really make sense for repl mode so we would // have to have a way to check if we are in repl mode. m_runtimeError = true; Lox.Error(stmt.m_startLine, "Redefinition of identifier " + stmt.m_identifier.m_identifier); } }
protected void ResolveVarDeclStmt(AstVarDeclStmt stmt) { var scope = Scope(); if (scope == null) { return; // TODO: Better global handling } if (scope.ContainsKey(stmt.m_identifier.m_identifier)) { m_error = true; Lox.Error(stmt.m_startLine, "Redefinition of identifier \"" + stmt.m_identifier.m_identifier + "\" in same scope"); return; } // Declared but not yet initialized scope[stmt.m_identifier.m_identifier] = false; if (stmt.m_initExpr != null) { ResolveExpr(stmt.m_initExpr); } // Declared and initialized scope[stmt.m_identifier.m_identifier] = true; }
public AstForStmt(int startLine, AstVarDeclStmt pre, AstExpr condition, AstExpr post, AstStmt body) : base(STMTK.For, startLine) { m_preDecl = pre; m_condition = condition; m_post = post; m_body = body; }
protected AstStmt ParseForStmt() { PushLoop(); try { Token forToken = Previous(); Debug.Assert(forToken.m_tokenk == TOKENK.For); Token openParen; Token closeParen; AstVarDeclStmt preDecl = null; AstExpr preExpr = null; AstExpr condition = null; AstExpr post = null; Token semicolon; if ((openParen = TryMatch(TOKENK.OpenParen)) == null) { return(ErrorStmt(forToken.m_line, "Expected '(' after \"for\"")); } if ((semicolon = TryMatch(TOKENK.Semicolon)) == null) { Token varToken; if ((varToken = TryMatch(TOKENK.Var)) != null) { AstStmt stmt = ParseVarDeclStmt(); if (stmt == null) { return(EmptyErrorStmt()); } Debug.Assert(stmt.m_stmtk == STMTK.VarDecl); preDecl = (AstVarDeclStmt)stmt; } else { AstStmt stmt = ParseExprStmt(); if (stmt == null) { return(EmptyErrorStmt()); } Debug.Assert(stmt.m_stmtk == STMTK.Expr); preExpr = ((AstExprStmt)stmt).m_expr; } } if ((semicolon = TryMatch(TOKENK.Semicolon)) == null) { AstStmt stmt = ParseExprStmt(); if (stmt == null) { return(EmptyErrorStmt()); } Debug.Assert(stmt.m_stmtk == STMTK.Expr); condition = ((AstExprStmt)stmt).m_expr; } if ((closeParen = TryMatch(TOKENK.CloseParen)) == null) { post = ParseExpr(); if (post == null) { return(EmptyErrorStmt()); } if ((closeParen = TryMatch(TOKENK.CloseParen)) == null) { return(ErrorStmt(forToken.m_line, "Expected ')' at end of \"for\"")); } } AstStmt body = ParseStmt(); if (body == null) { return(EmptyErrorStmt()); } if (preDecl != null) { return(new AstForStmt(forToken.m_line, preDecl, condition, post, body)); } else { return(new AstForStmt(forToken.m_line, preExpr, condition, post, body)); } } finally { PopLoop(); } }