Example #1
0
    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;
        }
    }
Example #2
0
    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;
        }
    }
Example #3
0
    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);
    }
Example #4
0
    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);
    }
Example #5
0
    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;
        }
    }
Example #6
0
    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);
    }