--- a/js/src/frontend/BinSource.cpp
+++ b/js/src/frontend/BinSource.cpp
@@ -108,22 +108,22 @@ private:
bool parseBlockStatement(SimpleTokenReader* reader, UniquePtr<ParseNode>&);
bool parseCatchClause(SimpleTokenReader* reader, UniquePtr<ParseNode>&);
bool parseVariableDeclarator(SimpleTokenReader* reader, UniquePtr<ParseNode>&);
bool parsePatternList(SimpleTokenReader* reader, UniquePtr<ParseNode>&);
bool parseDirectiveList(SimpleTokenReader* reader, UniquePtr<ParseNode>&);
// --- Parse the contents of a node whose kind has already been determined.
- bool parseFunctionAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
- bool parsePatternAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
- bool parseBlockStatementAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
- bool parseExpressionStatementAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
- bool parseExpressionAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
- bool parseVariableDeclarationAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
+ bool parseFunctionAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
+ bool parsePatternAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
+ bool parseBlockStatementAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
+ bool parseExpressionStatementAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
+ bool parseExpressionAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
+ bool parseVariableDeclarationAux(SimpleTokenReader* reader, const BinKind kind, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out);
// --- Utilities.
bool readString(SimpleTokenReader* reader, std::string&);
bool readString(SimpleTokenReader* reader, MutableHandleString);
bool readString(SimpleTokenReader* reader, MutableHandleAtom);
const Directives& currentDirectives() const;
@@ -190,118 +190,127 @@ ASTReader::parse(char* start, char* stop
}
bool
ASTReader::parseProgram(SimpleTokenReader* reader, UniquePtr<ParseNode>& out) {
if (out) {
// Already parsed.
return this->raiseError();
}
- SimpleTokenReader::Fields fields(this->cx);
+ BinKind kind;
+ SimpleTokenReader::BinFields fields(this->cx);
SimpleTokenReader sub(this->cx);
- std::string name;
- if (!reader->taggedTuple(&name, &fields, &sub)) {
+ if (!reader->taggedTuple(kind, fields, &sub)) {
return false;
}
- if (name != "Program") {
+ if (kind != BinKind::program) {
return this->raiseError();
}
- return this->parseBlockStatementAux(&sub, name, &fields, out);
+ return this->parseBlockStatementAux(&sub, kind, fields, out);
}
bool
ASTReader::parseScope(SimpleTokenReader* reader,
ScopeData& out)
{
if (out.hasDirectEval.isSome()
|| out.letNames.address() != nullptr
|| out.constNames.address() != nullptr
|| out.varNames.address() != nullptr
|| out.capturedNames.address() != nullptr) {
// Already parsed.
return this->raiseError();
}
- SimpleTokenReader::Fields fields(this->cx);
+ BinKind kind;
+ SimpleTokenReader::BinFields fields(this->cx);
SimpleTokenReader sub(this->cx);
- std::string name;
- if (!reader->taggedTuple(&name, &fields, &sub)) {
+ if (!reader->taggedTuple(kind, fields, &sub)) {
return false;
}
- if (name != BINJS_SCOPE) {
+ if (kind != BinKind::binjs_scope) {
return this->raiseError();
}
for (auto field: fields) {
- if (field == BINJS_DIRECT_EVAL) {
- if (!this->parseBool(reader, &out.hasDirectEval)) {
- return false;
- }
- } else if (field == BINJS_LET_NAME) {
- if (!this->parseStringList(reader, &out.letNames)) {
- return false;
- }
- } else if (field == BINJS_CONST_NAME) {
- if (!this->parseStringList(reader, &out.constNames)) {
- return false;
- }
- } else if (field == BINJS_VAR_NAME) {
- if (!this->parseStringList(reader, &out.varNames)) {
- return false;
- }
- } else if (field == BINJS_CAPTURED_NAME) {
- if (!this->parseStringSet(reader, &out.capturedNames)) {
- return false;
- }
- } else {
- return this->raiseError();
+ switch (field) {
+ case BinField::has_direct_eval:
+ if (!this->parseBool(reader, &out.hasDirectEval)) {
+ return false;
+ }
+ break;
+ case BinField::let_decl_names:
+ if (!this->parseStringList(reader, &out.letNames)) {
+ return false;
+ }
+ break;
+ case BinField::const_decl_names:
+ if (!this->parseStringList(reader, &out.constNames)) {
+ return false;
+ }
+ break;
+ case BinField::var_decl_names:
+ if (!this->parseStringList(reader, &out.varNames)) {
+ return false;
+ }
+ break;
+ case BinField::captured_names:
+ if (!this->parseStringSet(reader, &out.capturedNames)) {
+ return false;
+ }
+ break;
+ default:
+ return this->raiseError();
}
}
if (out.hasDirectEval.isNothing()
|| out.letNames.address() == nullptr
|| out.constNames.address() == nullptr
|| out.varNames.address() == nullptr
|| out.capturedNames.address() == nullptr) {
return this->raiseError();
}
return true;
}
bool
ASTReader::parseBlockStatementAux(SimpleTokenReader* reader,
- const std::string& name,
- const SimpleTokenReader::Fields* fields,
+ const BinKind name,
+ const SimpleTokenReader::BinFields& fields,
UniquePtr<ParseNode>& out)
{
UniquePtr<ParseNode> body;
UniquePtr<ParseNode> directives;
ScopeData scope(this->cx);
- for (auto field: *fields) {
- if (field == BINJS_SCOPE) {
- if (!this->parseScope(reader, scope)) {
- return false;
- }
- } else if (field == "body") {
- if (!this->parseStatementList(reader, body)) {
- return false;
- }
- } else if (field == "directives") {
- if (!this->parseDirectiveList(reader, directives)) {
- return false;
- }
- } else {
- this->raiseError();
- return false;
+ for (auto field: fields) {
+ switch (field) {
+ case BinField::binjs_scope:
+ if (!this->parseScope(reader, scope)) {
+ return false;
+ }
+ break;
+ case BinField::body:
+ if (!this->parseStatementList(reader, body)) {
+ return false;
+ }
+ break;
+ case BinField::directives:
+ if (!this->parseDirectiveList(reader, directives)) {
+ return false;
+ }
+ break;
+ default:
+ return this->raiseError();
}
}
// Check if all fields have been parsed.
if (!body || !directives || !scope.isSome()) {
// FIXME: Once we have headers + header validation, this error check
// should become an assertion.
return this->raiseError();
@@ -407,187 +416,217 @@ ASTReader::parseStatementList(SimpleToke
return true;
}
bool
ASTReader::parseStatement(SimpleTokenReader* reader, UniquePtr<ParseNode>& out) {
if (out) {
return this->raiseError();
}
- SimpleTokenReader::Fields fields(this->cx);
+ BinKind kind;
+ SimpleTokenReader::BinFields fields(this->cx);
SimpleTokenReader sub(this->cx);
- std::string name;
- if (!reader->taggedTuple(&name, &fields, &sub)) {
+ if (!reader->taggedTuple(kind, fields, &sub)) {
return false;
}
- if (name == "EmptyStatement") {
- UniquePtr<ParseNode> result(new_<NullaryNode>(PNK_NOP, TokenPos()));
- if (!result) {
- return false;
+ switch (kind) {
+ case BinKind::empty_statement: {
+ UniquePtr<ParseNode> result(new_<NullaryNode>(PNK_NOP, TokenPos()));
+ if (!result) {
+ return false;
+ }
+ out = Move(result);
+ break;
}
- out = Move(result);
- } else if (name == "BlockStatement") {
- UniquePtr<ParseNode> body;
- if (!this->parseBlockStatementAux(&sub, name, &fields, body)) {
- return false;
+ case BinKind::block_statement: {
+ UniquePtr<ParseNode> body;
+ if (!this->parseBlockStatementAux(&sub, kind, fields, body)) {
+ return false;
+ }
+ out = Move(body);
+ break;
}
- out = Move(body);
- } else if (name == "ExpressionStatement") {
- UniquePtr<ParseNode> body;
- if (!this->parseExpressionStatementAux(&sub, name, &fields, body)) {
- return false;
+ case BinKind::expression_statement: {
+ UniquePtr<ParseNode> body;
+ if (!this->parseExpressionStatementAux(&sub, kind, fields, body)) {
+ return false;
+ }
+ out = Move(body);
+ break;
}
- out = Move(body);
- } else if (name == "DebuggerStatement") {
- UniquePtr<ParseNode> result(new_<DebuggerStatement>(TokenPos()));
- if (!result) {
- return false;
+ case BinKind::debugger_statement: {
+ UniquePtr<ParseNode> result(new_<DebuggerStatement>(TokenPos()));
+ if (!result) {
+ return false;
+ }
+ out = Move(result);
+ break;
}
- out = Move(result);
- } else if (name == "WithStatement") {
- UniquePtr<ParseNode> body;
- UniquePtr<ParseNode> expr;
- for (auto field: fields) {
- if (field == "body") {
- if (!this->parseStatement(&sub, body)) {
- return false;
+ case BinKind::with_statement: {
+ UniquePtr<ParseNode> body;
+ UniquePtr<ParseNode> expr;
+ for (auto field: fields) {
+ switch (field) {
+ case BinField::body:
+ if (!this->parseStatement(&sub, body)) {
+ return false;
+ }
+ break;
+ case BinField::object:
+ if (!this->parseExpression(&sub, body)) {
+ return false;
+ }
+ break;
+ default:
+ return this->raiseError();
}
- } else if (field == "object") {
- if (!this->parseExpression(&sub, body)) {
- return false;
- }
- } else {
+ }
+ if (!body || !expr) {
+ return false;
+ }
+
+ UniquePtr<ParseNode> result(new_<BinaryNode>(PNK_WITH, JSOP_NOP, TokenPos(),
+ expr.get(), body.get()));
+ if (!result) {
return this->raiseError();
}
- }
- if (!body || !expr) {
- return false;
- }
+ Unused << expr.release();
+ Unused << body.release();
- UniquePtr<ParseNode> result(new_<BinaryNode>(PNK_WITH, JSOP_NOP, TokenPos(),
- expr.get(), body.get()));
- if (!result) {
- return this->raiseError();
+ out = Move(result);
+ break;
}
- Unused << expr.release();
- Unused << body.release();
-
- out = Move(result);
-
- } else if (name == "ReturnStatement") {
+ case BinKind::return_statement: {
+ UniquePtr<ParseNode> arg;
+ for (auto field: fields) {
+ switch (field) {
+ case BinField::argument:
+ if (!this->parseExpression(&sub, arg)) { // FIXME: Make sure that it works with no expression.
+ return false;
+ }
+ break;
+ default:
+ return this->raiseError();
+ }
+ }
- UniquePtr<ParseNode> arg;
- for (auto field: fields) {
- if (field == "argument") {
- if (!this->parseExpression(&sub, arg)) { // FIXME: Make sure that it works with no expression.
- return false;
- }
- } else {
+ // `arg` is optional, so we don't check whether it's `nullptr`.
+ UniquePtr<ParseNode> result(new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, TokenPos(), arg.get()));
+ if (!result) {
return this->raiseError();
}
+
+ Unused << arg.release();
+ out = Move(result);
+ break;
}
-
- // `arg` is optional, so we don't check whether it's `nullptr`.
- UniquePtr<ParseNode> result(new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, TokenPos(), arg.get()));
- if (!result) {
- return this->raiseError();
- }
-
- Unused << arg.release();
- out = Move(result);
-
- } else if (name == "LabeledStatement") {
+ case BinKind::labeled_statement: {
+ UniquePtr<PropertyName> label;
+ UniquePtr<ParseNode> body;
- UniquePtr<PropertyName> label;
- UniquePtr<ParseNode> body;
+ for (auto field: fields) {
+ switch (field) {
+ case BinField::label:
+ if (!this->parsePropertyName(&sub, label)) {
+ return false;
+ }
+ break;
+ case BinField::body:
+ if (!this->parseStatement(&sub, body)) {
+ return false;
+ }
+ break;
+ default:
+ return this->raiseError();
+ }
+ }
- for (auto field: fields) {
- if (field == "label") {
- if (!this->parsePropertyName(&sub, label)) {
- return false;
- }
- } else if (field == "body") {
- if (!this->parseStatement(&sub, body)) {
- return false;
- }
- } else {
+ if (!label || !body) {
return this->raiseError();
}
- }
- if (!label || !body) {
- return this->raiseError();
- }
+ UniquePtr<ParseNode> result(new_<LabeledStatement>(label.get(), body.get(), 0));
+ if (!result) {
+ return false;
+ }
- UniquePtr<ParseNode> result(new_<LabeledStatement>(label.get(), body.get(), 0));
- if (!result) {
- return false;
- }
-
- Unused << label.release();
- Unused << body.release();
- out = Move(result);
-
- } else if (name == "BreakStatement" || name == "ContinueStatement") {
+ Unused << label.release();
+ Unused << body.release();
+ out = Move(result);
+ break;
+ }
+ case BinKind::break_statement: MOZ_FALLTHROUGH;
+ case BinKind::continue_statement: {
UniquePtr<PropertyName> label;
for (auto field: fields) {
- if (field == "label") {
- if (!this->parsePropertyName(&sub, label)) {
- return false;
- }
- } else {
- return this->raiseError();
+ switch (field) {
+ case BinField::label:
+ if (!this->parsePropertyName(&sub, label)) {
+ return false;
+ }
+ break;
+ default:
+ return this->raiseError();
}
}
if (!label) {
return this->raiseError();
}
- if (name == "BreakStatement") {
+ if (kind == BinKind::break_statement) {
UniquePtr<ParseNode> result(new_<BreakStatement>(label.get(), TokenPos()));
if (!result) {
return false;
}
out = Move(result);
} else {
UniquePtr<ParseNode> result(new_<ContinueStatement>(label.get(), TokenPos()));
if (!result) {
return false;
}
out = Move(result);
}
Unused << label.release();
+ break;
- } else if (name == "IfStatement") {
+ }
+ case BinKind::if_statement: {
UniquePtr<ParseNode> test;
UniquePtr<ParseNode> consequent;
UniquePtr<ParseNode> alternate; // Optional
for (auto field: fields) {
- if (field == "test") {
- if (!this->parseExpression(&sub, test)) {
- return false;
+ switch (field) {
+ case BinField::test: {
+ if (!this->parseExpression(&sub, test)) {
+ return false;
+ }
+ break;
}
- } else if (field == "consequent") {
- if (!this->parseStatement(&sub, consequent)) {
- return false;
+ case BinField::consequent: {
+ if (!this->parseStatement(&sub, consequent)) {
+ return false;
+ }
+ break;
}
- } else if (field == "alternate") {
- if (!this->parseStatement(&sub, alternate)) {
- return false;
+ case BinField::alternate: {
+ if (!this->parseStatement(&sub, alternate)) {
+ return false;
+ }
+ break;
}
- } else {
- return this->raiseError();
+ default:
+ return this->raiseError();
}
}
if (!test || !consequent) {
// Do not test `alternate`, since that value is optional.
return this->raiseError();
}
@@ -596,82 +635,95 @@ ASTReader::parseStatement(SimpleTokenRea
return false;
}
Unused << test.release();
Unused << consequent.release();
Unused << alternate.release();
out = Move(result);
-
- } else if (name == "SwitchStatement") {
+ break;
+ }
+ case BinKind::switch_statement: {
UniquePtr<ParseNode> discriminant;
UniquePtr<ParseNode> cases;
for (auto field: fields) {
- if (field == "discriminant") {
- if (!this->parseExpression(&sub, discriminant)) {
- return false;
+ switch (field) {
+ case BinField::discriminant: {
+ if (!this->parseExpression(&sub, discriminant)) {
+ return false;
+ }
+ break;
}
- } else if (field == "cases") {
- if (!this->parseSwitchCaseList(&sub, cases)) {
- return false;
+ case BinField::cases: {
+ if (!this->parseSwitchCaseList(&sub, cases)) {
+ return false;
+ }
+ break;
}
- } else {
- return this->raiseError();
+ default:
+ return this->raiseError();
}
}
if (!discriminant || !cases) {
return this->raiseError();
}
UniquePtr<ParseNode> result(new_<BinaryNode>(PNK_SWITCH, JSOP_NOP, TokenPos(), discriminant.get(), cases.get()));
if (!result) {
return false;
}
Unused << discriminant.release();
Unused << cases.release();
out = Move(result);
-
- } else if (name == "SwitchCase") {
+ break;
+ }
+ case BinKind::switch_case: {
UniquePtr<ParseNode> test;
UniquePtr<ParseNode> consequent;
for (auto field: fields) {
- if (field == "test") {
- if (!this->parseExpression(&sub, test)) {
- return false;
- }
- } else if (field == "consequent") {
- if (!this->parseStatementList(&sub, consequent)) {
- return false;
- }
- } else {
- return this->raiseError();
+ switch (field) {
+ case BinField::test:
+ if (!this->parseExpression(&sub, test)) {
+ return false;
+ }
+ break;
+ case BinField::consequent:
+ if (!this->parseStatementList(&sub, consequent)) {
+ return false;
+ }
+ break;
+ default:
+ return this->raiseError();
}
}
UniquePtr<ParseNode> result(new_<CaseClause>(test.get(), consequent.get(), 0));
if (!result) {
return false;
}
Unused << test.release();
Unused << consequent.release();
out = Move(result);
+ break;
- } else if (name == "ThrowStatement") {
+ }
+
+ case BinKind::throw_statement: {
UniquePtr<ParseNode> arg;
for (auto field: fields) {
- if (field == "argument") {
+ if (field == BinField::arguments) {
if (!this->parseExpression(&sub, arg)) {
return false;
}
} else {
return this->raiseError();
}
}
@@ -681,38 +733,45 @@ ASTReader::parseStatement(SimpleTokenRea
UniquePtr<ParseNode> result(new_<UnaryNode>(PNK_THROW, JSOP_THROW, TokenPos(), arg.get()));
if (!result) {
return this->raiseError();
}
Unused << arg.release();
out = Move(result);
+ break;
- } else if (name == "TryStatement") {
+ }
+
+ case BinKind::try_statement: {
UniquePtr<ParseNode> block;
UniquePtr<ParseNode> handler;
UniquePtr<ParseNode> finalizer;
for (auto field: fields) {
- if (field == "block") {
- if (!this->parseBlockStatement(&sub, block)) {
- return false;
- }
- } else if (field == "handler") {
- if (!this->parseCatchClause(&sub, handler)) {
- return false;
- }
- } else if (field == "finalizer") {
- if (!this->parseBlockStatement(&sub, finalizer)) {
- return false;
- }
- } else {
- return this->raiseError();
+ switch (field) {
+ case BinField::block:
+ if (!this->parseBlockStatement(&sub, block)) {
+ return false;
+ }
+ break;
+ case BinField::handler:
+ if (!this->parseCatchClause(&sub, handler)) {
+ return false;
+ }
+ break;
+ case BinField::finalizer:
+ if (!this->parseBlockStatement(&sub, finalizer)) {
+ return false;
+ }
+ break;
+ default:
+ return this->raiseError();
}
}
if (!block || !handler) { // `finalizer` is optional
return this->raiseError();
}
UniquePtr<ParseNode> result(new_<TernaryNode>(PNK_TRY, JSOP_NOP, block.get(), handler.get(), finalizer.get(), TokenPos()));
@@ -720,41 +779,48 @@ ASTReader::parseStatement(SimpleTokenRea
return false;
}
Unused << block.release();
Unused << handler.release();
Unused << finalizer.release();
out = Move(result);
+ break;
- } else if (name == "WhileStatement" || name == "DoWhileStatement") {
+ }
+
+ case BinKind::while_statement: MOZ_FALLTHROUGH;
+ case BinKind::do_while_statement: {
UniquePtr<ParseNode> test;
UniquePtr<ParseNode> body;
for (auto field: fields) {
- if (field == "test") {
- if (!this->parseExpression(&sub, test)) {
- return false;
- }
- } else if (field == "body") {
- if (!this->parseStatement(&sub, test)) {
- return false;
- }
- } else {
- return this->raiseError();
+ switch (field) {
+ case BinField::test:
+ if (!this->parseExpression(&sub, test)) {
+ return false;
+ }
+ break;
+ case BinField::body:
+ if (!this->parseStatement(&sub, test)) {
+ return false;
+ }
+ break;
+ default:
+ return this->raiseError();
}
}
if (!test || !body) {
return this->raiseError();
}
- if (name == "WhileStatement") {
+ if (kind == BinKind::while_statement) {
UniquePtr<ParseNode> result(new_<BinaryNode>(PNK_WHILE, JSOP_NOP, TokenPos(), body.get(), test.get()));
if (!result) {
return false;
}
out = Move(result);
} else {
UniquePtr<ParseNode> result(new_<BinaryNode>(PNK_DOWHILE, JSOP_NOP, TokenPos(), body.get(), test.get()));
@@ -762,66 +828,72 @@ ASTReader::parseStatement(SimpleTokenRea
if (!result) {
return false;
}
out = Move(result);
}
Unused << test.release();
Unused << body.release();
+ break;
+ }
- } else if (name == "ForStatement") {
+ case BinKind::for_statement: {
UniquePtr<ParseNode> init; // Optional
UniquePtr<ParseNode> test; // Optional
UniquePtr<ParseNode> update; // Optional
ScopeData scope(this->cx); // Optional
UniquePtr<ParseNode> body; // Required
for (auto field: fields) {
- if (field == "init") {
-
- // This can be either a VarDecl or an Expression.
- SimpleTokenReader::Fields subFields(this->cx);
- SimpleTokenReader subSub(this->cx);
- std::string subName;
+ switch (field) {
+ case BinField::init: {
+ // This can be either a VarDecl or an Expression.
+ SimpleTokenReader::BinFields subFields(this->cx);
+ SimpleTokenReader subSub(this->cx);
+ BinKind subKind;
- if (!sub.taggedTuple(&subName, &subFields, &subSub)) {
- return false;
- }
-
-
- if (subName == "VariableDeclaration") {
- if (!this->parseVariableDeclarationAux(&subSub, subName, &subFields, init)) {
- return false;
- }
- } else /* Parse as expression */ {
- if (!this->parseExpressionAux(&subSub, subName, &subFields, init)) {
+ if (!sub.taggedTuple(subKind, subFields, &subSub)) {
return false;
}
- }
- } else if (field == "test") {
- if (!this->parseExpression(&sub, test)) {
- return false;
- }
- } else if (field == "update") {
- if (!this->parseExpression(&sub, update)) {
- return false;
+ if (subKind == BinKind::variable_declaration) {
+ if (!this->parseVariableDeclarationAux(&subSub, subKind, subFields, init)) {
+ return false;
+ }
+ } else /* Parse as expression */ {
+ if (!this->parseExpressionAux(&subSub, subKind, subFields, init)) {
+ return false;
+ }
+ }
+ break;
}
- } else if (field == BINJS_SCOPE) {
- if (!this->parseScope(&sub, scope)) {
- return false;
- }
- } else if (field == "body") {
- if (!this->parseStatement(&sub, body)) {
- return false;
- }
- } else {
- return this->raiseError();
+ case BinField::test:
+ if (!this->parseExpression(&sub, test)) {
+ return false;
+ }
+ break;
+ case BinField::update:
+ if (!this->parseExpression(&sub, update)) {
+ return false;
+ }
+ break;
+ case BinField::binjs_scope:
+ if (!this->parseScope(&sub, scope)) {
+ return false;
+ }
+ break;
+ case BinField::body:
+ if (!this->parseStatement(&sub, body)) {
+ return false;
+ }
+ break;
+ default:
+ return this->raiseError();
}
}
if (!body) {
return this->raiseError();
}
UniquePtr<ParseNode> forHead(new_<TernaryNode>(PNK_FORHEAD, JSOP_NOP, init.get(), test.get(), update.get(), TokenPos()));
@@ -838,61 +910,66 @@ ASTReader::parseStatement(SimpleTokenRea
if (!result) {
return false;
}
Unused << forHead.release();
Unused << body.release();
out = Move(result);
+ break;
+ }
- } else if (name == "ForInStatement") {
+ case BinKind::for_in_statement: {
UniquePtr<ParseNode> left;
UniquePtr<ParseNode> right;
UniquePtr<ParseNode> body;
ScopeData scope(this->cx); // Optional
for (auto field: fields) {
- if (field == "left") {
-
- // This can be either a VarDecl or a Pattern.
- SimpleTokenReader::Fields subFields(this->cx);
- SimpleTokenReader subSub(this->cx);
- std::string subName;
+ switch (field) {
+ case BinField::left: {
+ // This can be either a VarDecl or a Pattern.
+ SimpleTokenReader::BinFields subFields(this->cx);
+ SimpleTokenReader subSub(this->cx);
+ BinKind subKind;
- if (!sub.taggedTuple(&subName, &subFields, &subSub)) {
- return false;
- }
-
-
- if (subName == "VariableDeclaration") {
- if (!this->parseVariableDeclarationAux(&subSub, subName, &subFields, left)) {
+ if (!sub.taggedTuple(subKind, subFields, &subSub)) {
return false;
}
- } else /* Parse as pattern */ {
- if (!this->parsePatternAux(&subSub, subName, &subFields, left)) {
+
+ if (subKind == BinKind::variable_declaration) {
+ if (!this->parseVariableDeclarationAux(&subSub, subKind, subFields, left)) {
+ return false;
+ }
+ } else /* Parse as pattern */ {
+ if (!this->parsePatternAux(&subSub, subKind, subFields, left)) {
+ return false;
+ }
+ }
+ break;
+ }
+ case BinField::right:
+ if (!this->parseExpression(&sub, right)) {
return false;
}
- }
-
- } else if (field == "right") {
- if (!this->parseExpression(&sub, right)) {
- return false;
- }
- } else if (field == "body") {
- if (!this->parseExpression(&sub, body)) {
- return false;
- }
- } else if (field == BINJS_SCOPE) {
- if (!this->parseScope(&sub, scope)) {
- return false;
- }
- } else {
- return this->raiseError();
+ break;
+ case BinField::body:
+ if (!this->parseExpression(&sub, body)) {
+ return false;
+ }
+ break;
+ case BinField::binjs_scope:
+ if (!this->parseScope(&sub, scope)) {
+ return false;
+ }
+ break;
+ default:
+ return this->raiseError();
}
}
if (!left || !right || !body) {
return this->raiseError();
}
UniquePtr<ParseNode> forHead(new_<TernaryNode>(PNK_FORIN, JSOP_NOP, left.get(), nullptr, right.get(), TokenPos()));
@@ -908,43 +985,51 @@ ASTReader::parseStatement(SimpleTokenRea
if (!result) {
return false;
}
Unused << forHead.release();
Unused << body.release();
out = Move(result);
+ break;
- } else if (name == "FunctionDeclaration") {
+ }
+
+ case BinKind::function_declaration: {
RootedAtom funName(this->cx);
UniquePtr<ParseNode> params;
UniquePtr<ParseNode> body;
ScopeData scope(this->cx);
for (auto field: fields) {
- if (field == "id") {
- if (!this->readString(&sub, &funName)) {
- return false;
- }
- } else if (field == "params") {
- if (!this->parsePatternList(&sub, params)) {
- return false;
- }
- } else if (field == "body") {
- if (!this->parseStatement(&sub, body)) {
- return false;
- }
- } else if (field == BINJS_SCOPE) {
- if (!this->parseScope(&sub, scope)) {
- return false;
- }
- } else {
- return this->raiseError();
+ switch (field) {
+ case BinField::id:
+ if (!this->readString(&sub, &funName)) {
+ return false;
+ }
+ break;
+ case BinField::params:
+ if (!this->parsePatternList(&sub, params)) {
+ return false;
+ }
+ break;
+ case BinField::body:
+ if (!this->parseStatement(&sub, body)) {
+ return false;
+ }
+ break;
+ case BinField::binjs_scope:
+ if (!this->parseScope(&sub, scope)) {
+ return false;
+ }
+ break;
+ default:
+ return this->raiseError();
}
}
if (!funName || !params || !body || !scope.isSome()) {
return this->raiseError();
}
RootedFunction fun(this->cx,
@@ -989,100 +1074,108 @@ ASTReader::parseStatement(SimpleTokenRea
return false;
}
result->pn_funbox = funbox;
result->pn_body = params.release();
out = Move(result);
// FIXME: Scope
+ break;
- } else if (name == "VariableDeclaration") {
-
- if (!this->parseVariableDeclarationAux(&sub, name, &fields, out)) {
+ }
+ case BinKind::variable_declaration:
+ if (!this->parseVariableDeclarationAux(&sub, kind, fields, out)) {
return false;
}
-
- } else {
+ break;
+ default:
return this->raiseError();
}
return true;
}
bool
-ASTReader::parseVariableDeclarationAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out) {
+ASTReader::parseVariableDeclarationAux(SimpleTokenReader* reader, const BinKind name, const SimpleTokenReader::BinFields& fields, UniquePtr<ParseNode>& out) {
if (!out) {
return this->raiseError();
}
ParseNodeKind kind = PNK_LIMIT;
JSOp op = JSOP_NOP;
UniquePtr<ParseNode> result;
- for (auto field: *fields) {
- if (field == "kind") {
- std::string kindName;
- if (!this->readString(reader, kindName)) {
- return false;
- }
+ for (auto field: fields) {
+ switch (field) {
+ case BinField::kind: {
+ std::string kindName;
+ if (!this->readString(reader, kindName)) {
+ return false;
+ }
- if (kindName == "let") {
- kind = PNK_LET;
- op = JSOP_DEFLET;
- } else if (kindName == "var") {
- kind = PNK_VAR;
- op = JSOP_DEFVAR;
- } else if (kindName == "const") {
- kind = PNK_CONST;
- op = JSOP_DEFCONST;
- } else {
- return this->raiseError();
+ if (kindName == "let") {
+ kind = PNK_LET;
+ op = JSOP_DEFLET;
+ } else if (kindName == "var") {
+ kind = PNK_VAR;
+ op = JSOP_DEFVAR;
+ } else if (kindName == "const") {
+ kind = PNK_CONST;
+ op = JSOP_DEFCONST;
+ } else {
+ return this->raiseError();
+ }
+ break;
}
- } else if (field == "declarations") {
- if (result) {
- // Already parsed.
- return this->raiseError();
- }
+ case BinField::declarations: {
+ if (result) {
+ // Already parsed.
+ return this->raiseError();
+ }
- uint32_t length;
- SimpleTokenReader sub(this->cx);
+ uint32_t length;
+ SimpleTokenReader sub(this->cx);
- if (!reader->readList(&length, &sub)) {
- return false;
- }
+ if (!reader->readList(&length, &sub)) {
+ return false;
+ }
- if (length == 0) {
- return this->raiseError();
- }
+ if (length == 0) {
+ return this->raiseError();
+ }
- UniquePtr<ParseNode> root(new_<ListNode>(PNK_LIMIT /*Placeholder*/, JSOP_NOP/*Placeholder*/, TokenPos()));
- if (!root) {
- return false;
- }
+ UniquePtr<ParseNode> root(new_<ListNode>(PNK_LIMIT /*Placeholder*/, JSOP_NOP/*Placeholder*/, TokenPos()));
+ if (!root) {
+ return false;
+ }
- UniquePtr<ParseNode> first;
- if (!this->parseVariableDeclarator(&sub, first)) {
- return false;
- }
- root->initList(first.release());
+ UniquePtr<ParseNode> first;
+ if (!this->parseVariableDeclarator(&sub, first)) {
+ return false;
+ }
+ root->initList(first.release());
- for (uint32_t i = 1; i < length; ++i) {
- UniquePtr<ParseNode> current;
- if (!this->parseVariableDeclarator(&sub, current)) {
- return false;
+ for (uint32_t i = 1; i < length; ++i) {
+ UniquePtr<ParseNode> current;
+ if (!this->parseVariableDeclarator(&sub, current)) {
+ return false;
+ }
+ if (!current) {
+ return this->raiseError();
+ }
+ root->append(current.release());
}
- if (!current) {
- return this->raiseError();
- }
- root->append(current.release());
+
+ result = Move(root);
+ break;
}
-
- result = Move(root);
+ default:
+ return this->raiseError();
}
}
if (!result || kind == PNK_LIMIT) {
return this->raiseError();
}
result->setKind(kind);
@@ -1104,54 +1197,69 @@ ASTReader::parseBool(SimpleTokenReader*
}
bool
ASTReader::parseExpression(SimpleTokenReader* reader, UniquePtr<ParseNode>& out) {
if (out) {
return this->raiseError();
}
- SimpleTokenReader::Fields fields(this->cx);
+ SimpleTokenReader::BinFields fields(this->cx);
SimpleTokenReader sub(this->cx);
+ BinKind kind;
- std::string name;
- if (!reader->taggedTuple(&name, &fields, &sub)) {
+ if (!reader->taggedTuple(kind, fields, &sub)) {
return false;
}
- if (name == "ThisExpression") {
- // FIXME: Implement
- } else if (name == "ArrayExpression") {
- // FIXME: Implement
- } else if (name == "ObjectExpression") {
- // FIXME: Implement
- } else if (name == "FunctionExpression") {
- // FIXME: Implement
- } else if (name == "UnaryExpression") {
- // FIXME: Implement
- } else if (name == "UpdateExpression") {
- // FIXME: Implement
- } else if (name == "BinaryExpression") {
- // FIXME: Implement
- } else if (name == "AssignmentExpression") {
- // FIXME: Implement
- } else if (name == "LogicalExpression") {
- // FIXME: Implement
- } else if (name == "MemberExpression") {
- // FIXME: Implement
- } else if (name == "ConditionalExpression") {
- // FIXME: Implement
- } else if (name == "CallExpression") {
- // FIXME: Implement
- } else if (name == "NewExpression") {
- // FIXME: Implement
- } else if (name == "SequenceExpression") {
- // FIXME: Implement
- } else {
- return this->raiseError();
+ switch (kind) {
+ case BinKind::this_expression:
+ // FIXME: Implement
+ break;
+ case BinKind::array_expression:
+ // FIXME: Implement
+ break;
+ case BinKind::object_expression:
+ // FIXME: Implement
+ break;
+ case BinKind::function_expression:
+ // FIXME: Implement
+ break;
+ case BinKind::unary_expression:
+ // FIXME: Implement
+ break;
+ case BinKind::update_expression:
+ // FIXME: Implement
+ break;
+ case BinKind::binary_expression:
+ // FIXME: Implement
+ break;
+ case BinKind::assignment_expression:
+ // FIXME: Implement
+ break;
+ case BinKind::logical_expression:
+ // FIXME: Implement
+ break;
+ case BinKind::member_expression:
+ // FIXME: Implement
+ break;
+ case BinKind::conditional_expression:
+ // FIXME: Implement
+ break;
+ case BinKind::call_expression:
+ // FIXME: Implement
+ break;
+ case BinKind::new_expression:
+ // FIXME: Implement
+ break;
+ case BinKind::sequence_expression:
+ // FIXME: Implement
+ break;
+ default:
+ return this->raiseError();
}
return false;
}
bool
ASTReader::raiseError() {
--- a/js/src/frontend/BinTokenReader.h
+++ b/js/src/frontend/BinTokenReader.h
@@ -7,17 +7,17 @@
#include <js/TypeDecls.h>
namespace js {
namespace frontend {
using namespace mozilla;
using namespace JS;
-enum class Kind {
+enum class BinKind {
array_expression,
assignment_expression,
assignment_operator,
binary_expression,
binary_operator,
binjs_scope,
block_statement,
boolean_literal,
@@ -73,66 +73,71 @@ enum class Kind {
update_operator,
variable_declaration,
variable_declarator,
variable_kind,
while_statement,
with_statement,
};
-enum class Field {
+enum class BinField {
alternate,
argument,
arguments,
binjs_scope,
block,
callee,
cases,
consequent,
computed,
body,
+ captured_names,
+ const_decl_names,
declarations,
directives,
discriminant,
elements,
expression,
expressions,
finalizer,
flags,
handler,
+ has_direct_eval,
id,
init,
key,
kind,
label,
left,
+ let_decl_names,
name,
object,
operator_,
param,
params,
pattern,
prefix,
properties,
property,
right,
test,
update,
value,
+ var_decl_names,
};
/**
* A simple, extremely sub-optimal TokenReader, used as scaffolding for testing
* the implementation of binary parsing.
*/
class SimpleTokenReader MOZ_STACK_CLASS
{
public:
using Fields = Vector<std::string, 8>;
- using BinFields = Vector<Field, 8>;
+ using BinFields = Vector<BinField, 8>;
public:
SimpleTokenReader(JSContext* cx_)
: cx(cx_)
, initialized(false)
, parent(nullptr)
, errored(false)
, current(nullptr)
, stop(nullptr)
@@ -288,17 +293,17 @@ public:
*
* Before destructing `subReader`, callers MUST reach the end of the
* tagged tuple. Failure to do so may either raise an error or cause
* an inconsistent sequence of tokens in the parent.
*
* @return out If the header of the tuple is invalid.
*/
bool taggedTuple(std::string* tag, SimpleTokenReader::Fields *fields, SimpleTokenReader *subReader);
- bool taggedTuple(Kind& tag, SimpleTokenReader::BinFields& fields, SimpleTokenReader *subReader);
+ bool taggedTuple(BinKind& tag, SimpleTokenReader::BinFields& fields, SimpleTokenReader *subReader);
/**
* Start reading an untagged tuple.
* @param subReader (OUT) A token reader for the list. It does NOT
* support `skip()`.
*
* Before destructing `subReader`, callers MUST reach the end of the
* tuple. Failure to do so may either raise an error or cause