Esempio n. 1
0
        private bool EvaluateExpression(ref ASTNode expr)
        {
            if (expr == null || (expr.Type != ASTNodeType.UNARY_EXPRESSION && expr.Type != ASTNodeType.BINARY_EXPRESSION && expr.Type != ASTNodeType.LOGICAL_EXPRESSION))
            {
                throw new RunTimeError(expr, "No expression following control statement");
            }

            var node = expr.FirstChild();

            if (node == null)
            {
                throw new RunTimeError(expr, "Empty expression following control statement");
            }

            switch (expr.Type)
            {
            case ASTNodeType.UNARY_EXPRESSION:
                return(EvaluateUnaryExpression(ref node));

            case ASTNodeType.BINARY_EXPRESSION:
                return(EvaluateBinaryExpression(ref node));
            }

            bool lhs = EvaluateExpression(ref node);

            node = node.Next();

            while (node != null)
            {
                // Capture the operator
                var op = node.Type;
                node = node.Next();

                if (node == null)
                {
                    throw new RunTimeError(node, "Invalid logical expression");
                }

                bool rhs;

                var e = node.FirstChild();

                switch (node.Type)
                {
                case ASTNodeType.UNARY_EXPRESSION:
                    rhs = EvaluateUnaryExpression(ref e);
                    break;

                case ASTNodeType.BINARY_EXPRESSION:
                    rhs = EvaluateBinaryExpression(ref e);
                    break;

                default:
                    throw new RunTimeError(node, "Nested logical expressions are not possible");
                }

                switch (op)
                {
                case ASTNodeType.AND:
                    lhs = lhs && rhs;
                    break;

                case ASTNodeType.OR:
                    lhs = lhs || rhs;
                    break;

                default:
                    throw new RunTimeError(node, "Invalid logical operator");
                }

                node = node.Next();
            }

            return(lhs);
        }
