Example #1
0
        private object EvaluateOperand(StackValue value)
        {
            switch (value.Type)
            {
            case ValType.Integer:
                return((int)value.Value);

            case ValType.Float:
                return((float)value.Value);

            case ValType.Bool:
                return((bool)value.Value);

            case ValType.Char:
                return((char)value.Value);

            case ValType.String:
                return((string)value.Value);

            case ValType.Identifier:
                return(CurrentScope.Get((string)value.Value));

            case ValType.Type:
                return(value.CastTo <ValType>());

            case ValType.Null:
                return(null);

            default:
                return(0);
            }
        }
Example #2
0
        private bool Truthify(StackValue value)
        {
            switch (value.Type)
            {
            case ValType.Null:
                return(false);

            case ValType.Bool:
                return(value.CastTo <bool>());

            case ValType.Identifier:
                return(Truthify(ResolveStackValue(value)));

            default:
                return(true);
            }
        }
Example #3
0
 StackValue ResolveStackValue(StackValue stackValue)
 {
     if (stackValue.Type == ValType.Identifier)
     {
         var varname = stackValue.CastTo <string>();
         if (!CurrentScope.Contain(varname))
         {
             RuntimeError($"{varname} is not defined");
         }
         var value = CurrentScope.Get(varname);
         if (value is null)
         {
             return(new StackValue(ValType.Null, null));
         }
         else if (value.GetType() == typeof(float))
         {
             return(new StackValue(ValType.Float, value));
         }
         else if (value.GetType() == typeof(bool))
         {
             return(new StackValue(ValType.Bool, value));
         }
         else if (value.GetType() == typeof(char))
         {
             return(new StackValue(ValType.Char, value));
         }
         else if (value.GetType() == typeof(string))
         {
             return(new StackValue(ValType.String, value));
         }
         else
         {
             return(new StackValue(ValType.Integer, value));
         }
     }
     else
     {
         return(stackValue);
     }
 }
