diff --git a/packages/babylon/src/parser/statement.js b/packages/babylon/src/parser/statement.js index 9f96ccf826..536db0a82c 100644 --- a/packages/babylon/src/parser/statement.js +++ b/packages/babylon/src/parser/statement.js @@ -13,18 +13,8 @@ const pp = Parser.prototype; pp.parseTopLevel = function (file, program) { program.sourceType = this.options.sourceType; - program.body = []; - let first = true; - while (!this.match(tt.eof)) { - let stmt = this.parseStatement(true, true); - program.body.push(stmt); - if (first) { - if (this.isUseStrict(stmt)) this.setStrict(true); - first = false; - } - } - this.next(); + this.parseBlockBody(program, true, tt.eof); file.program = this.finishNode(program, "Program"); file.comments = this.state.comments; @@ -35,6 +25,16 @@ pp.parseTopLevel = function (file, program) { const loopLabel = {kind: "loop"}, switchLabel = {kind: "switch"}; +// TODO + +pp.parseDirective = function () { + let node = this.startNode(); + node.raw = this.input.slice(this.state.start, this.state.end); + node.value = node.raw.slice(1, -1); // remove quotes + this.next(); + return this.finishNode(node, "Directive"); +}; + // Parse a single statement. // // If expecting a statement and finding a slash operator, parse a @@ -415,22 +415,41 @@ pp.parseExpressionStatement = function (node, expr) { // function bodies). pp.parseBlock = function (allowStrict) { - let node = this.startNode(), first = true, oldStrict; - node.body = []; + let node = this.startNode(); this.expect(tt.braceL); - while (!this.eat(tt.braceR)) { - let stmt = this.parseStatement(true); - node.body.push(stmt); - if (first && allowStrict && this.isUseStrict(stmt)) { - oldStrict = this.state.strict; - this.setStrict(this.state.strict = true); - } - first = false; - } - if (oldStrict === false) this.setStrict(false); + this.parseBlockBody(node, allowStrict, tt.braceR); return this.finishNode(node, "BlockStatement"); }; +// TODO + +pp.parseBlockBody = function (node, allowStrict, end) { + node.body = []; + node.directives = []; + + let parsedNonDirective = false; + let oldStrict; + + while (!this.eat(end)) { + if (!parsedNonDirective && this.match(tt.string)) { + let stmt = this.parseDirective(); + node.directives.push(stmt); + + if (allowStrict && stmt.value === "use strict") { + oldStrict = this.state.strict; + this.setStrict(this.state.strict = true); + } + } else { + parsedNonDirective = true; + node.body.push(this.parseStatement(true)); + } + } + + if (oldStrict === false) { + this.setStrict(false); + } +}; + // Parse a regular `for` loop. The disambiguation code in // `parseStatement` will already have parsed the init statement or // expression. diff --git a/packages/babylon/src/parser/util.js b/packages/babylon/src/parser/util.js index 29cdc074c6..2b1dd9e1b2 100644 --- a/packages/babylon/src/parser/util.js +++ b/packages/babylon/src/parser/util.js @@ -6,12 +6,6 @@ const pp = Parser.prototype; // ## Parser utilities -// Test whether a statement node is the string literal `"use strict"`. - -pp.isUseStrict = function (stmt) { - return stmt.type === "ExpressionStatement" && stmt.expression.type === "StringLiteral" && stmt.expression.raw.slice(1, -1) === "use strict"; -}; - // TODO pp.isRelational = function (op) {