예제 #1
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
                _statement = _statement.Next();

                // 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)
                            {
                                _statement = _statement.Next();
                                break;
                            }
                        }
                    }
                    else if (node.Type == ASTNodeType.ELSE)
                    {
                        if (depth == 0)
                        {
                            // Jump into the else clause
                            _statement = _statement.Next();
                            break;
                        }
                    }
                    else if (node.Type == ASTNodeType.ENDIF)
                    {
                        if (depth == 0)
                        {
                            break;
                        }

                        depth--;
                    }

                    _statement = _statement.Next();
                }

                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--;
                    }

                    _statement = _statement.Next();
                }

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

                break;

            case ASTNodeType.ENDIF:
                PopScope();
                _statement = _statement.Next();
                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--;
                    }

                    _statement = _statement.Next();
                }

                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
                _statement = _statement.Next();

                // 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
                                _statement = _statement.Next();
                                break;
                            }

                            depth--;
                        }

                        _statement = _statement.Next();
                    }
                }
                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
                    _statement = _statement.Next();
                }
                else
                {
                    // Walk until the end of the loop
                    _statement = _statement.Next();

                    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
                                _statement = _statement.Next();
                                break;
                            }

                            depth--;
                        }

                        _statement = _statement.Next();
                    }
                }
            }
            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
                    _statement = _statement.Next();
                }
                else
                {
                    // Walk until the end of the loop
                    _statement = _statement.Next();

                    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
                                _statement = _statement.Next();
                                break;
                            }

                            depth--;
                        }

                        _statement = _statement.Next();
                    }
                }
                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
                _statement = _statement.Next();

                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
                            _statement = _statement.Next();
                            break;
                        }

                        depth--;
                    }

                    _statement = _statement.Next();
                }

                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))
                {
                    _statement = _statement.Next();
                }

                break;
            }

            return((_statement != null) ? true : false);
        }
예제 #2
0
 public void SetVar(string name, Argument val)
 {
     _namespace[name] = val;
 }