Example #4
0
        private StackValue Evaluate(ASTNode Expression)
        {
            #region operation
            int IntegerOperation(StackValue operand1, StackValue operand2, TokenType op)
            {
                int i1 = (int)operand1.Value;
                int i2 = (int)operand2.Value;

                switch (op)
                {
                case TokenType.PLUS:
                    return(i1 + i2);

                case TokenType.MINUS:
                    return(i1 - i2);

                case TokenType.MULTIPLY:
                    return(i1 * i2);

                case TokenType.DIVIDE:
                    return(i1 / i2);

                case TokenType.MODULO:
                    return(i1 % i2);
                }

                return(0);
            }

            float FloatOperation(StackValue operand1, StackValue operand2, TokenType op)
            {
                float f1 = operand1.Value is float?(float)operand1.Value : (int)operand1.Value;
                float f2 = operand2.Value is float?(float)operand2.Value : (int)operand2.Value;

                switch (op)
                {
                case TokenType.PLUS:
                    return(f1 + f2);

                case TokenType.MINUS:
                    return(f1 - f2);

                case TokenType.MULTIPLY:
                    return(f1 * f2);

                case TokenType.DIVIDE:
                    return(f1 / f2);

                case TokenType.EXPONENT:
                    return((float)Math.Pow(f1, f2));
                }

                return(0);
            }

            string StringOperation(StackValue operand1, StackValue operand2, TokenType op)
            {
                string s1 = operand1.Value.ToString();
                string s2 = operand2.Value.ToString();

                if (op == TokenType.PLUS)
                {
                    return(s1 + s2);
                }

                return("");
            }

            bool BoolOperation(StackValue operand1, StackValue operand2, TokenType op)
            {
                bool b1 = (bool)operand1.Value;
                bool b2 = op == TokenType.NOT ? true : (bool)operand2.Value;

                switch (op)
                {
                case TokenType.AND:
                    return(b1 && b2);

                case TokenType.OR:
                    return(b1 || b2);

                case TokenType.XOR:
                    return(b1 ^ b2);

                case TokenType.NOT:
                    return(!b1);
                }

                return(false);
            }

            bool IntComparison(StackValue operand1, StackValue operand2, TokenType op)
            {
                int i1 = (int)operand1.Value;
                int i2 = (int)operand2.Value;

                switch (op)
                {
                case TokenType.EQUAL:
                    return(i1 == i2);

                case TokenType.NOTEQUAL:
                    return(i1 != i2);

                case TokenType.LARGER:
                    return(i1 > i2);

                case TokenType.LARGEREQUAL:
                    return(i1 >= i2);

                case TokenType.LESSER:
                    return(i1 < i2);

                case TokenType.LESSEREQUAL:
                    return(i1 <= i2);
                }
                return(false);
            }

            bool FloatComparison(StackValue operand1, StackValue operand2, TokenType op)
            {
                float f1 = (float)operand1.Value;
                float f2 = (float)operand2.Value;

                switch (op)
                {
                case TokenType.EQUAL:
                    return(f1 == f2);

                case TokenType.NOTEQUAL:
                    return(f1 != f2);

                case TokenType.LARGER:
                    return(f1 > f2);

                case TokenType.LARGEREQUAL:
                    return(f1 >= f2);

                case TokenType.LESSER:
                    return(f1 < f2);

                case TokenType.LESSEREQUAL:
                    return(f1 <= f2);
                }
                return(false);
            }

            bool CharComparison(StackValue operand1, StackValue operand2, TokenType op)
            {
                char c1 = (char)operand1.Value;
                char c2 = (char)operand2.Value;

                switch (op)
                {
                case TokenType.EQUAL:
                    return(c1 == c2);

                case TokenType.NOTEQUAL:
                    return(c1 != c2);

                case TokenType.LARGER:
                    return(c1 > c2);

                case TokenType.LARGEREQUAL:
                    return(c1 >= c2);

                case TokenType.LESSER:
                    return(c1 < c2);

                case TokenType.LESSEREQUAL:
                    return(c1 <= c2);
                }
                return(false);
            }

            bool StringComparison(StackValue operand1, StackValue operand2, TokenType op)
            {
                string s1         = (string)operand1.Value;
                string s2         = (string)operand2.Value;
                var    comparison = s1.CompareTo(s2);

                switch (op)
                {
                case TokenType.EQUAL:
                    return(s1.Equals(s2));

                case TokenType.NOTEQUAL:
                    return(!s1.Equals(s2));

                case TokenType.LARGER:
                    return(comparison > 0);

                case TokenType.LARGEREQUAL:
                    return(comparison >= 0);

                case TokenType.LESSER:
                    return(comparison < 0);

                case TokenType.LESSEREQUAL:
                    return(comparison <= 0);
                }
                return(false);
            }

            bool BoolComparison(StackValue operand1, StackValue operand2, TokenType op)
            {
                bool b1 = (bool)operand1.Value;
                bool b2 = (bool)operand2.Value;

                switch (op)
                {
                case TokenType.EQUAL:
                    return(b1 == b2);

                case TokenType.NOTEQUAL:
                    return(b1 != b2);
                }
                return(false);
            }

            bool Comparison(StackValue operand1, StackValue operand2, TokenType op)
            {
                bool result = true;

                switch (operand1.Type)
                {
                case ValType.Integer:
                    int i1 = (int)operand1.Value;
                    if (operand2.Type == ValType.Float)
                    {
                        //do int comparison
                        int i2 = (int)(float)operand2.Value;
                        switch (op)
                        {
                        case TokenType.EQUAL:
                            result = i1 == i2;
                            break;

                        case TokenType.NOTEQUAL:
                            result = i1 != i2;
                            break;

                        case TokenType.LARGER:
                            result = i1 > i2;
                            break;

                        case TokenType.LARGEREQUAL:
                            result = i1 >= i2;
                            break;

                        case TokenType.LESSER:
                            result = i1 < i2;
                            break;

                        case TokenType.LESSEREQUAL:
                            result = i1 <= i2;
                            break;
                        }
                    }
                    else if (operand2.Type == ValType.Char)
                    {
                        //do int comparison
                        int i2 = (int)(char)operand2.Value;
                        switch (op)
                        {
                        case TokenType.EQUAL:
                            result = i1 == i2;
                            break;

                        case TokenType.NOTEQUAL:
                            result = i1 != i2;
                            break;

                        case TokenType.LARGER:
                            result = i1 > i2;
                            break;

                        case TokenType.LARGEREQUAL:
                            result = i1 >= i2;
                            break;

                        case TokenType.LESSER:
                            result = i1 < i2;
                            break;

                        case TokenType.LESSEREQUAL:
                            result = i1 <= i2;
                            break;
                        }
                    }
                    else
                    {
                        BinaryRuntimeError(operand1, operand2, op);
                    }
                    break;

                case ValType.Float:
                    float f1 = (float)operand1.Value;
                    if (operand2.Type == ValType.Integer)
                    {
                        //do flt math
                        float f2 = (float)(int)operand2.Value;
                        switch (op)
                        {
                        case TokenType.EQUAL:
                            result = f1 == f2;
                            break;

                        case TokenType.NOTEQUAL:
                            result = f1 != f2;
                            break;

                        case TokenType.LARGER:
                            result = f1 > f2;
                            break;

                        case TokenType.LARGEREQUAL:
                            result = f1 >= f2;
                            break;

                        case TokenType.LESSER:
                            result = f1 < f2;
                            break;

                        case TokenType.LESSEREQUAL:
                            result = f1 <= f2;
                            break;
                        }
                    }
                    else
                    {
                        BinaryRuntimeError(operand1, operand2, op);
                    }
                    break;

                case ValType.Char:
                    int c1 = (int)(char)operand1.Value;
                    if (operand2.Type == ValType.Integer)
                    {
                        //do int comparison
                        int c2 = (int)(char)operand2.Value;
                        switch (op)
                        {
                        case TokenType.EQUAL:
                            result = c1 == c2;
                            break;

                        case TokenType.NOTEQUAL:
                            result = c1 != c2;
                            break;

                        case TokenType.LARGER:
                            result = c1 > c2;
                            break;

                        case TokenType.LARGEREQUAL:
                            result = c1 >= c2;
                            break;

                        case TokenType.LESSER:
                            result = c1 < c2;
                            break;

                        case TokenType.LESSEREQUAL:
                            result = c1 <= c2;
                            break;
                        }
                    }
                    else
                    {
                        BinaryRuntimeError(operand1, operand2, op);
                    }
                    break;

                case ValType.Bool:
                    //cause there is no boolean comparison operator with mixed type
                    BinaryRuntimeError(operand1, operand2, op);
                    break;

                case ValType.String:
                    //cause there is no string comparison operator with mixed type
                    BinaryRuntimeError(operand1, operand2, op);
                    break;

                case ValType.Null:
                    BinaryRuntimeError(operand1, operand2, op);
                    break;
                }
                return(result);
            }

            bool TypeTesting(StackValue operand1, StackValue operand2, TokenType op)
            {
                ValType type = operand2.CastTo <ValType>();

                switch (op)
                {
                case TokenType.EQUAL:
                case TokenType.NOTEQUAL:
                    if (operand1.Type != ValType.Type)
                    {
                        return(false);
                    }
                    else
                    {
                        var type2 = operand1.CastTo <ValType>();
                        return(op == TokenType.EQUAL ? type == type2 : !(type == type2));
                    }

                case TokenType.IS:
                    // <value> is <Type>
                    return(operand1.Type == type);
                }

                return(false);
            }

            #endregion

            #region evaluate expression
            void EvaluateBinaryOperation(StackValue operand1, StackValue operand2, TokenType op)
            {
                var v1 = ResolveStackValue(operand1);
                var v2 = ResolveStackValue(operand2);

                if (v1.Type == v2.Type)
                {
                    switch (v1.Type)
                    {
                    case ValType.Integer:
                        switch (op)
                        {
                        case TokenType.PLUS:
                        case TokenType.MINUS:
                        case TokenType.MULTIPLY:
                        case TokenType.DIVIDE:
                        case TokenType.MODULO:
                            Push(IntegerOperation(v1, v2, op));
                            break;

                        case TokenType.EXPONENT:
                            Push(FloatOperation(v1, v2, TokenType.EXPONENT));
                            break;

                        case TokenType.EQUAL:
                        case TokenType.NOTEQUAL:
                        case TokenType.LARGER:
                        case TokenType.LARGEREQUAL:
                        case TokenType.LESSER:
                        case TokenType.LESSEREQUAL:
                            Push(IntComparison(v1, v2, op));
                            break;

                        default:
                            BinaryRuntimeError(v1, v2, op);
                            break;
                        }
                        break;

                    case ValType.Float:
                        switch (op)
                        {
                        case TokenType.PLUS:
                        case TokenType.MINUS:
                        case TokenType.MULTIPLY:
                        case TokenType.DIVIDE:
                        case TokenType.EXPONENT:
                            Push(FloatOperation(v1, v2, op));
                            break;

                        case TokenType.EQUAL:
                        case TokenType.NOTEQUAL:
                        case TokenType.LARGER:
                        case TokenType.LARGEREQUAL:
                        case TokenType.LESSER:
                        case TokenType.LESSEREQUAL:
                            Push(FloatComparison(v1, v2, op));
                            break;

                        default:
                            BinaryRuntimeError(v1, v2, op);
                            break;
                        }
                        break;

                    case ValType.Bool:
                        switch (op)
                        {
                        case TokenType.AND:
                        case TokenType.OR:
                        case TokenType.XOR:
                            Push(BoolOperation(v1, v2, op));
                            break;

                        case TokenType.EQUAL:
                        case TokenType.NOTEQUAL:
                            Push(BoolComparison(v1, v2, op));
                            break;

                        default:
                            BinaryRuntimeError(v1, v2, op);
                            break;
                        }
                        break;

                    case ValType.Char:
                        //concat char
                        switch (op)
                        {
                        case TokenType.PLUS:
                            Push(StringOperation(v1, v2, TokenType.PLUS));
                            break;

                        case TokenType.EQUAL:
                        case TokenType.NOTEQUAL:
                        case TokenType.LARGER:
                        case TokenType.LARGEREQUAL:
                        case TokenType.LESSER:
                        case TokenType.LESSEREQUAL:
                            Push(CharComparison(v1, v2, op));
                            break;

                        default:
                            BinaryRuntimeError(v1, v2, op);
                            break;
                        }
                        break;

                    case ValType.String:
                        //concat string
                        switch (op)
                        {
                        case TokenType.PLUS:
                            Push(StringOperation(v1, v2, TokenType.PLUS));
                            break;

                        case TokenType.EQUAL:
                        case TokenType.NOTEQUAL:
                        case TokenType.LARGER:
                        case TokenType.LARGEREQUAL:
                        case TokenType.LESSER:
                        case TokenType.LESSEREQUAL:
                            Push(StringComparison(v1, v2, op));
                            break;

                        default:
                            BinaryRuntimeError(v1, v2, op);
                            break;
                        }
                        break;

                    case ValType.Null:
                        BinaryRuntimeError(v1, v2, op);
                        break;

                    case ValType.Type:
                        switch (op)
                        {
                        case TokenType.EQUAL:
                        case TokenType.NOTEQUAL:
                            Push(TypeTesting(v1, v2, op));
                            break;

                        default:
                            BinaryRuntimeError(v1, v2, op);
                            break;
                        }
                        break;

                    default:
                        switch (op)
                        {
                        case TokenType.IS:
                            Push(TypeTesting(v1, v2, op));
                            break;

                        default:
                            BinaryRuntimeError(v1, v2, op);
                            break;
                        }
                        break;
                    }
                }
                else
                {
                    switch (v1.Type)
                    {
                    case ValType.Integer:
                        if (v2.Type == ValType.Float)
                        {
                            //do flt math
                            switch (op)
                            {
                            case TokenType.PLUS:
                            case TokenType.MINUS:
                            case TokenType.MULTIPLY:
                            case TokenType.DIVIDE:
                            case TokenType.EXPONENT:
                                Push(FloatOperation(v1, v2, op));
                                break;

                            case TokenType.EQUAL:
                            case TokenType.NOTEQUAL:
                            case TokenType.LARGER:
                            case TokenType.LARGEREQUAL:
                            case TokenType.LESSER:
                            case TokenType.LESSEREQUAL:
                                Push(Comparison(v1, v2, op));
                                break;
                            }
                        }
                        else if (v2.Type == ValType.Char)
                        {
                            //do int math
                            switch (op)
                            {
                            case TokenType.PLUS:
                            case TokenType.MINUS:
                            case TokenType.MULTIPLY:
                            case TokenType.DIVIDE:
                                Push(IntegerOperation(v1, v2, op));
                                break;

                            case TokenType.EXPONENT:
                                Push(FloatOperation(v1, v2, TokenType.EXPONENT));
                                break;

                            case TokenType.EQUAL:
                            case TokenType.NOTEQUAL:
                            case TokenType.LARGER:
                            case TokenType.LARGEREQUAL:
                            case TokenType.LESSER:
                            case TokenType.LESSEREQUAL:
                                Push(Comparison(v1, v2, op));
                                break;
                            }
                        }
                        else if (op == TokenType.IS)
                        {
                            Push(TypeTesting(v1, v2, op));
                        }
                        else
                        {
                            BinaryRuntimeError(v1, v2, op);
                        }
                        break;

                    case ValType.Float:
                        if (v2.Type == ValType.Integer)
                        {
                            //do flt math
                            switch (op)
                            {
                            case TokenType.PLUS:
                            case TokenType.MINUS:
                            case TokenType.MULTIPLY:
                            case TokenType.DIVIDE:
                            case TokenType.EXPONENT:
                                Push(FloatOperation(v1, v2, op));
                                break;

                            case TokenType.EQUAL:
                            case TokenType.NOTEQUAL:
                            case TokenType.LARGER:
                            case TokenType.LARGEREQUAL:
                            case TokenType.LESSER:
                            case TokenType.LESSEREQUAL:
                                Push(Comparison(v1, v2, op));
                                break;
                            }
                        }
                        else if (op == TokenType.IS)
                        {
                            Push(TypeTesting(v1, v2, op));
                        }
                        else
                        {
                            BinaryRuntimeError(v1, v2, op);
                        }
                        break;

                    case ValType.Char:
                        switch (op)
                        {
                        case TokenType.EQUAL:
                        case TokenType.NOTEQUAL:
                        case TokenType.LARGER:
                        case TokenType.LARGEREQUAL:
                        case TokenType.LESSER:
                        case TokenType.LESSEREQUAL:
                            Push(Comparison(v1, v2, op));
                            break;

                        case TokenType.IS:
                            Push(TypeTesting(v1, v2, op));
                            break;

                        default:
                            BinaryRuntimeError(v1, v2, op);
                            break;
                        }
                        break;

                    case ValType.Bool:
                        if (op == TokenType.IS)
                        {
                            Push(TypeTesting(v1, v2, op));
                        }
                        else
                        {
                            BinaryRuntimeError(v1, v2, op);
                        }
                        break;

                    case ValType.String:
                        //concat string
                        if (op == TokenType.PLUS)
                        {
                            Push(StringOperation(v1, v2, TokenType.PLUS));
                        }
                        else if (op == TokenType.IS)
                        {
                            Push(TypeTesting(v1, v2, op));
                        }
                        else if (op == TokenType.IS)
                        {
                            Push(TypeTesting(v1, v2, op));
                        }
                        else
                        {
                            BinaryRuntimeError(v1, v2, op);
                        }
                        break;

                    default:
                        switch (op)
                        {
                        case TokenType.IS:
                            Push(TypeTesting(v1, v2, op));
                            break;

                        default:
                            BinaryRuntimeError(v1, v2, op);
                            break;
                        }
                        break;
                    }
                }
            }

            void EvaluateUnaryOperation(StackValue operand, TokenType op)
            {
                var v = ResolveStackValue(operand);

                switch (op)
                {
                case TokenType.MINUS:
                    if (v.Type == ValType.Integer)
                    {
                        int i = v.CastTo <int>();
                        Push(-i);
                    }
                    else if (v.Type == ValType.Float)
                    {
                        float f = v.CastTo <float>();
                        Push(-f);
                    }
                    else
                    {
                        UnaryRuntimeError(operand, op);
                    }
                    break;

                case TokenType.NOT:
                    if (v.Type == ValType.Bool)
                    {
                        bool b = v.CastTo <bool>();
                        Push(!b);
                    }
                    break;

                case TokenType.TYPEOF:
                    Push(v.Type);
                    break;
                }
            }

            #endregion

            #region visit the astnode
            Expression.Accept(this);
            #endregion

            #region process operand
            if (EvaluationStack.Count == 0)
            {
                return(StackValue.Null);
            }

            ReverseStack();
            while (EvaluationStack.Count > 1)
            {
                StackValue operand1 = EvaluationStack.Pop();
                StackValue operand2 = EvaluationStack.Pop();
                TokenType  op;
                if (operand2.Type == ValType.Operator)
                {
                    //unary opearation
                    op = (TokenType)operand2.Value;
                    EvaluateUnaryOperation(operand1, op);
                }
                else
                {
                    var tots = EvaluationStack.Pop();
                    op = (TokenType)tots.Value;

                    if (op == TokenType.ASSIGN)
                    {
                        //do assignment
                        //todo check type
                        var varname = (string)operand2.Value;
                        if (!CurrentScope.Contain(varname))
                        {
                            RuntimeError($"{varname} is not defined");
                        }
                        CurrentScope.Assign(varname, ResolveStackValue(operand1).Value);
                        Push(ResolveStackValue(operand2));
                    }
                    else if (op == TokenType.VAR)
                    {
                        //declare a variable in the environment
                        var varname = operand2.CastTo <string>();
                        if (CurrentScope.Contain(varname))
                        {
                            RuntimeError($"{varname} already defined");
                        }
                        CurrentScope.Define(varname, ResolveStackValue(operand1).Value);
                        Push(ResolveStackValue(operand2));
                    }
                    else
                    {
                        EvaluateBinaryOperation(operand1, operand2, op);
                    }
                }
            }

            return(ResolveStackValue(EvaluationStack.Pop()));

            #endregion
        }