Esempio n. 2
0
        public bool ExecuteNext()
        {
            if (_statement == null)
            {
                return(false);
            }

            if (_statement.Type != ASTNodeType.STATEMENT)
            {
                throw new RunTimeError(_statement, "Invalid script");
            }

            var node = _statement.FirstChild();

            if (node == null)
            {
                throw new RunTimeError(_statement, "Invalid statement");
            }

            int depth = 0;

            switch (node.Type)
            {
            case ASTNodeType.IF:
            {
                PushScope(node);

                var expr   = node.FirstChild();
                var result = EvaluateExpression(ref expr);

                // Advance to next statement
                Advance();

                // Evaluated true. Jump right into execution.
                if (result)
                {
                    break;
                }

                // The expression evaluated false, so keep advancing until
                // we hit an elseif, else, or endif statement that matches
                // and try again.
                depth = 0;

                while (_statement != null)
                {
                    node = _statement.FirstChild();

                    if (node.Type == ASTNodeType.IF)
                    {
                        depth++;
                    }
                    else if (node.Type == ASTNodeType.ELSEIF)
                    {
                        if (depth == 0)
                        {
                            expr   = node.FirstChild();
                            result = EvaluateExpression(ref expr);

                            // Evaluated true. Jump right into execution
                            if (result)
                            {
                                Advance();
                                break;
                            }
                        }
                    }
                    else if (node.Type == ASTNodeType.ELSE)
                    {
                        if (depth == 0)
                        {
                            // Jump into the else clause
                            Advance();
                            break;
                        }
                    }
                    else if (node.Type == ASTNodeType.ENDIF)
                    {
                        if (depth == 0)
                        {
                            break;
                        }

                        depth--;
                    }

                    Advance();
                }

                if (_statement == null)
                {
                    throw new RunTimeError(node, "If with no matching endif");
                }

                break;
            }

            case ASTNodeType.ELSEIF:
                // If we hit the elseif statement during normal advancing, skip over it. The only way
                // to execute an elseif clause is to jump directly in from an if statement.
                depth = 0;

                while (_statement != null)
                {
                    node = _statement.FirstChild();

                    if (node.Type == ASTNodeType.IF)
                    {
                        depth++;
                    }
                    else if (node.Type == ASTNodeType.ENDIF)
                    {
                        if (depth == 0)
                        {
                            break;
                        }

                        depth--;
                    }

                    Advance();
                }

                if (_statement == null)
                {
                    throw new RunTimeError(node, "If with no matching endif");
                }

                break;

            case ASTNodeType.ENDIF:
                PopScope();
                Advance();
                break;

            case ASTNodeType.ELSE:
                // If we hit the else statement during normal advancing, skip over it. The only way
                // to execute an else clause is to jump directly in from an if statement.
                depth = 0;

                while (_statement != null)
                {
                    node = _statement.FirstChild();

                    if (node.Type == ASTNodeType.IF)
                    {
                        depth++;
                    }
                    else if (node.Type == ASTNodeType.ENDIF)
                    {
                        if (depth == 0)
                        {
                            break;
                        }

                        depth--;
                    }

                    Advance();
                }

                if (_statement == null)
                {
                    throw new RunTimeError(node, "If with no matching endif");
                }

                break;

            case ASTNodeType.WHILE:
            {
                // When we first enter the loop, push a new scope
                if (_scope.StartNode != node)
                {
                    PushScope(node);
                }

                var expr   = node.FirstChild();
                var result = EvaluateExpression(ref expr);

                // Advance to next statement
                Advance();

                // The expression evaluated false, so keep advancing until
                // we hit an endwhile statement.
                if (!result)
                {
                    depth = 0;

                    while (_statement != null)
                    {
                        node = _statement.FirstChild();

                        if (node.Type == ASTNodeType.WHILE)
                        {
                            depth++;
                        }
                        else if (node.Type == ASTNodeType.ENDWHILE)
                        {
                            if (depth == 0)
                            {
                                PopScope();
                                // Go one past the endwhile so the loop doesn't repeat
                                Advance();
                                break;
                            }

                            depth--;
                        }

                        Advance();
                    }
                }
                break;
            }

            case ASTNodeType.ENDWHILE:
                // Walk backward to the while statement
                _statement = _statement.Prev();

                depth = 0;

                while (_statement != null)
                {
                    node = _statement.FirstChild();

                    if (node.Type == ASTNodeType.ENDWHILE)
                    {
                        depth++;
                    }
                    else if (node.Type == ASTNodeType.WHILE)
                    {
                        if (depth == 0)
                        {
                            break;
                        }

                        depth--;
                    }

                    _statement = _statement.Prev();
                }

                if (_statement == null)
                {
                    throw new RunTimeError(node, "Unexpected endwhile");
                }

                break;

            case ASTNodeType.FOR:
            {
                // The iterator variable's name is the hash code of the for loop's ASTNode.
                var iterName = node.GetHashCode().ToString();

                // When we first enter the loop, push a new scope
                if (_scope.StartNode != node)
                {
                    PushScope(node);

                    // Grab the arguments
                    var max = node.FirstChild();

                    if (max.Type != ASTNodeType.INTEGER)
                    {
                        throw new RunTimeError(max, "Invalid for loop syntax");
                    }

                    // Create a dummy argument that acts as our loop variable
                    var iter = new ASTNode(ASTNodeType.INTEGER, "0", node, 0);

                    _scope.SetVar(iterName, new Argument(this, iter));
                }
                else
                {
                    // Increment the iterator argument
                    var arg = _scope.GetVar(iterName);

                    var iter = new ASTNode(ASTNodeType.INTEGER, (arg.AsUInt() + 1).ToString(), node, 0);

                    _scope.SetVar(iterName, new Argument(this, iter));
                }

                // Check loop condition
                var i = _scope.GetVar(iterName);

                // Grab the max value to iterate to
                node = node.FirstChild();
                var end = new Argument(this, node);

                if (i.AsUInt() < end.AsUInt())
                {
                    // enter the loop
                    Advance();
                }
                else
                {
                    // Walk until the end of the loop
                    Advance();

                    depth = 0;

                    while (_statement != null)
                    {
                        node = _statement.FirstChild();

                        if (node.Type == ASTNodeType.FOR ||
                            node.Type == ASTNodeType.FOREACH)
                        {
                            depth++;
                        }
                        else if (node.Type == ASTNodeType.ENDFOR)
                        {
                            if (depth == 0)
                            {
                                PopScope();
                                // Go one past the end so the loop doesn't repeat
                                Advance();
                                break;
                            }

                            depth--;
                        }

                        Advance();
                    }
                }
            }
            break;

            case ASTNodeType.FOREACH:
            {
                // foreach VAR in LIST
                // The iterator's name is the hash code of the for loop's ASTNode.
                var varName  = node.FirstChild().Lexeme;
                var listName = node.FirstChild().Next().Lexeme;
                var iterName = node.GetHashCode().ToString();

                // When we first enter the loop, push a new scope
                if (_scope.StartNode != node)
                {
                    PushScope(node);

                    // Create a dummy argument that acts as our iterator object
                    var iter = new ASTNode(ASTNodeType.INTEGER, "0", node, 0);
                    _scope.SetVar(iterName, new Argument(this, iter));

                    // Make the user-chosen variable have the value for the front of the list
                    var arg = Interpreter.GetListValue(listName, 0);

                    if (arg != null)
                    {
                        _scope.SetVar(varName, arg);
                    }
                    else
                    {
                        _scope.ClearVar(varName);
                    }
                }
                else
                {
                    // Increment the iterator argument
                    var idx  = _scope.GetVar(iterName).AsInt() + 1;
                    var iter = new ASTNode(ASTNodeType.INTEGER, idx.ToString(), node, 0);
                    _scope.SetVar(iterName, new Argument(this, iter));

                    // Update the user-chosen variable
                    var arg = Interpreter.GetListValue(listName, idx);

                    if (arg != null)
                    {
                        _scope.SetVar(varName, arg);
                    }
                    else
                    {
                        _scope.ClearVar(varName);
                    }
                }

                // Check loop condition
                var i = _scope.GetVar(varName);

                if (i != null)
                {
                    // enter the loop
                    Advance();
                }
                else
                {
                    // Walk until the end of the loop
                    Advance();

                    depth = 0;

                    while (_statement != null)
                    {
                        node = _statement.FirstChild();

                        if (node.Type == ASTNodeType.FOR ||
                            node.Type == ASTNodeType.FOREACH)
                        {
                            depth++;
                        }
                        else if (node.Type == ASTNodeType.ENDFOR)
                        {
                            if (depth == 0)
                            {
                                PopScope();
                                // Go one past the end so the loop doesn't repeat
                                Advance();
                                break;
                            }

                            depth--;
                        }

                        Advance();
                    }
                }
                break;
            }

            case ASTNodeType.ENDFOR:
                // Walk backward to the for statement
                _statement = _statement.Prev();

                while (_statement != null)
                {
                    node = _statement.FirstChild();

                    if (node.Type == ASTNodeType.FOR ||
                        node.Type == ASTNodeType.FOREACH)
                    {
                        break;
                    }

                    _statement = _statement.Prev();
                }

                if (_statement == null)
                {
                    throw new RunTimeError(node, "Unexpected endfor");
                }

                break;

            case ASTNodeType.BREAK:
                // Walk until the end of the loop
                Advance();

                depth = 0;

                while (_statement != null)
                {
                    node = _statement.FirstChild();

                    if (node.Type == ASTNodeType.WHILE ||
                        node.Type == ASTNodeType.FOR ||
                        node.Type == ASTNodeType.FOREACH)
                    {
                        depth++;
                    }
                    else if (node.Type == ASTNodeType.ENDWHILE ||
                             node.Type == ASTNodeType.ENDFOR)
                    {
                        if (depth == 0)
                        {
                            PopScope();

                            // Go one past the end so the loop doesn't repeat
                            Advance();
                            break;
                        }

                        depth--;
                    }

                    Advance();
                }

                PopScope();
                break;

            case ASTNodeType.CONTINUE:
                // Walk backward to the loop statement
                _statement = _statement.Prev();

                depth = 0;

                while (_statement != null)
                {
                    node = _statement.FirstChild();

                    if (node.Type == ASTNodeType.ENDWHILE ||
                        node.Type == ASTNodeType.ENDFOR)
                    {
                        depth++;
                    }
                    else if (node.Type == ASTNodeType.WHILE ||
                             node.Type == ASTNodeType.FOR ||
                             node.Type == ASTNodeType.FOREACH)
                    {
                        if (depth == 0)
                        {
                            break;
                        }

                        depth--;
                    }

                    _statement = _statement.Prev();
                }

                if (_statement == null)
                {
                    throw new RunTimeError(node, "Unexpected continue");
                }
                break;

            case ASTNodeType.STOP:
                _statement = null;
                break;

            case ASTNodeType.REPLAY:
                _statement = _statement.Parent.FirstChild();
                break;

            case ASTNodeType.QUIET:
            case ASTNodeType.FORCE:
            case ASTNodeType.COMMAND:
                if (ExecuteCommand(node))
                {
                    Advance();
                }

                break;
            }

            return((_statement != null) ? true : false);
        }
