function parseStatement()

in benchmarks/JetStream2/ARES-6/Basic/parser.js [313:524]


    function parseStatement()
    {
        let statement = {};
        statement.lineNumber = consumeKind("userLineNumber").userLineNumber;
        program.statements.set(statement.lineNumber, statement);
        
        let command = nextToken();
        statement.sourceLineNumber = command.sourceLineNumber;
        switch (command.kind) {
        case "keyword":
            switch (command.string.toLowerCase()) {
            case "def":
                statement.process = Basic.Def;
                statement.name = consumeKind("identifier");
                statement.parameters = [];
                if (peekToken().string == "(") {
                    do {
                        nextToken();
                        statement.parameters.push(consumeKind("identifier"));
                    } while (peekToken().string == ",");
                }
                statement.expression = parseNumericExpression();
                break;
            case "let":
                statement.process = Basic.Let;
                statement.variable = parseVariable();
                consumeToken("=");
                if (statement.process == Basic.Let)
                    statement.expression = parseNumericExpression();
                else
                    statement.expression = parseStringExpression();
                break;
            case "go": {
                let next = nextToken();
                if (next.string == "to")
                    parseGoToStatement();
                else if (next.string == "sub")
                    parseGoSubStatement();
                else
                    throw new Error("At " + next.sourceLineNumber + ": expected to or sub but got: " + next.string);
                break;
            }
            case "goto":
                parseGoToStatement();
                break;
            case "gosub":
                parseGoSubStatement();
                break;
            case "if":
                statement.process = Basic.If;
                statement.condition = parseRelationalExpression();
                consumeToken("then");
                statement.target = parseNonNegativeInteger();
                break;
            case "return":
                statement.process = Basic.Return;
                break;
            case "stop":
                statement.process = Basic.Stop;
                break;
            case "on":
                statement.process = Basic.On;
                statement.expression = parseNumericExpression();
                if (peekToken().string == "go") {
                    consumeToken("go");
                    consumeToken("to");
                } else
                    consumeToken("goto");
                statement.targets = [];
                for (;;) {
                    statement.targets.push(parseNonNegativeInteger());
                    if (peekToken().string != ",")
                        break;
                    nextToken();
                }
                break;
            case "for":
                statement.process = Basic.For;
                statement.variable = consumeKind("identifier").string;
                consumeToken("=");
                statement.initial = parseNumericExpression();
                consumeToken("to");
                statement.limit = parseNumericExpression();
                if (peekToken().string == "step") {
                    nextToken();
                    statement.step = parseNumericExpression();
                } else
                    statement.step = {evaluate: Basic.Const, value: 1};
                consumeKind("newLine");
                let lastStatement = parseStatements();
                if (lastStatement.process != Basic.Next)
                    throw new Error("At " + lastStatement.sourceLineNumber + ": expected next statement");
                if (lastStatement.variable != statement.variable)
                    throw new Error("At " + lastStatement.sourceLineNumber + ": expected next for " + statement.variable + " but got " + lastStatement.variable);
                lastStatement.target = statement;
                statement.target = lastStatement;
                return statement;
            case "next":
                statement.process = Basic.Next;
                statement.variable = consumeKind("identifier").string;
                break;
            case "print": {
                statement.process = Basic.Print;
                statement.items = [];
                let ok = true;
                while (ok) {
                    switch (peekToken().string) {
                    case ",":
                        nextToken();
                        statement.items.push({kind: "comma"});
                        break;
                    case ";":
                        nextToken();
                        break;
                    case "tab":
                        nextToken();
                        consumeToken("(");
                        statement.items.push({kind: "tab", value: parseNumericExpression()});
                        break;
                    case "\n":
                        ok = false;
                        break;
                    default:
                        if (isStringExpression()) {
                            statement.items.push({kind: "string", value: parseStringExpression()});
                            break;
                        }
                        statement.items.push({kind: "number", value: parseNumericExpression()});
                        break;
                    }
                }
                break;
            }
            case "input":
                statement.process = Basic.Input;
                statement.items = [];
                for (;;) {
                    stament.items.push(parseVariable());
                    if (peekToken().string != ",")
                        break;
                    nextToken();
                }
                break;
            case "read":
                statement.process = Basic.Read;
                statement.items = [];
                for (;;) {
                    stament.items.push(parseVariable());
                    if (peekToken().string != ",")
                        break;
                    nextToken();
                }
                break;
            case "restore":
                statement.process = Basic.Restore;
                break;
            case "data":
                for (;;) {
                    program.data.push(parseConstant());
                    if (peekToken().string != ",")
                        break;
                    nextToken();
                }
                break;
            case "dim":
                statement.process = Basic.Dim;
                statement.items = [];
                for (;;) {
                    let name = consumeKind("identifier").string;
                    consumeToken("(");
                    let bounds = [];
                    bounds.push(parseNonNegativeInteger());
                    if (peekToken().string == ",") {
                        nextToken();
                        bounds.push(parseNonNegativeInteger());
                    }
                    consumeToken(")");
                    statement.items.push({name, bounds});
                    
                    if (peekToken().string != ",")
                        break;
                    consumeToken(",");
                }
                break;
            case "option": {
                consumeToken("base");
                let base = parseNonNegativeInteger();
                if (base != 0 && base != 1)
                    throw new Error("At " + command.sourceLineNumber + ": unexpected base: " + base);
                program.base = base;
                break;
            }
            case "randomize":
                statement.process = Basic.Randomize;
                break;
            case "end":
                statement.process = Basic.End;
                break;
            default:
                throw new Error("At " + command.sourceLineNumber + ": unexpected command but got: " + command.string);
            }
            break;
        case "remark":
            // Just ignore it.
            break;
        default:
            throw new Error("At " + command.sourceLineNumber + ": expected command but got: " + command.string + " (of kind " + command.kind + ")");
        }
        
        consumeKind("newLine");
        return statement;
    }