summaryrefslogtreecommitdiffstats
path: root/third_party/webkit/PerformanceTests/ARES-6/Basic/parser.js
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/webkit/PerformanceTests/ARES-6/Basic/parser.js')
-rw-r--r--third_party/webkit/PerformanceTests/ARES-6/Basic/parser.js558
1 files changed, 558 insertions, 0 deletions
diff --git a/third_party/webkit/PerformanceTests/ARES-6/Basic/parser.js b/third_party/webkit/PerformanceTests/ARES-6/Basic/parser.js
new file mode 100644
index 0000000000..562e157595
--- /dev/null
+++ b/third_party/webkit/PerformanceTests/ARES-6/Basic/parser.js
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+"use strict";
+
+function parse(tokenizer)
+{
+ let program;
+
+ let pushBackBuffer = [];
+
+ function nextToken()
+ {
+ if (pushBackBuffer.length)
+ return pushBackBuffer.pop();
+ let result = tokenizer.next();
+ if (result.done)
+ return {kind: "endOfFile", string: "<end of file>"};
+ return result.value;
+ }
+
+ function pushToken(token)
+ {
+ pushBackBuffer.push(token);
+ }
+
+ function peekToken()
+ {
+ let result = nextToken();
+ pushToken(result);
+ return result;
+ }
+
+ function consumeKind(kind)
+ {
+ let token = nextToken();
+ if (token.kind != kind) {
+ throw new Error("At " + token.sourceLineNumber + ": expected " + kind + " but got: " + token.string);
+ }
+ return token;
+ }
+
+ function consumeToken(string)
+ {
+ let token = nextToken();
+ if (token.string.toLowerCase() != string.toLowerCase())
+ throw new Error("At " + token.sourceLineNumber + ": expected " + string + " but got: " + token.string);
+ return token;
+ }
+
+ function parseVariable()
+ {
+ let name = consumeKind("identifier").string;
+ let result = {evaluate: Basic.Variable, name, parameters: []};
+ if (peekToken().string == "(") {
+ do {
+ nextToken();
+ result.parameters.push(parseNumericExpression());
+ } while (peekToken().string == ",");
+ consumeToken(")");
+ }
+ return result;
+ }
+
+ function parseNumericExpression()
+ {
+ function parsePrimary()
+ {
+ let token = nextToken();
+ switch (token.kind) {
+ case "identifier": {
+ let result = {evaluate: Basic.NumberApply, name: token.string, parameters: []};
+ if (peekToken().string == "(") {
+ do {
+ nextToken();
+ result.parameters.push(parseNumericExpression());
+ } while (peekToken().string == ",");
+ consumeToken(")");
+ }
+ return result;
+ }
+
+ case "number":
+ return {evaluate: Basic.Const, value: token.value};
+
+ case "operator":
+ switch (token.string) {
+ case "(": {
+ let result = parseNumericExpression();
+ consumeToken(")");
+ return result;
+ } }
+ break;
+ }
+ throw new Error("At " + token.sourceLineNumber + ": expected identifier, number, or (, but got: " + token.string);
+ }
+
+ function parseFactor()
+ {
+ let primary = parsePrimary();
+
+ let ok = true;
+ while (ok) {
+ switch (peekToken().string) {
+ case "^":
+ nextToken();
+ primary = {evaluate: Basic.NumberPow, left: primary, right: parsePrimary()};
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ }
+
+ return primary;
+ }
+
+ function parseTerm()
+ {
+ let factor = parseFactor();
+
+ let ok = true;
+ while (ok) {
+ switch (peekToken().string) {
+ case "*":
+ nextToken();
+ factor = {evaluate: Basic.NumberMul, left: factor, right: parseFactor()};
+ break;
+ case "/":
+ nextToken();
+ factor = {evaluate: Basic.NumberDiv, left: factor, right: parseFactor()};
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ }
+
+ return factor;
+ }
+
+ // Only the leading term in Basic can have a sign.
+ let negate = false;
+ switch (peekToken().string) {
+ case "+":
+ nextToken();
+ break;
+ case "-":
+ negate = true;
+ nextToken()
+ break;
+ }
+
+ let term = parseTerm();
+ if (negate)
+ term = {evaluate: Basic.NumberNeg, term: term};
+
+ let ok = true;
+ while (ok) {
+ switch (peekToken().string) {
+ case "+":
+ nextToken();
+ term = {evaluate: Basic.NumberAdd, left: term, right: parseTerm()};
+ break;
+ case "-":
+ nextToken();
+ term = {evaluate: Basic.NumberSub, left: term, right: parseTerm()};
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ }
+
+ return term;
+ }
+
+ function parseConstant()
+ {
+ switch (peekToken().string) {
+ case "+":
+ nextToken();
+ return consumeKind("number").value;
+ case "-":
+ nextToken();
+ return -consumeKind("number").value;
+ default:
+ if (isStringExpression())
+ return consumeKind("string").value;
+ return consumeKind("number").value;
+ }
+ }
+
+ function parseStringExpression()
+ {
+ let token = nextToken();
+ switch (token.kind) {
+ case "string":
+ return {evaluate: Basic.Const, value: token.value};
+ case "identifier":
+ consumeToken("$");
+ return {evaluate: Basic.StringVar, name: token.string};
+ default:
+ throw new Error("At " + token.sourceLineNumber + ": expected string expression but got " + token.string);
+ }
+ }
+
+ function isStringExpression()
+ {
+ // A string expression must start with a string variable or a string constant.
+ let token = nextToken();
+ if (token.kind == "string") {
+ pushToken(token);
+ return true;
+ }
+ if (token.kind == "identifier") {
+ let result = peekToken().string == "$";
+ pushToken(token);
+ return result;
+ }
+ pushToken(token);
+ return false;
+ }
+
+ function parseRelationalExpression()
+ {
+ if (isStringExpression()) {
+ let left = parseStringExpression();
+ let operator = nextToken();
+ let evaluate;
+ switch (operator.string) {
+ case "=":
+ evaluate = Basic.Equals;
+ break;
+ case "<>":
+ evaluate = Basic.NotEquals;
+ break;
+ default:
+ throw new Error("At " + operator.sourceLineNumber + ": expected a string comparison operator but got: " + operator.string);
+ }
+ return {evaluate, left, right: parseStringExpression()};
+ }
+
+ let left = parseNumericExpression();
+ let operator = nextToken();
+ let evaluate;
+ switch (operator.string) {
+ case "=":
+ evaluate = Basic.Equals;
+ break;
+ case "<>":
+ evaluate = Basic.NotEquals;
+ break;
+ case "<":
+ evaluate = Basic.LessThan;
+ break;
+ case ">":
+ evaluate = Basic.GreaterThan;
+ break;
+ case "<=":
+ evaluate = Basic.LessEqual;
+ break;
+ case ">=":
+ evaluate = Basic.GreaterEqual;
+ break;
+ default:
+ throw new Error("At " + operator.sourceLineNumber + ": expected a numeric comparison operator but got: " + operator.string);
+ }
+ return {evaluate, left, right: parseNumericExpression()};
+ }
+
+ function parseNonNegativeInteger()
+ {
+ let token = nextToken();
+ if (!/^[0-9]+$/.test(token.string))
+ throw new Error("At ", token.sourceLineNumber + ": expected a line number but got: " + token.string);
+ return token.value;
+ }
+
+ function parseGoToStatement()
+ {
+ statement.kind = Basic.GoTo;
+ statement.target = parseNonNegativeInteger();
+ }
+
+ function parseGoSubStatement()
+ {
+ statement.kind = Basic.GoSub;
+ statement.target = parseNonNegativeInteger();
+ }
+
+ 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;
+ }
+
+ function parseStatements()
+ {
+ let statement;
+ do {
+ statement = parseStatement();
+ } while (!statement.process || !statement.process.isBlockEnd);
+ return statement;
+ }
+
+ return {
+ program()
+ {
+ program = {
+ process: Basic.Program,
+ statements: new Map(),
+ data: [],
+ base: 0
+ };
+ let lastStatement = parseStatements(program.statements);
+ if (lastStatement.process != Basic.End)
+ throw new Error("At " + lastStatement.sourceLineNumber + ": expected end");
+
+ return program;
+ },
+
+ statement(program_)
+ {
+ program = program_;
+ return parseStatement();
+ }
+ };
+}
+