Esempio n. 3
0
 public void Advance()
 {
     Interpreter.ClearTimeout();
     _statement = _statement.Next();
 }
Esempio n. 4
0
 private void PushScope(ASTNode node)
 {
     _scope = new Scope(_scope, node);
 }
Esempio n. 5
0
 public Argument(Script script, ASTNode node)
 {
     _node   = node;
     _script = script;
 }
Esempio n. 6
0
 public RunTimeError(ASTNode node, string error) : base(error)
 {
     Node = node;
 }
Esempio n. 7
0
 public Scope(Scope parent, ASTNode start)
 {
     Parent    = parent;
     StartNode = start;
 }
Esempio n. 8
0
        private bool EvaluateBinaryExpression(ref ASTNode node)
        {
            // Evaluate the left hand side
            var lhs = EvaluateBinaryOperand(ref node);

            // Capture the operator
            var op = node.Type;

            node = node.Next();

            // Evaluate the right hand side
            var rhs = EvaluateBinaryOperand(ref node);

            if (lhs.GetType() != rhs.GetType())
            {
                // Different types. Try to convert one to match the other.

                // Special case for rhs doubles because we don't want to lose precision.
                if (rhs is double)
                {
                    double tmp = (double)lhs;
                    lhs = tmp;
                }
                else
                {
                    var tmp = Convert.ChangeType(rhs, lhs.GetType());
                    rhs = (IComparable)tmp;
                }
            }

            try
            {
                // Evaluate the whole expression
                switch (op)
                {
                case ASTNodeType.EQUAL:
                    return(lhs.CompareTo(rhs) == 0);

                case ASTNodeType.NOT_EQUAL:
                    return(lhs.CompareTo(rhs) != 0);

                case ASTNodeType.LESS_THAN:
                    return(lhs.CompareTo(rhs) < 0);

                case ASTNodeType.LESS_THAN_OR_EQUAL:
                    return(lhs.CompareTo(rhs) <= 0);

                case ASTNodeType.GREATER_THAN:
                    return(lhs.CompareTo(rhs) > 0);

                case ASTNodeType.GREATER_THAN_OR_EQUAL:
                    return(lhs.CompareTo(rhs) >= 0);
                }
            }
            catch (ArgumentException e)
            {
                throw new RunTimeError(node, e.Message);
            }

            throw new RunTimeError(node, "Unknown operator in expression");
        }