protected void ExecuteStmt(AstStmt stmt) { if (HadErrorOrReturn()) { return; } switch (stmt.m_stmtk) { case STMTK.Expr: ExecuteExprStmt((AstExprStmt)stmt); break; case STMTK.Print: ExecutePrintStmt((AstPrintStmt)stmt); break; case STMTK.VarDecl: ExecuteVarDeclStmt((AstVarDeclStmt)stmt); break; case STMTK.FunDecl: ExecuteFunDeclStmt((AstFunDeclStmt)stmt); break; case STMTK.ClassDecl: ExecuteClassDeclStmt((AstClassDeclStmt)stmt); break; case STMTK.Block: ExecuteBlockStmt((AstBlockStmt)stmt); break; case STMTK.If: ExecuteIfStmt((AstIfStmt)stmt); break; case STMTK.While: ExecuteWhileStmt((AstWhileStmt)stmt); break; case STMTK.For: ExecuteForStmt((AstForStmt)stmt); break; case STMTK.Break: ExecuteBreakStmt((AstBreakStmt)stmt); break; case STMTK.Continue: ExecuteContinueStmt((AstContinueStmt)stmt); break; case STMTK.Return: ExecuteReturnStmt((AstReturnStmt)stmt); break; default: { m_runtimeError = true; Lox.InternalError(stmt.m_startLine, "Unexpected statement kind " + stmt.m_stmtk); } break; } }
protected void ResolveStmt(AstStmt stmt) { // todo when error? switch (stmt.m_stmtk) { case STMTK.Expr: ResolveExprStmt((AstExprStmt)stmt); break; case STMTK.Print: ResolvePrintStmt((AstPrintStmt)stmt); break; case STMTK.VarDecl: ResolveVarDeclStmt((AstVarDeclStmt)stmt); break; case STMTK.FunDecl: ResolveFunDeclStmt((AstFunDeclStmt)stmt); break; case STMTK.ClassDecl: ResolveClassDeclStmt((AstClassDeclStmt)stmt); break; case STMTK.Block: ResolveBlockStmt((AstBlockStmt)stmt); break; case STMTK.If: ResolveIfStmt((AstIfStmt)stmt); break; case STMTK.While: ResolveWhileStmt((AstWhileStmt)stmt); break; case STMTK.For: ResolveForStmt((AstForStmt)stmt); break; case STMTK.Return: ResolveReturnStmt((AstReturnStmt)stmt); break; // NOP case STMTK.Break: case STMTK.Continue: break; default: { m_error = true; Lox.InternalError(stmt.m_startLine, "Unexpected statement kind in resolver " + stmt.m_stmtk); } break; } }
protected object EvaluateExpr(AstExpr expr) { if (HadErrorOrReturn()) { return(null); } switch (expr.m_exprk) { case EXPRK.Assignment: return(EvaluateAssignmentExpr((AstAssignmentExpr)expr)); case EXPRK.Unary: return(EvaluateUnaryExpr((AstUnaryExpr)expr)); case EXPRK.Binary: return(EvaluateBinaryExpr((AstBinaryExpr)expr)); case EXPRK.Literal: return(EvaluateLiteralExpr((AstLiteralExpr)expr)); case EXPRK.Group: return(EvaluateGroupExpr((AstGroupExpr)expr)); case EXPRK.Var: return(EvaluateVarExpr((AstVarExpr)expr)); case EXPRK.FunCall: return(EvaluateFunCallExpr((AstFunCallExpr)expr)); case EXPRK.This: return(EvaluateThisExpr((AstThisExpr)expr)); default: { m_runtimeError = true; Lox.InternalError(expr.m_startLine, "Unexpected expression kind " + expr.m_exprk); } break; } Debug.Assert(m_runtimeError); return(null); }
protected object EvaluateUnaryExpr(AstUnaryExpr expr) { if (HadErrorOrReturn()) { return(null); } object value = EvaluateExpr(expr.m_expr); switch (expr.m_tokenkOp) { case TOKENK.Bang: { return(!IsTruthy(value)); } break; case TOKENK.Minus: { double?numVal = value as double?; if (numVal.HasValue) { return(-numVal.Value); } m_runtimeError = true; Lox.Error(expr.m_startLine, "Unary - operator can only be applied to numbers"); } break; default: { m_runtimeError = true; Lox.InternalError(expr.m_startLine, "Unary expression has unexpected operator: " + expr.m_tokenkOp); } break; } Debug.Assert(m_runtimeError); return(null); }
protected void ResolveExpr(AstExpr expr) { // todo when error? switch (expr.m_exprk) { case EXPRK.Assignment: ResolveAssignmentExpr((AstAssignmentExpr)expr); break; case EXPRK.Unary: ResolveUnaryExpr((AstUnaryExpr)expr); break; case EXPRK.Binary: ResolveBinaryExpr((AstBinaryExpr)expr); break; case EXPRK.Group: ResolveGroupExpr((AstGroupExpr)expr); break; case EXPRK.Var: ResolveVarExpr((AstVarExpr)expr); break; case EXPRK.FunCall: ResolveFunCallExpr((AstFunCallExpr)expr); break; case EXPRK.This: ResolveThisExpr((AstThisExpr)expr); break; // NOP case EXPRK.Literal: break; default: { m_error = true; Lox.InternalError(expr.m_startLine, "Unexpected expression kind in resolver " + expr.m_exprk); } break; } }
protected object EvaluateBinaryExpr(AstBinaryExpr expr) { if (HadErrorOrReturn()) { return(null); } object lValue = EvaluateExpr(expr.m_leftExpr); // Test the logical operators first so we can short circuit w/o evaluating rhs switch (expr.m_tokenkOp) { case TOKENK.Or: { if (IsTruthy(lValue)) { return(lValue); } object rVal = EvaluateExpr(expr.m_rightExpr); return(rVal); } break; case TOKENK.And: { if (!IsTruthy(lValue)) { return(lValue); } object rVal = EvaluateExpr(expr.m_rightExpr); return(rVal); } break; } object rValue = EvaluateExpr(expr.m_rightExpr); double?lNum = lValue as double?; double?rNum = rValue as double?; switch (expr.m_tokenkOp) { case TOKENK.Minus: { if (lNum.HasValue && rNum.HasValue) { return(lNum.Value - rNum.Value); } m_runtimeError = true; Lox.Error(expr.m_startLine, "'-' only supported for numbers"); } break; case TOKENK.Slash: { if (lNum.HasValue && rNum.HasValue) { if (rNum.Value == 0) { m_runtimeError = true; Lox.Error(expr.m_startLine, "Divide by 0 error"); return(null); } return(lNum.Value / rNum.Value); } m_runtimeError = true; Lox.Error(expr.m_startLine, "'/' only supported for numbers"); } break; case TOKENK.Star: { if (lNum.HasValue && rNum.HasValue) { return(lNum.Value * rNum.Value); } m_runtimeError = true; Lox.Error(expr.m_startLine, "'*' only supported for numbers"); } break; case TOKENK.Plus: { string lStr = lValue as string; string rStr = rValue as string; if ((lStr == null && !lNum.HasValue) || (rStr == null && !rNum.HasValue)) { m_runtimeError = true; Lox.Error(expr.m_startLine, "'+' only supported for numbers and strings"); } else { if (lNum.HasValue && rNum.HasValue) { return(lNum.Value + rNum.Value); } if (lStr != null) { if (rStr != null) { return(lStr + rStr); } Debug.Assert(rNum.HasValue); return(lStr + rNum.Value); } Debug.Assert(rStr != null); Debug.Assert(lNum.HasValue); return(lNum.Value + rStr); } } break; case TOKENK.EqualEqual: { return(IsEqual(lValue, rValue)); } break; case TOKENK.BangEqual: { return(IsEqual(lValue, rValue)); } break; // TODO: support lexically comparing strings? case TOKENK.Lesser: { if (lNum.HasValue && rNum.HasValue) { return(lNum.Value < rNum.Value); } m_runtimeError = true; Lox.Error(expr.m_startLine, "'<' only supported for numbers"); } break; case TOKENK.Greater: { if (lNum.HasValue && rNum.HasValue) { return(lNum.Value > rNum.Value); } m_runtimeError = true; Lox.Error(expr.m_startLine, "'>' only supported for numbers"); } break; case TOKENK.LesserEqual: { if (lNum.HasValue && rNum.HasValue) { return(lNum.Value <= rNum.Value); } m_runtimeError = true; Lox.Error(expr.m_startLine, "'<=' only supported for numbers"); } break; case TOKENK.GreaterEqual: { if (lNum.HasValue && rNum.HasValue) { return(lNum.Value >= rNum.Value); } m_runtimeError = true; Lox.Error(expr.m_startLine, "'>=' only supported for numbers"); } break; default: { m_runtimeError = true; Lox.InternalError(expr.m_startLine, "Binary expression has unexpected operator: " + expr.m_tokenkOp); } break; } Debug.Assert(m_runtimeError); return(null); }