diff --git a/AUTHORS b/AUTHORS
deleted file mode 100755
index 799a063354..0000000000
--- a/AUTHORS
+++ /dev/null
@@ -1,32 +0,0 @@
-List of Acorn contributors. Updated before every release.
-
-Alistair Braidwood
-Aparajita Fishman
-Arian Stolwijk
-Artem Govorov
-Brandon Mills
-Charles Hughes
-Conrad Irwin
-David Bonnet
-impinball
-Ingvar Stepanyan
-Jiaxing Wang
-Johannes Herr
-Jürg Lehni
-keeyipchan
-krator
-Marijn Haverbeke
-Martin Carlberg
-Mathias Bynens
-Mathieu 'p01' Henri
-Max Schaefer
-Mihai Bazon
-Mike Rennie
-Oskar Schöldström
-Paul Harper
-Peter Rust
-PlNG
-r-e-d
-Rich Harris
-Sebastian McKenzie
-zsjforcn
diff --git a/LICENSE b/LICENSE
deleted file mode 100755
index d4c7fc5838..0000000000
--- a/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (C) 2012-2014 by various contributors (see AUTHORS)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000..d8da1c161c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,7 @@
+
+
+
+
+
+ Babylon is a streaming parser for Babel.
+
diff --git a/index.js b/index.js
deleted file mode 100644
index a9c3b90793..0000000000
--- a/index.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export * from "./src/index";
-import "./plugins/flow";
-
-import inject from "acorn-jsx/inject";
-import * as acorn from "./src/index";
-inject(acorn);
diff --git a/package.json b/package.json
old mode 100755
new mode 100644
index 4067160963..767cde522a
--- a/package.json
+++ b/package.json
@@ -1,44 +1,12 @@
{
- "name": "acorn",
- "description": "ECMAScript parser",
- "homepage": "https://github.com/marijnh/acorn",
- "main": "index.js",
- "version": "1.0.0",
- "engines": {
- "node": ">=0.4.0"
- },
- "maintainers": [
- {
- "name": "Marijn Haverbeke",
- "email": "marijnh@gmail.com",
- "web": "http://marijnhaverbeke.nl"
- },
- {
- "name": "Ingvar Stepanyan",
- "email": "me@rreverser.com",
- "web": "http://rreverser.com/"
- }
- ],
- "repository": {
- "type": "git",
- "url": "https://github.com/marijnh/acorn.git"
- },
- "licenses": [
- {
- "type": "MIT",
- "url": "https://raw.githubusercontent.com/marijnh/acorn/master/LICENSE"
- }
- ],
- "scripts": {
- "test": "node test/run.js",
- "prepublish": "node bin/prepublish.sh"
- },
- "bin": {
- "acorn": "./bin/acorn"
- },
- "devDependencies": {
- "babelify": "^5.0.4",
- "browserify": "^9.0.3",
- "unicode-7.0.0": "~0.1.5"
+ "name": "babylon",
+ "description": "",
+ "author": "Sebastian McKenzie ",
+ "homepage": "https://babeljs.io/",
+ "license": "MIT",
+ "repository": "babel/babel",
+ "main": "lib/index.js",
+ "dependencies": {
+ "bluebird": "^2.9.33"
}
}
diff --git a/plugins/flow.js b/plugins/flow.js
deleted file mode 100644
index 34919438f4..0000000000
--- a/plugins/flow.js
+++ /dev/null
@@ -1,830 +0,0 @@
-var acorn = require("../src/index")
-
-var pp = acorn.Parser.prototype
-var tt = acorn.tokTypes
-
-pp.isRelational = function (op) {
- return this.type === tt.relational && this.value === op
-}
-
-pp.expectRelational = function (op) {
- if (this.isRelational(op)) {
- this.next()
- } else {
- this.unexpected()
- }
-}
-
-pp.flow_parseTypeInitialiser = function (tok) {
- var oldInType = this.inType
- this.inType = true
- this.expect(tok || tt.colon)
- var type = this.flow_parseType()
- this.inType = oldInType
- return type;
-}
-
-pp.flow_parseDeclareClass = function (node) {
- this.next()
- this.flow_parseInterfaceish(node, true)
- return this.finishNode(node, "DeclareClass")
-}
-
-pp.flow_parseDeclareFunction = function (node) {
- this.next()
-
- var id = node.id = this.parseIdent()
-
- var typeNode = this.startNode()
- var typeContainer = this.startNode()
-
- if (this.isRelational("<")) {
- typeNode.typeParameters = this.flow_parseTypeParameterDeclaration()
- } else {
- typeNode.typeParameters = null
- }
-
- this.expect(tt.parenL)
- var tmp = this.flow_parseFunctionTypeParams()
- typeNode.params = tmp.params
- typeNode.rest = tmp.rest
- this.expect(tt.parenR)
- typeNode.returnType = this.flow_parseTypeInitialiser()
-
- typeContainer.typeAnnotation = this.finishNode(typeNode, "FunctionTypeAnnotation")
- id.typeAnnotation = this.finishNode(typeContainer, "TypeAnnotation")
-
- this.finishNode(id, id.type)
-
- this.semicolon()
-
- return this.finishNode(node, "DeclareFunction")
-}
-
-pp.flow_parseDeclare = function (node) {
- if (this.type === tt._class) {
- return this.flow_parseDeclareClass(node)
- } else if (this.type === tt._function) {
- return this.flow_parseDeclareFunction(node)
- } else if (this.type === tt._var) {
- return this.flow_parseDeclareVariable(node)
- } else if (this.isContextual("module")) {
- return this.flow_parseDeclareModule(node)
- } else {
- this.unexpected()
- }
-}
-
-pp.flow_parseDeclareVariable = function (node) {
- this.next()
- node.id = this.flow_parseTypeAnnotatableIdentifier()
- this.semicolon()
- return this.finishNode(node, "DeclareVariable")
-}
-
-pp.flow_parseDeclareModule = function (node) {
- this.next()
-
- if (this.type === tt.string) {
- node.id = this.parseExprAtom()
- } else {
- node.id = this.parseIdent()
- }
-
- var bodyNode = node.body = this.startNode()
- var body = bodyNode.body = []
- this.expect(tt.braceL)
- while (this.type !== tt.braceR) {
- var node2 = this.startNode()
-
- // todo: declare check
- this.next()
-
- body.push(this.flow_parseDeclare(node2))
- }
- this.expect(tt.braceR)
-
- this.finishNode(bodyNode, "BlockStatement")
- return this.finishNode(node, "DeclareModule")
-}
-
-
-// Interfaces
-
-pp.flow_parseInterfaceish = function (node, allowStatic) {
- node.id = this.parseIdent()
-
- if (this.isRelational("<")) {
- node.typeParameters = this.flow_parseTypeParameterDeclaration()
- } else {
- node.typeParameters = null
- }
-
- node.extends = []
-
- if (this.eat(tt._extends)) {
- do {
- node.extends.push(this.flow_parseInterfaceExtends())
- } while(this.eat(tt.comma))
- }
-
- node.body = this.flow_parseObjectType(allowStatic)
-}
-
-pp.flow_parseInterfaceExtends = function () {
- var node = this.startNode()
-
- node.id = this.parseIdent()
- if (this.isRelational("<")) {
- node.typeParameters = this.flow_parseTypeParameterInstantiation()
- } else {
- node.typeParameters = null
- }
-
- return this.finishNode(node, "InterfaceExtends")
-}
-
-pp.flow_parseInterface = function (node) {
- this.flow_parseInterfaceish(node, false)
- return this.finishNode(node, "InterfaceDeclaration")
-}
-
-// Type aliases
-
-pp.flow_parseTypeAlias = function (node) {
- node.id = this.parseIdent()
-
- if (this.isRelational("<")) {
- node.typeParameters = this.flow_parseTypeParameterDeclaration()
- } else {
- node.typeParameters = null
- }
-
- node.right = this.flow_parseTypeInitialiser(tt.eq)
- this.semicolon()
-
- return this.finishNode(node, "TypeAlias")
-}
-
-// Type annotations
-
-pp.flow_parseTypeParameterDeclaration = function () {
- var node = this.startNode()
- node.params = []
-
- this.expectRelational("<")
- while (!this.isRelational(">")) {
- node.params.push(this.flow_parseTypeAnnotatableIdentifier())
- if (!this.isRelational(">")) {
- this.expect(tt.comma)
- }
- }
- this.expectRelational(">")
-
- return this.finishNode(node, "TypeParameterDeclaration")
-}
-
-pp.flow_parseTypeParameterInstantiation = function () {
- var node = this.startNode(), oldInType = this.inType
- node.params = []
-
- this.inType = true
-
- this.expectRelational("<")
- while (!this.isRelational(">")) {
- node.params.push(this.flow_parseType())
- if (!this.isRelational(">")) {
- this.expect(tt.comma)
- }
- }
- this.expectRelational(">")
-
- this.inType = oldInType
-
- return this.finishNode(node, "TypeParameterInstantiation")
-}
-
-pp.flow_parseObjectPropertyKey = function () {
- return (this.type === tt.num || this.type === tt.string) ? this.parseExprAtom() : this.parseIdent(true)
-}
-
-pp.flow_parseObjectTypeIndexer = function (node, isStatic) {
- node.static = isStatic
-
- this.expect(tt.bracketL)
- node.id = this.flow_parseObjectPropertyKey()
- node.key = this.flow_parseTypeInitialiser()
- this.expect(tt.bracketR)
- node.value = this.flow_parseTypeInitialiser()
-
- this.flow_objectTypeSemicolon()
- return this.finishNode(node, "ObjectTypeIndexer")
-}
-
-pp.flow_parseObjectTypeMethodish = function (node) {
- node.params = []
- node.rest = null
- node.typeParameters = null
-
- if (this.isRelational("<")) {
- node.typeParameters = this.flow_parseTypeParameterDeclaration()
- }
-
- this.expect(tt.parenL)
- while (this.type === tt.name) {
- node.params.push(this.flow_parseFunctionTypeParam())
- if (this.type !== tt.parenR) {
- this.expect(tt.comma)
- }
- }
-
- if (this.eat(tt.ellipsis)) {
- node.rest = this.flow_parseFunctionTypeParam()
- }
- this.expect(tt.parenR)
- node.returnType = this.flow_parseTypeInitialiser()
-
- return this.finishNode(node, "FunctionTypeAnnotation")
-}
-
-pp.flow_parseObjectTypeMethod = function (start, isStatic, key) {
- var node = this.startNodeAt(start)
- node.value = this.flow_parseObjectTypeMethodish(this.startNodeAt(start))
- node.static = isStatic
- node.key = key
- node.optional = false
- this.flow_objectTypeSemicolon()
- return this.finishNode(node, "ObjectTypeProperty")
-}
-
-pp.flow_parseObjectTypeCallProperty = function (node, isStatic) {
- var valueNode = this.startNode()
- node.static = isStatic
- node.value = this.flow_parseObjectTypeMethodish(valueNode)
- this.flow_objectTypeSemicolon()
- return this.finishNode(node, "ObjectTypeCallProperty")
-}
-
-pp.flow_parseObjectType = function (allowStatic) {
- var nodeStart = this.startNode()
- var node
- var optional = false
- var property
- var propertyKey
- var propertyTypeAnnotation
- var token
- var isStatic
-
- nodeStart.callProperties = []
- nodeStart.properties = []
- nodeStart.indexers = []
-
- this.expect(tt.braceL)
-
- while (this.type !== tt.braceR) {
- var start = this.markPosition()
- node = this.startNode()
- if (allowStatic && this.isContextual("static")) {
- this.next()
- isStatic = true
- }
-
- if (this.type === tt.bracketL) {
- nodeStart.indexers.push(this.flow_parseObjectTypeIndexer(node, isStatic))
- } else if (this.type === tt.parenL || this.isRelational("<")) {
- nodeStart.callProperties.push(this.flow_parseObjectTypeCallProperty(node, allowStatic))
- } else {
- if (isStatic && this.type === tt.colon) {
- propertyKey = this.parseIdent()
- } else {
- propertyKey = this.flow_parseObjectPropertyKey()
- }
- if (this.isRelational("<") || this.type === tt.parenL) {
- // This is a method property
- nodeStart.properties.push(this.flow_parseObjectTypeMethod(start, isStatic, propertyKey))
- } else {
- if (this.eat(tt.question)) {
- optional = true
- }
- node.key = propertyKey
- node.value = this.flow_parseTypeInitialiser()
- node.optional = optional
- node.static = isStatic
- this.flow_objectTypeSemicolon()
- nodeStart.properties.push(this.finishNode(node, "ObjectTypeProperty"))
- }
- }
- }
-
- this.expect(tt.braceR)
-
- return this.finishNode(nodeStart, "ObjectTypeAnnotation")
-}
-
-pp.flow_objectTypeSemicolon = function () {
- if (!this.eat(tt.semi) && !this.eat(tt.comma) && this.type !== tt.braceR) {
- this.unexpected()
- }
-}
-
-pp.flow_parseGenericType = function (start, id) {
- var node = this.startNodeAt(start)
-
- node.typeParameters = null
- node.id = id
-
- while (this.eat(tt.dot)) {
- var node2 = this.startNodeAt(start)
- node2.qualification = node.id
- node2.id = this.parseIdent()
- node.id = this.finishNode(node2, "QualifiedTypeIdentifier")
- }
-
- if (this.isRelational("<")) {
- node.typeParameters = this.flow_parseTypeParameterInstantiation()
- }
-
- return this.finishNode(node, "GenericTypeAnnotation")
-}
-
-pp.flow_parseTypeofType = function () {
- var node = this.startNode()
- this.expect(tt._typeof)
- node.argument = this.flow_parsePrimaryType()
- return this.finishNode(node, "TypeofTypeAnnotation")
-}
-
-pp.flow_parseTupleType = function () {
- var node = this.startNode()
- node.types = []
- this.expect(tt.bracketL)
- // We allow trailing commas
- while (this.pos < this.input.length && this.type !== tt.bracketR) {
- node.types.push(this.flow_parseType())
- if (this.type === tt.bracketR) break
- this.expect(tt.comma)
- }
- this.expect(tt.bracketR)
- return this.finishNode(node, "TupleTypeAnnotation")
-}
-
-pp.flow_parseFunctionTypeParam = function () {
- var optional = false
- var node = this.startNode()
- node.name = this.parseIdent()
- if (this.eat(tt.question)) {
- optional = true
- }
- node.optional = optional
- node.typeAnnotation = this.flow_parseTypeInitialiser()
- return this.finishNode(node, "FunctionTypeParam")
-}
-
-pp.flow_parseFunctionTypeParams = function () {
- var ret = { params: [], rest: null }
- while (this.type === tt.name) {
- ret.params.push(this.flow_parseFunctionTypeParam())
- if (this.type !== tt.parenR) {
- this.expect(tt.comma)
- }
- }
- if (this.eat(tt.ellipsis)) {
- ret.rest = this.flow_parseFunctionTypeParam()
- }
- return ret
-}
-
-pp.flow_identToTypeAnnotation = function (start, node, id) {
- switch (id.name) {
- case "any":
- return this.finishNode(node, "AnyTypeAnnotation")
-
- case "void":
- return this.finishNode(node, "VoidTypeAnnotation")
-
- case "bool":
- case "boolean":
- return this.finishNode(node, "BooleanTypeAnnotation")
-
- case "mixed":
- return this.finishNode(node, "MixedTypeAnnotation")
-
- case "number":
- return this.finishNode(node, "NumberTypeAnnotation")
-
- case "string":
- return this.finishNode(node, "StringTypeAnnotation")
-
- default:
- return this.flow_parseGenericType(start, id)
- }
-}
-
-// The parsing of types roughly parallels the parsing of expressions, and
-// primary types are kind of like primary expressions...they're the
-// primitives with which other types are constructed.
-pp.flow_parsePrimaryType = function () {
- var typeIdentifier = null
- var params = null
- var returnType = null
- var start = this.markPosition()
- var node = this.startNode()
- var rest = null
- var tmp
- var typeParameters
- var token
- var type
- var isGroupedType = false
-
- switch (this.type) {
- case tt.name:
- return this.flow_identToTypeAnnotation(start, node, this.parseIdent())
-
- case tt.braceL:
- return this.flow_parseObjectType()
-
- case tt.bracketL:
- return this.flow_parseTupleType()
-
- case tt.relational:
- if (this.value === "<") {
- node.typeParameters = this.flow_parseTypeParameterDeclaration()
- this.expect(tt.parenL)
- tmp = this.flow_parseFunctionTypeParams()
- node.params = tmp.params
- node.rest = tmp.rest
- this.expect(tt.parenR)
-
- this.expect(tt.arrow)
-
- node.returnType = this.flow_parseType()
-
- return this.finishNode(node, "FunctionTypeAnnotation")
- }
-
- case tt.parenL:
- this.next()
-
- // Check to see if this is actually a grouped type
- if (this.type !== tt.parenR && this.type !== tt.ellipsis) {
- if (this.type === tt.name) {
- var token = this.lookahead().type
- isGroupedType = token !== tt.question && token !== tt.colon
- } else {
- isGroupedType = true
- }
- }
-
- if (isGroupedType) {
- type = this.flow_parseType()
- this.expect(tt.parenR)
-
- // If we see a => next then someone was probably confused about
- // function types, so we can provide a better error message
- if (this.eat(tt.arrow)) {
- this.raise(node,
- "Unexpected token =>. It looks like " +
- "you are trying to write a function type, but you ended up " +
- "writing a grouped type followed by an =>, which is a syntax " +
- "error. Remember, function type parameters are named so function " +
- "types look like (name1: type1, name2: type2) => returnType. You " +
- "probably wrote (type1) => returnType"
- )
- }
-
- return type
- }
-
- tmp = this.flow_parseFunctionTypeParams()
- node.params = tmp.params
- node.rest = tmp.rest
-
- this.expect(tt.parenR)
-
- this.expect(tt.arrow)
-
- node.returnType = this.flow_parseType()
- node.typeParameters = null
-
- return this.finishNode(node, "FunctionTypeAnnotation")
-
- case tt.string:
- node.value = this.value
- node.raw = this.input.slice(this.start, this.end)
- this.next()
- return this.finishNode(node, "StringLiteralTypeAnnotation")
-
- default:
- if (this.type.keyword === "typeof") {
- return this.flow_parseTypeofType()
- }
- }
-
- this.unexpected()
-}
-
-pp.flow_parsePostfixType = function () {
- var node = this.startNode()
- var type = node.elementType = this.flow_parsePrimaryType()
- if (this.type === tt.bracketL) {
- this.expect(tt.bracketL)
- this.expect(tt.bracketR)
- return this.finishNode(node, "ArrayTypeAnnotation")
- }
- return type
-}
-
-pp.flow_parsePrefixType = function () {
- var node = this.startNode()
- if (this.eat(tt.question)) {
- node.typeAnnotation = this.flow_parsePrefixType()
- return this.finishNode(node, "NullableTypeAnnotation")
- }
- return this.flow_parsePostfixType()
-}
-
-pp.flow_parseIntersectionType = function () {
- var node = this.startNode()
- var type = this.flow_parsePrefixType()
- node.types = [type]
- while (this.eat(tt.bitwiseAND)) {
- node.types.push(this.flow_parsePrefixType())
- }
- return node.types.length === 1 ? type : this.finishNode(node, "IntersectionTypeAnnotation")
-}
-
-pp.flow_parseUnionType = function () {
- var node = this.startNode()
- var type = this.flow_parseIntersectionType()
- node.types = [type]
- while (this.eat(tt.bitwiseOR)) {
- node.types.push(this.flow_parseIntersectionType())
- }
- return node.types.length === 1 ? type : this.finishNode(node, "UnionTypeAnnotation")
-}
-
-pp.flow_parseType = function () {
- var oldInType = this.inType
- this.inType = true
- var type = this.flow_parseUnionType()
- this.inType = oldInType
- return type
-}
-
-pp.flow_parseTypeAnnotation = function () {
- var node = this.startNode()
- node.typeAnnotation = this.flow_parseTypeInitialiser()
- return this.finishNode(node, "TypeAnnotation")
-}
-
-pp.flow_parseTypeAnnotatableIdentifier = function (requireTypeAnnotation, canBeOptionalParam) {
- var node = this.startNode()
- var ident = this.parseIdent()
- var isOptionalParam = false
-
- if (canBeOptionalParam && this.eat(tt.question)) {
- this.expect(tt.question)
- isOptionalParam = true
- }
-
- if (requireTypeAnnotation || this.type === tt.colon) {
- ident.typeAnnotation = this.flow_parseTypeAnnotation()
- this.finishNode(ident, ident.type)
- }
-
- if (isOptionalParam) {
- ident.optional = true
- this.finishNode(ident, ident.type)
- }
-
- return ident
-}
-
-acorn.plugins.flow = function (instance) {
- // function name(): string {}
- instance.extend("parseFunctionBody", function (inner) {
- return function (node, allowExpression) {
- if (this.type === tt.colon) {
- node.returnType = this.flow_parseTypeAnnotation()
- }
-
- return inner.call(this, node, allowExpression)
- }
- })
-
- instance.extend("parseStatement", function (inner) {
- return function(declaration, topLevel) {
- // strict mode handling of `interface` since it's a reserved word
- if (this.strict && this.type === tt.name && this.value === "interface") {
- var node = this.startNode()
- this.next()
- return this.flow_parseInterface(node)
- } else {
- return inner.call(this, declaration, topLevel)
- }
- }
- })
-
- instance.extend("parseExpressionStatement", function (inner) {
- return function (node, expr) {
- if (expr.type === "Identifier") {
- if (expr.name === "declare") {
- if (this.type === tt._class || this.type === tt.name || this.type === tt._function || this.type === tt._var) {
- return this.flow_parseDeclare(node)
- }
- } else if (this.type === tt.name) {
- if (expr.name === "interface") {
- return this.flow_parseInterface(node)
- } else if (expr.name === "type") {
- return this.flow_parseTypeAlias(node)
- }
- }
- }
-
- return inner.call(this, node, expr)
- }
- })
-
- instance.extend("shouldParseExportDeclaration", function (inner) {
- return function () {
- return this.isContextual("type") || inner.call(this)
- }
- })
-
- instance.extend("parseParenItem", function (inner) {
- return function (node, start) {
- if (this.type === tt.colon) {
- var typeCastNode = this.startNodeAt(start)
- typeCastNode.expression = node
- typeCastNode.typeAnnotation = this.flow_parseTypeAnnotation()
- return this.finishNode(typeCastNode, "TypeCastExpression")
- } else {
- return node
- }
- }
- })
-
- instance.extend("parseClassId", function (inner) {
- return function (node, isStatement) {
- inner.call(this, node, isStatement)
- if (this.isRelational("<")) {
- node.typeParameters = this.flow_parseTypeParameterDeclaration()
- }
- }
- })
-
- // don't consider `void` to be a keyword as then it'll use the void token type
- // and set startExpr
- instance.extend("isKeyword", function (inner) {
- return function(name) {
- if (this.inType && name === "void") {
- return false
- } else {
- return inner.call(this, name)
- }
- }
- })
-
- instance.extend("readToken", function (inner) {
- return function(code) {
- if (this.inType && (code === 62 || code === 60)) {
- return this.finishOp(tt.relational, 1)
- } else {
- return inner.call(this, code)
- }
- }
- })
-
- instance.extend("jsx_readToken", function (inner) {
- return function () {
- if (!this.inType) return inner.call(this)
- }
- })
-
- instance.extend("parseParenArrowList", function (inner) {
- return function (start, exprList, isAsync) {
- for (var i = 0; i < exprList.length; i++) {
- var listItem = exprList[i]
- if (listItem.type === "TypeCastExpression") {
- var expr = listItem.expression
- expr.typeAnnotation = listItem.typeAnnotation
- exprList[i] = expr
- }
- }
- return inner.call(this, start, exprList, isAsync)
- }
- })
-
- instance.extend("parseClassProperty", function (inner) {
- return function (node) {
- if (this.type === tt.colon) {
- node.typeAnnotation = this.flow_parseTypeAnnotation()
- }
- return inner.call(this, node)
- }
- })
- instance.extend("isClassProperty", function (inner) {
- return function () {
- return this.type === tt.colon || inner.call(this)
- }
- })
-
- instance.extend("parseClassMethod", function (inner) {
- return function (classBody, method, isGenerator, isAsync) {
- var typeParameters
- if (this.isRelational("<")) {
- typeParameters = this.flow_parseTypeParameterDeclaration()
- }
- method.value = this.parseMethod(isGenerator, isAsync)
- method.value.typeParameters = typeParameters
- classBody.body.push(this.finishNode(method, "MethodDefinition"))
- }
- })
-
- instance.extend("parseClassSuper", function (inner) {
- return function (node, isStatement) {
- inner.call(this, node, isStatement)
- if (node.superClass && this.isRelational("<")) {
- node.superTypeParameters = this.flow_parseTypeParameterInstantiation()
- }
- if (this.isContextual("implements")) {
- this.next()
- var implemented = node.implements = []
- do {
- var node = this.startNode()
- node.id = this.parseIdent()
- if (this.isRelational("<")) {
- node.typeParameters = this.flow_parseTypeParameterInstantiation()
- } else {
- node.typeParameters = null
- }
- implemented.push(this.finishNode(node, "ClassImplements"))
- } while(this.eat(tt.comma))
- }
- }
- })
-
- instance.extend("parseObjPropValue", function (inner) {
- return function (prop) {
- var typeParameters
- if (this.isRelational("<")) {
- typeParameters = this.flow_parseTypeParameterDeclaration()
- if (this.type !== tt.parenL) this.unexpected()
- }
- inner.apply(this, arguments)
- prop.value.typeParameters = typeParameters
- }
- })
-
- instance.extend("parseAssignableListItemTypes", function (inner) {
- return function (param) {
- if (this.eat(tt.question)) {
- param.optional = true
- }
- if (this.type === tt.colon) {
- param.typeAnnotation = this.flow_parseTypeAnnotation()
- }
- this.finishNode(param, param.type)
- return param
- }
- })
-
- instance.extend("parseImportSpecifiers", function (inner) {
- return function (node) {
- node.isType = false
- if (this.isContextual("type")) {
- var start = this.markPosition()
- var typeId = this.parseIdent()
- if ((this.type === tt.name && this.value !== "from") || this.type === tt.braceL || this.type === tt.star) {
- node.isType = true
- } else {
- node.specifiers.push(this.parseImportSpecifierDefault(typeId, start))
- if (this.isContextual("from")) return
- this.eat(tt.comma)
- }
- }
- inner.call(this, node)
- }
- })
-
- // function foo() {}
- instance.extend("parseFunctionParams", function (inner) {
- return function (node) {
- if (this.isRelational("<")) {
- node.typeParameters = this.flow_parseTypeParameterDeclaration()
- }
- inner.call(this, node)
- }
- })
-
- // var foo: string = bar
- instance.extend("parseVarHead", function (inner) {
- return function (decl) {
- inner.call(this, decl)
- if (this.type === tt.colon) {
- decl.id.typeAnnotation = this.flow_parseTypeAnnotation()
- this.finishNode(decl.id, decl.id.type)
- }
- }
- })
-}
diff --git a/src/expression.js b/src/expression.js
index ba94cd5249..2126431a17 100755
--- a/src/expression.js
+++ b/src/expression.js
@@ -16,56 +16,56 @@
//
// [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser
-import {types as tt} from "./tokentype"
-import {Parser} from "./state"
-import {reservedWords} from "./identifier"
-import {has} from "./util"
+import {types as tt} from "./tokentype";
+import {Parser} from "./state";
+import {reservedWords} from "./identifier";
+import {has} from "./util";
-const pp = Parser.prototype
+const pp = Parser.prototype;
// Check if property name clashes with already added.
// Object/class getters and setters are not allowed to clash —
// either with each other or with an init property — and in
// strict mode, init properties are also not allowed to be repeated.
-pp.checkPropClash = function(prop, propHash) {
+pp.checkPropClash = function (prop, propHash) {
if (this.options.ecmaVersion >= 6 && (prop.computed || prop.method || prop.shorthand))
- return
- let key = prop.key, name
+ return;
+ let key = prop.key, name;
switch (key.type) {
- case "Identifier": name = key.name; break
- case "Literal": name = String(key.value); break
- default: return
+ case "Identifier": name = key.name; break;
+ case "Literal": name = String(key.value); break;
+ default: return;
}
- let kind = prop.kind
+ let kind = prop.kind;
if (this.options.ecmaVersion >= 6) {
if (name === "__proto__" && kind === "init") {
if (propHash.proto) this.raise(key.start, "Redefinition of __proto__ property");
- propHash.proto = true
+ propHash.proto = true;
}
- return
+ return;
}
- let other
- if (has(propHash, name)) {
- other = propHash[name]
- let isGetSet = kind !== "init"
+ let other;
+ if (propHash[name]) {
+ other = propHash[name];
+ let isGetSet = kind !== "init";
if ((this.strict || isGetSet) && other[kind] || !(isGetSet ^ other.init))
- this.raise(key.start, "Redefinition of property")
+ this.raise(key.start, "Redefinition of property");
} else {
other = propHash[name] = {
init: false,
get: false,
set: false
- }
+ };
}
- other[kind] = true
-}
+ other[kind] = true;
+};
// ### Expression parsing
// These nest, from the most general expression type at the top to
// 'atomic', nondivisible expression types at the bottom. Most of
-// the functions will simply let the function(s) below them parse,
+// the functions will simply let the function (s) below them parse,
// and, *if* the syntactic construct they handle is present, wrap
// the AST node that the inner parser gave them in another node.
@@ -76,87 +76,91 @@ pp.checkPropClash = function(prop, propHash) {
// and object pattern might appear (so it's possible to raise
// delayed syntax error at correct position).
-pp.parseExpression = function(noIn, refShorthandDefaultPos) {
- let start = this.markPosition()
- let expr = this.parseMaybeAssign(noIn, refShorthandDefaultPos)
+pp.parseExpression = function (noIn, refShorthandDefaultPos) {
+ let startPos = this.start, startLoc = this.startLoc;
+ let expr = this.parseMaybeAssign(noIn, refShorthandDefaultPos);
if (this.type === tt.comma) {
- let node = this.startNodeAt(start)
- node.expressions = [expr]
- while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(noIn, refShorthandDefaultPos))
- return this.finishNode(node, "SequenceExpression")
+ let node = this.startNodeAt(startPos, startLoc);
+ node.expressions = [expr];
+ while (this.eat(tt.comma)) {
+ node.expressions.push(this.parseMaybeAssign(noIn, refShorthandDefaultPos));
+ }
+ return this.finishNode(node, "SequenceExpression");
}
- return expr
-}
+ return expr;
+};
// Parse an assignment expression. This includes applications of
// operators like `+=`.
-pp.parseMaybeAssign = function(noIn, refShorthandDefaultPos, afterLeftParse) {
- if (this.type == tt._yield && this.inGenerator) return this.parseYield()
-
- let failOnShorthandAssign
- if (!refShorthandDefaultPos) {
- refShorthandDefaultPos = {start: 0}
- failOnShorthandAssign = true
- } else {
- failOnShorthandAssign = false
+pp.parseMaybeAssign = function (noIn, refShorthandDefaultPos, afterLeftParse) {
+ if (this.type === tt._yield && this.inGenerator) {
+ return this.parseYield();
}
- let start = this.markPosition()
- if (this.type == tt.parenL || this.type == tt.name)
- this.potentialArrowAt = this.start
- let left = this.parseMaybeConditional(noIn, refShorthandDefaultPos)
- if (afterLeftParse) left = afterLeftParse.call(this, left, start)
+
+ let failOnShorthandAssign;
+ if (!refShorthandDefaultPos) {
+ refShorthandDefaultPos = {start: 0};
+ failOnShorthandAssign = true;
+ } else {
+ failOnShorthandAssign = false;
+ }
+ let startPos = this.start, startLoc = this.startLoc;
+ if (this.type === tt.parenL || this.type === tt.name)
+ this.potentialArrowAt = this.start;
+ let left = this.parseMaybeConditional(noIn, refShorthandDefaultPos);
+ if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc);
if (this.type.isAssign) {
- let node = this.startNodeAt(start)
- node.operator = this.value
- node.left = this.type === tt.eq ? this.toAssignable(left) : left
- refShorthandDefaultPos.start = 0 // reset because shorthand default was used correctly
- this.checkLVal(left)
+ let node = this.startNodeAt(startPos, startLoc);
+ node.operator = this.value;
+ node.left = this.type === tt.eq ? this.toAssignable(left) : left;
+ refShorthandDefaultPos.start = 0; // reset because shorthand default was used correctly
+ this.checkLVal(left);
if (left.parenthesizedExpression) {
- let errorMsg
+ let errorMsg;
if (left.type === "ObjectPattern") {
- errorMsg = "`({a}) = 0` use `({a} = 0)`"
+ errorMsg = "`({a}) = 0` use `({a} = 0)`";
} else if (left.type === "ArrayPattern") {
- errorMsg = "`([a]) = 0` use `([a] = 0)`"
+ errorMsg = "`([a]) = 0` use `([a] = 0)`";
}
if (errorMsg) {
- this.raise(left.start, `You're trying to assign to a parenthesized expression, eg. instead of ${errorMsg}`)
+ this.raise(left.start, `You're trying to assign to a parenthesized expression, eg. instead of ${errorMsg}`);
}
}
- this.next()
- node.right = this.parseMaybeAssign(noIn)
- return this.finishNode(node, "AssignmentExpression")
+ this.next();
+ node.right = this.parseMaybeAssign(noIn);
+ return this.finishNode(node, "AssignmentExpression");
} else if (failOnShorthandAssign && refShorthandDefaultPos.start) {
- this.unexpected(refShorthandDefaultPos.start)
+ this.unexpected(refShorthandDefaultPos.start);
}
- return left
-}
+ return left;
+};
// Parse a ternary conditional (`?:`) operator.
-pp.parseMaybeConditional = function(noIn, refShorthandDefaultPos) {
- let start = this.markPosition()
- let expr = this.parseExprOps(noIn, refShorthandDefaultPos)
- if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr
+pp.parseMaybeConditional = function (noIn, refShorthandDefaultPos) {
+ let startPos = this.start, startLoc = this.startLoc;
+ let expr = this.parseExprOps(noIn, refShorthandDefaultPos);
+ if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
if (this.eat(tt.question)) {
- let node = this.startNodeAt(start)
- node.test = expr
- node.consequent = this.parseMaybeAssign()
- this.expect(tt.colon)
- node.alternate = this.parseMaybeAssign(noIn)
- return this.finishNode(node, "ConditionalExpression")
+ let node = this.startNodeAt(startPos, startLoc);
+ node.test = expr;
+ node.consequent = this.parseMaybeAssign();
+ this.expect(tt.colon);
+ node.alternate = this.parseMaybeAssign(noIn);
+ return this.finishNode(node, "ConditionalExpression");
}
- return expr
-}
+ return expr;
+};
// Start the precedence parser.
-pp.parseExprOps = function(noIn, refShorthandDefaultPos) {
- let start = this.markPosition()
- let expr = this.parseMaybeUnary(refShorthandDefaultPos)
- if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr
- return this.parseExprOp(expr, start, -1, noIn)
-}
+pp.parseExprOps = function (noIn, refShorthandDefaultPos) {
+ let startPos = this.start, startLoc = this.startLoc;
+ let expr = this.parseMaybeUnary(refShorthandDefaultPos);
+ if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
+ return this.parseExprOp(expr, startPos, startLoc, -1, noIn);
+};
// Parse binary operators with the operator precedence parsing
// algorithm. `left` is the left-hand side of the operator.
@@ -164,141 +168,148 @@ pp.parseExprOps = function(noIn, refShorthandDefaultPos) {
// defer further parser to one of its callers when it encounters an
// operator that has a lower precedence than the set it is parsing.
-pp.parseExprOp = function(left, leftStart, minPrec, noIn) {
- let prec = this.type.binop
+pp.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, noIn) {
+ let prec = this.type.binop;
if (prec != null && (!noIn || this.type !== tt._in)) {
if (prec > minPrec) {
- let node = this.startNodeAt(leftStart)
- node.left = left
- node.operator = this.value
- let op = this.type
- this.next()
- let start = this.markPosition()
- node.right = this.parseExprOp(this.parseMaybeUnary(), start, op.rightAssociative ? (prec - 1) : prec, noIn)
- this.finishNode(node, (op === tt.logicalOR || op === tt.logicalAND) ? "LogicalExpression" : "BinaryExpression")
- return this.parseExprOp(node, leftStart, minPrec, noIn)
+ let node = this.startNodeAt(leftStartPos, leftStartLoc);
+ node.left = left;
+ node.operator = this.value;
+ let op = this.type;
+ this.next();
+ let startPos = this.start, startLoc = this.startLoc;
+ node.right = this.parseExprOp(this.parseMaybeUnary(), startPos, startLoc, op.rightAssociative ? prec - 1 : prec, noIn);
+ this.finishNode(node, (op === tt.logicalOR || op === tt.logicalAND) ? "LogicalExpression" : "BinaryExpression");
+ return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn);
}
}
- return left
-}
+ return left;
+};
// Parse unary operators, both prefix and postfix.
-pp.parseMaybeUnary = function(refShorthandDefaultPos) {
+pp.parseMaybeUnary = function (refShorthandDefaultPos) {
if (this.type.prefix) {
- let node = this.startNode(), update = this.type === tt.incDec
- node.operator = this.value
- node.prefix = true
- this.next()
- node.argument = this.parseMaybeUnary()
- if (refShorthandDefaultPos && refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start)
- if (update) this.checkLVal(node.argument)
+ let node = this.startNode(), update = this.type === tt.incDec;
+ node.operator = this.value;
+ node.prefix = true;
+ this.next();
+ node.argument = this.parseMaybeUnary();
+ if (refShorthandDefaultPos && refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start);
+ if (update) this.checkLVal(node.argument);
else if (this.strict && node.operator === "delete" &&
node.argument.type === "Identifier")
- this.raise(node.start, "Deleting local variable in strict mode")
- return this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression")
+ this.raise(node.start, "Deleting local variable in strict mode");
+ return this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression");
}
- let start = this.markPosition()
- let expr = this.parseExprSubscripts(refShorthandDefaultPos)
- if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr
+ let startPos = this.start, startLoc = this.startLoc;
+ let expr = this.parseExprSubscripts(refShorthandDefaultPos);
+ if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
while (this.type.postfix && !this.canInsertSemicolon()) {
- let node = this.startNodeAt(start)
- node.operator = this.value
- node.prefix = false
- node.argument = expr
- this.checkLVal(expr)
- this.next()
- expr = this.finishNode(node, "UpdateExpression")
+ let node = this.startNodeAt(startPos, startLoc);
+ node.operator = this.value;
+ node.prefix = false;
+ node.argument = expr;
+ this.checkLVal(expr);
+ this.next();
+ expr = this.finishNode(node, "UpdateExpression");
}
- return expr
-}
+ return expr;
+};
// Parse call, dot, and `[]`-subscript expressions.
-pp.parseExprSubscripts = function(refShorthandDefaultPos) {
- let start = this.markPosition()
- let expr = this.parseExprAtom(refShorthandDefaultPos)
- if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr
- return this.parseSubscripts(expr, start)
-}
+pp.parseExprSubscripts = function (refShorthandDefaultPos) {
+ let startPos = this.start, startLoc = this.startLoc;
+ let expr = this.parseExprAtom(refShorthandDefaultPos);
+ if (refShorthandDefaultPos && refShorthandDefaultPos.start) {
+ return expr;
+ } else {
+ return this.parseSubscripts(expr, startPos, startLoc);
+ }
+};
-pp.parseSubscripts = function(base, start, noCalls) {
- if (!noCalls && this.eat(tt.doubleColon)) {
- let node = this.startNodeAt(start)
- node.object = base
- node.callee = this.parseNoCallExpr()
- return this.parseSubscripts(this.finishNode(node, "BindExpression"), start, noCalls)
- } else if (this.eat(tt.dot)) {
- let node = this.startNodeAt(start)
- node.object = base
- node.property = this.parseIdent(true)
- node.computed = false
- return this.parseSubscripts(this.finishNode(node, "MemberExpression"), start, noCalls)
- } else if (this.eat(tt.bracketL)) {
- let node = this.startNodeAt(start)
- node.object = base
- node.property = this.parseExpression()
- node.computed = true
- this.expect(tt.bracketR)
- return this.parseSubscripts(this.finishNode(node, "MemberExpression"), start, noCalls)
- } else if (!noCalls && this.eat(tt.parenL)) {
- let node = this.startNodeAt(start)
- node.callee = base
- node.arguments = this.parseExprList(tt.parenR, this.options.features["es7.trailingFunctionCommas"])
- return this.parseSubscripts(this.finishNode(node, "CallExpression"), start, noCalls)
- } else if (this.type === tt.backQuote) {
- let node = this.startNodeAt(start)
- node.tag = base
- node.quasi = this.parseTemplate()
- return this.parseSubscripts(this.finishNode(node, "TaggedTemplateExpression"), start, noCalls)
- } return base
-}
+pp.parseSubscripts = function(base, startPos, startLoc, noCalls) {
+ for (;;) {
+ if (!noCalls && this.eat(tt.doubleColon)) {
+ let node = this.startNodeAt(startPos, startLoc);
+ node.object = base;
+ node.callee = this.parseNoCallExpr();
+ return this.parseSubscripts(this.finishNode(node, "BindExpression"), startPos, startLoc, noCalls);
+ } else if (this.eat(tt.dot)) {
+ let node = this.startNodeAt(startPos, startLoc);
+ node.object = base;
+ node.property = this.parseIdent(true);
+ node.computed = false;
+ base = this.finishNode(node, "MemberExpression");
+ } else if (this.eat(tt.bracketL)) {
+ let node = this.startNodeAt(startPos, startLoc);
+ node.object = base;
+ node.property = this.parseExpression();
+ node.computed = true;
+ this.expect(tt.bracketR);
+ base = this.finishNode(node, "MemberExpression");
+ } else if (!noCalls && this.eat(tt.parenL)) {
+ let node = this.startNodeAt(startPos, startLoc);
+ node.callee = base;
+ node.arguments = this.parseExprList(tt.parenR, this.options.features["es7.trailingFunctionCommas"]);
+ base = this.finishNode(node, "CallExpression");
+ } else if (this.type === tt.backQuote) {
+ let node = this.startNodeAt(startPos, startLoc);
+ node.tag = base;
+ node.quasi = this.parseTemplate();
+ base = this.finishNode(node, "TaggedTemplateExpression");
+ } else {
+ return base;
+ }
+ }
+};
// Parse a no-call expression (like argument of `new` or `::` operators).
-pp.parseNoCallExpr = function() {
- let start = this.markPosition()
- return this.parseSubscripts(this.parseExprAtom(), start, true)
-}
+pp.parseNoCallExpr = function () {
+ let startPos = this.start, startLoc = this.startLoc;
+ return this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true);
+};
// Parse an atomic expression — either a single token that is an
// expression, an expression started by a keyword like `function` or
// `new`, or an expression wrapped in punctuation like `()`, `[]`,
// or `{}`.
-pp.parseExprAtom = function(refShorthandDefaultPos) {
- let node, canBeArrow = this.potentialArrowAt == this.start
+pp.parseExprAtom = function (refShorthandDefaultPos) {
+ let node, canBeArrow = this.potentialArrowAt === this.start;
switch (this.type) {
case tt._super:
if (!this.inFunction)
- this.raise(this.start, "'super' outside of function or class")
+ this.raise(this.start, "'super' outside of function or class");
case tt._this:
- let type = this.type === tt._this ? "ThisExpression" : "Super"
- node = this.startNode()
- this.next()
- return this.finishNode(node, type)
+ let type = this.type === tt._this ? "ThisExpression" : "Super";
+ node = this.startNode();
+ this.next();
+ return this.finishNode(node, type);
case tt._yield:
- if (this.inGenerator) this.unexpected()
+ if (this.inGenerator) this.unexpected();
case tt._do:
if (this.options.features["es7.doExpressions"]) {
- let node = this.startNode()
- this.next()
- var oldInFunction = this.inFunction
- var oldLabels = this.labels
- this.labels = []
- this.inFunction = false
- node.body = this.parseBlock()
- this.inFunction = oldInFunction
- this.labels = oldLabels
- return this.finishNode(node, "DoExpression")
+ let node = this.startNode();
+ this.next();
+ var oldInFunction = this.inFunction;
+ var oldLabels = this.labels;
+ this.labels = [];
+ this.inFunction = false;
+ node.body = this.parseBlock();
+ this.inFunction = oldInFunction;
+ this.labels = oldLabels;
+ return this.finishNode(node, "DoExpression");
}
case tt.name:
- let start = this.markPosition()
- node = this.startNode()
- let id = this.parseIdent(this.type !== tt.name)
+ let startPos = this.start, startLoc = this.startLoc;
+ node = this.startNode();
+ let id = this.parseIdent(true);
//
if (this.options.features["es7.asyncFunctions"]) {
@@ -306,441 +317,453 @@ pp.parseExprAtom = function(refShorthandDefaultPos) {
if (id.name === "async" && !this.canInsertSemicolon()) {
// arrow functions
if (this.type === tt.parenL) {
- let expr = this.parseParenAndDistinguishExpression(start, true, true)
+ let expr = this.parseParenAndDistinguishExpression(startPos, startLoc, true, true);
if (expr && expr.type === "ArrowFunctionExpression") {
- return expr
+ return expr;
} else {
- node.callee = id
+ node.callee = id;
if (!expr) {
- node.arguments = []
+ node.arguments = [];
} else if (expr.type === "SequenceExpression") {
- node.arguments = expr.expressions
+ node.arguments = expr.expressions;
} else {
- node.arguments = [expr]
+ node.arguments = [expr];
}
- return this.parseSubscripts(this.finishNode(node, "CallExpression"), start)
+ return this.parseSubscripts(this.finishNode(node, "CallExpression"), startPos, startLoc);
}
} else if (this.type === tt.name) {
- id = this.parseIdent()
- this.expect(tt.arrow)
- return this.parseArrowExpression(node, [id], true)
+ id = this.parseIdent();
+ this.expect(tt.arrow);
+ return this.parseArrowExpression(node, [id], true);
}
// normal functions
if (this.type === tt._function && !this.canInsertSemicolon()) {
- this.next()
- return this.parseFunction(node, false, false, true)
+ this.next();
+ return this.parseFunction(node, false, false, true);
}
} else if (id.name === "await") {
- if (this.inAsync) return this.parseAwait(node)
+ if (this.inAsync) return this.parseAwait(node);
}
}
//
if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow))
- return this.parseArrowExpression(this.startNodeAt(start), [id])
- return id
+ return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id]);
+
+ return id;
case tt.regexp:
- let value = this.value
- node = this.parseLiteral(value.value)
- node.regex = {pattern: value.pattern, flags: value.flags}
- return node
+ let value = this.value;
+ node = this.parseLiteral(value.value);
+ node.regex = {pattern: value.pattern, flags: value.flags};
+ return node;
case tt.num: case tt.string:
- return this.parseLiteral(this.value)
+ return this.parseLiteral(this.value);
case tt._null: case tt._true: case tt._false:
- node = this.startNode()
- node.value = this.type === tt._null ? null : this.type === tt._true
- node.raw = this.type.keyword
- this.next()
- return this.finishNode(node, "Literal")
+ node = this.startNode();
+ node.value = this.type === tt._null ? null : this.type === tt._true;
+ node.raw = this.type.keyword;
+ this.next();
+ return this.finishNode(node, "Literal");
case tt.parenL:
- return this.parseParenAndDistinguishExpression(null, null, canBeArrow)
+ return this.parseParenAndDistinguishExpression(null, null, canBeArrow);
case tt.bracketL:
- node = this.startNode()
- this.next()
+ node = this.startNode();
+ this.next();
// check whether this is array comprehension or regular array
if ((this.options.ecmaVersion >= 7 || this.options.features["es7.comprehensions"]) && this.type === tt._for) {
- return this.parseComprehension(node, false)
+ return this.parseComprehension(node, false);
}
- node.elements = this.parseExprList(tt.bracketR, true, true, refShorthandDefaultPos)
- return this.finishNode(node, "ArrayExpression")
+ node.elements = this.parseExprList(tt.bracketR, true, true, refShorthandDefaultPos);
+ return this.finishNode(node, "ArrayExpression");
case tt.braceL:
- return this.parseObj(false, refShorthandDefaultPos)
+ return this.parseObj(false, refShorthandDefaultPos);
case tt._function:
- node = this.startNode()
- this.next()
- return this.parseFunction(node, false)
+ node = this.startNode();
+ this.next();
+ return this.parseFunction(node, false);
case tt.at:
- this.parseDecorators()
+ this.parseDecorators();
case tt._class:
- node = this.startNode()
- this.takeDecorators(node)
- return this.parseClass(node, false)
+ node = this.startNode();
+ this.takeDecorators(node);
+ return this.parseClass(node, false);
case tt._new:
- return this.parseNew()
+ return this.parseNew();
case tt.backQuote:
- return this.parseTemplate()
+ return this.parseTemplate();
case tt.doubleColon:
- node = this.startNode()
- this.next()
- node.object = null
- let callee = node.callee = this.parseNoCallExpr()
- if (callee.type !== "MemberExpression")
- this.raise(callee.start, "Binding should be performed on object property.")
- return this.finishNode(node, "BindExpression")
-
- default:
- this.unexpected()
- }
-}
-
-pp.parseLiteral = function(value) {
- let node = this.startNode()
- node.value = value
- node.raw = this.input.slice(this.start, this.end)
- this.next()
- return this.finishNode(node, "Literal")
-}
-
-pp.parseParenExpression = function() {
- this.expect(tt.parenL)
- let val = this.parseExpression()
- this.expect(tt.parenR)
- return val
-}
-
-pp.parseParenAndDistinguishExpression = function(start, isAsync, canBeArrow) {
- start = start || this.markPosition()
- let val
- if (this.options.ecmaVersion >= 6) {
- this.next()
-
- if ((this.options.features["es7.comprehensions"] || this.options.ecmaVersion >= 7) && this.type === tt._for) {
- return this.parseComprehension(this.startNodeAt(start), true)
+ node = this.startNode();
+ this.next();
+ node.object = null;
+ let callee = node.callee = this.parseNoCallExpr();
+ if (callee.type === "MemberExpression") {
+ return this.finishNode(node, "BindExpression");
+ } else {
+ this.raise(callee.start, "Binding should be performed on object property.");
}
- let innerStart = this.markPosition(), exprList = [], first = true
- let refShorthandDefaultPos = {start: 0}, spreadStart, innerParenStart, optionalCommaStart
+ default:
+ this.unexpected();
+ }
+};
+
+pp.parseLiteral = function (value) {
+ let node = this.startNode();
+ node.value = value;
+ node.raw = this.input.slice(this.start, this.end);
+ this.next();
+ return this.finishNode(node, "Literal");
+};
+
+pp.parseParenExpression = function () {
+ this.expect(tt.parenL);
+ let val = this.parseExpression();
+ this.expect(tt.parenR);
+ return val;
+};
+
+pp.parseParenAndDistinguishExpression = function (startPos, startLoc, canBeArrow, isAsync) {
+ startPos = startPos || this.start;
+ startLoc = startLoc || this.startLoc;
+ let val;
+ if (this.options.ecmaVersion >= 6) {
+ this.next();
+
+ if ((this.options.features["es7.comprehensions"] || this.options.ecmaVersion >= 7) && this.type === tt._for) {
+ return this.parseComprehension(this.startNodeAt(startPos, startLoc), true);
+ }
+
+ let innerStartPos = this.start, innerStartLoc = this.startLoc;
+ let exprList = [], first = true;
+ let refShorthandDefaultPos = {start: 0}, spreadStart, innerParenStart, optionalCommaStart;
while (this.type !== tt.parenR) {
if (first) {
first = false;
} else {
- this.expect(tt.comma)
+ this.expect(tt.comma);
if (this.type === tt.parenR && this.options.features["es7.trailingFunctionCommas"]) {
- optionalCommaStart = this.start
- break
+ optionalCommaStart = this.start;
+ break;
}
}
if (this.type === tt.ellipsis) {
- let spreadNodeStart = this.markPosition()
- spreadStart = this.start
- exprList.push(this.parseParenItem(this.parseRest(), spreadNodeStart))
- break
+ let spreadNodeStartPos = this.start, spreadNodeStartLoc = this.startLoc;
+ spreadStart = this.start;
+ exprList.push(this.parseParenItem(this.parseRest(), spreadNodeStartLoc, spreadNodeStartPos));
+ break;
} else {
if (this.type === tt.parenL && !innerParenStart) {
- innerParenStart = this.start
+ innerParenStart = this.start;
}
- exprList.push(this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem))
+ exprList.push(this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem));
}
}
- let innerEnd = this.markPosition()
- this.expect(tt.parenR)
+ let innerEndPos = this.start, innerEndLoc = this.startLoc;
+ this.expect(tt.parenR);
if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) {
- if (innerParenStart) this.unexpected(innerParenStart)
- return this.parseParenArrowList(start, exprList, isAsync)
+ if (innerParenStart) this.unexpected(innerParenStart);
+ return this.parseParenArrowList(startPos, startLoc, exprList, isAsync);
}
if (!exprList.length) {
if (isAsync) {
- return
+ return;
} else {
- this.unexpected(this.lastTokStart)
+ this.unexpected(this.lastTokStart);
}
}
- if (optionalCommaStart) this.unexpected(optionalCommaStart)
- if (spreadStart) this.unexpected(spreadStart)
- if (refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start)
+ if (optionalCommaStart) this.unexpected(optionalCommaStart);
+ if (spreadStart) this.unexpected(spreadStart);
+ if (refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start);
if (exprList.length > 1) {
- val = this.startNodeAt(innerStart)
- val.expressions = exprList
- this.finishNodeAt(val, "SequenceExpression", innerEnd)
+ val = this.startNodeAt(innerStartPos, innerStartLoc);
+ val.expressions = exprList;
+ this.finishNodeAt(val, "SequenceExpression", innerEndPos, innerEndLoc);
} else {
- val = exprList[0]
+ val = exprList[0];
}
} else {
- val = this.parseParenExpression()
+ val = this.parseParenExpression();
}
- if (this.options.preserveParens) {
- let par = this.startNodeAt(start)
- par.expression = val
- return this.finishNode(par, "ParenthesizedExpression")
- } else {
- val.parenthesizedExpression = true
- return val
- }
-}
+ val.parenthesizedExpression = true;
+ return val;
+};
-pp.parseParenArrowList = function(start, exprList, isAsync) {
- return this.parseArrowExpression(this.startNodeAt(start), exprList, isAsync)
-}
+pp.parseParenArrowList = function (startPos, startLoc, exprList, isAsync) {
+ return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList, isAsync);
+};
-pp.parseParenItem = function(node, start) {
- return node
-}
+pp.parseParenItem = function (node) {
+ return node;
+};
// New's precedence is slightly tricky. It must allow its argument
// to be a `[]` or dot subscript expression, but not a call — at
// least, not without wrapping it in parentheses. Thus, it uses the
-const empty = []
+pp.parseNew = function () {
+ let node = this.startNode();
+ let meta = this.parseIdent(true);
-pp.parseNew = function() {
- let node = this.startNode()
- let meta = this.parseIdent(true)
if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) {
- node.meta = meta
- node.property = this.parseIdent(true)
- if (node.property.name !== "target")
- this.raise(node.property.start, "The only valid meta property for new is new.target")
- return this.finishNode(node, "MetaProperty")
+ node.meta = meta;
+ node.property = this.parseIdent(true);
+
+ if (node.property.name !== "target") {
+ this.raise(node.property.start, "The only valid meta property for new is new.target");
+ }
+
+ return this.finishNode(node, "MetaProperty");
}
- node.callee = this.parseNoCallExpr()
- if (this.eat(tt.parenL)) node.arguments = this.parseExprList(
- tt.parenR,
- this.options.features["es7.trailingFunctionCommas"]
- )
- else node.arguments = empty
- return this.finishNode(node, "NewExpression")
-}
+
+ node.callee = this.parseNoCallExpr();
+
+ if (this.eat(tt.parenL)) {
+ node.arguments = this.parseExprList(tt.parenR, this.options.features["es7.trailingFunctionCommas"]);
+ } else {
+ node.arguments = [];
+ }
+
+ return this.finishNode(node, "NewExpression");
+};
// Parse template expression.
-pp.parseTemplateElement = function() {
- let elem = this.startNode()
+pp.parseTemplateElement = function () {
+ let elem = this.startNode();
elem.value = {
- raw: this.input.slice(this.start, this.end).replace(/\r\n?/g, '\n'),
+ raw: this.input.slice(this.start, this.end).replace(/\r\n?/g, "\n"),
cooked: this.value
- }
- this.next()
- elem.tail = this.type === tt.backQuote
- return this.finishNode(elem, "TemplateElement")
-}
+ };
+ this.next();
+ elem.tail = this.type === tt.backQuote;
+ return this.finishNode(elem, "TemplateElement");
+};
-pp.parseTemplate = function() {
- let node = this.startNode()
- this.next()
- node.expressions = []
- let curElt = this.parseTemplateElement()
- node.quasis = [curElt]
+pp.parseTemplate = function () {
+ let node = this.startNode();
+ this.next();
+ node.expressions = [];
+ let curElt = this.parseTemplateElement();
+ node.quasis = [curElt];
while (!curElt.tail) {
- this.expect(tt.dollarBraceL)
- node.expressions.push(this.parseExpression())
- this.expect(tt.braceR)
- node.quasis.push(curElt = this.parseTemplateElement())
+ this.expect(tt.dollarBraceL);
+ node.expressions.push(this.parseExpression());
+ this.expect(tt.braceR);
+ node.quasis.push(curElt = this.parseTemplateElement());
}
- this.next()
- return this.finishNode(node, "TemplateLiteral")
-}
+ this.next();
+ return this.finishNode(node, "TemplateLiteral");
+};
// Parse an object literal or binding pattern.
-pp.parseObj = function(isPattern, refShorthandDefaultPos) {
- let node = this.startNode(), first = true, propHash = {}
- node.properties = []
- let decorators = []
- this.next()
+pp.parseObj = function (isPattern, refShorthandDefaultPos) {
+ let node = this.startNode(), first = true, propHash = Object.create(null);
+ node.properties = [];
+ let decorators = [];
+ this.next();
while (!this.eat(tt.braceR)) {
- if (!first) {
- this.expect(tt.comma)
- if (this.afterTrailingComma(tt.braceR)) break
- } else first = false
- while (this.type === tt.at) {
- decorators.push(this.parseDecorator())
+ if (first) {
+ first = false;
+ } else {
+ this.expect(tt.comma);
+ if (this.afterTrailingComma(tt.braceR)) break;
}
- let prop = this.startNode(), isGenerator = false, isAsync = false, start
+
+ while (this.type === tt.at) {
+ decorators.push(this.parseDecorator());
+ }
+
+ let prop = this.startNode(), isGenerator = false, isAsync = false, startPos, startLoc;
if (decorators.length) {
- prop.decorators = decorators
- decorators = []
+ prop.decorators = decorators;
+ decorators = [];
}
if (this.options.features["es7.objectRestSpread"] && this.type === tt.ellipsis) {
- prop = this.parseSpread()
- prop.type = "SpreadProperty"
- node.properties.push(prop)
- continue
+ prop = this.parseSpread();
+ prop.type = "SpreadProperty";
+ node.properties.push(prop);
+ continue;
}
if (this.options.ecmaVersion >= 6) {
- prop.method = false
- prop.shorthand = false
- if (isPattern || refShorthandDefaultPos)
- start = this.markPosition()
+ prop.method = false;
+ prop.shorthand = false;
+ if (isPattern || refShorthandDefaultPos) {
+ startPos = this.start;
+ startLoc = this.startLoc;
+ }
if (!isPattern)
- isGenerator = this.eat(tt.star)
+ isGenerator = this.eat(tt.star);
}
if (this.options.features["es7.asyncFunctions"] && this.isContextual("async")) {
- if (isGenerator || isPattern) this.unexpected()
- var asyncId = this.parseIdent()
+ if (isGenerator || isPattern) this.unexpected();
+ var asyncId = this.parseIdent();
if (this.type === tt.colon || this.type === tt.parenL) {
- prop.key = asyncId
+ prop.key = asyncId;
} else {
- isAsync = true
- this.parsePropertyName(prop)
+ isAsync = true;
+ this.parsePropertyName(prop);
}
} else {
- this.parsePropertyName(prop)
+ this.parsePropertyName(prop);
}
- this.parseObjPropValue(prop, start, isGenerator, isAsync, isPattern, refShorthandDefaultPos);
- this.checkPropClash(prop, propHash)
- node.properties.push(this.finishNode(prop, "Property"))
+ this.parseObjPropValue(prop, startPos, startLoc, isGenerator, isAsync, isPattern, refShorthandDefaultPos);
+ this.checkPropClash(prop, propHash);
+ node.properties.push(this.finishNode(prop, "Property"));
}
if (decorators.length) {
this.raise(this.start, "You have trailing decorators with no property");
}
- return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression")
-}
+ return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression");
+};
-pp.parseObjPropValue = function (prop, start, isGenerator, isAsync, isPattern, refShorthandDefaultPos) {
+pp.parseObjPropValue = function (prop, startPos, startLoc, isGenerator, isAsync, isPattern, refShorthandDefaultPos) {
if (this.eat(tt.colon)) {
- prop.value = isPattern ? this.parseMaybeDefault() : this.parseMaybeAssign(false, refShorthandDefaultPos)
- prop.kind = "init"
+ prop.value = isPattern ? this.parseMaybeDefault(this.start, this.startLoc) : this.parseMaybeAssign(false, refShorthandDefaultPos);
+ prop.kind = "init";
} else if (this.options.ecmaVersion >= 6 && this.type === tt.parenL) {
- if (isPattern) this.unexpected()
- prop.kind = "init"
- prop.method = true
- prop.value = this.parseMethod(isGenerator, isAsync)
+ if (isPattern) this.unexpected();
+ prop.kind = "init";
+ prop.method = true;
+ prop.value = this.parseMethod(isGenerator, isAsync);
} else if (this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" &&
(prop.key.name === "get" || prop.key.name === "set") &&
- (this.type != tt.comma && this.type != tt.braceR)) {
- if (isGenerator || isAsync || isPattern) this.unexpected()
- prop.kind = prop.key.name
- this.parsePropertyName(prop)
- prop.value = this.parseMethod(false)
- let paramCount = prop.kind === "get" ? 0 : 1
+ (this.type !== tt.comma && this.type !== tt.braceR)) {
+ if (isGenerator || isAsync || isPattern) this.unexpected();
+ prop.kind = prop.key.name;
+ this.parsePropertyName(prop);
+ prop.value = this.parseMethod(false);
+ let paramCount = prop.kind === "get" ? 0 : 1;
if (prop.value.params.length !== paramCount) {
- let start = prop.value.start
+ let start = prop.value.start;
if (prop.kind === "get")
this.raise(start, "getter should have no params");
else
- this.raise(start, "setter should have exactly one param")
+ this.raise(start, "setter should have exactly one param");
}
} else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") {
- prop.kind = "init"
+ prop.kind = "init";
if (isPattern) {
if (this.isKeyword(prop.key.name) ||
(this.strict && (reservedWords.strictBind(prop.key.name) || reservedWords.strict(prop.key.name))) ||
(!this.options.allowReserved && this.isReservedWord(prop.key.name)))
- this.raise(prop.key.start, "Binding " + prop.key.name)
- prop.value = this.parseMaybeDefault(start, prop.key)
+ this.raise(prop.key.start, "Binding " + prop.key.name);
+ prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key);
} else if (this.type === tt.eq && refShorthandDefaultPos) {
if (!refShorthandDefaultPos.start)
- refShorthandDefaultPos.start = this.start
- prop.value = this.parseMaybeDefault(start, prop.key)
+ refShorthandDefaultPos.start = this.start;
+ prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key);
} else {
- prop.value = prop.key
+ prop.value = prop.key;
}
- prop.shorthand = true
- } else this.unexpected()
-}
+ prop.shorthand = true;
+ } else {
+ this.unexpected();
+ }
+};
-pp.parsePropertyName = function(prop) {
+pp.parsePropertyName = function (prop) {
if (this.options.ecmaVersion >= 6) {
if (this.eat(tt.bracketL)) {
- prop.computed = true
- prop.key = this.parseMaybeAssign()
- this.expect(tt.bracketR)
- return prop.key
+ prop.computed = true;
+ prop.key = this.parseMaybeAssign();
+ this.expect(tt.bracketR);
+ return prop.key;
} else {
- prop.computed = false
+ prop.computed = false;
}
}
- return prop.key = (this.type === tt.num || this.type === tt.string) ? this.parseExprAtom() : this.parseIdent(true)
-}
+ return prop.key = (this.type === tt.num || this.type === tt.string) ? this.parseExprAtom() : this.parseIdent(true);
+};
// Initialize empty function node.
-pp.initFunction = function(node, isAsync) {
- node.id = null
+pp.initFunction = function (node, isAsync) {
+ node.id = null;
if (this.options.ecmaVersion >= 6) {
- node.generator = false
- node.expression = false
+ node.generator = false;
+ node.expression = false;
}
if (this.options.features["es7.asyncFunctions"]) {
- node.async = !!isAsync
+ node.async = !!isAsync;
}
-}
+};
// Parse object or class method.
-pp.parseMethod = function(isGenerator, isAsync) {
- let node = this.startNode()
- this.initFunction(node, isAsync)
- this.expect(tt.parenL)
- node.params = this.parseBindingList(tt.parenR, false, this.options.features["es7.trailingFunctionCommas"])
+pp.parseMethod = function (isGenerator, isAsync) {
+ let node = this.startNode();
+ this.initFunction(node, isAsync);
+ this.expect(tt.parenL);
+ node.params = this.parseBindingList(tt.parenR, false, this.options.features["es7.trailingFunctionCommas"]);
if (this.options.ecmaVersion >= 6) {
- node.generator = isGenerator
+ node.generator = isGenerator;
}
- this.parseFunctionBody(node)
- return this.finishNode(node, "FunctionExpression")
-}
+ this.parseFunctionBody(node);
+ return this.finishNode(node, "FunctionExpression");
+};
// Parse arrow function expression with given parameters.
-pp.parseArrowExpression = function(node, params, isAsync) {
- this.initFunction(node, isAsync)
- node.params = this.toAssignableList(params, true)
- this.parseFunctionBody(node, true)
- return this.finishNode(node, "ArrowFunctionExpression")
-}
+pp.parseArrowExpression = function (node, params, isAsync) {
+ this.initFunction(node, isAsync);
+ node.params = this.toAssignableList(params, true);
+ this.parseFunctionBody(node, true);
+ return this.finishNode(node, "ArrowFunctionExpression");
+};
// Parse function body and check parameters.
-pp.parseFunctionBody = function(node, allowExpression) {
- let isExpression = allowExpression && this.type !== tt.braceL
+pp.parseFunctionBody = function (node, allowExpression) {
+ let isExpression = allowExpression && this.type !== tt.braceL;
- var oldInAsync = this.inAsync
- this.inAsync = node.async
+ var oldInAsync = this.inAsync;
+ this.inAsync = node.async;
if (isExpression) {
- node.body = this.parseMaybeAssign()
- node.expression = true
+ node.body = this.parseMaybeAssign();
+ node.expression = true;
} else {
// Start a new scope with regard to labels and the `inFunction`
// flag (restore them to their old value afterwards).
- let oldInFunc = this.inFunction, oldInGen = this.inGenerator, oldLabels = this.labels
- this.inFunction = true; this.inGenerator = node.generator; this.labels = []
- node.body = this.parseBlock(true)
- node.expression = false
- this.inFunction = oldInFunc; this.inGenerator = oldInGen; this.labels = oldLabels
+ let oldInFunc = this.inFunction, oldInGen = this.inGenerator, oldLabels = this.labels;
+ this.inFunction = true; this.inGenerator = node.generator; this.labels = [];
+ node.body = this.parseBlock(true);
+ node.expression = false;
+ this.inFunction = oldInFunc; this.inGenerator = oldInGen; this.labels = oldLabels;
}
- this.inAsync = oldInAsync
+ this.inAsync = oldInAsync;
// If this is a strict mode function, verify that argument names
// are not repeated, and it does not try to bind the words `eval`
// or `arguments`.
if (this.strict || !isExpression && node.body.body.length && this.isUseStrict(node.body.body[0])) {
- let nameHash = {}, oldStrict = this.strict
- this.strict = true
+ let nameHash = Object.create(null), oldStrict = this.strict;
+ this.strict = true;
if (node.id)
- this.checkLVal(node.id, true)
+ this.checkLVal(node.id, true);
for (let i = 0; i < node.params.length; i++)
- this.checkLVal(node.params[i], true, nameHash)
- this.strict = oldStrict
+ this.checkLVal(node.params[i], true, nameHash);
+ this.strict = oldStrict;
}
-}
+};
// Parses a comma-separated list of expressions, and returns them as
// an array. `close` is the token type that ends the list, and
@@ -748,94 +771,97 @@ pp.parseFunctionBody = function(node, allowExpression) {
// nothing in between them to be parsed as `null` (which is needed
// for array literals).
-pp.parseExprList = function(close, allowTrailingComma, allowEmpty, refShorthandDefaultPos) {
- let elts = [], first = true
+pp.parseExprList = function (close, allowTrailingComma, allowEmpty, refShorthandDefaultPos) {
+ let elts = [], first = true;
while (!this.eat(close)) {
- if (!first) {
- this.expect(tt.comma)
- if (allowTrailingComma && this.afterTrailingComma(close)) break
- } else first = false
-
- if (allowEmpty && this.type === tt.comma) {
- elts.push(null)
+ if (first) {
+ first = false;
} else {
- if (this.type === tt.ellipsis)
- elts.push(this.parseSpread(refShorthandDefaultPos))
- else
- elts.push(this.parseMaybeAssign(false, refShorthandDefaultPos))
+ this.expect(tt.comma);
+ if (allowTrailingComma && this.afterTrailingComma(close)) break;
}
+
+ let elt;
+ if (allowEmpty && this.type === tt.comma) {
+ elt = null;
+ } else if (this.type === tt.ellipsis) {
+ elt = this.parseSpread(refShorthandDefaultPos);
+ } else {
+ elt = this.parseMaybeAssign(false, refShorthandDefaultPos);
+ }
+ elts.push(elt);
}
- return elts
-}
+ return elts;
+};
// Parse the next token as an identifier. If `liberal` is true (used
// when parsing properties), it will also convert keywords into
// identifiers.
-pp.parseIdent = function(liberal) {
- let node = this.startNode()
- if (liberal && this.options.allowReserved == "never") liberal = false
+pp.parseIdent = function (liberal) {
+ let node = this.startNode();
+ if (liberal && this.options.allowReserved === "never") liberal = false;
if (this.type === tt.name) {
if (!liberal &&
((!this.options.allowReserved && this.isReservedWord(this.value)) ||
(this.strict && reservedWords.strict(this.value)) &&
(this.options.ecmaVersion >= 6 ||
- this.input.slice(this.start, this.end).indexOf("\\") == -1)))
- this.raise(this.start, "The keyword '" + this.value + "' is reserved")
- node.name = this.value
+ this.input.slice(this.start, this.end).indexOf("\\") === -1)))
+ this.raise(this.start, "The keyword '" + this.value + "' is reserved");
+ node.name = this.value;
} else if (liberal && this.type.keyword) {
- node.name = this.type.keyword
+ node.name = this.type.keyword;
} else {
- this.unexpected()
+ this.unexpected();
}
- this.next()
- return this.finishNode(node, "Identifier")
-}
+ this.next();
+ return this.finishNode(node, "Identifier");
+};
// Parses await expression inside async function.
pp.parseAwait = function (node) {
if (this.eat(tt.semi) || this.canInsertSemicolon()) {
- this.unexpected()
+ this.unexpected();
}
- node.all = this.eat(tt.star)
- node.argument = this.parseMaybeUnary()
- return this.finishNode(node, "AwaitExpression")
+ node.all = this.eat(tt.star);
+ node.argument = this.parseMaybeUnary();
+ return this.finishNode(node, "AwaitExpression");
};
// Parses yield expression inside generator.
-pp.parseYield = function() {
- let node = this.startNode()
- this.next()
- if (this.type == tt.semi || this.canInsertSemicolon() || (this.type != tt.star && !this.type.startsExpr)) {
- node.delegate = false
- node.argument = null
+pp.parseYield = function () {
+ let node = this.startNode();
+ this.next();
+ if (this.type === tt.semi || this.canInsertSemicolon() || (this.type !== tt.star && !this.type.startsExpr)) {
+ node.delegate = false;
+ node.argument = null;
} else {
- node.delegate = this.eat(tt.star)
- node.argument = this.parseMaybeAssign()
+ node.delegate = this.eat(tt.star);
+ node.argument = this.parseMaybeAssign();
}
- return this.finishNode(node, "YieldExpression")
-}
+ return this.finishNode(node, "YieldExpression");
+};
// Parses array and generator comprehensions.
-pp.parseComprehension = function(node, isGenerator) {
- node.blocks = []
+pp.parseComprehension = function (node, isGenerator) {
+ node.blocks = [];
while (this.type === tt._for) {
- let block = this.startNode()
- this.next()
- this.expect(tt.parenL)
- block.left = this.parseBindingAtom()
- this.checkLVal(block.left, true)
- this.expectContextual("of")
- block.right = this.parseExpression()
- this.expect(tt.parenR)
- node.blocks.push(this.finishNode(block, "ComprehensionBlock"))
+ let block = this.startNode();
+ this.next();
+ this.expect(tt.parenL);
+ block.left = this.parseBindingAtom();
+ this.checkLVal(block.left, true);
+ this.expectContextual("of");
+ block.right = this.parseExpression();
+ this.expect(tt.parenR);
+ node.blocks.push(this.finishNode(block, "ComprehensionBlock"));
}
- node.filter = this.eat(tt._if) ? this.parseParenExpression() : null
- node.body = this.parseExpression()
- this.expect(isGenerator ? tt.parenR : tt.bracketR)
- node.generator = isGenerator
- return this.finishNode(node, "ComprehensionExpression")
-}
+ node.filter = this.eat(tt._if) ? this.parseParenExpression() : null;
+ node.body = this.parseExpression();
+ this.expect(isGenerator ? tt.parenR : tt.bracketR);
+ node.generator = isGenerator;
+ return this.finishNode(node, "ComprehensionExpression");
+};
diff --git a/src/identifier.js b/src/identifier.js
index 11713b05d6..a656c92320 100755
--- a/src/identifier.js
+++ b/src/identifier.js
@@ -8,10 +8,10 @@
// It starts by sorting the words by length.
function makePredicate(words) {
- words = words.split(" ")
- return function(str) {
- return words.indexOf(str) >= 0
- }
+ words = words.split(" ");
+ return function (str) {
+ return words.indexOf(str) >= 0;
+ };
}
// Reserved word lists for various dialects of the language
@@ -22,16 +22,16 @@ export const reservedWords = {
6: makePredicate("enum await"),
strict: makePredicate("implements interface let package private protected public static yield"),
strictBind: makePredicate("eval arguments")
-}
+};
// And the keywords
-var ecma5AndLessKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this"
+var ecma5AndLessKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this";
export const keywords = {
5: makePredicate(ecma5AndLessKeywords),
6: makePredicate(ecma5AndLessKeywords + " let const class extends export import yield super")
-}
+};
// ## Character categories
@@ -41,57 +41,75 @@ export const keywords = {
// code point above 128.
// Generated by `tools/generate-identifier-regex.js`.
-let nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0-\u08b2\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua7ad\ua7b0\ua7b1\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab5f\uab64\uab65\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc"
-let nonASCIIidentifierChars = "\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08e4-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c03\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d01-\u0d03\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19b0-\u19c0\u19c8\u19c9\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2-\u1cf4\u1cf8\u1cf9\u1dc0-\u1df5\u1dfc-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f1\ua900-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2d\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f"
+let nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0-\u08b2\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua7ad\ua7b0\ua7b1\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab5f\uab64\uab65\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc";
+let nonASCIIidentifierChars = "\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08e4-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c03\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d01-\u0d03\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19b0-\u19c0\u19c8\u19c9\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2-\u1cf4\u1cf8\u1cf9\u1dc0-\u1df5\u1dfc-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f1\ua900-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2d\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f";
-const nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]")
-const nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]")
+const nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
+const nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
-nonASCIIidentifierStartChars = nonASCIIidentifierChars = null
+nonASCIIidentifierStartChars = nonASCIIidentifierChars = null;
// These are a run-length and offset encoded representation of the
// >0xffff code points that are a valid part of identifiers. The
// offset starts at 0x10000, and each pair of numbers represents an
// offset to the next range, and then a size of the range. They were
// generated by tools/generate-identifier-regex.js
-var astralIdentifierStartCodes = [0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,17,26,6,37,11,29,3,35,5,7,2,4,43,157,99,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,98,21,11,25,71,55,7,1,65,0,16,3,2,2,2,26,45,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,955,52,76,44,33,24,27,35,42,34,4,0,13,47,15,3,22,0,38,17,2,24,133,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,32,4,287,47,21,1,2,0,185,46,82,47,21,0,60,42,502,63,32,0,449,56,1288,920,104,110,2962,1070,13266,568,8,30,114,29,19,47,17,3,32,20,6,18,881,68,12,0,67,12,16481,1,3071,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,4149,196,1340,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42710,42,4148,12,221,16355,541]
-var astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,1306,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,52,0,13,2,49,13,16,9,83,11,168,11,6,9,8,2,57,0,2,6,3,1,3,2,10,0,11,1,3,6,4,4,316,19,13,9,214,6,3,8,112,16,16,9,82,12,9,9,535,9,20855,9,135,4,60,6,26,9,1016,45,17,3,19723,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,4305,6,792618,239]
+var astralIdentifierStartCodes = [
+ 0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 17, 26, 6, 37, 11, 29, 3, 35, 5,
+ 7, 2, 4, 43, 157, 99, 39, 9, 51, 157, 310, 10, 21, 11, 7, 153, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30,
+ 98, 21, 11, 25, 71, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 26, 45, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14,
+ 17, 111, 72, 955, 52, 76, 44, 33, 24, 27, 35, 42, 34, 4, 0, 13, 47, 15, 3, 22, 0, 38, 17, 2, 24, 133, 46, 39, 7,
+ 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 32, 4, 287, 47, 21, 1, 2, 0, 185, 46, 82, 47, 21, 0, 60, 42, 502, 63, 32, 0,
+ 449, 56, 1288, 920, 104, 110, 2962, 1070, 13266, 568, 8, 30, 114, 29, 19, 47, 17, 3, 32, 20, 6, 18, 881, 68, 12,
+ 0, 67, 12, 16481, 1, 3071, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2,
+ 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2,
+ 24, 2, 30, 2, 24, 2, 7, 4149, 196, 1340, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2,
+ 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2,
+ 4, 2, 16, 4421, 42710, 42, 4148, 12, 221, 16355, 541
+];
+var astralIdentifierCodes = [
+ 509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 1306, 2, 54, 14, 32, 9, 16, 3, 46, 10,
+ 54, 9, 7, 2, 37, 13, 2, 9, 52, 0, 13, 2, 49, 13, 16, 9, 83, 11, 168, 11, 6, 9, 8, 2, 57, 0, 2, 6, 3, 1, 3, 2, 10,
+ 0, 11, 1, 3, 6, 4, 4, 316, 19, 13, 9, 214, 6, 3, 8, 112, 16, 16, 9, 82, 12, 9, 9, 535, 9, 20855, 9, 135, 4, 60, 6,
+ 26, 9, 1016, 45, 17, 3, 19723, 1, 5319, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 4305, 6, 792618, 239
+];
// This has a complexity linear to the value of the code. The
// assumption is that looking up astral identifier characters is
// rare.
function isInAstralSet(code, set) {
- let pos = 0x10000
+ let pos = 0x10000;
for (let i = 0; i < set.length; i += 2) {
- pos += set[i]
- if (pos > code) return false
- pos += set[i + 1]
- if (pos >= code) return true
+ pos += set[i];
+ if (pos > code) return false;
+
+ pos += set[i + 1];
+ if (pos >= code) return true;
}
}
// Test whether a given character code starts an identifier.
export function isIdentifierStart(code, astral) {
- if (code < 65) return code === 36
- if (code < 91) return true
- if (code < 97) return code === 95
- if (code < 123) return true
- if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code))
- if (astral === false) return false
- return isInAstralSet(code, astralIdentifierStartCodes)
+ if (code < 65) return code === 36;
+ if (code < 91) return true;
+ if (code < 97) return code === 95;
+ if (code < 123) return true;
+ if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code));
+ if (astral === false) return false;
+ return isInAstralSet(code, astralIdentifierStartCodes);
}
// Test whether a given character is part of an identifier.
export function isIdentifierChar(code, astral) {
- if (code < 48) return code === 36
- if (code < 58) return true
- if (code < 65) return false
- if (code < 91) return true
- if (code < 97) return code === 95
- if (code < 123) return true
- if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code))
- if (astral === false) return false
- return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes)
+ if (code < 48) return code === 36;
+ if (code < 58) return true;
+ if (code < 65) return false;
+ if (code < 91) return true;
+ if (code < 97) return code === 95;
+ if (code < 123) return true;
+ if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code));
+ if (astral === false) return false;
+ return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes);
}
diff --git a/src/index.js b/src/index.js
index 4aa982fa19..6b0541ea41 100755
--- a/src/index.js
+++ b/src/index.js
@@ -19,26 +19,31 @@
// [dammit]: acorn_loose.js
// [walk]: util/walk.js
-import {Parser} from "./state"
-import {getOptions} from "./options"
-import "./parseutil"
-import "./statement"
-import "./lval"
-import "./expression"
-import "./lookahead"
+import {Parser, plugins} from "./state";
+import {getOptions} from "./options";
+import "./parseutil";
+import "./statement";
+import "./lval";
+import "./expression";
+import "./lookahead";
+import "./tokentype";
+import "./tokencontext";
-export {Parser, plugins} from "./state"
-export {defaultOptions} from "./options"
-export {SourceLocation} from "./location"
-export {getLineInfo} from "./location"
-export {Node} from "./node"
-export {TokenType, types as tokTypes} from "./tokentype"
-export {TokContext, types as tokContexts} from "./tokencontext"
-export {isIdentifierChar, isIdentifierStart} from "./identifier"
-export {Token} from "./tokenize"
-export {isNewLine, lineBreak, lineBreakG} from "./whitespace"
+export {Parser, plugins} from "./state";
+export {defaultOptions} from "./options";
+export {SourceLocation} from "./location";
+export {getLineInfo} from "./location";
+export {Node} from "./node";
+export {TokenType, types as tokTypes} from "./tokentype";
+export {TokContext, types as tokContexts} from "./tokencontext";
+export {isIdentifierChar, isIdentifierStart} from "./identifier";
+export {Token} from "./tokenize";
+export {isNewLine, lineBreak, lineBreakG} from "./whitespace";
-export const version = "1.0.0"
+import flowPlugin from "./plugins/flow";
+import jsxPlugin from "./plugins/jsx";
+plugins.flow = flowPlugin;
+plugins.jsx = jsxPlugin;
// The main exported interface (under `self.acorn` when in the
// browser) is a `parse` function that takes a code string and
@@ -48,32 +53,5 @@ export const version = "1.0.0"
// [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API
export function parse(input, options) {
- let p = parser(options, input)
- let startPos = p.options.locations ? [p.pos, p.curPosition()] : p.pos
- p.nextToken()
- return p.parseTopLevel(p.options.program || p.startNodeAt(startPos))
-}
-
-// This function tries to parse a single expression at a given
-// offset in a string. Useful for parsing mixed-language formats
-// that embed JavaScript expressions.
-
-export function parseExpressionAt(input, pos, options) {
- let p = parser(options, input, pos)
- p.nextToken()
- return p.parseExpression()
-}
-
-// Acorn is organized as a tokenizer and a recursive-descent parser.
-// The `tokenize` export provides an interface to the tokenizer.
-// Because the tokenizer is optimized for being efficiently used by
-// the Acorn parser itself, this interface is somewhat crude and not
-// very modular.
-
-export function tokenizer(input, options) {
- return parser(options, input)
-}
-
-function parser(options, input) {
- return new Parser(getOptions(options), String(input))
+ return new Parser(getOptions(options), input).parse();
}
diff --git a/src/location.js b/src/location.js
index 31d40a3501..5ab0028460 100755
--- a/src/location.js
+++ b/src/location.js
@@ -1,25 +1,25 @@
-import {Parser} from "./state"
-import {lineBreakG} from "./whitespace"
+import {Parser} from "./state";
+import {lineBreakG} from "./whitespace";
// These are used when `options.locations` is on, for the
// `startLoc` and `endLoc` properties.
export class Position {
constructor(line, col) {
- this.line = line
- this.column = col
+ this.line = line;
+ this.column = col;
}
offset(n) {
- return new Position(this.line, this.column + n)
+ return new Position(this.line, this.column + n);
}
}
export class SourceLocation {
constructor(p, start, end) {
- this.start = start
- this.end = end
- if (p.sourceFile !== null) this.source = p.sourceFile
+ this.start = start;
+ this.end = end;
+ if (p.sourceFile !== null) this.source = p.sourceFile;
}
}
@@ -30,19 +30,19 @@ export class SourceLocation {
// into.
export function getLineInfo(input, offset) {
- for (let line = 1, cur = 0;;) {
- lineBreakG.lastIndex = cur
- let match = lineBreakG.exec(input)
+ for (let line = 1, cur = 0; ;) {
+ lineBreakG.lastIndex = cur;
+ let match = lineBreakG.exec(input);
if (match && match.index < offset) {
- ++line
- cur = match.index + match[0].length
+ ++line;
+ cur = match.index + match[0].length;
} else {
- return new Position(line, offset - cur)
+ return new Position(line, offset - cur);
}
}
}
-const pp = Parser.prototype
+const pp = Parser.prototype;
// This function is used to raise exceptions on parse errors. It
// takes an offset integer (into the current `input`) to indicate
@@ -50,18 +50,18 @@ const pp = Parser.prototype
// of the error message, and then raises a `SyntaxError` with that
// message.
-pp.raise = function(pos, message) {
- let loc = getLineInfo(this.input, pos)
- message += " (" + loc.line + ":" + loc.column + ")"
- let err = new SyntaxError(message)
- err.pos = pos; err.loc = loc; err.raisedAt = this.pos
- throw err
-}
+pp.raise = function (pos, message) {
+ let loc = getLineInfo(this.input, pos);
+ message += ` (${loc.line}:${loc.column})`;
+ let err = new SyntaxError(message);
+ err.pos = pos;
+ err.loc = loc;
+ err.raisedAt = this.pos;
+ throw err;
+};
-pp.curPosition = function() {
- return new Position(this.curLine, this.pos - this.lineStart)
-}
-
-pp.markPosition = function() {
- return this.options.locations ? [this.start, this.startLoc] : this.start
-}
+pp.curPosition = function () {
+ if (this.options.locations) {
+ return new Position(this.curLine, this.pos - this.lineStart);
+ }
+};
diff --git a/src/lookahead.js b/src/lookahead.js
index cd3a9c7d08..f6f456cfa3 100644
--- a/src/lookahead.js
+++ b/src/lookahead.js
@@ -1,6 +1,6 @@
-import {Parser} from "./state"
+import {Parser} from "./state";
-const pp = Parser.prototype
+const pp = Parser.prototype;
var STATE_KEYS = [
"lastTokStartLoc",
@@ -27,21 +27,21 @@ var STATE_KEYS = [
];
pp.getState = function () {
- var state = {}
+ var state = {};
for (var i = 0; i < STATE_KEYS.length; i++) {
- var key = STATE_KEYS[i]
- state[key] = this[key]
+ var key = STATE_KEYS[i];
+ state[key] = this[key];
}
- state.context = this.context.slice()
- state.labels = this.labels.slice()
- return state
+ state.context = this.context.slice();
+ state.labels = this.labels.slice();
+ return state;
};
-pp.lookahead = function() {
+pp.lookahead = function () {
var old = this.getState();
- this.isLookahead = true
- this.next()
- this.isLookahead = false
+ this.isLookahead = true;
+ this.next();
+ this.isLookahead = false;
var curr = this.getState();
for (var key in old) this[key] = old[key];
return curr;
diff --git a/src/lval.js b/src/lval.js
index a7718736c6..6a6dc98b7f 100755
--- a/src/lval.js
+++ b/src/lval.js
@@ -1,205 +1,210 @@
-import {types as tt} from "./tokentype"
-import {Parser} from "./state"
-import {reservedWords} from "./identifier"
-import {has} from "./util"
+import {types as tt} from "./tokentype";
+import {Parser} from "./state";
+import {reservedWords} from "./identifier";
+import {has} from "./util";
-const pp = Parser.prototype
+const pp = Parser.prototype;
// Convert existing expression atom to assignable pattern
// if possible.
-pp.toAssignable = function(node, isBinding) {
+pp.toAssignable = function (node, isBinding) {
if (this.options.ecmaVersion >= 6 && node) {
switch (node.type) {
case "Identifier":
case "ObjectPattern":
case "ArrayPattern":
case "AssignmentPattern":
- break
+ break;
case "ObjectExpression":
- node.type = "ObjectPattern"
+ node.type = "ObjectPattern";
for (let i = 0; i < node.properties.length; i++) {
- let prop = node.properties[i]
+ let prop = node.properties[i];
if (prop.type === "SpreadProperty") continue;
- if (prop.kind !== "init") this.raise(prop.key.start, "Object pattern can't contain getter or setter")
- this.toAssignable(prop.value, isBinding)
+ if (prop.kind !== "init") this.raise(prop.key.start, "Object pattern can't contain getter or setter");
+ this.toAssignable(prop.value, isBinding);
}
- break
+ break;
case "ArrayExpression":
- node.type = "ArrayPattern"
- this.toAssignableList(node.elements, isBinding)
- break
+ node.type = "ArrayPattern";
+ this.toAssignableList(node.elements, isBinding);
+ break;
case "AssignmentExpression":
if (node.operator === "=") {
- node.type = "AssignmentPattern"
- delete node.operator
+ node.type = "AssignmentPattern";
+ delete node.operator;
} else {
- this.raise(node.left.end, "Only '=' operator can be used for specifying default value.")
+ this.raise(node.left.end, "Only '=' operator can be used for specifying default value.");
}
- break
+ break;
case "MemberExpression":
- if (!isBinding) break
+ if (!isBinding) break;
default:
- this.raise(node.start, "Assigning to rvalue")
+ this.raise(node.start, "Assigning to rvalue");
}
}
- return node
-}
+ return node;
+};
// Convert list of expression atoms to binding list.
-pp.toAssignableList = function(exprList, isBinding) {
- let end = exprList.length
+pp.toAssignableList = function (exprList, isBinding) {
+ let end = exprList.length;
if (end) {
- let last = exprList[end - 1]
- if (last && last.type == "RestElement") {
- --end
- } else if (last && last.type == "SpreadElement") {
- last.type = "RestElement"
- let arg = last.argument
- this.toAssignable(arg, isBinding)
- if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern")
- this.unexpected(arg.start)
- --end
+ let last = exprList[end - 1];
+ if (last && last.type === "RestElement") {
+ --end;
+ } else if (last && last.type === "SpreadElement") {
+ last.type = "RestElement";
+ let arg = last.argument;
+ this.toAssignable(arg, isBinding);
+ if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern") {
+ this.unexpected(arg.start);
+ }
+ --end;
}
}
for (let i = 0; i < end; i++) {
- let elt = exprList[i]
- if (elt) this.toAssignable(elt, isBinding)
+ let elt = exprList[i];
+ if (elt) this.toAssignable(elt, isBinding);
}
- return exprList
-}
+ return exprList;
+};
// Parses spread element.
-pp.parseSpread = function(refShorthandDefaultPos) {
- let node = this.startNode()
- this.next()
- node.argument = this.parseMaybeAssign(refShorthandDefaultPos)
- return this.finishNode(node, "SpreadElement")
-}
+pp.parseSpread = function (refShorthandDefaultPos) {
+ let node = this.startNode();
+ this.next();
+ node.argument = this.parseMaybeAssign(refShorthandDefaultPos);
+ return this.finishNode(node, "SpreadElement");
+};
-pp.parseRest = function() {
- let node = this.startNode()
- this.next()
- node.argument = this.type === tt.name || this.type === tt.bracketL ? this.parseBindingAtom() : this.unexpected()
- return this.finishNode(node, "RestElement")
-}
+pp.parseRest = function () {
+ let node = this.startNode();
+ this.next();
+ node.argument = this.type === tt.name || this.type === tt.bracketL ? this.parseBindingAtom() : this.unexpected();
+ return this.finishNode(node, "RestElement");
+};
// Parses lvalue (assignable) atom.
-pp.parseBindingAtom = function() {
- if (this.options.ecmaVersion < 6) return this.parseIdent()
+pp.parseBindingAtom = function () {
+ if (this.options.ecmaVersion < 6) return this.parseIdent();
switch (this.type) {
case tt.name:
- return this.parseIdent()
+ return this.parseIdent();
case tt.bracketL:
- let node = this.startNode()
- this.next()
- node.elements = this.parseBindingList(tt.bracketR, true, true)
- return this.finishNode(node, "ArrayPattern")
+ let node = this.startNode();
+ this.next();
+ node.elements = this.parseBindingList(tt.bracketR, true, true);
+ return this.finishNode(node, "ArrayPattern");
case tt.braceL:
- return this.parseObj(true)
+ return this.parseObj(true);
default:
- this.unexpected()
+ this.unexpected();
}
-}
+};
-pp.parseBindingList = function(close, allowEmpty, allowTrailingComma) {
- var elts = [], first = true
+pp.parseBindingList = function (close, allowEmpty, allowTrailingComma) {
+ var elts = [], first = true;
while (!this.eat(close)) {
- if (first) first = false
- else this.expect(tt.comma)
+ if (first) first = false;
+ else this.expect(tt.comma);
if (allowEmpty && this.type === tt.comma) {
- elts.push(null)
+ elts.push(null);
} else if (allowTrailingComma && this.afterTrailingComma(close)) {
- break
+ break;
} else if (this.type === tt.ellipsis) {
- elts.push(this.parseAssignableListItemTypes(this.parseRest()))
- this.expect(close)
- break
+ elts.push(this.parseAssignableListItemTypes(this.parseRest()));
+ this.expect(close);
+ break;
} else {
- var left = this.parseMaybeDefault()
- this.parseAssignableListItemTypes(left)
- elts.push(this.parseMaybeDefault(null, left))
+ var left = this.parseMaybeDefault();
+ this.parseAssignableListItemTypes(left);
+ elts.push(this.parseMaybeDefault(null, null, left));
}
}
- return elts
-}
+ return elts;
+};
-pp.parseAssignableListItemTypes = function(param) {
- return param
-}
+pp.parseAssignableListItemTypes = function (param) {
+ return param;
+};
// Parses assignment pattern around given atom if possible.
-pp.parseMaybeDefault = function(startPos, left) {
- startPos = startPos || this.markPosition()
- left = left || this.parseBindingAtom()
- if (!this.eat(tt.eq)) return left
- let node = this.startNodeAt(startPos)
- node.operator = "="
- node.left = left
- node.right = this.parseMaybeAssign()
- return this.finishNode(node, "AssignmentPattern")
-}
+pp.parseMaybeDefault = function (startPos, startLoc, left) {
+ startLoc = startLoc || this.startLoc;
+ startPos = startPos || this.start;
+ left = left || this.parseBindingAtom();
+ if (!this.eat(tt.eq)) return left;
+
+ let node = this.startNodeAt(startPos, startLoc);
+ node.operator = "=";
+ node.left = left;
+ node.right = this.parseMaybeAssign();
+ return this.finishNode(node, "AssignmentPattern");
+};
// Verify that a node is an lval — something that can be assigned
// to.
-pp.checkLVal = function(expr, isBinding, checkClashes) {
+pp.checkLVal = function (expr, isBinding, checkClashes) {
switch (expr.type) {
case "Identifier":
if (this.strict && (reservedWords.strictBind(expr.name) || reservedWords.strict(expr.name)))
- this.raise(expr.start, (isBinding ? "Binding " : "Assigning to ") + expr.name + " in strict mode")
+ this.raise(expr.start, (isBinding ? "Binding " : "Assigning to ") + expr.name + " in strict mode");
if (checkClashes) {
- if (has(checkClashes, expr.name))
- this.raise(expr.start, "Argument name clash in strict mode")
- checkClashes[expr.name] = true
+ if (checkClashes[expr.name]) {
+ this.raise(expr.start, "Argument name clash in strict mode");
+ } else {
+ checkClashes[expr.name] = true;
+ }
}
- break
+ break;
case "MemberExpression":
- if (isBinding) this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression")
- break
+ if (isBinding) this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression");
+ break;
case "ObjectPattern":
for (let i = 0; i < expr.properties.length; i++) {
var prop = expr.properties[i];
if (prop.type === "Property") prop = prop.value;
- this.checkLVal(prop, isBinding, checkClashes)
+ this.checkLVal(prop, isBinding, checkClashes);
}
- break
+ break;
case "ArrayPattern":
for (let i = 0; i < expr.elements.length; i++) {
- let elem = expr.elements[i]
- if (elem) this.checkLVal(elem, isBinding, checkClashes)
+ let elem = expr.elements[i];
+ if (elem) this.checkLVal(elem, isBinding, checkClashes);
}
- break
+ break;
case "AssignmentPattern":
- this.checkLVal(expr.left, isBinding, checkClashes)
- break
+ this.checkLVal(expr.left, isBinding, checkClashes);
+ break;
case "SpreadProperty":
case "RestElement":
- this.checkLVal(expr.argument, isBinding, checkClashes)
- break
+ this.checkLVal(expr.argument, isBinding, checkClashes);
+ break;
case "ParenthesizedExpression":
- this.checkLVal(expr.expression, isBinding, checkClashes)
- break
+ this.checkLVal(expr.expression, isBinding, checkClashes);
+ break;
default:
- this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue")
+ this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue");
}
-}
+};
diff --git a/src/node.js b/src/node.js
index 250f2dde0a..e58a28dc55 100755
--- a/src/node.js
+++ b/src/node.js
@@ -1,57 +1,48 @@
-import {Parser} from "./state"
-import {SourceLocation} from "./location"
+import {Parser} from "./state";
+import {SourceLocation} from "./location";
// Start an AST node, attaching a start offset.
-const pp = Parser.prototype
+const pp = Parser.prototype;
-export class Node {}
-
-pp.startNode = function() {
- let node = new Node
- node.start = this.start
- if (this.options.locations)
- node.loc = new SourceLocation(this, this.startLoc)
- if (this.options.directSourceFile)
- node.sourceFile = this.options.directSourceFile
- if (this.options.ranges)
- node.range = [this.start, 0]
- return node
+export class Node {
+ constructor(parser, pos, loc) {
+ this.type = "";
+ this.start = pos;
+ this.end = 0;
+ if (parser.options.locations)
+ this.loc = new SourceLocation(parser, loc);
+ if (parser.options.directSourceFile)
+ this.sourceFile = parser.options.directSourceFile;
+ if (parser.options.ranges)
+ this.range = [pos, 0];
+ }
}
-pp.startNodeAt = function(pos) {
- let node = new Node, start = pos
- if (this.options.locations) {
- node.loc = new SourceLocation(this, start[1])
- start = pos[0]
- }
- node.start = start
- if (this.options.directSourceFile)
- node.sourceFile = this.options.directSourceFile
- if (this.options.ranges)
- node.range = [start, 0]
- return node
+pp.startNode = function () {
+ return new Node(this, this.start, this.startLoc);
+};
+
+pp.startNodeAt = function (pos, loc) {
+ return new Node(this, pos, loc);
+};
+
+function finishNodeAt(node, type, pos, loc) {
+ node.type = type;
+ node.end = pos;
+ if (this.options.locations) node.loc.end = loc;
+ if (this.options.ranges) node.range[1] = pos;
+ return node;
}
// Finish an AST node, adding `type` and `end` properties.
-pp.finishNode = function(node, type) {
- node.type = type
- node.end = this.lastTokEnd
- if (this.options.locations)
- node.loc.end = this.lastTokEndLoc
- if (this.options.ranges)
- node.range[1] = this.lastTokEnd
- return node
-}
+pp.finishNode = function (node, type) {
+ return finishNodeAt.call(this, node, type, this.lastTokEnd, this.lastTokEndLoc);
+};
// Finish node at given position
-pp.finishNodeAt = function(node, type, pos) {
- if (this.options.locations) { node.loc.end = pos[1]; pos = pos[0] }
- node.type = type
- node.end = pos
- if (this.options.ranges)
- node.range[1] = pos
- return node
-}
+pp.finishNodeAt = function (node, type, pos, loc) {
+ return finishNodeAt.call(this, node, type, pos, loc);
+};
diff --git a/src/options.js b/src/options.js
index 6a81762f40..88ea8fce47 100755
--- a/src/options.js
+++ b/src/options.js
@@ -1,5 +1,5 @@
-import {has, isArray} from "./util"
-import {SourceLocation} from "./location"
+import {has} from "./util";
+import {SourceLocation} from "./location";
// A second optional argument can be given to further configure
// the parser process. These options are recognized:
@@ -85,38 +85,37 @@ export const defaultOptions = {
// Babel-specific options
features: {},
strictMode: null
-}
+};
// Interpret and default an options object
export function getOptions(opts) {
- let options = {}
+ let options = {};
for (let opt in defaultOptions)
- options[opt] = opts && has(opts, opt) ? opts[opt] : defaultOptions[opt]
+ options[opt] = opts && has(opts, opt) ? opts[opt] : defaultOptions[opt];
- if (isArray(options.onToken)) {
- let tokens = options.onToken
- options.onToken = (token) => tokens.push(token)
+ if (Array.isArray(options.onToken)) {
+ let tokens = options.onToken;
+ options.onToken = (token) => tokens.push(token);
}
- if (isArray(options.onComment))
- options.onComment = pushComment(options, options.onComment)
+ if (Array.isArray(options.onComment))
+ options.onComment = pushComment(options, options.onComment);
- return options
+ return options;
}
function pushComment(options, array) {
return function (block, text, start, end, startLoc, endLoc) {
let comment = {
- type: block ? 'Block' : 'Line',
+ type: block ? "Block" : "Line",
value: text,
start: start,
end: end
- }
+ };
if (options.locations)
- comment.loc = new SourceLocation(this, startLoc, endLoc)
+ comment.loc = new SourceLocation(this, startLoc, endLoc);
if (options.ranges)
- comment.range = [start, end]
- array.push(comment)
- }
+ comment.range = [start, end];
+ array.push(comment);
+ };
}
-
diff --git a/src/parseutil.js b/src/parseutil.js
index 3d464a22dc..2fae5e6729 100755
--- a/src/parseutil.js
+++ b/src/parseutil.js
@@ -1,89 +1,89 @@
-import {types as tt} from "./tokentype"
-import {Parser} from "./state"
-import {lineBreak} from "./whitespace"
+import {types as tt} from "./tokentype";
+import {Parser} from "./state";
+import {lineBreak} from "./whitespace";
-const pp = Parser.prototype
+const pp = Parser.prototype;
// ## Parser utilities
// Test whether a statement node is the string literal `"use strict"`.
-pp.isUseStrict = function(stmt) {
+pp.isUseStrict = function (stmt) {
return this.options.ecmaVersion >= 5 && stmt.type === "ExpressionStatement" &&
- stmt.expression.type === "Literal" && stmt.expression.value === "use strict"
-}
+ stmt.expression.type === "Literal" && stmt.expression.value === "use strict";
+};
// Predicate that tests whether the next token is of the given
// type, and if yes, consumes it as a side effect.
-pp.eat = function(type) {
+pp.eat = function (type) {
if (this.type === type) {
- this.next()
- return true
+ this.next();
+ return true;
} else {
- return false
+ return false;
}
-}
+};
// Tests whether parsed token is a contextual keyword.
-pp.isContextual = function(name) {
- return this.type === tt.name && this.value === name
-}
+pp.isContextual = function (name) {
+ return this.type === tt.name && this.value === name;
+};
// Consumes contextual keyword if possible.
-pp.eatContextual = function(name) {
- return this.value === name && this.eat(tt.name)
-}
+pp.eatContextual = function (name) {
+ return this.value === name && this.eat(tt.name);
+};
// Asserts that following token is given contextual keyword.
-pp.expectContextual = function(name) {
- if (!this.eatContextual(name)) this.unexpected()
-}
+pp.expectContextual = function (name) {
+ if (!this.eatContextual(name)) this.unexpected();
+};
// Test whether a semicolon can be inserted at the current position.
-pp.canInsertSemicolon = function() {
+pp.canInsertSemicolon = function () {
return this.type === tt.eof ||
this.type === tt.braceR ||
- lineBreak.test(this.input.slice(this.lastTokEnd, this.start))
-}
+ lineBreak.test(this.input.slice(this.lastTokEnd, this.start));
+};
-pp.insertSemicolon = function() {
+pp.insertSemicolon = function () {
if (this.canInsertSemicolon()) {
if (this.options.onInsertedSemicolon)
- this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc)
- return true
+ this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc);
+ return true;
}
-}
+};
// Consume a semicolon, or, failing that, see if we are allowed to
// pretend that there is a semicolon at this position.
-pp.semicolon = function() {
- if (!this.eat(tt.semi) && !this.insertSemicolon()) this.unexpected()
-}
+pp.semicolon = function () {
+ if (!this.eat(tt.semi) && !this.insertSemicolon()) this.unexpected();
+};
-pp.afterTrailingComma = function(tokType) {
- if (this.type == tokType) {
+pp.afterTrailingComma = function (tokType) {
+ if (this.type === tokType) {
if (this.options.onTrailingComma)
- this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc)
- this.next()
- return true
+ this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc);
+ this.next();
+ return true;
}
-}
+};
// Expect a token of a given type. If found, consume it, otherwise,
// raise an unexpected token error.
-pp.expect = function(type) {
- this.eat(type) || this.unexpected()
-}
+pp.expect = function (type) {
+ return this.eat(type) || this.unexpected();
+};
// Raise an unexpected token error.
-pp.unexpected = function(pos) {
- this.raise(pos != null ? pos : this.start, "Unexpected token")
-}
+pp.unexpected = function (pos) {
+ this.raise(pos != null ? pos : this.start, "Unexpected token");
+};
diff --git a/src/plugins/flow.js b/src/plugins/flow.js
new file mode 100644
index 0000000000..a219d6b37d
--- /dev/null
+++ b/src/plugins/flow.js
@@ -0,0 +1,823 @@
+import { types as tt } from "../tokentype";
+import { Parser } from "../state";
+
+var pp = Parser.prototype;
+
+pp.isRelational = function (op) {
+ return this.type === tt.relational && this.value === op;
+};
+
+pp.expectRelational = function (op) {
+ if (this.isRelational(op)) {
+ this.next();
+ } else {
+ this.unexpected();
+ }
+};
+
+pp.flowParseTypeInitialiser = function (tok) {
+ var oldInType = this.inType;
+ this.inType = true;
+ this.expect(tok || tt.colon);
+ var type = this.flowParseType();
+ this.inType = oldInType;
+ return type;
+};
+
+pp.flowParseDeclareClass = function (node) {
+ this.next();
+ this.flowParseInterfaceish(node, true);
+ return this.finishNode(node, "DeclareClass");
+};
+
+pp.flowParseDeclareFunction = function (node) {
+ this.next();
+
+ var id = node.id = this.parseIdent();
+
+ var typeNode = this.startNode();
+ var typeContainer = this.startNode();
+
+ if (this.isRelational("<")) {
+ typeNode.typeParameters = this.flowParseTypeParameterDeclaration();
+ } else {
+ typeNode.typeParameters = null;
+ }
+
+ this.expect(tt.parenL);
+ var tmp = this.flowParseFunctionTypeParams();
+ typeNode.params = tmp.params;
+ typeNode.rest = tmp.rest;
+ this.expect(tt.parenR);
+ typeNode.returnType = this.flowParseTypeInitialiser();
+
+ typeContainer.typeAnnotation = this.finishNode(typeNode, "FunctionTypeAnnotation");
+ id.typeAnnotation = this.finishNode(typeContainer, "TypeAnnotation");
+
+ this.finishNode(id, id.type);
+
+ this.semicolon();
+
+ return this.finishNode(node, "DeclareFunction");
+};
+
+pp.flowParseDeclare = function (node) {
+ if (this.type === tt._class) {
+ return this.flowParseDeclareClass(node);
+ } else if (this.type === tt._function) {
+ return this.flowParseDeclareFunction(node);
+ } else if (this.type === tt._var) {
+ return this.flowParseDeclareVariable(node);
+ } else if (this.isContextual("module")) {
+ return this.flowParseDeclareModule(node);
+ } else {
+ this.unexpected();
+ }
+};
+
+pp.flowParseDeclareVariable = function (node) {
+ this.next();
+ node.id = this.flowParseTypeAnnotatableIdentifier();
+ this.semicolon();
+ return this.finishNode(node, "DeclareVariable");
+};
+
+pp.flowParseDeclareModule = function (node) {
+ this.next();
+
+ if (this.type === tt.string) {
+ node.id = this.parseExprAtom();
+ } else {
+ node.id = this.parseIdent();
+ }
+
+ var bodyNode = node.body = this.startNode();
+ var body = bodyNode.body = [];
+ this.expect(tt.braceL);
+ while (this.type !== tt.braceR) {
+ var node2 = this.startNode();
+
+ // todo: declare check
+ this.next();
+
+ body.push(this.flowParseDeclare(node2));
+ }
+ this.expect(tt.braceR);
+
+ this.finishNode(bodyNode, "BlockStatement");
+ return this.finishNode(node, "DeclareModule");
+};
+
+
+// Interfaces
+
+pp.flowParseInterfaceish = function (node, allowStatic) {
+ node.id = this.parseIdent();
+
+ if (this.isRelational("<")) {
+ node.typeParameters = this.flowParseTypeParameterDeclaration();
+ } else {
+ node.typeParameters = null;
+ }
+
+ node.extends = [];
+
+ if (this.eat(tt._extends)) {
+ do {
+ node.extends.push(this.flowParseInterfaceExtends());
+ } while(this.eat(tt.comma));
+ }
+
+ node.body = this.flowParseObjectType(allowStatic);
+};
+
+pp.flowParseInterfaceExtends = function () {
+ var node = this.startNode();
+
+ node.id = this.parseIdent();
+ if (this.isRelational("<")) {
+ node.typeParameters = this.flowParseTypeParameterInstantiation();
+ } else {
+ node.typeParameters = null;
+ }
+
+ return this.finishNode(node, "InterfaceExtends");
+};
+
+pp.flowParseInterface = function (node) {
+ this.flowParseInterfaceish(node, false);
+ return this.finishNode(node, "InterfaceDeclaration");
+};
+
+// Type aliases
+
+pp.flowParseTypeAlias = function (node) {
+ node.id = this.parseIdent();
+
+ if (this.isRelational("<")) {
+ node.typeParameters = this.flowParseTypeParameterDeclaration();
+ } else {
+ node.typeParameters = null;
+ }
+
+ node.right = this.flowParseTypeInitialiser(tt.eq);
+ this.semicolon();
+
+ return this.finishNode(node, "TypeAlias");
+};
+
+// Type annotations
+
+pp.flowParseTypeParameterDeclaration = function () {
+ var node = this.startNode();
+ node.params = [];
+
+ this.expectRelational("<");
+ while (!this.isRelational(">")) {
+ node.params.push(this.flowParseTypeAnnotatableIdentifier());
+ if (!this.isRelational(">")) {
+ this.expect(tt.comma);
+ }
+ }
+ this.expectRelational(">");
+
+ return this.finishNode(node, "TypeParameterDeclaration");
+};
+
+pp.flowParseTypeParameterInstantiation = function () {
+ var node = this.startNode(), oldInType = this.inType;
+ node.params = [];
+
+ this.inType = true;
+
+ this.expectRelational("<");
+ while (!this.isRelational(">")) {
+ node.params.push(this.flowParseType());
+ if (!this.isRelational(">")) {
+ this.expect(tt.comma);
+ }
+ }
+ this.expectRelational(">");
+
+ this.inType = oldInType;
+
+ return this.finishNode(node, "TypeParameterInstantiation");
+};
+
+pp.flowParseObjectPropertyKey = function () {
+ return (this.type === tt.num || this.type === tt.string) ? this.parseExprAtom() : this.parseIdent(true);
+};
+
+pp.flowParseObjectTypeIndexer = function (node, isStatic) {
+ node.static = isStatic;
+
+ this.expect(tt.bracketL);
+ node.id = this.flowParseObjectPropertyKey();
+ node.key = this.flowParseTypeInitialiser();
+ this.expect(tt.bracketR);
+ node.value = this.flowParseTypeInitialiser();
+
+ this.flowObjectTypeSemicolon();
+ return this.finishNode(node, "ObjectTypeIndexer");
+};
+
+pp.flowParseObjectTypeMethodish = function (node) {
+ node.params = [];
+ node.rest = null;
+ node.typeParameters = null;
+
+ if (this.isRelational("<")) {
+ node.typeParameters = this.flowParseTypeParameterDeclaration();
+ }
+
+ this.expect(tt.parenL);
+ while (this.type === tt.name) {
+ node.params.push(this.flowParseFunctionTypeParam());
+ if (this.type !== tt.parenR) {
+ this.expect(tt.comma);
+ }
+ }
+
+ if (this.eat(tt.ellipsis)) {
+ node.rest = this.flowParseFunctionTypeParam();
+ }
+ this.expect(tt.parenR);
+ node.returnType = this.flowParseTypeInitialiser();
+
+ return this.finishNode(node, "FunctionTypeAnnotation");
+};
+
+pp.flowParseObjectTypeMethod = function (startPos, startLoc, isStatic, key) {
+ var node = this.startNodeAt(startPos, startLoc);
+ node.value = this.flowParseObjectTypeMethodish(this.startNodeAt(startPos, startLoc));
+ node.static = isStatic;
+ node.key = key;
+ node.optional = false;
+ this.flowObjectTypeSemicolon();
+ return this.finishNode(node, "ObjectTypeProperty");
+};
+
+pp.flowParseObjectTypeCallProperty = function (node, isStatic) {
+ var valueNode = this.startNode();
+ node.static = isStatic;
+ node.value = this.flowParseObjectTypeMethodish(valueNode);
+ this.flowObjectTypeSemicolon();
+ return this.finishNode(node, "ObjectTypeCallProperty");
+};
+
+pp.flowParseObjectType = function (allowStatic) {
+ var nodeStart = this.startNode();
+ var node;
+ var optional = false;
+ var propertyKey;
+ var isStatic;
+
+ nodeStart.callProperties = [];
+ nodeStart.properties = [];
+ nodeStart.indexers = [];
+
+ this.expect(tt.braceL);
+
+ while (this.type !== tt.braceR) {
+ var startPos = this.start, startLoc = this.startLoc;
+ node = this.startNode();
+ if (allowStatic && this.isContextual("static")) {
+ this.next();
+ isStatic = true;
+ }
+
+ if (this.type === tt.bracketL) {
+ nodeStart.indexers.push(this.flowParseObjectTypeIndexer(node, isStatic));
+ } else if (this.type === tt.parenL || this.isRelational("<")) {
+ nodeStart.callProperties.push(this.flowParseObjectTypeCallProperty(node, allowStatic));
+ } else {
+ if (isStatic && this.type === tt.colon) {
+ propertyKey = this.parseIdent();
+ } else {
+ propertyKey = this.flowParseObjectPropertyKey();
+ }
+ if (this.isRelational("<") || this.type === tt.parenL) {
+ // This is a method property
+ nodeStart.properties.push(this.flowParseObjectTypeMethod(startPos, startLoc, isStatic, propertyKey));
+ } else {
+ if (this.eat(tt.question)) {
+ optional = true;
+ }
+ node.key = propertyKey;
+ node.value = this.flowParseTypeInitialiser();
+ node.optional = optional;
+ node.static = isStatic;
+ this.flowObjectTypeSemicolon();
+ nodeStart.properties.push(this.finishNode(node, "ObjectTypeProperty"));
+ }
+ }
+ }
+
+ this.expect(tt.braceR);
+
+ return this.finishNode(nodeStart, "ObjectTypeAnnotation");
+};
+
+pp.flowObjectTypeSemicolon = function () {
+ if (!this.eat(tt.semi) && !this.eat(tt.comma) && this.type !== tt.braceR) {
+ this.unexpected();
+ }
+};
+
+pp.flowParseGenericType = function (startPos, startLoc, id) {
+ var node = this.startNodeAt(startPos, startLoc);
+
+ node.typeParameters = null;
+ node.id = id;
+
+ while (this.eat(tt.dot)) {
+ var node2 = this.startNodeAt(startPos, startLoc);
+ node2.qualification = node.id;
+ node2.id = this.parseIdent();
+ node.id = this.finishNode(node2, "QualifiedTypeIdentifier");
+ }
+
+ if (this.isRelational("<")) {
+ node.typeParameters = this.flowParseTypeParameterInstantiation();
+ }
+
+ return this.finishNode(node, "GenericTypeAnnotation");
+};
+
+pp.flowParseTypeofType = function () {
+ var node = this.startNode();
+ this.expect(tt._typeof);
+ node.argument = this.flowParsePrimaryType();
+ return this.finishNode(node, "TypeofTypeAnnotation");
+};
+
+pp.flowParseTupleType = function () {
+ var node = this.startNode();
+ node.types = [];
+ this.expect(tt.bracketL);
+ // We allow trailing commas
+ while (this.pos < this.input.length && this.type !== tt.bracketR) {
+ node.types.push(this.flowParseType());
+ if (this.type === tt.bracketR) break;
+ this.expect(tt.comma);
+ }
+ this.expect(tt.bracketR);
+ return this.finishNode(node, "TupleTypeAnnotation");
+};
+
+pp.flowParseFunctionTypeParam = function () {
+ var optional = false;
+ var node = this.startNode();
+ node.name = this.parseIdent();
+ if (this.eat(tt.question)) {
+ optional = true;
+ }
+ node.optional = optional;
+ node.typeAnnotation = this.flowParseTypeInitialiser();
+ return this.finishNode(node, "FunctionTypeParam");
+};
+
+pp.flowParseFunctionTypeParams = function () {
+ var ret = { params: [], rest: null };
+ while (this.type === tt.name) {
+ ret.params.push(this.flowParseFunctionTypeParam());
+ if (this.type !== tt.parenR) {
+ this.expect(tt.comma);
+ }
+ }
+ if (this.eat(tt.ellipsis)) {
+ ret.rest = this.flowParseFunctionTypeParam();
+ }
+ return ret;
+};
+
+pp.flowIdentToTypeAnnotation = function (startPos, startLoc, node, id) {
+ switch (id.name) {
+ case "any":
+ return this.finishNode(node, "AnyTypeAnnotation");
+
+ case "void":
+ return this.finishNode(node, "VoidTypeAnnotation");
+
+ case "bool":
+ case "boolean":
+ return this.finishNode(node, "BooleanTypeAnnotation");
+
+ case "mixed":
+ return this.finishNode(node, "MixedTypeAnnotation");
+
+ case "number":
+ return this.finishNode(node, "NumberTypeAnnotation");
+
+ case "string":
+ return this.finishNode(node, "StringTypeAnnotation");
+
+ default:
+ return this.flowParseGenericType(startPos, startLoc, id);
+ }
+};
+
+// The parsing of types roughly parallels the parsing of expressions, and
+// primary types are kind of like primary expressions...they're the
+// primitives with which other types are constructed.
+pp.flowParsePrimaryType = function () {
+ var startPos = this.start, startLoc = this.startLoc;
+ var node = this.startNode();
+ var tmp;
+ var type;
+ var isGroupedType = false;
+
+ switch (this.type) {
+ case tt.name:
+ return this.flowIdentToTypeAnnotation(startPos, startLoc, node, this.parseIdent());
+
+ case tt.braceL:
+ return this.flowParseObjectType();
+
+ case tt.bracketL:
+ return this.flowParseTupleType();
+
+ case tt.relational:
+ if (this.value === "<") {
+ node.typeParameters = this.flowParseTypeParameterDeclaration();
+ this.expect(tt.parenL);
+ tmp = this.flowParseFunctionTypeParams();
+ node.params = tmp.params;
+ node.rest = tmp.rest;
+ this.expect(tt.parenR);
+
+ this.expect(tt.arrow);
+
+ node.returnType = this.flowParseType();
+
+ return this.finishNode(node, "FunctionTypeAnnotation");
+ }
+
+ case tt.parenL:
+ this.next();
+
+ // Check to see if this is actually a grouped type
+ if (this.type !== tt.parenR && this.type !== tt.ellipsis) {
+ if (this.type === tt.name) {
+ var token = this.lookahead().type;
+ isGroupedType = token !== tt.question && token !== tt.colon;
+ } else {
+ isGroupedType = true;
+ }
+ }
+
+ if (isGroupedType) {
+ type = this.flowParseType();
+ this.expect(tt.parenR);
+
+ // If we see a => next then someone was probably confused about
+ // function types, so we can provide a better error message
+ if (this.eat(tt.arrow)) {
+ this.raise(node,
+ "Unexpected token =>. It looks like " +
+ "you are trying to write a function type, but you ended up " +
+ "writing a grouped type followed by an =>, which is a syntax " +
+ "error. Remember, function type parameters are named so function " +
+ "types look like (name1: type1, name2: type2) => returnType. You " +
+ "probably wrote (type1) => returnType"
+ );
+ }
+
+ return type;
+ }
+
+ tmp = this.flowParseFunctionTypeParams();
+ node.params = tmp.params;
+ node.rest = tmp.rest;
+
+ this.expect(tt.parenR);
+
+ this.expect(tt.arrow);
+
+ node.returnType = this.flowParseType();
+ node.typeParameters = null;
+
+ return this.finishNode(node, "FunctionTypeAnnotation");
+
+ case tt.string:
+ node.value = this.value;
+ node.raw = this.input.slice(this.start, this.end);
+ this.next();
+ return this.finishNode(node, "StringLiteralTypeAnnotation");
+
+ default:
+ if (this.type.keyword === "typeof") {
+ return this.flowParseTypeofType();
+ }
+ }
+
+ this.unexpected();
+};
+
+pp.flowParsePostfixType = function () {
+ var node = this.startNode();
+ var type = node.elementType = this.flowParsePrimaryType();
+ if (this.type === tt.bracketL) {
+ this.expect(tt.bracketL);
+ this.expect(tt.bracketR);
+ return this.finishNode(node, "ArrayTypeAnnotation");
+ } else {
+ return type;
+ }
+};
+
+pp.flowParsePrefixType = function () {
+ var node = this.startNode();
+ if (this.eat(tt.question)) {
+ node.typeAnnotation = this.flowParsePrefixType();
+ return this.finishNode(node, "NullableTypeAnnotation");
+ } else {
+ return this.flowParsePostfixType();
+ }
+};
+
+pp.flowParseIntersectionType = function () {
+ var node = this.startNode();
+ var type = this.flowParsePrefixType();
+ node.types = [type];
+ while (this.eat(tt.bitwiseAND)) {
+ node.types.push(this.flowParsePrefixType());
+ }
+ return node.types.length === 1 ? type : this.finishNode(node, "IntersectionTypeAnnotation");
+};
+
+pp.flowParseUnionType = function () {
+ var node = this.startNode();
+ var type = this.flowParseIntersectionType();
+ node.types = [type];
+ while (this.eat(tt.bitwiseOR)) {
+ node.types.push(this.flowParseIntersectionType());
+ }
+ return node.types.length === 1 ? type : this.finishNode(node, "UnionTypeAnnotation");
+};
+
+pp.flowParseType = function () {
+ var oldInType = this.inType;
+ this.inType = true;
+ var type = this.flowParseUnionType();
+ this.inType = oldInType;
+ return type;
+};
+
+pp.flowParseTypeAnnotation = function () {
+ var node = this.startNode();
+ node.typeAnnotation = this.flowParseTypeInitialiser();
+ return this.finishNode(node, "TypeAnnotation");
+};
+
+pp.flowParseTypeAnnotatableIdentifier = function (requireTypeAnnotation, canBeOptionalParam) {
+ var ident = this.parseIdent();
+ var isOptionalParam = false;
+
+ if (canBeOptionalParam && this.eat(tt.question)) {
+ this.expect(tt.question);
+ isOptionalParam = true;
+ }
+
+ if (requireTypeAnnotation || this.type === tt.colon) {
+ ident.typeAnnotation = this.flowParseTypeAnnotation();
+ this.finishNode(ident, ident.type);
+ }
+
+ if (isOptionalParam) {
+ ident.optional = true;
+ this.finishNode(ident, ident.type);
+ }
+
+ return ident;
+};
+
+export default function (instance) {
+ // function name(): string {}
+ instance.extend("parseFunctionBody", function (inner) {
+ return function (node, allowExpression) {
+ if (this.type === tt.colon) {
+ node.returnType = this.flowParseTypeAnnotation();
+ }
+
+ return inner.call(this, node, allowExpression);
+ };
+ });
+
+ instance.extend("parseStatement", function (inner) {
+ return function (declaration, topLevel) {
+ // strict mode handling of `interface` since it's a reserved word
+ if (this.strict && this.type === tt.name && this.value === "interface") {
+ var node = this.startNode();
+ this.next();
+ return this.flowParseInterface(node);
+ } else {
+ return inner.call(this, declaration, topLevel);
+ }
+ };
+ });
+
+ instance.extend("parseExpressionStatement", function (inner) {
+ return function (node, expr) {
+ if (expr.type === "Identifier") {
+ if (expr.name === "declare") {
+ if (this.type === tt._class || this.type === tt.name || this.type === tt._function || this.type === tt._var) {
+ return this.flowParseDeclare(node);
+ }
+ } else if (this.type === tt.name) {
+ if (expr.name === "interface") {
+ return this.flowParseInterface(node);
+ } else if (expr.name === "type") {
+ return this.flowParseTypeAlias(node);
+ }
+ }
+ }
+
+ return inner.call(this, node, expr);
+ };
+ });
+
+ instance.extend("shouldParseExportDeclaration", function (inner) {
+ return function () {
+ return this.isContextual("type") || inner.call(this);
+ };
+ });
+
+ instance.extend("parseParenItem", function () {
+ return function (node, startLoc, startPos) {
+ if (this.type === tt.colon) {
+ var typeCastNode = this.startNodeAt(startLoc, startPos);
+ typeCastNode.expression = node;
+ typeCastNode.typeAnnotation = this.flowParseTypeAnnotation();
+ return this.finishNode(typeCastNode, "TypeCastExpression");
+ } else {
+ return node;
+ }
+ };
+ });
+
+ instance.extend("parseClassId", function (inner) {
+ return function (node, isStatement) {
+ inner.call(this, node, isStatement);
+ if (this.isRelational("<")) {
+ node.typeParameters = this.flowParseTypeParameterDeclaration();
+ }
+ };
+ });
+
+ // don't consider `void` to be a keyword as then it'll use the void token type
+ // and set startExpr
+ instance.extend("isKeyword", function (inner) {
+ return function (name) {
+ if (this.inType && name === "void") {
+ return false;
+ } else {
+ return inner.call(this, name);
+ }
+ };
+ });
+
+ instance.extend("readToken", function (inner) {
+ return function (code) {
+ if (this.inType && (code === 62 || code === 60)) {
+ return this.finishOp(tt.relational, 1);
+ } else {
+ return inner.call(this, code);
+ }
+ };
+ });
+
+ instance.extend("jsx_readToken", function (inner) {
+ return function () {
+ if (!this.inType) return inner.call(this);
+ };
+ });
+
+ instance.extend("parseParenArrowList", function (inner) {
+ return function (startPos, startLoc, exprList, isAsync) {
+ for (var i = 0; i < exprList.length; i++) {
+ var listItem = exprList[i];
+ if (listItem.type === "TypeCastExpression") {
+ var expr = listItem.expression;
+ expr.typeAnnotation = listItem.typeAnnotation;
+ exprList[i] = expr;
+ }
+ }
+ return inner.call(this, startPos, startLoc, exprList, isAsync);
+ };
+ });
+
+ instance.extend("parseClassProperty", function (inner) {
+ return function (node) {
+ if (this.type === tt.colon) {
+ node.typeAnnotation = this.flowParseTypeAnnotation();
+ }
+ return inner.call(this, node);
+ };
+ });
+
+ instance.extend("isClassProperty", function (inner) {
+ return function () {
+ return this.type === tt.colon || inner.call(this);
+ };
+ });
+
+ instance.extend("parseClassMethod", function () {
+ return function (classBody, method, isGenerator, isAsync) {
+ var typeParameters;
+ if (this.isRelational("<")) {
+ typeParameters = this.flowParseTypeParameterDeclaration();
+ }
+ method.value = this.parseMethod(isGenerator, isAsync);
+ method.value.typeParameters = typeParameters;
+ classBody.body.push(this.finishNode(method, "MethodDefinition"));
+ };
+ });
+
+ instance.extend("parseClassSuper", function (inner) {
+ return function (node, isStatement) {
+ inner.call(this, node, isStatement);
+ if (node.superClass && this.isRelational("<")) {
+ node.superTypeParameters = this.flowParseTypeParameterInstantiation();
+ }
+ if (this.isContextual("implements")) {
+ this.next();
+ var implemented = node.implements = [];
+ do {
+ let node = this.startNode();
+ node.id = this.parseIdent();
+ if (this.isRelational("<")) {
+ node.typeParameters = this.flowParseTypeParameterInstantiation();
+ } else {
+ node.typeParameters = null;
+ }
+ implemented.push(this.finishNode(node, "ClassImplements"));
+ } while(this.eat(tt.comma))
+ }
+ };
+ });
+
+ instance.extend("parseObjPropValue", function (inner) {
+ return function (prop) {
+ var typeParameters;
+ if (this.isRelational("<")) {
+ typeParameters = this.flowParseTypeParameterDeclaration();
+ if (this.type !== tt.parenL) this.unexpected();
+ }
+ inner.apply(this, arguments);
+ prop.value.typeParameters = typeParameters;
+ };
+ });
+
+ instance.extend("parseAssignableListItemTypes", function () {
+ return function (param) {
+ if (this.eat(tt.question)) {
+ param.optional = true;
+ }
+ if (this.type === tt.colon) {
+ param.typeAnnotation = this.flowParseTypeAnnotation();
+ }
+ this.finishNode(param, param.type);
+ return param;
+ };
+ });
+
+ instance.extend("parseImportSpecifiers", function (inner) {
+ return function (node) {
+ node.isType = false;
+ if (this.isContextual("type")) {
+ var startPos = this.start, startLoc = this.startLoc;
+ var typeId = this.parseIdent();
+ if ((this.type === tt.name && this.value !== "from") || this.type === tt.braceL || this.type === tt.star) {
+ node.isType = true;
+ } else {
+ node.specifiers.push(this.parseImportSpecifierDefault(typeId, startPos, startLoc));
+ if (this.isContextual("from")) return;
+ this.eat(tt.comma);
+ }
+ }
+ inner.call(this, node);
+ };
+ });
+
+ // function foo() {}
+ instance.extend("parseFunctionParams", function (inner) {
+ return function (node) {
+ if (this.isRelational("<")) {
+ node.typeParameters = this.flowParseTypeParameterDeclaration();
+ }
+ inner.call(this, node);
+ };
+ });
+
+ // var foo: string = bar
+ instance.extend("parseVarHead", function (inner) {
+ return function (decl) {
+ inner.call(this, decl);
+ if (this.type === tt.colon) {
+ decl.id.typeAnnotation = this.flowParseTypeAnnotation();
+ this.finishNode(decl.id, decl.id.type);
+ }
+ };
+ });
+};
diff --git a/src/plugins/jsx/index.js b/src/plugins/jsx/index.js
new file mode 100644
index 0000000000..19ff2e3697
--- /dev/null
+++ b/src/plugins/jsx/index.js
@@ -0,0 +1,421 @@
+import XHTMLEntities from "./xhtml";
+import { TokenType, types as tt } from "../../tokentype";
+import { TokContext, types as tc } from "../../tokencontext";
+import { Parser } from "../../state";
+import { isIdentifierChar, isIdentifierStart } from "../../identifier";
+import { isNewLine, lineBreak, lineBreakG } from "../../whitespace";
+
+const HEX_NUMBER = /^[\da-fA-F]+$/;
+const DECIMAL_NUMBER = /^\d+$/;
+
+tc.j_oTag = new TokContext("...", true, true);
+
+tt.jsxName = new TokenType("jsxName");
+tt.jsxText = new TokenType("jsxText", { beforeExpr: true });
+tt.jsxTagStart = new TokenType("jsxTagStart");
+tt.jsxTagEnd = new TokenType("jsxTagEnd");
+
+tt.jsxTagStart.updateContext = function() {
+ this.context.push(tc.j_expr); // treat as beginning of JSX expression
+ this.context.push(tc.j_oTag); // start opening tag context
+ this.exprAllowed = false;
+};
+
+tt.jsxTagEnd.updateContext = function(prevType) {
+ var out = this.context.pop();
+ if (out === tc.j_oTag && prevType === tt.slash || out === tc.j_cTag) {
+ this.context.pop();
+ this.exprAllowed = this.curContext() === tc.j_expr;
+ } else {
+ this.exprAllowed = true;
+ }
+};
+
+var pp = Parser.prototype;
+
+// Reads inline JSX contents token.
+
+pp.jsxReadToken = function() {
+ var out = "", chunkStart = this.pos;
+ for (;;) {
+ if (this.pos >= this.input.length)
+ this.raise(this.start, "Unterminated JSX contents");
+ var ch = this.input.charCodeAt(this.pos);
+
+ switch (ch) {
+ case 60: // "<"
+ case 123: // "{"
+ if (this.pos === this.start) {
+ if (ch === 60 && this.exprAllowed) {
+ ++this.pos;
+ return this.finishToken(tt.jsxTagStart);
+ }
+ return this.getTokenFromCode(ch);
+ }
+ out += this.input.slice(chunkStart, this.pos);
+ return this.finishToken(tt.jsxText, out);
+
+ case 38: // "&"
+ out += this.input.slice(chunkStart, this.pos);
+ out += this.jsxReadEntity();
+ chunkStart = this.pos;
+ break;
+
+ default:
+ if (isNewLine(ch)) {
+ out += this.input.slice(chunkStart, this.pos);
+ out += this.jsxReadNewLine(true);
+ chunkStart = this.pos;
+ } else {
+ ++this.pos;
+ }
+ }
+ }
+};
+
+pp.jsxReadNewLine = function(normalizeCRLF) {
+ var ch = this.input.charCodeAt(this.pos);
+ var out;
+ ++this.pos;
+ if (ch === 13 && this.input.charCodeAt(this.pos) === 10) {
+ ++this.pos;
+ out = normalizeCRLF ? "\n" : "\r\n";
+ } else {
+ out = String.fromCharCode(ch);
+ }
+ if (this.options.locations) {
+ ++this.curLine;
+ this.lineStart = this.pos;
+ }
+
+ return out;
+};
+
+pp.jsxReadString = function(quote) {
+ var out = "", chunkStart = ++this.pos;
+ for (;;) {
+ if (this.pos >= this.input.length)
+ this.raise(this.start, "Unterminated string constant");
+ var ch = this.input.charCodeAt(this.pos);
+ if (ch === quote) break;
+ if (ch === 38) { // "&"
+ out += this.input.slice(chunkStart, this.pos);
+ out += this.jsxReadEntity();
+ chunkStart = this.pos;
+ } else if (isNewLine(ch)) {
+ out += this.input.slice(chunkStart, this.pos);
+ out += this.jsxReadNewLine(false);
+ chunkStart = this.pos;
+ } else {
+ ++this.pos;
+ }
+ }
+ out += this.input.slice(chunkStart, this.pos++);
+ return this.finishToken(tt.string, out);
+};
+
+pp.jsxReadEntity = function() {
+ var str = "", count = 0, entity;
+ var ch = this.input[this.pos];
+ if (ch !== "&")
+ this.raise(this.pos, "Entity must start with an ampersand");
+ var startPos = ++this.pos;
+ while (this.pos < this.input.length && count++ < 10) {
+ ch = this.input[this.pos++];
+ if (ch === ";") {
+ if (str[0] === "#") {
+ if (str[1] === "x") {
+ str = str.substr(2);
+ if (HEX_NUMBER.test(str))
+ entity = String.fromCharCode(parseInt(str, 16));
+ } else {
+ str = str.substr(1);
+ if (DECIMAL_NUMBER.test(str))
+ entity = String.fromCharCode(parseInt(str, 10));
+ }
+ } else {
+ entity = XHTMLEntities[str];
+ }
+ break;
+ }
+ str += ch;
+ }
+ if (!entity) {
+ this.pos = startPos;
+ return "&";
+ }
+ return entity;
+};
+
+
+// Read a JSX identifier (valid tag or attribute name).
+//
+// Optimized version since JSX identifiers can"t contain
+// escape characters and so can be read as single slice.
+// Also assumes that first character was already checked
+// by isIdentifierStart in readToken.
+
+pp.jsxReadWord = function() {
+ var ch, start = this.pos;
+ do {
+ ch = this.input.charCodeAt(++this.pos);
+ } while (isIdentifierChar(ch) || ch === 45); // "-"
+ return this.finishToken(tt.jsxName, this.input.slice(start, this.pos));
+};
+
+// Transforms JSX element name to string.
+
+function getQualifiedJSXName(object) {
+ if (object.type === "JSXIdentifier")
+ return object.name;
+
+ if (object.type === "JSXNamespacedName")
+ return object.namespace.name + ":" + object.name.name;
+
+ if (object.type === "JSXMemberExpression")
+ return getQualifiedJSXName(object.object) + "." +
+ getQualifiedJSXName(object.property);
+}
+
+// Parse next token as JSX identifier
+
+pp.jsxParseIdentifier = function() {
+ var node = this.startNode();
+ if (this.type === tt.jsxName)
+ node.name = this.value;
+ else if (this.type.keyword)
+ node.name = this.type.keyword;
+ else
+ this.unexpected();
+ this.next();
+ return this.finishNode(node, "JSXIdentifier");
+};
+
+// Parse namespaced identifier.
+
+pp.jsxParseNamespacedName = function() {
+ var startPos = this.start, startLoc = this.startLoc;
+ var name = this.jsxParseIdentifier();
+ if (!this.eat(tt.colon)) return name;
+ var node = this.startNodeAt(startPos, startLoc);
+ node.namespace = name;
+ node.name = this.jsxParseIdentifier();
+ return this.finishNode(node, "JSXNamespacedName");
+};
+
+// Parses element name in any form - namespaced, member
+// or single identifier.
+
+pp.jsxParseElementName = function() {
+ var startPos = this.start, startLoc = this.startLoc;
+ var node = this.jsxParseNamespacedName();
+ while (this.eat(tt.dot)) {
+ var newNode = this.startNodeAt(startPos, startLoc);
+ newNode.object = node;
+ newNode.property = this.jsxParseIdentifier();
+ node = this.finishNode(newNode, "JSXMemberExpression");
+ }
+ return node;
+};
+
+// Parses any type of JSX attribute value.
+
+pp.jsxParseAttributeValue = function() {
+ switch (this.type) {
+ case tt.braceL:
+ var node = this.jsxParseExpressionContainer();
+ if (node.expression.type === "JSXEmptyExpression")
+ this.raise(node.start, "JSX attributes must only be assigned a non-empty expression");
+ return node;
+
+ case tt.jsxTagStart:
+ case tt.string:
+ return this.parseExprAtom();
+
+ default:
+ this.raise(this.start, "JSX value should be either an expression or a quoted JSX text");
+ }
+};
+
+// JSXEmptyExpression is unique type since it doesn"t actually parse anything,
+// and so it should start at the end of last read token (left brace) and finish
+// at the beginning of the next one (right brace).
+
+pp.jsxParseEmptyExpression = function() {
+ var tmp = this.start;
+ this.start = this.lastTokEnd;
+ this.lastTokEnd = tmp;
+
+ tmp = this.startLoc;
+ this.startLoc = this.lastTokEndLoc;
+ this.lastTokEndLoc = tmp;
+
+ return this.finishNode(this.startNode(), "JSXEmptyExpression");
+};
+
+// Parses JSX expression enclosed into curly brackets.
+
+
+pp.jsxParseExpressionContainer = function() {
+ var node = this.startNode();
+ this.next();
+ node.expression = this.type === tt.braceR
+ ? this.jsxParseEmptyExpression()
+ : this.parseExpression();
+ this.expect(tt.braceR);
+ return this.finishNode(node, "JSXExpressionContainer");
+};
+
+// Parses following JSX attribute name-value pair.
+
+pp.jsxParseAttribute = function() {
+ var node = this.startNode();
+ if (this.eat(tt.braceL)) {
+ this.expect(tt.ellipsis);
+ node.argument = this.parseMaybeAssign();
+ this.expect(tt.braceR);
+ return this.finishNode(node, "JSXSpreadAttribute");
+ }
+ node.name = this.jsxParseNamespacedName();
+ node.value = this.eat(tt.eq) ? this.jsxParseAttributeValue() : null;
+ return this.finishNode(node, "JSXAttribute");
+};
+
+// Parses JSX opening tag starting after "<".
+
+pp.jsxParseOpeningElementAt = function(startPos, startLoc) {
+ var node = this.startNodeAt(startPos, startLoc);
+ node.attributes = [];
+ node.name = this.jsxParseElementName();
+ while (this.type !== tt.slash && this.type !== tt.jsxTagEnd)
+ node.attributes.push(this.jsxParseAttribute());
+ node.selfClosing = this.eat(tt.slash);
+ this.expect(tt.jsxTagEnd);
+ return this.finishNode(node, "JSXOpeningElement");
+};
+
+// Parses JSX closing tag starting after "".
+
+pp.jsxParseClosingElementAt = function(startPos, startLoc) {
+ var node = this.startNodeAt(startPos, startLoc);
+ node.name = this.jsxParseElementName();
+ this.expect(tt.jsxTagEnd);
+ return this.finishNode(node, "JSXClosingElement");
+};
+
+// Parses entire JSX element, including it"s opening tag
+// (starting after "<"), attributes, contents and closing tag.
+
+pp.jsxParseElementAt = function(startPos, startLoc) {
+ var node = this.startNodeAt(startPos, startLoc);
+ var children = [];
+ var openingElement = this.jsxParseOpeningElementAt(startPos, startLoc);
+ var closingElement = null;
+
+ if (!openingElement.selfClosing) {
+ contents: for (;;) {
+ switch (this.type) {
+ case tt.jsxTagStart:
+ startPos = this.start; startLoc = this.startLoc;
+ this.next();
+ if (this.eat(tt.slash)) {
+ closingElement = this.jsxParseClosingElementAt(startPos, startLoc);
+ break contents;
+ }
+ children.push(this.jsxParseElementAt(startPos, startLoc));
+ break;
+
+ case tt.jsxText:
+ children.push(this.parseExprAtom());
+ break;
+
+ case tt.braceL:
+ children.push(this.jsxParseExpressionContainer());
+ break;
+
+ default:
+ this.unexpected();
+ }
+ }
+ if (getQualifiedJSXName(closingElement.name) !== getQualifiedJSXName(openingElement.name)) {
+ this.raise(
+ closingElement.start,
+ "Expected corresponding JSX closing tag for <" + getQualifiedJSXName(openingElement.name) + ">");
+ }
+ }
+
+ node.openingElement = openingElement;
+ node.closingElement = closingElement;
+ node.children = children;
+ if (this.type === tt.relational && this.value === "<") {
+ this.raise(this.start, "Adjacent JSX elements must be wrapped in an enclosing tag");
+ }
+ return this.finishNode(node, "JSXElement");
+};
+
+// Parses entire JSX element from current position.
+
+pp.jsxParseElement = function() {
+ var startPos = this.start, startLoc = this.startLoc;
+ this.next();
+ return this.jsxParseElementAt(startPos, startLoc);
+};
+
+export default function(instance) {
+ instance.extend("parseExprAtom", function(inner) {
+ return function(refShortHandDefaultPos) {
+ if (this.type === tt.jsxText)
+ return this.parseLiteral(this.value);
+ else if (this.type === tt.jsxTagStart)
+ return this.jsxParseElement();
+ else
+ return inner.call(this, refShortHandDefaultPos);
+ };
+ });
+
+ instance.extend("readToken", function(inner) {
+ return function(code) {
+ var context = this.curContext();
+
+ if (context === tc.j_expr) return this.jsxReadToken();
+
+ if (context === tc.j_oTag || context === tc.j_cTag) {
+ if (isIdentifierStart(code)) return this.jsxReadWord();
+
+ if (code === 62) {
+ ++this.pos;
+ return this.finishToken(tt.jsxTagEnd);
+ }
+
+ if ((code === 34 || code === 39) && context === tc.j_oTag)
+ return this.jsxReadString(code);
+ }
+
+ if (code === 60 && this.exprAllowed) {
+ ++this.pos;
+ return this.finishToken(tt.jsxTagStart);
+ }
+ return inner.call(this, code);
+ };
+ });
+
+ instance.extend("updateContext", function(inner) {
+ return function(prevType) {
+ if (this.type === tt.braceL) {
+ var curContext = this.curContext();
+ if (curContext === tc.j_oTag) this.context.push(tc.b_expr);
+ else if (curContext === tc.j_expr) this.context.push(tc.b_tmpl);
+ else inner.call(this, prevType);
+ this.exprAllowed = true;
+ } else if (this.type === tt.slash && prevType === tt.jsxTagStart) {
+ this.context.length -= 2; // do not consider JSX expr -> JSX open tag -> ... anymore
+ this.context.push(tc.j_cTag); // reconsider as closing tag context
+ this.exprAllowed = false;
+ } else {
+ return inner.call(this, prevType);
+ }
+ };
+ });
+};
diff --git a/src/plugins/jsx/xhtml.js b/src/plugins/jsx/xhtml.js
new file mode 100644
index 0000000000..232f8b1b1a
--- /dev/null
+++ b/src/plugins/jsx/xhtml.js
@@ -0,0 +1,255 @@
+export default {
+ quot: "\u0022",
+ amp: "&",
+ apos: "\u0027",
+ lt: "<",
+ gt: ">",
+ nbsp: "\u00A0",
+ iexcl: "\u00A1",
+ cent: "\u00A2",
+ pound: "\u00A3",
+ curren: "\u00A4",
+ yen: "\u00A5",
+ brvbar: "\u00A6",
+ sect: "\u00A7",
+ uml: "\u00A8",
+ copy: "\u00A9",
+ ordf: "\u00AA",
+ laquo: "\u00AB",
+ not: "\u00AC",
+ shy: "\u00AD",
+ reg: "\u00AE",
+ macr: "\u00AF",
+ deg: "\u00B0",
+ plusmn: "\u00B1",
+ sup2: "\u00B2",
+ sup3: "\u00B3",
+ acute: "\u00B4",
+ micro: "\u00B5",
+ para: "\u00B6",
+ middot: "\u00B7",
+ cedil: "\u00B8",
+ sup1: "\u00B9",
+ ordm: "\u00BA",
+ raquo: "\u00BB",
+ frac14: "\u00BC",
+ frac12: "\u00BD",
+ frac34: "\u00BE",
+ iquest: "\u00BF",
+ Agrave: "\u00C0",
+ Aacute: "\u00C1",
+ Acirc: "\u00C2",
+ Atilde: "\u00C3",
+ Auml: "\u00C4",
+ Aring: "\u00C5",
+ AElig: "\u00C6",
+ Ccedil: "\u00C7",
+ Egrave: "\u00C8",
+ Eacute: "\u00C9",
+ Ecirc: "\u00CA",
+ Euml: "\u00CB",
+ Igrave: "\u00CC",
+ Iacute: "\u00CD",
+ Icirc: "\u00CE",
+ Iuml: "\u00CF",
+ ETH: "\u00D0",
+ Ntilde: "\u00D1",
+ Ograve: "\u00D2",
+ Oacute: "\u00D3",
+ Ocirc: "\u00D4",
+ Otilde: "\u00D5",
+ Ouml: "\u00D6",
+ times: "\u00D7",
+ Oslash: "\u00D8",
+ Ugrave: "\u00D9",
+ Uacute: "\u00DA",
+ Ucirc: "\u00DB",
+ Uuml: "\u00DC",
+ Yacute: "\u00DD",
+ THORN: "\u00DE",
+ szlig: "\u00DF",
+ agrave: "\u00E0",
+ aacute: "\u00E1",
+ acirc: "\u00E2",
+ atilde: "\u00E3",
+ auml: "\u00E4",
+ aring: "\u00E5",
+ aelig: "\u00E6",
+ ccedil: "\u00E7",
+ egrave: "\u00E8",
+ eacute: "\u00E9",
+ ecirc: "\u00EA",
+ euml: "\u00EB",
+ igrave: "\u00EC",
+ iacute: "\u00ED",
+ icirc: "\u00EE",
+ iuml: "\u00EF",
+ eth: "\u00F0",
+ ntilde: "\u00F1",
+ ograve: "\u00F2",
+ oacute: "\u00F3",
+ ocirc: "\u00F4",
+ otilde: "\u00F5",
+ ouml: "\u00F6",
+ divide: "\u00F7",
+ oslash: "\u00F8",
+ ugrave: "\u00F9",
+ uacute: "\u00FA",
+ ucirc: "\u00FB",
+ uuml: "\u00FC",
+ yacute: "\u00FD",
+ thorn: "\u00FE",
+ yuml: "\u00FF",
+ OElig: "\u0152",
+ oelig: "\u0153",
+ Scaron: "\u0160",
+ scaron: "\u0161",
+ Yuml: "\u0178",
+ fnof: "\u0192",
+ circ: "\u02C6",
+ tilde: "\u02DC",
+ Alpha: "\u0391",
+ Beta: "\u0392",
+ Gamma: "\u0393",
+ Delta: "\u0394",
+ Epsilon: "\u0395",
+ Zeta: "\u0396",
+ Eta: "\u0397",
+ Theta: "\u0398",
+ Iota: "\u0399",
+ Kappa: "\u039A",
+ Lambda: "\u039B",
+ Mu: "\u039C",
+ Nu: "\u039D",
+ Xi: "\u039E",
+ Omicron: "\u039F",
+ Pi: "\u03A0",
+ Rho: "\u03A1",
+ Sigma: "\u03A3",
+ Tau: "\u03A4",
+ Upsilon: "\u03A5",
+ Phi: "\u03A6",
+ Chi: "\u03A7",
+ Psi: "\u03A8",
+ Omega: "\u03A9",
+ alpha: "\u03B1",
+ beta: "\u03B2",
+ gamma: "\u03B3",
+ delta: "\u03B4",
+ epsilon: "\u03B5",
+ zeta: "\u03B6",
+ eta: "\u03B7",
+ theta: "\u03B8",
+ iota: "\u03B9",
+ kappa: "\u03BA",
+ lambda: "\u03BB",
+ mu: "\u03BC",
+ nu: "\u03BD",
+ xi: "\u03BE",
+ omicron: "\u03BF",
+ pi: "\u03C0",
+ rho: "\u03C1",
+ sigmaf: "\u03C2",
+ sigma: "\u03C3",
+ tau: "\u03C4",
+ upsilon: "\u03C5",
+ phi: "\u03C6",
+ chi: "\u03C7",
+ psi: "\u03C8",
+ omega: "\u03C9",
+ thetasym: "\u03D1",
+ upsih: "\u03D2",
+ piv: "\u03D6",
+ ensp: "\u2002",
+ emsp: "\u2003",
+ thinsp: "\u2009",
+ zwnj: "\u200C",
+ zwj: "\u200D",
+ lrm: "\u200E",
+ rlm: "\u200F",
+ ndash: "\u2013",
+ mdash: "\u2014",
+ lsquo: "\u2018",
+ rsquo: "\u2019",
+ sbquo: "\u201A",
+ ldquo: "\u201C",
+ rdquo: "\u201D",
+ bdquo: "\u201E",
+ dagger: "\u2020",
+ Dagger: "\u2021",
+ bull: "\u2022",
+ hellip: "\u2026",
+ permil: "\u2030",
+ prime: "\u2032",
+ Prime: "\u2033",
+ lsaquo: "\u2039",
+ rsaquo: "\u203A",
+ oline: "\u203E",
+ frasl: "\u2044",
+ euro: "\u20AC",
+ image: "\u2111",
+ weierp: "\u2118",
+ real: "\u211C",
+ trade: "\u2122",
+ alefsym: "\u2135",
+ larr: "\u2190",
+ uarr: "\u2191",
+ rarr: "\u2192",
+ darr: "\u2193",
+ harr: "\u2194",
+ crarr: "\u21B5",
+ lArr: "\u21D0",
+ uArr: "\u21D1",
+ rArr: "\u21D2",
+ dArr: "\u21D3",
+ hArr: "\u21D4",
+ forall: "\u2200",
+ part: "\u2202",
+ exist: "\u2203",
+ empty: "\u2205",
+ nabla: "\u2207",
+ isin: "\u2208",
+ notin: "\u2209",
+ ni: "\u220B",
+ prod: "\u220F",
+ sum: "\u2211",
+ minus: "\u2212",
+ lowast: "\u2217",
+ radic: "\u221A",
+ prop: "\u221D",
+ infin: "\u221E",
+ ang: "\u2220",
+ and: "\u2227",
+ or: "\u2228",
+ cap: "\u2229",
+ cup: "\u222A",
+ "int": "\u222B",
+ there4: "\u2234",
+ sim: "\u223C",
+ cong: "\u2245",
+ asymp: "\u2248",
+ ne: "\u2260",
+ equiv: "\u2261",
+ le: "\u2264",
+ ge: "\u2265",
+ sub: "\u2282",
+ sup: "\u2283",
+ nsub: "\u2284",
+ sube: "\u2286",
+ supe: "\u2287",
+ oplus: "\u2295",
+ otimes: "\u2297",
+ perp: "\u22A5",
+ sdot: "\u22C5",
+ lceil: "\u2308",
+ rceil: "\u2309",
+ lfloor: "\u230A",
+ rfloor: "\u230B",
+ lang: "\u2329",
+ rang: "\u232A",
+ loz: "\u25CA",
+ spades: "\u2660",
+ clubs: "\u2663",
+ hearts: "\u2665",
+ diams: "\u2666"
+};
diff --git a/src/state.js b/src/state.js
index cfc38c90de..651e485a7e 100755
--- a/src/state.js
+++ b/src/state.js
@@ -1,79 +1,88 @@
-import {reservedWords, keywords} from "./identifier"
-import {types as tt} from "./tokentype"
-import {lineBreak} from "./whitespace"
+import {reservedWords, keywords} from "./identifier";
+import {types as tt} from "./tokentype";
+import {lineBreak} from "./whitespace";
export function Parser(options, input, startPos) {
- this.options = options
- this.sourceFile = this.options.sourceFile || null
- this.isKeyword = keywords[this.options.ecmaVersion >= 6 ? 6 : 5]
- this.isReservedWord = reservedWords[this.options.ecmaVersion]
- this.input = input
- this.loadPlugins(this.options.plugins)
+ this.options = options;
+ this.sourceFile = this.options.sourceFile || null;
+ this.isKeyword = keywords[this.options.ecmaVersion >= 6 ? 6 : 5];
+ this.isReservedWord = reservedWords[this.options.ecmaVersion];
+ this.input = input;
+ this.loadPlugins(this.options.plugins);
// Set up token state
// The current position of the tokenizer in the input.
if (startPos) {
- this.pos = startPos
- this.lineStart = Math.max(0, this.input.lastIndexOf("\n", startPos))
- this.curLine = this.input.slice(0, this.lineStart).split(lineBreak).length
+ this.pos = startPos;
+ this.lineStart = Math.max(0, this.input.lastIndexOf("\n", startPos));
+ this.curLine = this.input.slice(0, this.lineStart).split(lineBreak).length;
} else {
- this.pos = this.lineStart = 0
- this.curLine = 1
+ this.pos = this.lineStart = 0;
+ this.curLine = 1;
}
// Properties of the current token:
// Its type
- this.type = tt.eof
+ this.type = tt.eof;
// For tokens that include more information than their type, the value
- this.value = null
+ this.value = null;
// Its start and end offset
- this.start = this.end = this.pos
+ this.start = this.end = this.pos;
// And, if locations are used, the {line, column} object
// corresponding to those offsets
- this.startLoc = this.endLoc = null
+ this.startLoc = this.endLoc = this.curPosition();
// Position information for the previous token
- this.lastTokEndLoc = this.lastTokStartLoc = null
- this.lastTokStart = this.lastTokEnd = this.pos
+ this.lastTokEndLoc = this.lastTokStartLoc = null;
+ this.lastTokStart = this.lastTokEnd = this.pos;
// The context stack is used to superficially track syntactic
// context to predict whether a regular expression is allowed in a
// given position.
- this.context = this.initialContext()
- this.exprAllowed = true
+ this.context = this.initialContext();
+ this.exprAllowed = true;
// Figure out if it's a module code.
- this.inModule = this.options.sourceType === "module"
- this.strict = this.options.strictMode === false ? false : this.inModule
+ this.inModule = this.options.sourceType === "module";
+ this.strict = this.options.strictMode === false ? false : this.inModule;
// Used to signify the start of a potential arrow function
- this.potentialArrowAt = -1
+ this.potentialArrowAt = -1;
// Flags to track whether we are in a function, a generator.
- this.inFunction = this.inGenerator = false
+ this.inFunction = this.inGenerator = false;
// Labels in scope.
- this.labels = []
+ this.labels = [];
- this.decorators = []
+ this.decorators = [];
// If enabled, skip leading hashbang line.
- if (this.pos === 0 && this.options.allowHashBang && this.input.slice(0, 2) === '#!')
- this.skipLineComment(2)
+ if (this.pos === 0 && this.options.allowHashBang && this.input.slice(0, 2) === "#!") {
+ this.skipLineComment(2);
+ }
}
-Parser.prototype.extend = function(name, f) {
- this[name] = f(this[name])
-}
+Parser.prototype.extend = function (name, f) {
+ this[name] = f(this[name]);
+};
// Registered plugins
-export const plugins = {}
+export const plugins = {};
-Parser.prototype.loadPlugins = function(plugins) {
+Parser.prototype.loadPlugins = function (plugins) {
for (let name in plugins) {
- let plugin = exports.plugins[name]
- if (!plugin) throw new Error("Plugin '" + name + "' not found")
- plugin(this, plugins[name])
+ let plugin = exports.plugins[name];
+ if (!plugin) throw new Error(`Plugin '${name}' not found`);
+ plugin(this, plugins[name]);
}
-}
+};
+
+Parser.prototype.parse = function () {
+ return new Promise((resolve) => {
+ let node = this.options.program || this.startNode();
+ this.nextToken();
+ resolve(this.parseTopLevel(node));
+ });
+};
diff --git a/src/statement.js b/src/statement.js
index 30940130fa..e62a54c2d4 100755
--- a/src/statement.js
+++ b/src/statement.js
@@ -1,8 +1,8 @@
-import {types as tt} from "./tokentype"
-import {Parser} from "./state"
-import {lineBreak} from "./whitespace"
+import {types as tt} from "./tokentype";
+import {Parser} from "./state";
+import {lineBreak} from "./whitespace";
-const pp = Parser.prototype
+const pp = Parser.prototype;
// ### Statement parsing
@@ -11,23 +11,25 @@ const pp = Parser.prototype
// `program` argument. If present, the statements will be appended
// to its body instead of creating a new node.
-pp.parseTopLevel = function(node) {
- let first = true
- if (!node.body) node.body = []
+pp.parseTopLevel = function (node) {
+ let first = true;
+ if (!node.body) node.body = [];
while (this.type !== tt.eof) {
- let stmt = this.parseStatement(true, true)
- node.body.push(stmt)
- if (first && this.isUseStrict(stmt)) this.setStrict(true)
- first = false
+ let stmt = this.parseStatement(true, true);
+ node.body.push(stmt);
+ if (first) {
+ if (this.isUseStrict(stmt)) this.setStrict(true);
+ first = false;
+ }
}
- this.next()
+ this.next();
if (this.options.ecmaVersion >= 6) {
- node.sourceType = this.options.sourceType
+ node.sourceType = this.options.sourceType;
}
- return this.finishNode(node, "Program")
-}
+ return this.finishNode(node, "Program");
+};
-const loopLabel = {kind: "loop"}, switchLabel = {kind: "switch"}
+const loopLabel = {kind: "loop"}, switchLabel = {kind: "switch"};
// Parse a single statement.
//
@@ -36,51 +38,52 @@ const loopLabel = {kind: "loop"}, switchLabel = {kind: "switch"}
// `if (foo) /blah/.exec(foo)`, where looking at the previous token
// does not help.
-pp.parseStatement = function(declaration, topLevel) {
+pp.parseStatement = function (declaration, topLevel) {
if (this.type === tt.at) {
- this.parseDecorators(true)
+ this.parseDecorators(true);
}
- let starttype = this.type, node = this.startNode()
+ let starttype = this.type, node = this.startNode();
// Most types of statements are recognized by the keyword they
// start with. Many are trivial to parse, some require a bit of
// complexity.
switch (starttype) {
- case tt._break: case tt._continue: return this.parseBreakContinueStatement(node, starttype.keyword)
- case tt._debugger: return this.parseDebuggerStatement(node)
- case tt._do: return this.parseDoStatement(node)
- case tt._for: return this.parseForStatement(node)
+ case tt._break: case tt._continue: return this.parseBreakContinueStatement(node, starttype.keyword);
+ case tt._debugger: return this.parseDebuggerStatement(node);
+ case tt._do: return this.parseDoStatement(node);
+ case tt._for: return this.parseForStatement(node);
case tt._function:
- if (!declaration && this.options.ecmaVersion >= 6) this.unexpected()
- return this.parseFunctionStatement(node)
+ if (!declaration && this.options.ecmaVersion >= 6) this.unexpected();
+ return this.parseFunctionStatement(node);
case tt._class:
- if (!declaration) this.unexpected()
- this.takeDecorators(node)
- return this.parseClass(node, true)
+ if (!declaration) this.unexpected();
+ this.takeDecorators(node);
+ return this.parseClass(node, true);
- case tt._if: return this.parseIfStatement(node)
- case tt._return: return this.parseReturnStatement(node)
- case tt._switch: return this.parseSwitchStatement(node)
- case tt._throw: return this.parseThrowStatement(node)
- case tt._try: return this.parseTryStatement(node)
- case tt._let: case tt._const: if (!declaration) this.unexpected() // NOTE: falls through to _var
- case tt._var: return this.parseVarStatement(node, starttype)
- case tt._while: return this.parseWhileStatement(node)
- case tt._with: return this.parseWithStatement(node)
- case tt.braceL: return this.parseBlock()
- case tt.semi: return this.parseEmptyStatement(node)
+ case tt._if: return this.parseIfStatement(node);
+ case tt._return: return this.parseReturnStatement(node);
+ case tt._switch: return this.parseSwitchStatement(node);
+ case tt._throw: return this.parseThrowStatement(node);
+ case tt._try: return this.parseTryStatement(node);
+ case tt._let: case tt._const: if (!declaration) this.unexpected(); // NOTE: falls through to _var
+ case tt._var: return this.parseVarStatement(node, starttype);
+ case tt._while: return this.parseWhileStatement(node);
+ case tt._with: return this.parseWithStatement(node);
+ case tt.braceL: return this.parseBlock();
+ case tt.semi: return this.parseEmptyStatement(node);
case tt._export:
case tt._import:
if (!this.options.allowImportExportEverywhere) {
if (!topLevel)
- this.raise(this.start, "'import' and 'export' may only appear at the top level")
+ this.raise(this.start, "'import' and 'export' may only appear at the top level");
+
if (!this.inModule)
- this.raise(this.start, "'import' and 'export' may appear only with 'sourceType: module'")
+ this.raise(this.start, "'import' and 'export' may appear only with 'sourceType: module'");
}
- return starttype === tt._import ? this.parseImport(node) : this.parseExport(node)
+ return starttype === tt._import ? this.parseImport(node) : this.parseExport(node);
case tt.name:
if (this.options.features["es7.asyncFunctions"] && this.value === "async") {
@@ -98,21 +101,24 @@ pp.parseStatement = function(declaration, topLevel) {
// next token is a colon and the expression was a simple
// Identifier node, we switch to interpreting it as a label.
default:
- let maybeName = this.value, expr = this.parseExpression()
- if (starttype === tt.name && expr.type === "Identifier" && this.eat(tt.colon))
- return this.parseLabeledStatement(node, maybeName, expr)
- else return this.parseExpressionStatement(node, expr)
- }
-}
+ let maybeName = this.value, expr = this.parseExpression();
-pp.takeDecorators = function(node) {
+ if (starttype === tt.name && expr.type === "Identifier" && this.eat(tt.colon)) {
+ return this.parseLabeledStatement(node, maybeName, expr);
+ } else {
+ return this.parseExpressionStatement(node, expr);
+ }
+ }
+};
+
+pp.takeDecorators = function (node) {
if (this.decorators.length) {
- node.decorators = this.decorators
- this.decorators = []
+ node.decorators = this.decorators;
+ this.decorators = [];
}
-}
+};
-pp.parseDecorators = function(allowExport) {
+pp.parseDecorators = function (allowExport) {
while (this.type === tt.at) {
this.decorators.push(this.parseDecorator());
}
@@ -124,61 +130,64 @@ pp.parseDecorators = function(allowExport) {
if (this.type !== tt._class) {
this.raise(this.start, "Leading decorators must be attached to a class declaration");
}
-}
+};
-pp.parseDecorator = function(allowExport) {
+pp.parseDecorator = function () {
if (!this.options.features["es7.decorators"]) {
- this.unexpected()
+ this.unexpected();
}
- let node = this.startNode()
- this.next()
- node.expression = this.parseMaybeAssign()
- return this.finishNode(node, "Decorator")
-}
+ let node = this.startNode();
+ this.next();
+ node.expression = this.parseMaybeAssign();
+ return this.finishNode(node, "Decorator");
+};
-pp.parseBreakContinueStatement = function(node, keyword) {
- let isBreak = keyword == "break"
- this.next()
- if (this.eat(tt.semi) || this.insertSemicolon()) node.label = null
- else if (this.type !== tt.name) this.unexpected()
- else {
- node.label = this.parseIdent()
- this.semicolon()
+pp.parseBreakContinueStatement = function (node, keyword) {
+ let isBreak = keyword === "break";
+ this.next();
+
+ if (this.eat(tt.semi) || this.insertSemicolon()) {
+ node.label = null;
+ } else if (this.type !== tt.name) {
+ this.unexpected();
+ } else {
+ node.label = this.parseIdent();
+ this.semicolon();
}
// Verify that there is an actual destination to break or
// continue to.
for (var i = 0; i < this.labels.length; ++i) {
- let lab = this.labels[i]
+ let lab = this.labels[i];
if (node.label == null || lab.name === node.label.name) {
- if (lab.kind != null && (isBreak || lab.kind === "loop")) break
- if (node.label && isBreak) break
+ if (lab.kind != null && (isBreak || lab.kind === "loop")) break;
+ if (node.label && isBreak) break;
}
}
- if (i === this.labels.length) this.raise(node.start, "Unsyntactic " + keyword)
- return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement")
-}
+ if (i === this.labels.length) this.raise(node.start, "Unsyntactic " + keyword);
+ return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement");
+};
-pp.parseDebuggerStatement = function(node) {
- this.next()
- this.semicolon()
- return this.finishNode(node, "DebuggerStatement")
-}
+pp.parseDebuggerStatement = function (node) {
+ this.next();
+ this.semicolon();
+ return this.finishNode(node, "DebuggerStatement");
+};
-pp.parseDoStatement = function(node) {
- let start = this.markPosition()
- this.next()
- this.labels.push(loopLabel)
- node.body = this.parseStatement(false)
- this.labels.pop()
- this.expect(tt._while)
- node.test = this.parseParenExpression()
- if (this.options.ecmaVersion >= 6)
- this.eat(tt.semi)
- else
- this.semicolon()
- return this.finishNode(node, "DoWhileStatement")
-}
+pp.parseDoStatement = function (node) {
+ this.next();
+ this.labels.push(loopLabel);
+ node.body = this.parseStatement(false);
+ this.labels.pop();
+ this.expect(tt._while);
+ node.test = this.parseParenExpression();
+ if (this.options.ecmaVersion >= 6) {
+ this.eat(tt.semi);
+ } else {
+ this.semicolon();
+ }
+ return this.finishNode(node, "DoWhileStatement");
+};
// Disambiguating between a `for` and a `for`/`in` or `for`/`of`
// loop is non-trivial. Basically, we have to parse the init `var`
@@ -188,575 +197,610 @@ pp.parseDoStatement = function(node) {
// part (semicolon immediately after the opening parenthesis), it
// is a regular `for` loop.
-pp.parseForStatement = function(node) {
- this.next()
- this.labels.push(loopLabel)
- this.expect(tt.parenL)
- if (this.type === tt.semi) return this.parseFor(node, null)
+pp.parseForStatement = function (node) {
+ this.next();
+ this.labels.push(loopLabel);
+ this.expect(tt.parenL);
+
+ if (this.type === tt.semi) {
+ return this.parseFor(node, null);
+ }
+
if (this.type === tt._var || this.type === tt._let || this.type === tt._const) {
- let init = this.startNode(), varKind = this.type
- this.next()
- this.parseVar(init, true, varKind)
- this.finishNode(init, "VariableDeclaration")
+ let init = this.startNode(), varKind = this.type;
+ this.next();
+ this.parseVar(init, true, varKind);
+ this.finishNode(init, "VariableDeclaration");
if ((this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) && init.declarations.length === 1 &&
!(varKind !== tt._var && init.declarations[0].init))
- return this.parseForIn(node, init)
- return this.parseFor(node, init)
+ return this.parseForIn(node, init);
+ return this.parseFor(node, init);
}
- let refShorthandDefaultPos = {start: 0}
- let init = this.parseExpression(true, refShorthandDefaultPos)
+
+ let refShorthandDefaultPos = {start: 0};
+ let init = this.parseExpression(true, refShorthandDefaultPos);
if (this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) {
- this.toAssignable(init)
- this.checkLVal(init)
- return this.parseForIn(node, init)
+ this.toAssignable(init);
+ this.checkLVal(init);
+ return this.parseForIn(node, init);
} else if (refShorthandDefaultPos.start) {
- this.unexpected(refShorthandDefaultPos.start)
+ this.unexpected(refShorthandDefaultPos.start);
}
- return this.parseFor(node, init)
-}
+ return this.parseFor(node, init);
+};
-pp.parseFunctionStatement = function(node) {
- this.next()
- return this.parseFunction(node, true)
-}
+pp.parseFunctionStatement = function (node) {
+ this.next();
+ return this.parseFunction(node, true);
+};
-pp.parseIfStatement = function(node) {
- this.next()
- node.test = this.parseParenExpression()
- node.consequent = this.parseStatement(false)
- node.alternate = this.eat(tt._else) ? this.parseStatement(false) : null
- return this.finishNode(node, "IfStatement")
-}
+pp.parseIfStatement = function (node) {
+ this.next();
+ node.test = this.parseParenExpression();
+ node.consequent = this.parseStatement(false);
+ node.alternate = this.eat(tt._else) ? this.parseStatement(false) : null;
+ return this.finishNode(node, "IfStatement");
+};
-pp.parseReturnStatement = function(node) {
- if (!this.inFunction && !this.options.allowReturnOutsideFunction)
- this.raise(this.start, "'return' outside of function")
- this.next()
+pp.parseReturnStatement = function (node) {
+ if (!this.inFunction && !this.options.allowReturnOutsideFunction) {
+ this.raise(this.start, "'return' outside of function");
+ }
+
+ this.next();
// In `return` (and `break`/`continue`), the keywords with
// optional arguments, we eagerly look for a semicolon or the
// possibility to insert one.
- if (this.eat(tt.semi) || this.insertSemicolon()) node.argument = null
- else { node.argument = this.parseExpression(); this.semicolon() }
- return this.finishNode(node, "ReturnStatement")
-}
+ if (this.eat(tt.semi) || this.insertSemicolon()) {
+ node.argument = null;
+ } else {
+ node.argument = this.parseExpression();
+ this.semicolon();
+ }
-pp.parseSwitchStatement = function(node) {
- this.next()
- node.discriminant = this.parseParenExpression()
- node.cases = []
- this.expect(tt.braceL)
- this.labels.push(switchLabel)
+ return this.finishNode(node, "ReturnStatement");
+};
+
+pp.parseSwitchStatement = function (node) {
+ this.next();
+ node.discriminant = this.parseParenExpression();
+ node.cases = [];
+ this.expect(tt.braceL);
+ this.labels.push(switchLabel);
// Statements under must be grouped (by label) in SwitchCase
// nodes. `cur` is used to keep the node that we are currently
// adding statements to.
- for (var cur, sawDefault; this.type != tt.braceR;) {
+ for (var cur, sawDefault; this.type !== tt.braceR; ) {
if (this.type === tt._case || this.type === tt._default) {
- let isCase = this.type === tt._case
- if (cur) this.finishNode(cur, "SwitchCase")
- node.cases.push(cur = this.startNode())
- cur.consequent = []
- this.next()
+ let isCase = this.type === tt._case;
+ if (cur) this.finishNode(cur, "SwitchCase");
+ node.cases.push(cur = this.startNode());
+ cur.consequent = [];
+ this.next();
if (isCase) {
- cur.test = this.parseExpression()
+ cur.test = this.parseExpression();
} else {
- if (sawDefault) this.raise(this.lastTokStart, "Multiple default clauses")
- sawDefault = true
- cur.test = null
+ if (sawDefault) this.raise(this.lastTokStart, "Multiple default clauses");
+ sawDefault = true;
+ cur.test = null;
}
- this.expect(tt.colon)
+ this.expect(tt.colon);
} else {
- if (!cur) this.unexpected()
- cur.consequent.push(this.parseStatement(true))
+ if (!cur) this.unexpected();
+ cur.consequent.push(this.parseStatement(true));
}
}
- if (cur) this.finishNode(cur, "SwitchCase")
- this.next() // Closing brace
- this.labels.pop()
- return this.finishNode(node, "SwitchStatement")
-}
+ if (cur) this.finishNode(cur, "SwitchCase");
+ this.next(); // Closing brace
+ this.labels.pop();
+ return this.finishNode(node, "SwitchStatement");
+};
-pp.parseThrowStatement = function(node) {
- this.next()
+pp.parseThrowStatement = function (node) {
+ this.next();
if (lineBreak.test(this.input.slice(this.lastTokEnd, this.start)))
- this.raise(this.lastTokEnd, "Illegal newline after throw")
- node.argument = this.parseExpression()
- this.semicolon()
- return this.finishNode(node, "ThrowStatement")
-}
+ this.raise(this.lastTokEnd, "Illegal newline after throw");
+ node.argument = this.parseExpression();
+ this.semicolon();
+ return this.finishNode(node, "ThrowStatement");
+};
// Reused empty array added for node fields that are always empty.
-const empty = []
+var empty = [];
-pp.parseTryStatement = function(node) {
- this.next()
- node.block = this.parseBlock()
- node.handler = null
+pp.parseTryStatement = function (node) {
+ this.next();
+ node.block = this.parseBlock();
+ node.handler = null;
if (this.type === tt._catch) {
- let clause = this.startNode()
- this.next()
- this.expect(tt.parenL)
- clause.param = this.parseBindingAtom()
- this.checkLVal(clause.param, true)
- this.expect(tt.parenR)
- clause.guard = null
- clause.body = this.parseBlock()
- node.handler = this.finishNode(clause, "CatchClause")
+ let clause = this.startNode();
+ this.next();
+ this.expect(tt.parenL);
+ clause.param = this.parseBindingAtom();
+ this.checkLVal(clause.param, true);
+ this.expect(tt.parenR);
+ clause.body = this.parseBlock();
+ node.handler = this.finishNode(clause, "CatchClause");
}
- node.guardedHandlers = empty
- node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null
- if (!node.handler && !node.finalizer)
- this.raise(node.start, "Missing catch or finally clause")
- return this.finishNode(node, "TryStatement")
-}
-pp.parseVarStatement = function(node, kind) {
- this.next()
- this.parseVar(node, false, kind)
- this.semicolon()
- return this.finishNode(node, "VariableDeclaration")
-}
+ node.guardedHandlers = empty;
+ node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null;
-pp.parseWhileStatement = function(node) {
- this.next()
- node.test = this.parseParenExpression()
- this.labels.push(loopLabel)
- node.body = this.parseStatement(false)
- this.labels.pop()
- return this.finishNode(node, "WhileStatement")
-}
+ if (!node.handler && !node.finalizer) {
+ this.raise(node.start, "Missing catch or finally clause");
+ }
-pp.parseWithStatement = function(node) {
- if (this.strict) this.raise(this.start, "'with' in strict mode")
- this.next()
- node.object = this.parseParenExpression()
- node.body = this.parseStatement(false)
- return this.finishNode(node, "WithStatement")
-}
+ return this.finishNode(node, "TryStatement");
+};
-pp.parseEmptyStatement = function(node) {
- this.next()
- return this.finishNode(node, "EmptyStatement")
-}
+pp.parseVarStatement = function (node, kind) {
+ this.next();
+ this.parseVar(node, false, kind);
+ this.semicolon();
+ return this.finishNode(node, "VariableDeclaration");
+};
-pp.parseLabeledStatement = function(node, maybeName, expr) {
- for (let i = 0; i < this.labels.length; ++i)
- if (this.labels[i].name === maybeName) this.raise(expr.start, "Label '" + maybeName + "' is already declared")
- let kind = this.type.isLoop ? "loop" : this.type === tt._switch ? "switch" : null
+pp.parseWhileStatement = function (node) {
+ this.next();
+ node.test = this.parseParenExpression();
+ this.labels.push(loopLabel);
+ node.body = this.parseStatement(false);
+ this.labels.pop();
+ return this.finishNode(node, "WhileStatement");
+};
+
+pp.parseWithStatement = function (node) {
+ if (this.strict) this.raise(this.start, "'with' in strict mode");
+ this.next();
+ node.object = this.parseParenExpression();
+ node.body = this.parseStatement(false);
+ return this.finishNode(node, "WithStatement");
+};
+
+pp.parseEmptyStatement = function (node) {
+ this.next();
+ return this.finishNode(node, "EmptyStatement");
+};
+
+pp.parseLabeledStatement = function (node, maybeName, expr) {
+ for (let i = 0; i < this.labels.length; ++i){
+ if (this.labels[i].name === maybeName) {
+ this.raise(expr.start, `Label '${maybeName}' is already declared`);
+ }
+ }
+
+ let kind = this.type.isLoop ? "loop" : this.type === tt._switch ? "switch" : null;
for (let i = this.labels.length - 1; i >= 0; i--) {
- let label = this.labels[i]
- if (label.statementStart == node.start) {
+ let label = this.labels[i];
+ if (label.statementStart === node.start) {
label.statementStart = this.start;
label.kind = kind;
- } else break;
+ } else {
+ break;
+ }
}
- this.labels.push({name: maybeName, kind: kind, statementStart: this.start})
- node.body = this.parseStatement(true)
- this.labels.pop()
- node.label = expr
- return this.finishNode(node, "LabeledStatement")
-}
-pp.parseExpressionStatement = function(node, expr) {
- node.expression = expr
- this.semicolon()
- return this.finishNode(node, "ExpressionStatement")
-}
+ this.labels.push({name: maybeName, kind: kind, statementStart: this.start});
+ node.body = this.parseStatement(true);
+ this.labels.pop();
+ node.label = expr;
+ return this.finishNode(node, "LabeledStatement");
+};
+
+pp.parseExpressionStatement = function (node, expr) {
+ node.expression = expr;
+ this.semicolon();
+ return this.finishNode(node, "ExpressionStatement");
+};
// Parse a semicolon-enclosed block of statements, handling `"use
// strict"` declarations when `allowStrict` is true (used for
// function bodies).
-pp.parseBlock = function(allowStrict) {
- let node = this.startNode(), first = true, oldStrict
- node.body = []
- this.expect(tt.braceL)
+pp.parseBlock = function (allowStrict) {
+ let node = this.startNode(), first = true, oldStrict;
+ node.body = [];
+ this.expect(tt.braceL);
while (!this.eat(tt.braceR)) {
- let stmt = this.parseStatement(true)
- node.body.push(stmt)
+ let stmt = this.parseStatement(true);
+ node.body.push(stmt);
if (first && allowStrict && this.isUseStrict(stmt)) {
- oldStrict = this.strict
- this.setStrict(this.strict = true)
+ oldStrict = this.strict;
+ this.setStrict(this.strict = true);
}
- first = false
+ first = false;
}
- if (oldStrict === false) this.setStrict(false)
- return this.finishNode(node, "BlockStatement")
-}
+ if (oldStrict === false) this.setStrict(false);
+ return this.finishNode(node, "BlockStatement");
+};
// Parse a regular `for` loop. The disambiguation code in
// `parseStatement` will already have parsed the init statement or
// expression.
-pp.parseFor = function(node, init) {
- node.init = init
- this.expect(tt.semi)
- node.test = this.type === tt.semi ? null : this.parseExpression()
- this.expect(tt.semi)
- node.update = this.type === tt.parenR ? null : this.parseExpression()
- this.expect(tt.parenR)
- node.body = this.parseStatement(false)
- this.labels.pop()
- return this.finishNode(node, "ForStatement")
-}
+pp.parseFor = function (node, init) {
+ node.init = init;
+ this.expect(tt.semi);
+ node.test = this.type === tt.semi ? null : this.parseExpression();
+ this.expect(tt.semi);
+ node.update = this.type === tt.parenR ? null : this.parseExpression();
+ this.expect(tt.parenR);
+ node.body = this.parseStatement(false);
+ this.labels.pop();
+ return this.finishNode(node, "ForStatement");
+};
// Parse a `for`/`in` and `for`/`of` loop, which are almost
// same from parser's perspective.
-pp.parseForIn = function(node, init) {
- let type = this.type === tt._in ? "ForInStatement" : "ForOfStatement"
- this.next()
- node.left = init
- node.right = this.parseExpression()
- this.expect(tt.parenR)
- node.body = this.parseStatement(false)
- this.labels.pop()
- return this.finishNode(node, type)
-}
+pp.parseForIn = function (node, init) {
+ let type = this.type === tt._in ? "ForInStatement" : "ForOfStatement";
+ this.next();
+ node.left = init;
+ node.right = this.parseExpression();
+ this.expect(tt.parenR);
+ node.body = this.parseStatement(false);
+ this.labels.pop();
+ return this.finishNode(node, type);
+};
// Parse a list of variable declarations.
-pp.parseVar = function(node, isFor, kind) {
- node.declarations = []
- node.kind = kind.keyword
+pp.parseVar = function (node, isFor, kind) {
+ node.declarations = [];
+ node.kind = kind.keyword;
for (;;) {
- let decl = this.startNode()
- this.parseVarHead(decl)
+ let decl = this.startNode();
+ this.parseVarHead(decl);
if (this.eat(tt.eq)) {
- decl.init = this.parseMaybeAssign(isFor)
+ decl.init = this.parseMaybeAssign(isFor);
} else if (kind === tt._const && !(this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of")))) {
- this.unexpected()
- } else if (decl.id.type != "Identifier" && !(isFor && (this.type === tt._in || this.isContextual("of")))) {
- this.raise(this.lastTokEnd, "Complex binding patterns require an initialization value")
+ this.unexpected();
+ } else if (decl.id.type !== "Identifier" && !(isFor && (this.type === tt._in || this.isContextual("of")))) {
+ this.raise(this.lastTokEnd, "Complex binding patterns require an initialization value");
} else {
- decl.init = null
+ decl.init = null;
}
- node.declarations.push(this.finishNode(decl, "VariableDeclarator"))
- if (!this.eat(tt.comma)) break
+ node.declarations.push(this.finishNode(decl, "VariableDeclarator"));
+ if (!this.eat(tt.comma)) break;
}
- return node
-}
+ return node;
+};
pp.parseVarHead = function (decl) {
- decl.id = this.parseBindingAtom()
- this.checkLVal(decl.id, true)
-}
+ decl.id = this.parseBindingAtom();
+ this.checkLVal(decl.id, true);
+};
// Parse a function declaration or literal (depending on the
// `isStatement` parameter).
-pp.parseFunction = function(node, isStatement, allowExpressionBody, isAsync) {
- this.initFunction(node, isAsync)
- if (this.options.ecmaVersion >= 6)
- node.generator = this.eat(tt.star)
- if (isStatement || this.type === tt.name)
- node.id = this.parseIdent()
- this.parseFunctionParams(node);
- this.parseFunctionBody(node, allowExpressionBody)
- return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression")
-}
+pp.parseFunction = function (node, isStatement, allowExpressionBody, isAsync) {
+ this.initFunction(node, isAsync);
+ if (this.options.ecmaVersion >= 6) {
+ node.generator = this.eat(tt.star);
+ }
-pp.parseFunctionParams = function(node) {
- this.expect(tt.parenL)
- node.params = this.parseBindingList(tt.parenR, false, this.options.features["es7.trailingFunctionCommas"])
-}
+ if (isStatement || this.type === tt.name) {
+ node.id = this.parseIdent();
+ }
+
+ this.parseFunctionParams(node);
+ this.parseFunctionBody(node, allowExpressionBody);
+ return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
+};
+
+pp.parseFunctionParams = function (node) {
+ this.expect(tt.parenL);
+ node.params = this.parseBindingList(tt.parenR, false, this.options.features["es7.trailingFunctionCommas"]);
+};
// Parse a class declaration or literal (depending on the
// `isStatement` parameter).
-pp.parseClass = function(node, isStatement) {
- this.next()
- this.parseClassId(node, isStatement)
- this.parseClassSuper(node)
- var classBody = this.startNode()
- let hadConstructor = false
- classBody.body = []
- this.expect(tt.braceL)
- let decorators = []
+pp.parseClass = function (node, isStatement) {
+ this.next();
+ this.parseClassId(node, isStatement);
+ this.parseClassSuper(node);
+ var classBody = this.startNode();
+ let hadConstructor = false;
+ classBody.body = [];
+ this.expect(tt.braceL);
+ let decorators = [];
while (!this.eat(tt.braceR)) {
- if (this.eat(tt.semi)) continue
+ if (this.eat(tt.semi)) continue;
if (this.type === tt.at) {
- decorators.push(this.parseDecorator())
- continue
+ decorators.push(this.parseDecorator());
+ continue;
}
- var method = this.startNode()
+ var method = this.startNode();
if (decorators.length) {
- method.decorators = decorators
- decorators = []
+ method.decorators = decorators;
+ decorators = [];
}
- let isMaybeStatic = this.type === tt.name && this.value === "static"
- var isGenerator = this.eat(tt.star), isAsync = false
- this.parsePropertyName(method)
- method.static = isMaybeStatic && this.type !== tt.parenL
+ let isMaybeStatic = this.type === tt.name && this.value === "static";
+ var isGenerator = this.eat(tt.star), isAsync = false;
+ this.parsePropertyName(method);
+ method.static = isMaybeStatic && this.type !== tt.parenL;
if (method.static) {
- if (isGenerator) this.unexpected()
- isGenerator = this.eat(tt.star)
- this.parsePropertyName(method)
+ if (isGenerator) this.unexpected();
+ isGenerator = this.eat(tt.star);
+ this.parsePropertyName(method);
}
if (!isGenerator && method.key.type === "Identifier" && !method.computed && this.isClassProperty()) {
- classBody.body.push(this.parseClassProperty(method))
- continue
+ classBody.body.push(this.parseClassProperty(method));
+ continue;
}
if (this.options.features["es7.asyncFunctions"] && this.type !== tt.parenL &&
!method.computed && method.key.type === "Identifier" && method.key.name === "async") {
- isAsync = true
- this.parsePropertyName(method)
+ isAsync = true;
+ this.parsePropertyName(method);
}
- let isGetSet = false
- method.kind = "method"
+ let isGetSet = false;
+ method.kind = "method";
if (!method.computed) {
- let {key} = method
+ let {key} = method;
if (!isAsync && !isGenerator && key.type === "Identifier" && this.type !== tt.parenL && (key.name === "get" || key.name === "set")) {
- isGetSet = true
- method.kind = key.name
- key = this.parsePropertyName(method)
+ isGetSet = true;
+ method.kind = key.name;
+ key = this.parsePropertyName(method);
}
if (!method.static && (key.type === "Identifier" && key.name === "constructor" ||
key.type === "Literal" && key.value === "constructor")) {
- if (hadConstructor) this.raise(key.start, "Duplicate constructor in the same class")
- if (isGetSet) this.raise(key.start, "Constructor can't have get/set modifier")
- if (isGenerator) this.raise(key.start, "Constructor can't be a generator")
- if (isAsync) this.raise(key.start, "Constructor can't be an async function")
- method.kind = "constructor"
- hadConstructor = true
+ if (hadConstructor) this.raise(key.start, "Duplicate constructor in the same class");
+ if (isGetSet) this.raise(key.start, "Constructor can't have get/set modifier");
+ if (isGenerator) this.raise(key.start, "Constructor can't be a generator");
+ if (isAsync) this.raise(key.start, "Constructor can't be an async function");
+ method.kind = "constructor";
+ hadConstructor = true;
}
}
if (method.kind === "constructor" && method.decorators) {
- this.raise(method.start, "You can't attach decorators to a class constructor")
+ this.raise(method.start, "You can't attach decorators to a class constructor");
}
- this.parseClassMethod(classBody, method, isGenerator, isAsync)
+ this.parseClassMethod(classBody, method, isGenerator, isAsync);
if (isGetSet) {
- let paramCount = method.kind === "get" ? 0 : 1
+ let paramCount = method.kind === "get" ? 0 : 1;
if (method.value.params.length !== paramCount) {
- let start = method.value.start
- if (method.kind === "get")
+ let start = method.value.start;
+ if (method.kind === "get") {
this.raise(start, "getter should have no params");
- else
- this.raise(start, "setter should have exactly one param")
+ } else {
+ this.raise(start, "setter should have exactly one param");
+ }
}
}
}
+
if (decorators.length) {
this.raise(this.start, "You have trailing decorators with no method");
}
- node.body = this.finishNode(classBody, "ClassBody")
- return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression")
-}
-pp.isClassProperty = function() {
- return this.type === tt.eq || (this.type === tt.semi || this.canInsertSemicolon())
-}
+ node.body = this.finishNode(classBody, "ClassBody");
+ return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression");
+};
-pp.parseClassProperty = function(node) {
+pp.isClassProperty = function () {
+ return this.type === tt.eq || (this.type === tt.semi || this.canInsertSemicolon());
+};
+
+pp.parseClassProperty = function (node) {
if (this.type === tt.eq) {
- if (!this.options.features["es7.classProperties"]) this.unexpected()
- this.next()
+ if (!this.options.features["es7.classProperties"]) this.unexpected();
+ this.next();
node.value = this.parseMaybeAssign();
} else {
node.value = null;
}
- this.semicolon()
- return this.finishNode(node, "ClassProperty")
-}
+ this.semicolon();
+ return this.finishNode(node, "ClassProperty");
+};
-pp.parseClassMethod = function(classBody, method, isGenerator, isAsync) {
- method.value = this.parseMethod(isGenerator, isAsync)
- classBody.body.push(this.finishNode(method, "MethodDefinition"))
-}
+pp.parseClassMethod = function (classBody, method, isGenerator, isAsync) {
+ method.value = this.parseMethod(isGenerator, isAsync);
+ classBody.body.push(this.finishNode(method, "MethodDefinition"));
+};
-pp.parseClassId = function(node, isStatement) {
- node.id = this.type === tt.name ? this.parseIdent() : isStatement ? this.unexpected() : null
-}
+pp.parseClassId = function (node, isStatement) {
+ node.id = this.type === tt.name ? this.parseIdent() : isStatement ? this.unexpected() : null;
+};
-pp.parseClassSuper = function(node) {
- node.superClass = this.eat(tt._extends) ? this.parseExprSubscripts() : null
-}
+pp.parseClassSuper = function (node) {
+ node.superClass = this.eat(tt._extends) ? this.parseExprSubscripts() : null;
+};
// Parses module export declaration.
-pp.parseExport = function(node) {
- this.next()
+pp.parseExport = function (node) {
+ this.next();
// export * from '...'
if (this.type === tt.star) {
- let specifier = this.startNode()
- this.next()
+ let specifier = this.startNode();
+ this.next();
if (this.options.features["es7.exportExtensions"] && this.eatContextual("as")) {
- specifier.exported = this.parseIdent()
- node.specifiers = [this.finishNode(specifier, "ExportNamespaceSpecifier")]
- this.parseExportSpecifiersMaybe(node)
- this.parseExportFrom(node)
+ specifier.exported = this.parseIdent();
+ node.specifiers = [this.finishNode(specifier, "ExportNamespaceSpecifier")];
+ this.parseExportSpecifiersMaybe(node);
+ this.parseExportFrom(node);
} else {
- this.parseExportFrom(node)
- return this.finishNode(node, "ExportAllDeclaration")
+ this.parseExportFrom(node);
+ return this.finishNode(node, "ExportAllDeclaration");
}
} else if (this.options.features["es7.exportExtensions"] && this.isExportDefaultSpecifier()) {
- let specifier = this.startNode()
- specifier.exported = this.parseIdent(true)
- node.specifiers = [this.finishNode(specifier, "ExportDefaultSpecifier")]
+ let specifier = this.startNode();
+ specifier.exported = this.parseIdent(true);
+ node.specifiers = [this.finishNode(specifier, "ExportDefaultSpecifier")];
if (this.type === tt.comma && this.lookahead().type === tt.star) {
- this.expect(tt.comma)
- let specifier = this.startNode()
- this.expect(tt.star)
- this.expectContextual("as")
- specifier.exported = this.parseIdent()
- node.specifiers.push(this.finishNode(specifier, "ExportNamespaceSpecifier"))
+ this.expect(tt.comma);
+ let specifier = this.startNode();
+ this.expect(tt.star);
+ this.expectContextual("as");
+ specifier.exported = this.parseIdent();
+ node.specifiers.push(this.finishNode(specifier, "ExportNamespaceSpecifier"));
} else {
- this.parseExportSpecifiersMaybe(node)
+ this.parseExportSpecifiersMaybe(node);
}
- this.parseExportFrom(node)
+ this.parseExportFrom(node);
} else if (this.eat(tt._default)) { // export default ...
- let expr = this.parseMaybeAssign()
- let needsSemi = true
- if (expr.type == "FunctionExpression" ||
- expr.type == "ClassExpression") {
- needsSemi = false
+ let expr = this.parseMaybeAssign();
+ let needsSemi = true;
+ if (expr.type === "FunctionExpression" || expr.type === "ClassExpression") {
+ needsSemi = false;
if (expr.id) {
- expr.type = expr.type == "FunctionExpression"
- ? "FunctionDeclaration"
- : "ClassDeclaration"
+ expr.type = expr.type === "FunctionExpression" ? "FunctionDeclaration" : "ClassDeclaration";
}
}
- node.declaration = expr
- if (needsSemi) this.semicolon()
- this.checkExport(node)
- return this.finishNode(node, "ExportDefaultDeclaration")
+ node.declaration = expr;
+ if (needsSemi) this.semicolon();
+ this.checkExport(node);
+ return this.finishNode(node, "ExportDefaultDeclaration");
} else if (this.type.keyword || this.shouldParseExportDeclaration()) {
- node.declaration = this.parseStatement(true)
- node.specifiers = []
- node.source = null
+ node.declaration = this.parseStatement(true);
+ node.specifiers = [];
+ node.source = null;
} else { // export { x, y as z } [from '...']
- node.declaration = null
- node.specifiers = this.parseExportSpecifiers()
+ node.declaration = null;
+ node.specifiers = this.parseExportSpecifiers();
if (this.eatContextual("from")) {
- node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected()
+ node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected();
} else {
- node.source = null
+ node.source = null;
}
- this.semicolon()
+ this.semicolon();
}
- this.checkExport(node)
- return this.finishNode(node, "ExportNamedDeclaration")
-}
+ this.checkExport(node);
+ return this.finishNode(node, "ExportNamedDeclaration");
+};
pp.isExportDefaultSpecifier = function () {
if (this.type === tt.name) {
- return this.value !== "type" && this.value !== "async"
+ return this.value !== "type" && this.value !== "async";
}
if (this.type !== tt._default) {
- return false
+ return false;
}
- var lookahead = this.lookahead()
- return lookahead.type === tt.comma || (lookahead.type === tt.name && lookahead.value === "from")
-}
+ var lookahead = this.lookahead();
+ return lookahead.type === tt.comma || (lookahead.type === tt.name && lookahead.value === "from");
+};
pp.parseExportSpecifiersMaybe = function (node) {
if (this.eat(tt.comma)) {
- node.specifiers = node.specifiers.concat(this.parseExportSpecifiers())
+ node.specifiers = node.specifiers.concat(this.parseExportSpecifiers());
}
-}
+};
-pp.parseExportFrom = function(node) {
- this.expectContextual("from")
- node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected()
- this.semicolon()
- this.checkExport(node)
-}
+pp.parseExportFrom = function (node) {
+ this.expectContextual("from");
+ node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected();
+ this.semicolon();
+ this.checkExport(node);
+};
-pp.shouldParseExportDeclaration = function() {
- return this.options.features["es7.asyncFunctions"] && this.isContextual("async")
-}
+pp.shouldParseExportDeclaration = function () {
+ return this.options.features["es7.asyncFunctions"] && this.isContextual("async");
+};
-pp.checkExport = function(node) {
+pp.checkExport = function (node) {
if (this.decorators.length) {
- var isClass = node.declaration && (node.declaration.type === "ClassDeclaration" || node.declaration.type === "ClassExpression")
+ var isClass = node.declaration && (node.declaration.type === "ClassDeclaration" || node.declaration.type === "ClassExpression");
if (!node.declaration || !isClass) {
this.raise(node.start, "You can only use decorators on an export when exporting a class");
}
- this.takeDecorators(node.declaration)
+ this.takeDecorators(node.declaration);
}
-}
+};
// Parses a comma-separated list of module exports.
-pp.parseExportSpecifiers = function() {
- let nodes = [], first = true
+pp.parseExportSpecifiers = function () {
+ let nodes = [], first = true;
// export { x, y as z } [from '...']
- this.expect(tt.braceL)
- while (!this.eat(tt.braceR)) {
- if (!first) {
- this.expect(tt.comma)
- if (this.afterTrailingComma(tt.braceR)) break
- } else first = false
+ this.expect(tt.braceL);
- let node = this.startNode()
- node.local = this.parseIdent(this.type === tt._default)
- node.exported = this.eatContextual("as") ? this.parseIdent(true) : node.local
- nodes.push(this.finishNode(node, "ExportSpecifier"))
+ while (!this.eat(tt.braceR)) {
+ if (first) {
+ first = false;
+ } else {
+ this.expect(tt.comma);
+ if (this.afterTrailingComma(tt.braceR)) break;
+ }
+
+ let node = this.startNode();
+ node.local = this.parseIdent(this.type === tt._default);
+ node.exported = this.eatContextual("as") ? this.parseIdent(true) : node.local;
+ nodes.push(this.finishNode(node, "ExportSpecifier"));
}
- return nodes
-}
+
+ return nodes;
+};
// Parses import declaration.
-pp.parseImport = function(node) {
- this.next()
+pp.parseImport = function (node) {
+ this.next();
+
// import '...'
if (this.type === tt.string) {
- node.specifiers = empty
- node.source = this.parseExprAtom()
+ node.specifiers = [];
+ node.source = this.parseExprAtom();
} else {
- node.specifiers = []
- this.parseImportSpecifiers(node)
- this.expectContextual("from")
- node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected()
+ node.specifiers = [];
+ this.parseImportSpecifiers(node);
+ this.expectContextual("from");
+ node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected();
}
- this.semicolon()
- return this.finishNode(node, "ImportDeclaration")
-}
+ this.semicolon();
+ return this.finishNode(node, "ImportDeclaration");
+};
// Parses a comma-separated list of module imports.
-pp.parseImportSpecifiers = function(node) {
- var first = true
+pp.parseImportSpecifiers = function (node) {
+ var first = true;
if (this.type === tt.name) {
// import defaultObj, { x, y as z } from '...'
- var start = this.markPosition()
- node.specifiers.push(this.parseImportSpecifierDefault(this.parseIdent(), start))
- if (!this.eat(tt.comma)) return
+ var startPos = this.start, startLoc = this.startLoc;
+ node.specifiers.push(this.parseImportSpecifierDefault(this.parseIdent(), startPos, startLoc));
+ if (!this.eat(tt.comma)) return;
}
+
if (this.type === tt.star) {
- var specifier = this.startNode()
- this.next()
- this.expectContextual("as")
- specifier.local = this.parseIdent()
- this.checkLVal(specifier.local, true)
- node.specifiers.push(this.finishNode(specifier, "ImportNamespaceSpecifier"))
- return
+ let specifier = this.startNode();
+ this.next();
+ this.expectContextual("as");
+ specifier.local = this.parseIdent();
+ this.checkLVal(specifier.local, true);
+ node.specifiers.push(this.finishNode(specifier, "ImportNamespaceSpecifier"));
+ return;
}
- this.expect(tt.braceL)
+
+ this.expect(tt.braceL);
while (!this.eat(tt.braceR)) {
- if (!first) {
- this.expect(tt.comma)
- if (this.afterTrailingComma(tt.braceR)) break
- } else first = false
+ if (first) {
+ first = false;
+ } else {
+ this.expect(tt.comma);
+ if (this.afterTrailingComma(tt.braceR)) break;
+ }
- var specifier = this.startNode()
- specifier.imported = this.parseIdent(true)
- specifier.local = this.eatContextual("as") ? this.parseIdent() : specifier.imported
- this.checkLVal(specifier.local, true)
- node.specifiers.push(this.finishNode(specifier, "ImportSpecifier"))
+ let specifier = this.startNode();
+ specifier.imported = this.parseIdent(true);
+ specifier.local = this.eatContextual("as") ? this.parseIdent() : specifier.imported;
+ this.checkLVal(specifier.local, true);
+ node.specifiers.push(this.finishNode(specifier, "ImportSpecifier"));
}
-}
+};
-pp.parseImportSpecifierDefault = function (id, start) {
- var node = this.startNodeAt(start)
- node.local = id
- this.checkLVal(node.local, true)
- return this.finishNode(node, "ImportDefaultSpecifier")
-}
+pp.parseImportSpecifierDefault = function (id, startPos, startLoc) {
+ var node = this.startNodeAt(startPos, startLoc);
+ node.local = id;
+ this.checkLVal(node.local, true);
+ return this.finishNode(node, "ImportDefaultSpecifier");
+};
diff --git a/src/tokencontext.js b/src/tokencontext.js
index f1cb36e7b8..8395160c8d 100755
--- a/src/tokencontext.js
+++ b/src/tokencontext.js
@@ -2,16 +2,16 @@
// given point in the program is loosely based on sweet.js' approach.
// See https://github.com/mozilla/sweet.js/wiki/design
-import {Parser} from "./state"
-import {types as tt} from "./tokentype"
-import {lineBreak} from "./whitespace"
+import {Parser} from "./state";
+import {types as tt} from "./tokentype";
+import {lineBreak} from "./whitespace";
export class TokContext {
constructor(token, isExpr, preserveSpace, override) {
- this.token = token
- this.isExpr = isExpr
- this.preserveSpace = preserveSpace
- this.override = override
+ this.token = token;
+ this.isExpr = !!isExpr;
+ this.preserveSpace = !!preserveSpace;
+ this.override = override;
}
}
@@ -23,85 +23,96 @@ export const types = {
p_expr: new TokContext("(", true),
q_tmpl: new TokContext("`", true, true, p => p.readTmplToken()),
f_expr: new TokContext("function", true)
-}
+};
-const pp = Parser.prototype
+const pp = Parser.prototype;
-pp.initialContext = function() {
- return [types.b_stat]
-}
+pp.initialContext = function () {
+ return [types.b_stat];
+};
+
+pp.braceIsBlock = function (prevType) {
+ if (prevType === tt.colon) {
+ let parent = this.curContext();
+ if (parent === types.b_stat || parent === types.b_expr)
+ return !parent.isExpr;
+ }
-pp.braceIsBlock = function(prevType) {
- let parent
- if (prevType === tt.colon && (parent = this.curContext()).token == "{")
- return !parent.isExpr
if (prevType === tt._return)
- return lineBreak.test(this.input.slice(this.lastTokEnd, this.start))
- if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof)
- return true
- if (prevType == tt.braceL)
- return this.curContext() === types.b_stat
- return !this.exprAllowed
-}
+ return lineBreak.test(this.input.slice(this.lastTokEnd, this.start));
-pp.updateContext = function(prevType) {
- let update, type = this.type
- if (type.keyword && prevType == tt.dot)
- this.exprAllowed = false
- else if (update = type.updateContext)
- update.call(this, prevType)
- else
- this.exprAllowed = type.beforeExpr
-}
+ if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof)
+ return true;
+
+ if (prevType === tt.braceL)
+ return this.curContext() === types.b_stat;
+
+ return !this.exprAllowed;
+};
+
+pp.updateContext = function (prevType) {
+ let update, type = this.type;
+ if (type.keyword && prevType === tt.dot) {
+ this.exprAllowed = false;
+ } else if (update = type.updateContext) {
+ update.call(this, prevType);
+ } else {
+ this.exprAllowed = type.beforeExpr;
+ }
+};
// Token-specific context update code
-tt.parenR.updateContext = tt.braceR.updateContext = function() {
- if (this.context.length == 1) {
- this.exprAllowed = true
- return
+tt.parenR.updateContext = tt.braceR.updateContext = function () {
+ if (this.context.length === 1) {
+ this.exprAllowed = true;
+ return;
}
- let out = this.context.pop()
+
+ let out = this.context.pop();
if (out === types.b_stat && this.curContext() === types.f_expr) {
- this.context.pop()
- this.exprAllowed = false
+ this.context.pop();
+ this.exprAllowed = false;
} else if (out === types.b_tmpl) {
- this.exprAllowed = true
+ this.exprAllowed = true;
} else {
- this.exprAllowed = !out.isExpr
+ this.exprAllowed = !out.isExpr;
}
-}
+};
-tt.braceL.updateContext = function(prevType) {
- this.context.push(this.braceIsBlock(prevType) ? types.b_stat : types.b_expr)
- this.exprAllowed = true
-}
+tt.braceL.updateContext = function (prevType) {
+ this.context.push(this.braceIsBlock(prevType) ? types.b_stat : types.b_expr);
+ this.exprAllowed = true;
+};
-tt.dollarBraceL.updateContext = function() {
- this.context.push(types.b_tmpl)
- this.exprAllowed = true
-}
+tt.dollarBraceL.updateContext = function () {
+ this.context.push(types.b_tmpl);
+ this.exprAllowed = true;
+};
-tt.parenL.updateContext = function(prevType) {
- let statementParens = prevType === tt._if || prevType === tt._for || prevType === tt._with || prevType === tt._while
- this.context.push(statementParens ? types.p_stat : types.p_expr)
- this.exprAllowed = true
-}
+tt.parenL.updateContext = function (prevType) {
+ let statementParens = prevType === tt._if || prevType === tt._for || prevType === tt._with || prevType === tt._while;
+ this.context.push(statementParens ? types.p_stat : types.p_expr);
+ this.exprAllowed = true;
+};
-tt.incDec.updateContext = function() {
+tt.incDec.updateContext = function () {
// tokExprAllowed stays unchanged
-}
+};
-tt._function.updateContext = function() {
- if (this.curContext() !== types.b_stat)
- this.context.push(types.f_expr)
- this.exprAllowed = false
-}
+tt._function.updateContext = function () {
+ if (this.curContext() !== types.b_stat) {
+ this.context.push(types.f_expr);
+ }
-tt.backQuote.updateContext = function() {
- if (this.curContext() === types.q_tmpl)
- this.context.pop()
- else
- this.context.push(types.q_tmpl)
- this.exprAllowed = false
-}
+ this.exprAllowed = false;
+};
+
+tt.backQuote.updateContext = function () {
+ if (this.curContext() === types.q_tmpl) {
+ this.context.pop();
+ } else {
+ this.context.push(types.q_tmpl);
+ }
+ this.exprAllowed = false;
+};
diff --git a/src/tokenize.js b/src/tokenize.js
index d9c22d5d04..8cade26638 100755
--- a/src/tokenize.js
+++ b/src/tokenize.js
@@ -1,8 +1,8 @@
-import {isIdentifierStart, isIdentifierChar} from "./identifier"
-import {types as tt, keywords as keywordTypes} from "./tokentype"
-import {Parser} from "./state"
-import {SourceLocation} from "./location"
-import {lineBreak, lineBreakG, isNewLine, nonASCIIwhitespace} from "./whitespace"
+import {isIdentifierStart, isIdentifierChar} from "./identifier";
+import {types as tt, keywords as keywordTypes} from "./tokentype";
+import {Parser} from "./state";
+import {SourceLocation} from "./location";
+import {lineBreak, lineBreakG, isNewLine, nonASCIIwhitespace} from "./whitespace";
// Object type used to represent tokens. Note that normally, tokens
// simply exist as properties on the parser object. This is only
@@ -10,194 +10,186 @@ import {lineBreak, lineBreakG, isNewLine, nonASCIIwhitespace} from "./whitespace
export class Token {
constructor(p) {
- this.type = p.type
- this.value = p.value
- this.start = p.start
- this.end = p.end
- if (p.options.locations)
- this.loc = new SourceLocation(p, p.startLoc, p.endLoc)
- if (p.options.ranges)
- this.range = [p.start, p.end]
+ this.type = p.type;
+ this.value = p.value;
+ this.start = p.start;
+ this.end = p.end;
+
+ if (p.options.locations) {
+ this.loc = new SourceLocation(p, p.startLoc, p.endLoc);
+ }
+
+ if (p.options.ranges) {
+ this.range = [p.start, p.end];
+ }
}
}
// ## Tokenizer
-const pp = Parser.prototype
+const pp = Parser.prototype;
// Are we running under Rhino?
-const isRhino = typeof Packages == "object" && Object.prototype.toString.call(Packages) == "[object JavaPackage]"
+const isRhino = typeof Packages === "object" && Object.prototype.toString.call(Packages) === "[object JavaPackage]";
// Move to the next token
-pp.next = function() {
+pp.next = function () {
if (this.options.onToken && !this.isLookahead)
- this.options.onToken(new Token(this))
+ this.options.onToken(new Token(this));
- this.lastTokEnd = this.end
- this.lastTokStart = this.start
- this.lastTokEndLoc = this.endLoc
- this.lastTokStartLoc = this.startLoc
- this.nextToken()
-}
+ this.lastTokEnd = this.end;
+ this.lastTokStart = this.start;
+ this.lastTokEndLoc = this.endLoc;
+ this.lastTokStartLoc = this.startLoc;
+ this.nextToken();
+};
-pp.getToken = function() {
- this.next()
- return new Token(this)
-}
-
-// If we're in an ES6 environment, make parsers iterable
-if (typeof Symbol !== "undefined")
- pp[Symbol.iterator] = function () {
- let self = this
- return {next: function () {
- let token = self.getToken()
- return {
- done: token.type === tt.eof,
- value: token
- }
- }}
- }
+pp.getToken = function () {
+ this.next();
+ return new Token(this);
+};
// Toggle strict mode. Re-reads the next number or string to please
// pedantic tests (`"use strict"; 010;` should fail).
-pp.setStrict = function(strict) {
- this.strict = strict
- if (this.type !== tt.num && this.type !== tt.string) return
- this.pos = this.start
+pp.setStrict = function (strict) {
+ this.strict = strict;
+ if (this.type !== tt.num && this.type !== tt.string) return;
+ this.pos = this.start;
if (this.options.locations) {
while (this.pos < this.lineStart) {
- this.lineStart = this.input.lastIndexOf("\n", this.lineStart - 2) + 1
- --this.curLine
+ this.lineStart = this.input.lastIndexOf("\n", this.lineStart - 2) + 1;
+ --this.curLine;
}
}
- this.nextToken()
-}
+ this.nextToken();
+};
-pp.curContext = function() {
- return this.context[this.context.length - 1]
-}
+pp.curContext = function () {
+ return this.context[this.context.length - 1];
+};
// Read a single token, updating the parser object's token-related
// properties.
-pp.nextToken = function() {
- let curContext = this.curContext()
- if (!curContext || !curContext.preserveSpace) this.skipSpace()
+pp.nextToken = function () {
+ let curContext = this.curContext();
+ if (!curContext || !curContext.preserveSpace) this.skipSpace();
- this.start = this.pos
- if (this.options.locations) this.startLoc = this.curPosition()
- if (this.pos >= this.input.length) return this.finishToken(tt.eof)
+ this.start = this.pos;
+ if (this.options.locations) this.startLoc = this.curPosition();
+ if (this.pos >= this.input.length) return this.finishToken(tt.eof);
- if (curContext.override) return curContext.override(this)
- else this.readToken(this.fullCharCodeAtPos())
-}
+ if (curContext.override) return curContext.override(this);
+ else this.readToken(this.fullCharCodeAtPos());
+};
-pp.readToken = function(code) {
+pp.readToken = function (code) {
// Identifier or keyword. '\uXXXX' sequences are allowed in
// identifiers, so '\' also dispatches to that.
if (isIdentifierStart(code, this.options.ecmaVersion >= 6) || code === 92 /* '\' */)
- return this.readWord()
+ return this.readWord();
- return this.getTokenFromCode(code)
-}
+ return this.getTokenFromCode(code);
+};
-pp.fullCharCodeAtPos = function() {
- let code = this.input.charCodeAt(this.pos)
- if (code <= 0xd7ff || code >= 0xe000) return code
- let next = this.input.charCodeAt(this.pos + 1)
- return (code << 10) + next - 0x35fdc00
-}
+pp.fullCharCodeAtPos = function () {
+ let code = this.input.charCodeAt(this.pos);
+ if (code <= 0xd7ff || code >= 0xe000) return code;
-pp.skipBlockComment = function() {
- let startLoc = this.options.onComment && this.options.locations && this.curPosition()
- let start = this.pos, end = this.input.indexOf("*/", this.pos += 2)
- if (end === -1) this.raise(this.pos - 2, "Unterminated comment")
- this.pos = end + 2
+ let next = this.input.charCodeAt(this.pos + 1);
+ return (code << 10) + next - 0x35fdc00;
+};
+
+pp.skipBlockComment = function () {
+ let startLoc = this.options.onComment && this.curPosition();
+ let start = this.pos, end = this.input.indexOf("*/", this.pos += 2);
+ if (end === -1) this.raise(this.pos - 2, "Unterminated comment");
+ this.pos = end + 2;
if (this.options.locations) {
- lineBreakG.lastIndex = start
- let match
+ lineBreakG.lastIndex = start;
+ let match;
while ((match = lineBreakG.exec(this.input)) && match.index < this.pos) {
- ++this.curLine
- this.lineStart = match.index + match[0].length
+ ++this.curLine;
+ this.lineStart = match.index + match[0].length;
}
}
if (this.options.onComment)
this.options.onComment(true, this.input.slice(start + 2, end), start, this.pos,
- startLoc, this.options.locations && this.curPosition())
-}
+ startLoc, this.curPosition());
+};
-pp.skipLineComment = function(startSkip) {
- let start = this.pos
- let startLoc = this.options.onComment && this.options.locations && this.curPosition()
- let ch = this.input.charCodeAt(this.pos+=startSkip)
+pp.skipLineComment = function (startSkip) {
+ let start = this.pos;
+ let startLoc = this.options.onComment && this.curPosition();
+ let ch = this.input.charCodeAt(this.pos+=startSkip);
while (this.pos < this.input.length && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) {
- ++this.pos
- ch = this.input.charCodeAt(this.pos)
+ ++this.pos;
+ ch = this.input.charCodeAt(this.pos);
}
if (this.options.onComment)
this.options.onComment(false, this.input.slice(start + startSkip, this.pos), start, this.pos,
- startLoc, this.options.locations && this.curPosition())
-}
+ startLoc, this.curPosition());
+};
// Called at the start of the parse and after every token. Skips
// whitespace and comments, and.
pp.skipSpace = function() {
- while (this.pos < this.input.length) {
- let ch = this.input.charCodeAt(this.pos)
- if (ch === 32) { // ' '
- ++this.pos
- } else if (ch === 13) {
- ++this.pos
- let next = this.input.charCodeAt(this.pos)
- if (next === 10) {
- ++this.pos
- }
- if (this.options.locations) {
- ++this.curLine
- this.lineStart = this.pos
- }
- } else if (ch === 10 || ch === 8232 || ch === 8233) {
- ++this.pos
- if (this.options.locations) {
- ++this.curLine
- this.lineStart = this.pos
- }
- } else if (ch > 8 && ch < 14) {
- ++this.pos
- } else if (ch === 47) { // '/'
- let next = this.input.charCodeAt(this.pos + 1)
- if (next === 42) { // '*'
- this.skipBlockComment()
- } else if (next === 47) { // '/'
- this.skipLineComment(2)
- } else break
- } else if (ch === 160) { // '\xa0'
- ++this.pos
- } else if (ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) {
- ++this.pos
- } else {
- break
+ loop: while (this.pos < this.input.length) {
+ let ch = this.input.charCodeAt(this.pos);
+ switch (ch) {
+ case 32: case 160: // ' '
+ ++this.pos;
+ break;
+ case 13:
+ if (this.input.charCodeAt(this.pos + 1) === 10) {
+ ++this.pos;
+ }
+ case 10: case 8232: case 8233:
+ ++this.pos;
+ if (this.options.locations) {
+ ++this.curLine;
+ this.lineStart = this.pos;
+ }
+ break;
+ case 47: // '/'
+ switch (this.input.charCodeAt(this.pos + 1)) {
+ case 42: // '*'
+ this.skipBlockComment();
+ break;
+ case 47:
+ this.skipLineComment(2);
+ break;
+ default:
+ break loop;
+ }
+ break;
+ default:
+ if (ch > 8 && ch < 14 || ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) {
+ ++this.pos;
+ } else {
+ break loop;
+ }
}
}
-}
+};
// Called at the end of every token. Sets `end`, `val`, and
// maintains `context` and `exprAllowed`, and skips the space after
// the token, so that the next one's `start` will point at the
// right position.
-pp.finishToken = function(type, val) {
- this.end = this.pos
- if (this.options.locations) this.endLoc = this.curPosition()
- let prevType = this.type
- this.type = type
- this.value = val
+pp.finishToken = function (type, val) {
+ this.end = this.pos;
+ if (this.options.locations) this.endLoc = this.curPosition();
+ let prevType = this.type;
+ this.type = type;
+ this.value = val;
- this.updateContext(prevType)
-}
+ this.updateContext(prevType);
+};
// ### Token reading
@@ -208,138 +200,155 @@ pp.finishToken = function(type, val) {
//
// All in the name of speed.
//
-pp.readToken_dot = function() {
- let next = this.input.charCodeAt(this.pos + 1)
- if (next >= 48 && next <= 57) return this.readNumber(true)
- let next2 = this.input.charCodeAt(this.pos + 2)
+pp.readToken_dot = function () {
+ let next = this.input.charCodeAt(this.pos + 1);
+ if (next >= 48 && next <= 57) return this.readNumber(true);
+
+ let next2 = this.input.charCodeAt(this.pos + 2);
if (this.options.ecmaVersion >= 6 && next === 46 && next2 === 46) { // 46 = dot '.'
- this.pos += 3
- return this.finishToken(tt.ellipsis)
+ this.pos += 3;
+ return this.finishToken(tt.ellipsis);
} else {
- ++this.pos
- return this.finishToken(tt.dot)
+ ++this.pos;
+ return this.finishToken(tt.dot);
}
-}
+};
-pp.readToken_slash = function() { // '/'
- let next = this.input.charCodeAt(this.pos + 1)
- if (this.exprAllowed) {++this.pos; return this.readRegexp();}
- if (next === 61) return this.finishOp(tt.assign, 2)
- return this.finishOp(tt.slash, 1)
-}
+pp.readToken_slash = function () { // '/'
+ let next = this.input.charCodeAt(this.pos + 1);
+ if (this.exprAllowed) {
+ ++this.pos;
+ return this.readRegexp();
+ }
+ if (next === 61) return this.finishOp(tt.assign, 2);
+ return this.finishOp(tt.slash, 1);
+};
-pp.readToken_mult_modulo = function(code) { // '%*'
- var type = code === 42 ? tt.star : tt.modulo
- var width = 1
- var next = this.input.charCodeAt(this.pos + 1)
+pp.readToken_mult_modulo = function (code) { // '%*'
+ var type = code === 42 ? tt.star : tt.modulo;
+ var width = 1;
+ var next = this.input.charCodeAt(this.pos + 1);
if (next === 42) { // '*'
- width++
- next = this.input.charCodeAt(this.pos + 2)
- type = tt.exponent
+ width++;
+ next = this.input.charCodeAt(this.pos + 2);
+ type = tt.exponent;
}
if (next === 61) {
- width++
- type = tt.assign
+ width++;
+ type = tt.assign;
}
- return this.finishOp(type, width)
-}
+ return this.finishOp(type, width);
+};
-pp.readToken_pipe_amp = function(code) { // '|&'
- let next = this.input.charCodeAt(this.pos + 1)
- if (next === code) return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2)
- if (next === 61) return this.finishOp(tt.assign, 2)
- return this.finishOp(code === 124 ? tt.bitwiseOR : tt.bitwiseAND, 1)
-}
+pp.readToken_pipe_amp = function (code) { // '|&'
+ let next = this.input.charCodeAt(this.pos + 1);
+ if (next === code) return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2);
+ if (next === 61) return this.finishOp(tt.assign, 2);
+ return this.finishOp(code === 124 ? tt.bitwiseOR : tt.bitwiseAND, 1);
+};
-pp.readToken_caret = function() { // '^'
- let next = this.input.charCodeAt(this.pos + 1)
- if (next === 61) return this.finishOp(tt.assign, 2)
- return this.finishOp(tt.bitwiseXOR, 1)
-}
+pp.readToken_caret = function () { // '^'
+ let next = this.input.charCodeAt(this.pos + 1);
+ if (next === 61) {
+ return this.finishOp(tt.assign, 2);
+ } else {
+ return this.finishOp(tt.bitwiseXOR, 1);
+ }
+};
+
+pp.readToken_plus_min = function (code) { // '+-'
+ let next = this.input.charCodeAt(this.pos + 1);
-pp.readToken_plus_min = function(code) { // '+-'
- let next = this.input.charCodeAt(this.pos + 1)
if (next === code) {
- if (next == 45 && this.input.charCodeAt(this.pos + 2) == 62 &&
- lineBreak.test(this.input.slice(this.lastTokEnd, this.pos))) {
+ if (next === 45 && this.input.charCodeAt(this.pos + 2) === 62 && lineBreak.test(this.input.slice(this.lastTokEnd, this.pos))) {
// A `-->` line comment
- this.skipLineComment(3)
- this.skipSpace()
- return this.nextToken()
+ this.skipLineComment(3);
+ this.skipSpace();
+ return this.nextToken();
}
- return this.finishOp(tt.incDec, 2)
+ return this.finishOp(tt.incDec, 2);
}
- if (next === 61) return this.finishOp(tt.assign, 2)
- return this.finishOp(tt.plusMin, 1)
-}
-pp.readToken_lt_gt = function(code) { // '<>'
- let next = this.input.charCodeAt(this.pos + 1)
- let size = 1
+ if (next === 61) {
+ return this.finishOp(tt.assign, 2);
+ } else {
+ return this.finishOp(tt.plusMin, 1);
+ }
+};
+
+pp.readToken_lt_gt = function (code) { // '<>'
+ let next = this.input.charCodeAt(this.pos + 1);
+ let size = 1;
+
if (next === code) {
- size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2
- if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1)
- return this.finishOp(tt.bitShift, size)
+ size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2;
+ if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1);
+ return this.finishOp(tt.bitShift, size);
}
- if (next == 33 && code == 60 && this.input.charCodeAt(this.pos + 2) == 45 &&
- this.input.charCodeAt(this.pos + 3) == 45) {
- if (this.inModule) this.unexpected()
+
+ if (next === 33 && code === 60 && this.input.charCodeAt(this.pos + 2) === 45 && this.input.charCodeAt(this.pos + 3) === 45) {
+ if (this.inModule) this.unexpected();
// `10;\n --> nothing", {
+ type: "Program",
+ body: [
+ {
+ type: "ExpressionStatement",
+ expression: {
+ type: "AssignmentExpression",
+ operator: "=",
+ left: {
+ type: "Identifier",
+ name: "x"
+ },
+ right: {
+ type: "BinaryExpression",
+ left: {
+ type: "UpdateExpression",
+ operator: "--",
+ prefix: false,
+ argument: {
+ type: "Identifier",
+ name: "y"
+ }
+ },
+ operator: ">",
+ right: {
+ type: "Literal",
+ value: 10
+ }
+ }
+ }
+ }
+ ]
+});
+
+test("'use strict';\nobject.static();", {
+ type: "Program",
+ body: [
+ {
+ type: "ExpressionStatement",
+ expression: {
+ type: "Literal",
+ value: "use strict",
+ raw: "'use strict'"
+ }
+ },
+ {
+ type: "ExpressionStatement",
+ expression: {
+ type: "CallExpression",
+ callee: {
+ type: "MemberExpression",
+ object: {
+ type: "Identifier",
+ name: "object"
+ },
+ property: {
+ type: "Identifier",
+ name: "static"
+ },
+ computed: false
+ },
+ arguments: []
+ }
+ }
+ ]
+});
+
+// Failure tests
+
+testFail("{",
+ "Unexpected token (1:1)");
+
+testFail("}",
+ "Unexpected token (1:0)");
+
+testFail("3ea",
+ "Invalid number (1:0)");
+
+testFail("3in []",
+ "Identifier directly after number (1:1)");
+
+testFail("3e",
+ "Invalid number (1:0)");
+
+testFail("3e+",
+ "Invalid number (1:0)");
+
+testFail("3e-",
+ "Invalid number (1:0)");
+
+testFail("3x",
+ "Identifier directly after number (1:1)");
+
+testFail("3x0",
+ "Identifier directly after number (1:1)");
+
+testFail("0x",
+ "Expected number in radix 16 (1:2)");
+
+testFail("09",
+ "Invalid number (1:0)");
+
+testFail("018",
+ "Invalid number (1:0)");
+
+testFail("01a",
+ "Identifier directly after number (1:2)");
+
+testFail("3in[]",
+ "Identifier directly after number (1:1)");
+
+testFail("0x3in[]",
+ "Identifier directly after number (1:3)");
+
+testFail("\"Hello\nWorld\"",
+ "Unterminated string constant (1:0)");
+
+testFail("x\\",
+ "Expecting Unicode escape sequence \\uXXXX (1:2)");
+
+testFail("x\\u005c",
+ "Invalid Unicode escape (1:1)");
+
+testFail("x\\u002a",
+ "Invalid Unicode escape (1:1)");
+
+testFail("/",
+ "Unterminated regular expression (1:1)");
+
+testFail("/test",
+ "Unterminated regular expression (1:1)");
+
+testFail("var x = /[a-z]/\\ux",
+ "Bad character escape sequence (1:17)");
+
+testFail("3 = 4",
+ "Assigning to rvalue (1:0)");
+
+testFail("func() = 4",
+ "Assigning to rvalue (1:0)");
+
+testFail("(1 + 1) = 10",
+ "Assigning to rvalue (1:1)");
+
+testFail("1++",
+ "Assigning to rvalue (1:0)");
+
+testFail("1--",
+ "Assigning to rvalue (1:0)");
+
+testFail("++1",
+ "Assigning to rvalue (1:2)");
+
+testFail("--1",
+ "Assigning to rvalue (1:2)");
+
+testFail("for((1 + 1) in list) process(x);",
+ "Assigning to rvalue (1:5)");
+
+testFail("[",
+ "Unexpected token (1:1)");
+
+testFail("[,",
+ "Unexpected token (1:2)");
+
+testFail("1 + {",
+ "Unexpected token (1:5)");
+
+testFail("1 + { t:t ",
+ "Unexpected token (1:10)");
+
+testFail("1 + { t:t,",
+ "Unexpected token (1:10)");
+
+testFail("var x = /\n/",
+ "Unterminated regular expression (1:9)");
+
+testFail("var x = \"\n",
+ "Unterminated string constant (1:8)");
+
+testFail("var if = 42",
+ "Unexpected token (1:4)");
+
+testFail("i + 2 = 42",
+ "Assigning to rvalue (1:0)");
+
+testFail("+i = 42",
+ "Assigning to rvalue (1:0)");
+
+testFail("1 + (",
+ "Unexpected token (1:5)");
+
+testFail("\n\n\n{",
+ "Unexpected token (4:1)");
+
+testFail("\n/* Some multiline\ncomment */\n)",
+ "Unexpected token (4:0)");
+
+testFail("{ set 1 }",
+ "Unexpected token (1:6)");
+
+testFail("{ get 2 }",
+ "Unexpected token (1:6)");
+
+testFail("({ set: s(if) { } })",
+ "Unexpected token (1:10)");
+
+testFail("({ set s(.) { } })",
+ "Unexpected token (1:9)");
+
+testFail("({ set: s() { } })",
+ "Unexpected token (1:12)");
+
+testFail("({ set: s(a, b) { } })",
+ "Unexpected token (1:16)");
+
+testFail("({ get: g(d) { } })",
+ "Unexpected token (1:13)");
+
+testFail("({ get i() { }, i: 42 })",
+ "Redefinition of property (1:16)");
+
+testFail("({ i: 42, get i() { } })",
+ "Redefinition of property (1:14)");
+
+testFail("({ set i(x) { }, i: 42 })",
+ "Redefinition of property (1:17)");
+
+testFail("({ i: 42, set i(x) { } })",
+ "Redefinition of property (1:14)");
+
+testFail("({ get i() { }, get i() { } })",
+ "Redefinition of property (1:20)");
+
+testFail("({ set i(x) { }, set i(x) { } })",
+ "Redefinition of property (1:21)");
+
+testFail("function t(...) { }",
+ "Unexpected token (1:11)");
+
+testFail("function t(...) { }",
+ "Unexpected token (1:14)",
+ { ecmaVersion: 6 });
+
+testFail("function t(...rest, b) { }",
+ "Unexpected token (1:18)",
+ { ecmaVersion: 6 });
+
+testFail("function t(if) { }",
+ "Unexpected token (1:11)");
+
+testFail("function t(true) { }",
+ "Unexpected token (1:11)");
+
+testFail("function t(false) { }",
+ "Unexpected token (1:11)");
+
+testFail("function t(null) { }",
+ "Unexpected token (1:11)");
+
+testFail("function null() { }",
+ "Unexpected token (1:9)");
+
+testFail("function true() { }",
+ "Unexpected token (1:9)");
+
+testFail("function false() { }",
+ "Unexpected token (1:9)");
+
+testFail("function if() { }",
+ "Unexpected token (1:9)");
+
+testFail("a b;",
+ "Unexpected token (1:2)");
+
+testFail("if.a;",
+ "Unexpected token (1:2)");
+
+testFail("a if;",
+ "Unexpected token (1:2)");
+
+testFail("a class;",
+ "Unexpected token (1:2)");
+
+testFail("break\n",
+ "Unsyntactic break (1:0)");
+
+testFail("break 1;",
+ "Unexpected token (1:6)");
+
+testFail("continue\n",
+ "Unsyntactic continue (1:0)");
+
+testFail("continue 2;",
+ "Unexpected token (1:9)");
+
+testFail("throw",
+ "Unexpected token (1:5)");
+
+testFail("throw;",
+ "Unexpected token (1:5)");
+
+testFail("for (var i, i2 in {});",
+ "Unexpected token (1:15)");
+
+testFail("for ((i in {}));",
+ "Unexpected token (1:14)");
+
+testFail("for (i + 1 in {});",
+ "Assigning to rvalue (1:5)");
+
+testFail("for (+i in {});",
+ "Assigning to rvalue (1:5)");
+
+testFail("if(false)",
+ "Unexpected token (1:9)");
+
+testFail("if(false) doThis(); else",
+ "Unexpected token (1:24)");
+
+testFail("do",
+ "Unexpected token (1:2)");
+
+testFail("while(false)",
+ "Unexpected token (1:12)");
+
+testFail("for(;;)",
+ "Unexpected token (1:7)");
+
+testFail("with(x)",
+ "Unexpected token (1:7)");
+
+testFail("try { }",
+ "Missing catch or finally clause (1:0)");
+
+testFail("‿ = 10",
+ "Unexpected character '‿' (1:0)");
+
+testFail("if(true) let a = 1;",
+ "Unexpected token (1:13)");
+
+testFail("switch (c) { default: default: }",
+ "Multiple default clauses (1:22)");
+
+testFail("new X().\"s\"",
+ "Unexpected token (1:8)");
+
+testFail("/*",
+ "Unterminated comment (1:0)");
+
+testFail("/*\n\n\n",
+ "Unterminated comment (1:0)");
+
+testFail("/**",
+ "Unterminated comment (1:0)");
+
+testFail("/*\n\n*",
+ "Unterminated comment (1:0)");
+
+testFail("/*hello",
+ "Unterminated comment (1:0)");
+
+testFail("/*hello *",
+ "Unterminated comment (1:0)");
+
+testFail("\n]",
+ "Unexpected token (2:0)");
+
+testFail("\r]",
+ "Unexpected token (2:0)");
+
+testFail("\r\n]",
+ "Unexpected token (2:0)");
+
+testFail("\n\r]",
+ "Unexpected token (3:0)");
+
+testFail("//\r\n]",
+ "Unexpected token (2:0)");
+
+testFail("//\n\r]",
+ "Unexpected token (3:0)");
+
+testFail("/a\\\n/",
+ "Unterminated regular expression (1:1)");
+
+testFail("//\r \n]",
+ "Unexpected token (3:0)");
+
+testFail("/*\r\n*/]",
+ "Unexpected token (2:2)");
+
+testFail("/*\n\r*/]",
+ "Unexpected token (3:2)");
+
+testFail("/*\r \n*/]",
+ "Unexpected token (3:2)");
+
+testFail("\\\\",
+ "Expecting Unicode escape sequence \\uXXXX (1:1)");
+
+testFail("\\u005c",
+ "Invalid Unicode escape (1:0)");
+
+testFail("\\x",
+ "Expecting Unicode escape sequence \\uXXXX (1:1)");
+
+testFail("\\u0000",
+ "Invalid Unicode escape (1:0)");
+
+testFail(" = []",
+ "Unexpected character '' (1:0)");
+
+testFail(" = []",
+ "Unexpected character '' (1:0)");
+
+testFail("\"\\",
+ "Unterminated string constant (1:0)");
+
+testFail("\"\\u",
+ "Bad character escape sequence (1:3)");
+
+testFail("return",
+ "'return' outside of function (1:0)");
+
+testFail("break",
+ "Unsyntactic break (1:0)");
+
+testFail("continue",
+ "Unsyntactic continue (1:0)");
+
+testFail("switch (x) { default: continue; }",
+ "Unsyntactic continue (1:22)");
+
+testFail("do { x } *",
+ "Unexpected token (1:9)");
+
+testFail("while (true) { break x; }",
+ "Unsyntactic break (1:15)");
+
+testFail("while (true) { continue x; }",
+ "Unsyntactic continue (1:15)");
+
+testFail("x: while (true) { (function () { break x; }); }",
+ "Unsyntactic break (1:33)");
+
+testFail("x: while (true) { (function () { continue x; }); }",
+ "Unsyntactic continue (1:33)");
+
+testFail("x: while (true) { (function () { break; }); }",
+ "Unsyntactic break (1:33)");
+
+testFail("x: while (true) { (function () { continue; }); }",
+ "Unsyntactic continue (1:33)");
+
+testFail("x: while (true) { x: while (true) { } }",
+ "Label 'x' is already declared (1:18)");
+
+testFail("(function () { 'use strict'; delete i; }())",
+ "Deleting local variable in strict mode (1:29)");
+
+testFail("(function () { 'use strict'; with (i); }())",
+ "'with' in strict mode (1:29)");
+
+testFail("function hello() {'use strict'; ({ i: 42, i: 42 }) }",
+ "Redefinition of property (1:42)");
+
+testFail("function hello() {'use strict'; ({ hasOwnProperty: 42, hasOwnProperty: 42 }) }",
+ "Redefinition of property (1:55)");
+
+testFail("function hello() {'use strict'; var eval = 10; }",
+ "Binding eval in strict mode (1:36)");
+
+testFail("function hello() {'use strict'; var arguments = 10; }",
+ "Binding arguments in strict mode (1:36)");
+
+testFail("function hello() {'use strict'; try { } catch (eval) { } }",
+ "Binding eval in strict mode (1:47)");
+
+testFail("function hello() {'use strict'; try { } catch (arguments) { } }",
+ "Binding arguments in strict mode (1:47)");
+
+testFail("function hello() {'use strict'; eval = 10; }",
+ "Assigning to eval in strict mode (1:32)");
+
+testFail("function hello() {'use strict'; arguments = 10; }",
+ "Assigning to arguments in strict mode (1:32)");
+
+testFail("function hello() {'use strict'; ++eval; }",
+ "Assigning to eval in strict mode (1:34)");
+
+testFail("function hello() {'use strict'; --eval; }",
+ "Assigning to eval in strict mode (1:34)");
+
+testFail("function hello() {'use strict'; ++arguments; }",
+ "Assigning to arguments in strict mode (1:34)");
+
+testFail("function hello() {'use strict'; --arguments; }",
+ "Assigning to arguments in strict mode (1:34)");
+
+testFail("function hello() {'use strict'; eval++; }",
+ "Assigning to eval in strict mode (1:32)");
+
+testFail("function hello() {'use strict'; eval--; }",
+ "Assigning to eval in strict mode (1:32)");
+
+testFail("function hello() {'use strict'; arguments++; }",
+ "Assigning to arguments in strict mode (1:32)");
+
+testFail("function hello() {'use strict'; arguments--; }",
+ "Assigning to arguments in strict mode (1:32)");
+
+testFail("function hello() {'use strict'; function eval() { } }",
+ "Binding eval in strict mode (1:41)");
+
+testFail("function hello() {'use strict'; function arguments() { } }",
+ "Binding arguments in strict mode (1:41)");
+
+testFail("function eval() {'use strict'; }",
+ "Binding eval in strict mode (1:9)");
+
+testFail("function arguments() {'use strict'; }",
+ "Binding arguments in strict mode (1:9)");
+
+testFail("function hello() {'use strict'; (function eval() { }()) }",
+ "Binding eval in strict mode (1:42)");
+
+testFail("function hello() {'use strict'; (function arguments() { }()) }",
+ "Binding arguments in strict mode (1:42)");
+
+testFail("(function eval() {'use strict'; })()",
+ "Binding eval in strict mode (1:10)");
+
+testFail("(function arguments() {'use strict'; })()",
+ "Binding arguments in strict mode (1:10)");
+
+testFail("function hello() {'use strict'; ({ s: function eval() { } }); }",
+ "Binding eval in strict mode (1:47)");
+
+testFail("(function package() {'use strict'; })()",
+ "Binding package in strict mode (1:10)");
+
+testFail("function hello() {'use strict'; ({ i: 10, set s(eval) { } }); }",
+ "Binding eval in strict mode (1:48)");
+
+testFail("function hello() {'use strict'; ({ set s(eval) { } }); }",
+ "Binding eval in strict mode (1:41)");
+
+testFail("function hello() {'use strict'; ({ s: function s(eval) { } }); }",
+ "Binding eval in strict mode (1:49)");
+
+testFail("function hello(eval) {'use strict';}",
+ "Binding eval in strict mode (1:15)");
+
+testFail("function hello(arguments) {'use strict';}",
+ "Binding arguments in strict mode (1:15)");
+
+testFail("function hello() { 'use strict'; function inner(eval) {} }",
+ "Binding eval in strict mode (1:48)");
+
+testFail("function hello() { 'use strict'; function inner(arguments) {} }",
+ "Binding arguments in strict mode (1:48)");
+
+testFail("function hello() { 'use strict'; \"\\1\"; }",
+ "Octal literal in strict mode (1:34)");
+
+testFail("function hello() { 'use strict'; 021; }",
+ "Invalid number (1:33)");
+
+testFail("function hello() { 'use strict'; ({ \"\\1\": 42 }); }",
+ "Octal literal in strict mode (1:37)");
+
+testFail("function hello() { 'use strict'; ({ 021: 42 }); }",
+ "Invalid number (1:36)");
+
+testFail("function hello() { \"use strict\"; function inner() { \"octal directive\\1\"; } }",
+ "Octal literal in strict mode (1:68)");
+
+testFail("function hello() { \"use strict\"; var implements; }",
+ "The keyword 'implements' is reserved (1:37)");
+
+testFail("function hello() { \"use strict\"; var interface; }",
+ "The keyword 'interface' is reserved (1:37)");
+
+testFail("function hello() { \"use strict\"; var package; }",
+ "The keyword 'package' is reserved (1:37)");
+
+testFail("function hello() { \"use strict\"; var private; }",
+ "The keyword 'private' is reserved (1:37)");
+
+testFail("function hello() { \"use strict\"; var protected; }",
+ "The keyword 'protected' is reserved (1:37)");
+
+testFail("function hello() { \"use strict\"; var public; }",
+ "The keyword 'public' is reserved (1:37)");
+
+testFail("function hello() { \"use strict\"; var static; }",
+ "The keyword 'static' is reserved (1:37)");
+
+testFail("function hello(static) { \"use strict\"; }",
+ "Binding static in strict mode (1:15)");
+
+testFail("function static() { \"use strict\"; }",
+ "Binding static in strict mode (1:9)");
+
+testFail("\"use strict\"; function static() { }",
+ "The keyword 'static' is reserved (1:23)");
+
+testFail("function a(t, t) { \"use strict\"; }",
+ "Argument name clash in strict mode (1:14)");
+
+testFail("function a(eval) { \"use strict\"; }",
+ "Binding eval in strict mode (1:11)");
+
+testFail("function a(package) { \"use strict\"; }",
+ "Binding package in strict mode (1:11)");
+
+testFail("function a() { \"use strict\"; function b(t, t) { }; }",
+ "Argument name clash in strict mode (1:43)");
+
+testFail("(function a(t, t) { \"use strict\"; })",
+ "Argument name clash in strict mode (1:15)");
+
+testFail("function a() { \"use strict\"; (function b(t, t) { }); }",
+ "Argument name clash in strict mode (1:44)");
+
+testFail("(function a(eval) { \"use strict\"; })",
+ "Binding eval in strict mode (1:12)");
+
+testFail("(function a(package) { \"use strict\"; })",
+ "Binding package in strict mode (1:12)");
+
+testFail("\"use strict\";function foo(){\"use strict\";}function bar(){var v = 015}",
+ "Invalid number (1:65)");
+
+testFail("var this = 10;", "Unexpected token (1:4)");
+
+testFail("throw\n10;", "Illegal newline after throw (1:5)");
+
+
+// ECMA < 6 mode should work as before
+
+testFail("const a;", "Unexpected token (1:6)");
+
+testFail("let x;", "Unexpected token (1:4)");
+
+testFail("const a = 1;", "Unexpected token (1:6)");
+
+testFail("let a = 1;", "Unexpected token (1:4)");
+
+testFail("for(const x = 0;;);", "Unexpected token (1:10)");
+
+testFail("for(let x = 0;;);", "Unexpected token (1:8)");
+
+test("let++", {
+ type: "Program",
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 5
+ }
+ },
+ body: [
+ {
+ type: "ExpressionStatement",
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 5
+ }
+ },
+ expression: {
+ type: "UpdateExpression",
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 5
+ }
+ },
+ operator: "++",
+ prefix: false,
+ argument: {
+ type: "Identifier",
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 3
+ }
+ },
+ name: "let"
+ }
+ }
+ }
+ ]
+});
+
+// ECMA 6 support
+
+test("let x", {
+ type: "Program",
+ body: [
+ {
+ type: "VariableDeclaration",
+ declarations: [
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "x",
+ loc: {
+ start: {
+ line: 1,
+ column: 4
+ },
+ end: {
+ line: 1,
+ column: 5
+ }
+ }
+ },
+ init: null,
+ loc: {
+ start: {
+ line: 1,
+ column: 4
+ },
+ end: {
+ line: 1,
+ column: 5
+ }
+ }
+ }
+ ],
+ kind: "let",
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 5
+ }
+ }
+ }
+ ],
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 5
+ }
+ }
+}, {ecmaVersion: 6, locations: true});
+
+test("let x, y;", {
+ type: "Program",
+ body: [
+ {
+ type: "VariableDeclaration",
+ declarations: [
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "x",
+ loc: {
+ start: {
+ line: 1,
+ column: 4
+ },
+ end: {
+ line: 1,
+ column: 5
+ }
+ }
+ },
+ init: null,
+ loc: {
+ start: {
+ line: 1,
+ column: 4
+ },
+ end: {
+ line: 1,
+ column: 5
+ }
+ }
+ },
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "y",
+ loc: {
+ start: {
+ line: 1,
+ column: 7
+ },
+ end: {
+ line: 1,
+ column: 8
+ }
+ }
+ },
+ init: null,
+ loc: {
+ start: {
+ line: 1,
+ column: 7
+ },
+ end: {
+ line: 1,
+ column: 8
+ }
+ }
+ }
+ ],
+ kind: "let",
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 9
+ }
+ }
+ }
+ ],
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 9
+ }
+ }
+}, {ecmaVersion: 6, locations: true});
+
+test("let x = 42", {
+ type: "Program",
+ body: [
+ {
+ type: "VariableDeclaration",
+ declarations: [
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "x",
+ loc: {
+ start: {
+ line: 1,
+ column: 4
+ },
+ end: {
+ line: 1,
+ column: 5
+ }
+ }
+ },
+ init: {
+ type: "Literal",
+ value: 42,
+ loc: {
+ start: {
+ line: 1,
+ column: 8
+ },
+ end: {
+ line: 1,
+ column: 10
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 4
+ },
+ end: {
+ line: 1,
+ column: 10
+ }
+ }
+ }
+ ],
+ kind: "let",
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 10
+ }
+ }
+ }
+ ],
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 10
+ }
+ }
+}, {ecmaVersion: 6, locations: true});
+
+test("let eval = 42, arguments = 42", {
+ type: "Program",
+ body: [
+ {
+ type: "VariableDeclaration",
+ declarations: [
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "eval",
+ loc: {
+ start: {
+ line: 1,
+ column: 4
+ },
+ end: {
+ line: 1,
+ column: 8
+ }
+ }
+ },
+ init: {
+ type: "Literal",
+ value: 42,
+ loc: {
+ start: {
+ line: 1,
+ column: 11
+ },
+ end: {
+ line: 1,
+ column: 13
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 4
+ },
+ end: {
+ line: 1,
+ column: 13
+ }
+ }
+ },
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "arguments",
+ loc: {
+ start: {
+ line: 1,
+ column: 15
+ },
+ end: {
+ line: 1,
+ column: 24
+ }
+ }
+ },
+ init: {
+ type: "Literal",
+ value: 42,
+ loc: {
+ start: {
+ line: 1,
+ column: 27
+ },
+ end: {
+ line: 1,
+ column: 29
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 15
+ },
+ end: {
+ line: 1,
+ column: 29
+ }
+ }
+ }
+ ],
+ kind: "let",
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 29
+ }
+ }
+ }
+ ],
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 29
+ }
+ }
+}, {ecmaVersion: 6, locations: true});
+
+test("let x = 14, y = 3, z = 1977", {
+ type: "Program",
+ body: [
+ {
+ type: "VariableDeclaration",
+ declarations: [
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "x",
+ loc: {
+ start: {
+ line: 1,
+ column: 4
+ },
+ end: {
+ line: 1,
+ column: 5
+ }
+ }
+ },
+ init: {
+ type: "Literal",
+ value: 14,
+ loc: {
+ start: {
+ line: 1,
+ column: 8
+ },
+ end: {
+ line: 1,
+ column: 10
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 4
+ },
+ end: {
+ line: 1,
+ column: 10
+ }
+ }
+ },
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "y",
+ loc: {
+ start: {
+ line: 1,
+ column: 12
+ },
+ end: {
+ line: 1,
+ column: 13
+ }
+ }
+ },
+ init: {
+ type: "Literal",
+ value: 3,
+ loc: {
+ start: {
+ line: 1,
+ column: 16
+ },
+ end: {
+ line: 1,
+ column: 17
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 12
+ },
+ end: {
+ line: 1,
+ column: 17
+ }
+ }
+ },
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "z",
+ loc: {
+ start: {
+ line: 1,
+ column: 19
+ },
+ end: {
+ line: 1,
+ column: 20
+ }
+ }
+ },
+ init: {
+ type: "Literal",
+ value: 1977,
+ loc: {
+ start: {
+ line: 1,
+ column: 23
+ },
+ end: {
+ line: 1,
+ column: 27
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 19
+ },
+ end: {
+ line: 1,
+ column: 27
+ }
+ }
+ }
+ ],
+ kind: "let",
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 27
+ }
+ }
+ }
+ ],
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 27
+ }
+ }
+}, {ecmaVersion: 6, locations: true});
+
+test("for(let x = 0;;);", {
+ type: "Program",
+ body: [
+ {
+ type: "ForStatement",
+ init: {
+ type: "VariableDeclaration",
+ declarations: [
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "x",
+ loc: {
+ start: {
+ line: 1,
+ column: 8
+ },
+ end: {
+ line: 1,
+ column: 9
+ }
+ }
+ },
+ init: {
+ type: "Literal",
+ value: 0,
+ loc: {
+ start: {
+ line: 1,
+ column: 12
+ },
+ end: {
+ line: 1,
+ column: 13
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 8
+ },
+ end: {
+ line: 1,
+ column: 13
+ }
+ }
+ }
+ ],
+ kind: "let",
+ loc: {
+ start: {
+ line: 1,
+ column: 4
+ },
+ end: {
+ line: 1,
+ column: 13
+ }
+ }
+ },
+ test: null,
+ update: null,
+ body: {
+ type: "EmptyStatement",
+ loc: {
+ start: {
+ line: 1,
+ column: 16
+ },
+ end: {
+ line: 1,
+ column: 17
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 17
+ }
+ }
+ }
+ ],
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 17
+ }
+ }
+}, {ecmaVersion: 6, locations: true});
+
+test("for(let x = 0, y = 1;;);", {
+ type: "Program",
+ body: [
+ {
+ type: "ForStatement",
+ init: {
+ type: "VariableDeclaration",
+ declarations: [
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "x",
+ loc: {
+ start: {
+ line: 1,
+ column: 8
+ },
+ end: {
+ line: 1,
+ column: 9
+ }
+ }
+ },
+ init: {
+ type: "Literal",
+ value: 0,
+ loc: {
+ start: {
+ line: 1,
+ column: 12
+ },
+ end: {
+ line: 1,
+ column: 13
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 8
+ },
+ end: {
+ line: 1,
+ column: 13
+ }
+ }
+ },
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "y",
+ loc: {
+ start: {
+ line: 1,
+ column: 15
+ },
+ end: {
+ line: 1,
+ column: 16
+ }
+ }
+ },
+ init: {
+ type: "Literal",
+ value: 1,
+ loc: {
+ start: {
+ line: 1,
+ column: 19
+ },
+ end: {
+ line: 1,
+ column: 20
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 15
+ },
+ end: {
+ line: 1,
+ column: 20
+ }
+ }
+ }
+ ],
+ kind: "let",
+ loc: {
+ start: {
+ line: 1,
+ column: 4
+ },
+ end: {
+ line: 1,
+ column: 20
+ }
+ }
+ },
+ test: null,
+ update: null,
+ body: {
+ type: "EmptyStatement",
+ loc: {
+ start: {
+ line: 1,
+ column: 23
+ },
+ end: {
+ line: 1,
+ column: 24
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 24
+ }
+ }
+ }
+ ],
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 24
+ }
+ }
+}, {ecmaVersion: 6, locations: true});
+
+test("for (let x in list) process(x);", {
+ type: "Program",
+ body: [
+ {
+ type: "ForInStatement",
+ left: {
+ type: "VariableDeclaration",
+ declarations: [
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "x",
+ loc: {
+ start: {
+ line: 1,
+ column: 9
+ },
+ end: {
+ line: 1,
+ column: 10
+ }
+ }
+ },
+ init: null,
+ loc: {
+ start: {
+ line: 1,
+ column: 9
+ },
+ end: {
+ line: 1,
+ column: 10
+ }
+ }
+ }
+ ],
+ kind: "let",
+ loc: {
+ start: {
+ line: 1,
+ column: 5
+ },
+ end: {
+ line: 1,
+ column: 10
+ }
+ }
+ },
+ right: {
+ type: "Identifier",
+ name: "list",
+ loc: {
+ start: {
+ line: 1,
+ column: 14
+ },
+ end: {
+ line: 1,
+ column: 18
+ }
+ }
+ },
+ body: {
+ type: "ExpressionStatement",
+ expression: {
+ type: "CallExpression",
+ callee: {
+ type: "Identifier",
+ name: "process",
+ loc: {
+ start: {
+ line: 1,
+ column: 20
+ },
+ end: {
+ line: 1,
+ column: 27
+ }
+ }
+ },
+ arguments: [
+ {
+ type: "Identifier",
+ name: "x",
+ loc: {
+ start: {
+ line: 1,
+ column: 28
+ },
+ end: {
+ line: 1,
+ column: 29
+ }
+ }
+ }
+ ],
+ loc: {
+ start: {
+ line: 1,
+ column: 20
+ },
+ end: {
+ line: 1,
+ column: 30
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 20
+ },
+ end: {
+ line: 1,
+ column: 31
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 31
+ }
+ }
+ }
+ ],
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 31
+ }
+ }
+}, {ecmaVersion: 6, locations: true});
+
+test("const x = 42", {
+ type: "Program",
+ body: [
+ {
+ type: "VariableDeclaration",
+ declarations: [
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "x",
+ loc: {
+ start: {
+ line: 1,
+ column: 6
+ },
+ end: {
+ line: 1,
+ column: 7
+ }
+ }
+ },
+ init: {
+ type: "Literal",
+ value: 42,
+ loc: {
+ start: {
+ line: 1,
+ column: 10
+ },
+ end: {
+ line: 1,
+ column: 12
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 6
+ },
+ end: {
+ line: 1,
+ column: 12
+ }
+ }
+ }
+ ],
+ kind: "const",
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 12
+ }
+ }
+ }
+ ],
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 12
+ }
+ }
+}, {ecmaVersion: 6, locations: true});
+
+test("const eval = 42, arguments = 42", {
+ type: "Program",
+ body: [
+ {
+ type: "VariableDeclaration",
+ declarations: [
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "eval",
+ loc: {
+ start: {
+ line: 1,
+ column: 6
+ },
+ end: {
+ line: 1,
+ column: 10
+ }
+ }
+ },
+ init: {
+ type: "Literal",
+ value: 42,
+ loc: {
+ start: {
+ line: 1,
+ column: 13
+ },
+ end: {
+ line: 1,
+ column: 15
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 6
+ },
+ end: {
+ line: 1,
+ column: 15
+ }
+ }
+ },
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "arguments",
+ loc: {
+ start: {
+ line: 1,
+ column: 17
+ },
+ end: {
+ line: 1,
+ column: 26
+ }
+ }
+ },
+ init: {
+ type: "Literal",
+ value: 42,
+ loc: {
+ start: {
+ line: 1,
+ column: 29
+ },
+ end: {
+ line: 1,
+ column: 31
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 17
+ },
+ end: {
+ line: 1,
+ column: 31
+ }
+ }
+ }
+ ],
+ kind: "const",
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 31
+ }
+ }
+ }
+ ],
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 31
+ }
+ }
+}, {ecmaVersion: 6, locations: true});
+
+test("const x = 14, y = 3, z = 1977", {
+ type: "Program",
+ body: [
+ {
+ type: "VariableDeclaration",
+ declarations: [
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "x",
+ loc: {
+ start: {
+ line: 1,
+ column: 6
+ },
+ end: {
+ line: 1,
+ column: 7
+ }
+ }
+ },
+ init: {
+ type: "Literal",
+ value: 14,
+ loc: {
+ start: {
+ line: 1,
+ column: 10
+ },
+ end: {
+ line: 1,
+ column: 12
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 6
+ },
+ end: {
+ line: 1,
+ column: 12
+ }
+ }
+ },
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "y",
+ loc: {
+ start: {
+ line: 1,
+ column: 14
+ },
+ end: {
+ line: 1,
+ column: 15
+ }
+ }
+ },
+ init: {
+ type: "Literal",
+ value: 3,
+ loc: {
+ start: {
+ line: 1,
+ column: 18
+ },
+ end: {
+ line: 1,
+ column: 19
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 14
+ },
+ end: {
+ line: 1,
+ column: 19
+ }
+ }
+ },
+ {
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "z",
+ loc: {
+ start: {
+ line: 1,
+ column: 21
+ },
+ end: {
+ line: 1,
+ column: 22
+ }
+ }
+ },
+ init: {
+ type: "Literal",
+ value: 1977,
+ loc: {
+ start: {
+ line: 1,
+ column: 25
+ },
+ end: {
+ line: 1,
+ column: 29
+ }
+ }
+ },
+ loc: {
+ start: {
+ line: 1,
+ column: 21
+ },
+ end: {
+ line: 1,
+ column: 29
+ }
+ }
+ }
+ ],
+ kind: "const",
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 29
+ }
+ }
+ }
+ ],
+ loc: {
+ start: {
+ line: 1,
+ column: 0
+ },
+ end: {
+ line: 1,
+ column: 29
+ }
+ }
+}, {ecmaVersion: 6, locations: true});
+
+testFail("const a;", "Unexpected token (1:7)", {ecmaVersion: 6});
+
+test("for(const x = 0;;);", {
+ type: "Program",
+ body: [{
+ type: "ForStatement",
+ init: {
+ type: "VariableDeclaration",
+ declarations: [{
+ type: "VariableDeclarator",
+ id: {
+ type: "Identifier",
+ name: "x",
+ range: [10, 11]
+ },
+ init: {
+ type: "Literal",
+ value: 0,
+ range: [14, 15]
+ },
+ range: [10, 15]
+ }],
+ kind: "const",
+ range: [4, 15]
+ },
+ test: null,
+ update: null,
+ body: {
+ type: "EmptyStatement",
+ range: [18, 19]
+ },
+ range: [0, 19]
+ }],
+ range: [0, 19]
+}, {ecmaVersion: 6, ranges: true});
+
+testFail("for(x of a);", "Unexpected token (1:6)");
+
+testFail("for(var x of a);", "Unexpected token (1:10)");
+
+// Assertion Tests
+test(function TestComments() {
+ // Bear class
+ function Bear(x,y,z) {
+ this.position = [x||0,y||0,z||0]
+ }
+
+ Bear.prototype.roar = function(message) {
+ return 'RAWWW: ' + message; // Whatever
+ };
+
+ function Cat() {
+ /* 1
+ 2
+ 3*/
+ }
+
+ Cat.prototype.roar = function(message) {
+ return 'MEOOWW: ' + /*stuff*/ message;
+ };
+}.toString().replace(/\r\n/g, '\n'), {}, {
+ onComment: [
+ {type: "Line", value: " Bear class"},
+ {type: "Line", value: " Whatever"},
+ {type: "Block", value: [
+ " 1",
+ " 2",
+ " 3"
+ ].join('\n')},
+ {type: "Block", value: "stuff"}
+ ]
+});
+
+test(" HTML comment", {}, {
+ locations: true,
+ onComment: [{
+ type: "Line",
+ value: " HTML comment",
+ loc: {
+ start: { line: 2, column: 0 },
+ end: { line: 2, column: 16 }
+ }
+ }]
+});
+
+var tokTypes = acorn.tokTypes;
+
+test('var x = (1 + 2)', {}, {
+ locations: true,
+ loose: false,
+ onToken: [
+ {
+ type: tokTypes._var,
+ value: "var",
+ loc: {
+ start: {line: 1, column: 0},
+ end: {line: 1, column: 3}
+ }
+ },
+ {
+ type: tokTypes.name,
+ value: "x",
+ loc: {
+ start: {line: 1, column: 4},
+ end: {line: 1, column: 5}
+ }
+ },
+ {
+ type: tokTypes.eq,
+ value: "=",
+ loc: {
+ start: {line: 1, column: 6},
+ end: {line: 1, column: 7}
+ }
+ },
+ {
+ type: tokTypes.parenL,
+ value: undefined,
+ loc: {
+ start: {line: 1, column: 8},
+ end: {line: 1, column: 9}
+ }
+ },
+ {
+ type: tokTypes.num,
+ value: 1,
+ loc: {
+ start: {line: 1, column: 9},
+ end: {line: 1, column: 10}
+ }
+ },
+ {
+ type: {binop: 9, prefix: true, beforeExpr: true},
+ value: "+",
+ loc: {
+ start: {line: 1, column: 11},
+ end: {line: 1, column: 12}
+ }
+ },
+ {
+ type: tokTypes.num,
+ value: 2,
+ loc: {
+ start: {line: 1, column: 13},
+ end: {line: 1, column: 14}
+ }
+ },
+ {
+ type: tokTypes.parenR,
+ value: undefined,
+ loc: {
+ start: {line: 1, column: 14},
+ end: {line: 1, column: 15}
+ }
+ },
+ {
+ type: tokTypes.eof,
+ value: undefined,
+ loc: {
+ start: {line: 1, column: 15},
+ end: {line: 1, column: 15}
+ }
+ }
+ ]
+});
+
+test("function f(f) { 'use strict'; }", {});
+
+// https://github.com/marijnh/acorn/issues/180
+test("#!/usr/bin/node\n;", {}, {
+ allowHashBang: true,
+ onComment: [{
+ type: "Line",
+ value: "/usr/bin/node",
+ start: 0,
+ end: 15
+ }]
+});
+
+// https://github.com/marijnh/acorn/issues/204
+test("(function () {} / 1)", {
+ type: "Program",
+ body: [{
+ type: "ExpressionStatement",
+ expression: {
+ type: "BinaryExpression",
+ left: {
+ type: "FunctionExpression",
+ id: null,
+ params: [],
+ body: {
+ type: "BlockStatement",
+ body: []
+ }
+ },
+ operator: "/",
+ right: {type: "Literal", value: 1}
+ }
+ }]
+});
+
+test("function f() {} / 1 /", {
+ type: "Program",
+ body: [
+ {
+ type: "FunctionDeclaration",
+ id: {type: "Identifier", name: "f"},
+ params: [],
+ body: {
+ type: "BlockStatement",
+ body: []
+ }
+ },
+ {
+ type: "ExpressionStatement",
+ expression: {
+ type: "Literal",
+ regex: {pattern: " 1 ", flags: ""},
+ value: / 1 /
+ }
+ }
+ ]
+});
+
+var semicolons = []
+testAssert("var x\nreturn\n10", function() {
+ var result = semicolons.join(" ");
+ semicolons.length = 0;
+ if (result != "5 12 15")
+ return "Unexpected result for onInsertedSemicolon: " + result;
+}, {onInsertedSemicolon: function(pos) { semicolons.push(pos); },
+ allowReturnOutsideFunction: true,
+ loose: false})
+
+var trailingCommas = []
+testAssert("[1,2,] + {foo: 1,}", function() {
+ var result = trailingCommas.join(" ");
+ trailingCommas.length = 0;
+ if (result != "4 16")
+ return "Unexpected result for onTrailingComma: " + result;
+}, {onTrailingComma: function(pos) { trailingCommas.push(pos); },
+ loose: false})
+
+// https://github.com/marijnh/acorn/issues/275
+
+testFail("({ get prop(x) {} })", "getter should have no params (1:11)");
+testFail("({ set prop() {} })", "setter should have exactly one param (1:11)");
+testFail("({ set prop(x, y) {} })", "setter should have exactly one param (1:11)");