Begin transition of Babel to a more scalable architecture, async flow to allow for RPC and better build system for multiple packages
This commit is contained in:
parent
04a29f8344
commit
423d8c510d
32
AUTHORS
32
AUTHORS
@ -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
|
||||
19
LICENSE
19
LICENSE
@ -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.
|
||||
7
README.md
Normal file
7
README.md
Normal file
@ -0,0 +1,7 @@
|
||||
<p align="center">
|
||||
<img alt="babylon" src="https://raw.githubusercontent.com/babel/logo/master/babylon.png" width="700">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
Babylon is a streaming parser for <a href="https://github.com/babel/babel">Babel</a>.
|
||||
</p>
|
||||
6
index.js
6
index.js
@ -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);
|
||||
50
package.json
Executable file → Normal file
50
package.json
Executable file → Normal file
@ -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 <sebmck@gmail.com>",
|
||||
"homepage": "https://babeljs.io/",
|
||||
"license": "MIT",
|
||||
"repository": "babel/babel",
|
||||
"main": "lib/index.js",
|
||||
"dependencies": {
|
||||
"bluebird": "^2.9.33"
|
||||
}
|
||||
}
|
||||
|
||||
830
plugins/flow.js
830
plugins/flow.js
@ -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<T>() {}
|
||||
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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
1012
src/expression.js
1012
src/expression.js
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
|
||||
70
src/index.js
70
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();
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
223
src/lval.js
223
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");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
79
src/node.js
79
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);
|
||||
};
|
||||
|
||||
@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -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");
|
||||
};
|
||||
|
||||
823
src/plugins/flow.js
Normal file
823
src/plugins/flow.js
Normal file
@ -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<T>() {}
|
||||
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);
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
421
src/plugins/jsx/index.js
Normal file
421
src/plugins/jsx/index.js
Normal file
@ -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("<tag", false);
|
||||
tc.j_cTag = new TokContext("</tag", false);
|
||||
tc.j_expr = new TokContext("<tag>...</tag>", 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);
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
255
src/plugins/jsx/xhtml.js
Normal file
255
src/plugins/jsx/xhtml.js
Normal file
@ -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"
|
||||
};
|
||||
87
src/state.js
87
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));
|
||||
});
|
||||
};
|
||||
|
||||
994
src/statement.js
994
src/statement.js
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
};
|
||||
|
||||
829
src/tokenize.js
829
src/tokenize.js
File diff suppressed because it is too large
Load Diff
108
src/tokentype.js
108
src/tokentype.js
@ -18,24 +18,24 @@
|
||||
|
||||
export class TokenType {
|
||||
constructor(label, conf = {}) {
|
||||
this.label = label
|
||||
this.keyword = conf.keyword
|
||||
this.beforeExpr = !!conf.beforeExpr
|
||||
this.startsExpr = !!conf.startsExpr
|
||||
this.rightAssociative = !!conf.rightAssociative
|
||||
this.isLoop = !!conf.isLoop
|
||||
this.isAssign = !!conf.isAssign
|
||||
this.prefix = !!conf.prefix
|
||||
this.postfix = !!conf.postfix
|
||||
this.binop = conf.binop || null
|
||||
this.updateContext = null
|
||||
this.label = label;
|
||||
this.keyword = conf.keyword;
|
||||
this.beforeExpr = !!conf.beforeExpr;
|
||||
this.startsExpr = !!conf.startsExpr;
|
||||
this.rightAssociative = !!conf.rightAssociative;
|
||||
this.isLoop = !!conf.isLoop;
|
||||
this.isAssign = !!conf.isAssign;
|
||||
this.prefix = !!conf.prefix;
|
||||
this.postfix = !!conf.postfix;
|
||||
this.binop = conf.binop || null;
|
||||
this.updateContext = null;
|
||||
}
|
||||
}
|
||||
|
||||
function binop(name, prec) {
|
||||
return new TokenType(name, {beforeExpr: true, binop: prec})
|
||||
return new TokenType(name, {beforeExpr: true, binop: prec});
|
||||
}
|
||||
const beforeExpr = {beforeExpr: true}, startsExpr = {startsExpr: true}
|
||||
const beforeExpr = {beforeExpr: true}, startsExpr = {startsExpr: true};
|
||||
|
||||
export const types = {
|
||||
num: new TokenType("num", startsExpr),
|
||||
@ -95,52 +95,52 @@ export const types = {
|
||||
star: binop("*", 10),
|
||||
slash: binop("/", 10),
|
||||
exponent: new TokenType("**", {beforeExpr: true, binop: 11, rightAssociative: true})
|
||||
}
|
||||
};
|
||||
|
||||
// Map keyword names to token types.
|
||||
|
||||
export const keywords = {}
|
||||
export const keywords = {};
|
||||
|
||||
// Succinct definitions of keyword token types
|
||||
function kw(name, options = {}) {
|
||||
options.keyword = name
|
||||
keywords[name] = types["_" + name] = new TokenType(name, options)
|
||||
options.keyword = name;
|
||||
keywords[name] = types["_" + name] = new TokenType(name, options);
|
||||
}
|
||||
|
||||
kw("break")
|
||||
kw("case", beforeExpr)
|
||||
kw("catch")
|
||||
kw("continue")
|
||||
kw("debugger")
|
||||
kw("default", beforeExpr)
|
||||
kw("do", {isLoop: true})
|
||||
kw("else", beforeExpr)
|
||||
kw("finally")
|
||||
kw("for", {isLoop: true})
|
||||
kw("function", startsExpr)
|
||||
kw("if")
|
||||
kw("return", beforeExpr)
|
||||
kw("switch")
|
||||
kw("throw", beforeExpr)
|
||||
kw("try")
|
||||
kw("var")
|
||||
kw("let")
|
||||
kw("const")
|
||||
kw("while", {isLoop: true})
|
||||
kw("with")
|
||||
kw("new", {beforeExpr: true, startsExpr: true})
|
||||
kw("this", startsExpr)
|
||||
kw("super", startsExpr)
|
||||
kw("class")
|
||||
kw("extends", beforeExpr)
|
||||
kw("export")
|
||||
kw("import")
|
||||
kw("yield", {beforeExpr: true, startsExpr: true})
|
||||
kw("null", startsExpr)
|
||||
kw("true", startsExpr)
|
||||
kw("false", startsExpr)
|
||||
kw("in", {beforeExpr: true, binop: 7})
|
||||
kw("instanceof", {beforeExpr: true, binop: 7})
|
||||
kw("typeof", {beforeExpr: true, prefix: true, startsExpr: true})
|
||||
kw("void", {beforeExpr: true, prefix: true, startsExpr: true})
|
||||
kw("delete", {beforeExpr: true, prefix: true, startsExpr: true})
|
||||
kw("break");
|
||||
kw("case", beforeExpr);
|
||||
kw("catch");
|
||||
kw("continue");
|
||||
kw("debugger");
|
||||
kw("default", beforeExpr);
|
||||
kw("do", {isLoop: true});
|
||||
kw("else", beforeExpr);
|
||||
kw("finally");
|
||||
kw("for", {isLoop: true});
|
||||
kw("function", startsExpr);
|
||||
kw("if");
|
||||
kw("return", beforeExpr);
|
||||
kw("switch");
|
||||
kw("throw", beforeExpr);
|
||||
kw("try");
|
||||
kw("var");
|
||||
kw("let");
|
||||
kw("const");
|
||||
kw("while", {isLoop: true});
|
||||
kw("with");
|
||||
kw("new", {beforeExpr: true, startsExpr: true});
|
||||
kw("this", startsExpr);
|
||||
kw("super", startsExpr);
|
||||
kw("class");
|
||||
kw("extends", beforeExpr);
|
||||
kw("export");
|
||||
kw("import");
|
||||
kw("yield", {beforeExpr: true, startsExpr: true});
|
||||
kw("null", startsExpr);
|
||||
kw("true", startsExpr);
|
||||
kw("false", startsExpr);
|
||||
kw("in", {beforeExpr: true, binop: 7});
|
||||
kw("instanceof", {beforeExpr: true, binop: 7});
|
||||
kw("typeof", {beforeExpr: true, prefix: true, startsExpr: true});
|
||||
kw("void", {beforeExpr: true, prefix: true, startsExpr: true});
|
||||
kw("delete", {beforeExpr: true, prefix: true, startsExpr: true});
|
||||
|
||||
@ -1,9 +1,5 @@
|
||||
export function isArray(obj) {
|
||||
return Object.prototype.toString.call(obj) === "[object Array]"
|
||||
}
|
||||
|
||||
// Checks if an object has a property.
|
||||
|
||||
export function has(obj, propName) {
|
||||
return Object.prototype.hasOwnProperty.call(obj, propName)
|
||||
return Object.prototype.hasOwnProperty.call(obj, propName);
|
||||
}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
// Matches a whole line break (where CRLF is considered a single
|
||||
// line break). Used to count lines.
|
||||
|
||||
export const lineBreak = /\r\n?|\n|\u2028|\u2029/
|
||||
export const lineBreakG = new RegExp(lineBreak.source, "g")
|
||||
export const lineBreak = /\r\n?|\n|\u2028|\u2029/;
|
||||
export const lineBreakG = new RegExp(lineBreak.source, "g");
|
||||
|
||||
export function isNewLine(code) {
|
||||
return code === 10 || code === 13 || code === 0x2028 || code == 0x2029
|
||||
return code === 10 || code === 13 || code === 0x2028 || code === 0x2029;
|
||||
}
|
||||
|
||||
export const nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/
|
||||
export const nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/;
|
||||
|
||||
|
||||
7
test/_browser.js
Normal file
7
test/_browser.js
Normal file
@ -0,0 +1,7 @@
|
||||
if (process.browser) {
|
||||
require("./tests");
|
||||
require("./tests-jsx");
|
||||
require("./tests-harmony");
|
||||
require("./tests-flow");
|
||||
require("./tests-babel");
|
||||
}
|
||||
87
test/driver.js
Executable file
87
test/driver.js
Executable file
@ -0,0 +1,87 @@
|
||||
var parse = require("../lib").parse;
|
||||
|
||||
exports.test = function(code, ast, options) {
|
||||
buildTest({code: code, ast: ast, options: options});
|
||||
};
|
||||
|
||||
exports.testFail = function(code, message, options) {
|
||||
buildTest({code: code, error: message, options: options});
|
||||
};
|
||||
|
||||
exports.testAssert = function(code, assert, options) {
|
||||
buildTest({code: code, assert: assert, options: options});
|
||||
};
|
||||
|
||||
function buildTest(config) {
|
||||
test(config.code, function () {
|
||||
return runTest(config);
|
||||
});
|
||||
}
|
||||
|
||||
function runTest(test) {
|
||||
if (test.filter && !test.filter(test)) return;
|
||||
var testOpts = test.options || {locations: true};
|
||||
var expected = {};
|
||||
if (expected.onComment = testOpts.onComment)
|
||||
testOpts.onComment = []
|
||||
if (expected.onToken = testOpts.onToken)
|
||||
testOpts.onToken = [];
|
||||
|
||||
return parse(test.code, testOpts).then(function (ast) {
|
||||
if (test.error) {
|
||||
throw new Error("Expected error message: " + test.error + ". But parsing succeeded.");
|
||||
} else if (test.assert) {
|
||||
var error = test.assert(ast);
|
||||
if (error) throw new Error("Assertion failed: " + error);
|
||||
} else {
|
||||
var mis = misMatch(test.ast, ast);
|
||||
for (var name in expected) {
|
||||
if (mis) break;
|
||||
if (expected[name]) {
|
||||
mis = misMatch(expected[name], testOpts[name]);
|
||||
testOpts[name] = expected[name];
|
||||
}
|
||||
}
|
||||
if (mis) throw new Error(mis);
|
||||
}
|
||||
}, function (err) {
|
||||
if (test.error) {
|
||||
if (err.message === test.error) {
|
||||
return;
|
||||
} else {
|
||||
throw new Error("Expected error message: " + test.error + ". Got error message: " + err.message);
|
||||
}
|
||||
}
|
||||
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
|
||||
function ppJSON(v) { return v instanceof RegExp ? v.toString() : JSON.stringify(v, null, 2); }
|
||||
function addPath(str, pt) {
|
||||
if (str.charAt(str.length-1) == ")")
|
||||
return str.slice(0, str.length-1) + "/" + pt + ")";
|
||||
return str + " (" + pt + ")";
|
||||
}
|
||||
|
||||
var misMatch = exports.misMatch = function(exp, act) {
|
||||
if (!exp || !act || (typeof exp != "object") || (typeof act != "object")) {
|
||||
if (exp !== act && typeof exp != "function")
|
||||
return ppJSON(exp) + " !== " + ppJSON(act);
|
||||
} else if (exp instanceof RegExp || act instanceof RegExp) {
|
||||
var left = ppJSON(exp), right = ppJSON(act);
|
||||
if (left !== right) return left + " !== " + right;
|
||||
} else if (exp.splice) {
|
||||
if (!act.slice) return ppJSON(exp) + " != " + ppJSON(act);
|
||||
if (act.length != exp.length) return "array length mismatch " + exp.length + " != " + act.length;
|
||||
for (var i = 0; i < act.length; ++i) {
|
||||
var mis = misMatch(exp[i], act[i]);
|
||||
if (mis) return addPath(mis, i);
|
||||
}
|
||||
} else {
|
||||
for (var prop in exp) {
|
||||
var mis = misMatch(exp[prop], act[prop]);
|
||||
if (mis) return addPath(mis, prop);
|
||||
}
|
||||
}
|
||||
};
|
||||
2
test/mocha.opts
Normal file
2
test/mocha.opts
Normal file
@ -0,0 +1,2 @@
|
||||
--reporter dot
|
||||
--ui tdd
|
||||
3433
test/tests-babel.js
Normal file
3433
test/tests-babel.js
Normal file
File diff suppressed because it is too large
Load Diff
11245
test/tests-flow.js
Normal file
11245
test/tests-flow.js
Normal file
File diff suppressed because it is too large
Load Diff
15331
test/tests-harmony.js
Executable file
15331
test/tests-harmony.js
Executable file
File diff suppressed because it is too large
Load Diff
3654
test/tests-jsx.js
Normal file
3654
test/tests-jsx.js
Normal file
File diff suppressed because it is too large
Load Diff
28853
test/tests.js
Executable file
28853
test/tests.js
Executable file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user