aboutsummaryrefslogtreecommitdiff
path: root/node_modules/acorn/src/lval.js
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2017-05-03 15:35:00 +0200
committerFlorian Dold <florian.dold@gmail.com>2017-05-03 15:35:00 +0200
commitde98e0b232509d5f40c135d540a70e415272ff85 (patch)
treea79222a5b58484ab3b80d18efcaaa7ccc4769b33 /node_modules/acorn/src/lval.js
parente0c9d480a73fa629c1e4a47d3e721f1d2d345406 (diff)
node_modules
Diffstat (limited to 'node_modules/acorn/src/lval.js')
-rw-r--r--node_modules/acorn/src/lval.js236
1 files changed, 236 insertions, 0 deletions
diff --git a/node_modules/acorn/src/lval.js b/node_modules/acorn/src/lval.js
new file mode 100644
index 000000000..815d9966a
--- /dev/null
+++ b/node_modules/acorn/src/lval.js
@@ -0,0 +1,236 @@
+import {types as tt} from "./tokentype"
+import {Parser} from "./state"
+import {has} from "./util"
+
+const pp = Parser.prototype
+
+// Convert existing expression atom to assignable pattern
+// if possible.
+
+pp.toAssignable = function(node, isBinding) {
+ if (this.options.ecmaVersion >= 6 && node) {
+ switch (node.type) {
+ case "Identifier":
+ if (this.inAsync && node.name === "await")
+ this.raise(node.start, "Can not use 'await' as identifier inside an async function")
+ break
+
+ case "ObjectPattern":
+ case "ArrayPattern":
+ break
+
+ case "ObjectExpression":
+ node.type = "ObjectPattern"
+ for (let i = 0; i < node.properties.length; i++) {
+ let prop = node.properties[i]
+ if (prop.kind !== "init") this.raise(prop.key.start, "Object pattern can't contain getter or setter")
+ this.toAssignable(prop.value, isBinding)
+ }
+ break
+
+ case "ArrayExpression":
+ node.type = "ArrayPattern"
+ this.toAssignableList(node.elements, isBinding)
+ break
+
+ case "AssignmentExpression":
+ if (node.operator === "=") {
+ node.type = "AssignmentPattern"
+ delete node.operator
+ this.toAssignable(node.left, isBinding)
+ // falls through to AssignmentPattern
+ } else {
+ this.raise(node.left.end, "Only '=' operator can be used for specifying default value.")
+ break
+ }
+
+ case "AssignmentPattern":
+ break
+
+ case "ParenthesizedExpression":
+ node.expression = this.toAssignable(node.expression, isBinding)
+ break
+
+ case "MemberExpression":
+ if (!isBinding) break
+
+ default:
+ this.raise(node.start, "Assigning to rvalue")
+ }
+ }
+ return node
+}
+
+// Convert list of expression atoms to binding list.
+
+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
+ }
+
+ if (isBinding && last && last.type === "RestElement" && last.argument.type !== "Identifier")
+ this.unexpected(last.argument.start)
+ }
+ for (let i = 0; i < end; i++) {
+ let elt = exprList[i]
+ if (elt) this.toAssignable(elt, isBinding)
+ }
+ return exprList
+}
+
+// Parses spread element.
+
+pp.parseSpread = function(refDestructuringErrors) {
+ let node = this.startNode()
+ this.next()
+ node.argument = this.parseMaybeAssign(false, refDestructuringErrors)
+ return this.finishNode(node, "SpreadElement")
+}
+
+pp.parseRest = function(allowNonIdent) {
+ let node = this.startNode()
+ this.next()
+
+ // RestElement inside of a function parameter must be an identifier
+ if (allowNonIdent) node.argument = this.type === tt.name ? this.parseIdent() : this.unexpected()
+ else 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()
+ switch (this.type) {
+ case tt.name:
+ 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")
+
+ case tt.braceL:
+ return this.parseObj(true)
+
+ default:
+ this.unexpected()
+ }
+}
+
+pp.parseBindingList = function(close, allowEmpty, allowTrailingComma, allowNonIdent) {
+ let elts = [], first = true
+ while (!this.eat(close)) {
+ if (first) first = false
+ else this.expect(tt.comma)
+ if (allowEmpty && this.type === tt.comma) {
+ elts.push(null)
+ } else if (allowTrailingComma && this.afterTrailingComma(close)) {
+ break
+ } else if (this.type === tt.ellipsis) {
+ let rest = this.parseRest(allowNonIdent)
+ this.parseBindingListItem(rest)
+ elts.push(rest)
+ if (this.type === tt.comma) this.raise(this.start, "Comma is not permitted after the rest element")
+ this.expect(close)
+ break
+ } else {
+ let elem = this.parseMaybeDefault(this.start, this.startLoc)
+ this.parseBindingListItem(elem)
+ elts.push(elem)
+ }
+ }
+ return elts
+}
+
+pp.parseBindingListItem = function(param) {
+ return param
+}
+
+// Parses assignment pattern around given atom if possible.
+
+pp.parseMaybeDefault = function(startPos, startLoc, left) {
+ left = left || this.parseBindingAtom()
+ if (this.options.ecmaVersion < 6 || !this.eat(tt.eq)) return left
+ let node = this.startNodeAt(startPos, startLoc)
+ 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.
+// bindingType can be either:
+// 'var' indicating that the lval creates a 'var' binding
+// 'let' indicating that the lval creates a lexical ('let' or 'const') binding
+// 'none' indicating that the binding should be checked for illegal identifiers, but not for duplicate references
+
+pp.checkLVal = function(expr, bindingType, checkClashes) {
+ switch (expr.type) {
+ case "Identifier":
+ if (this.strict && this.reservedWordsStrictBind.test(expr.name))
+ this.raiseRecoverable(expr.start, (bindingType ? "Binding " : "Assigning to ") + expr.name + " in strict mode")
+ if (checkClashes) {
+ if (has(checkClashes, expr.name))
+ this.raiseRecoverable(expr.start, "Argument name clash")
+ checkClashes[expr.name] = true
+ }
+ if (bindingType && bindingType !== "none") {
+ if (
+ bindingType === "var" && !this.canDeclareVarName(expr.name) ||
+ bindingType !== "var" && !this.canDeclareLexicalName(expr.name)
+ ) {
+ this.raiseRecoverable(expr.start, `Identifier '${expr.name}' has already been declared`)
+ }
+ if (bindingType === "var") {
+ this.declareVarName(expr.name)
+ } else {
+ this.declareLexicalName(expr.name)
+ }
+ }
+ break
+
+ case "MemberExpression":
+ if (bindingType) this.raiseRecoverable(expr.start, (bindingType ? "Binding" : "Assigning to") + " member expression")
+ break
+
+ case "ObjectPattern":
+ for (let i = 0; i < expr.properties.length; i++)
+ this.checkLVal(expr.properties[i].value, bindingType, checkClashes)
+ break
+
+ case "ArrayPattern":
+ for (let i = 0; i < expr.elements.length; i++) {
+ let elem = expr.elements[i]
+ if (elem) this.checkLVal(elem, bindingType, checkClashes)
+ }
+ break
+
+ case "AssignmentPattern":
+ this.checkLVal(expr.left, bindingType, checkClashes)
+ break
+
+ case "RestElement":
+ this.checkLVal(expr.argument, bindingType, checkClashes)
+ break
+
+ case "ParenthesizedExpression":
+ this.checkLVal(expr.expression, bindingType, checkClashes)
+ break
+
+ default:
+ this.raise(expr.start, (bindingType ? "Binding" : "Assigning to") + " rvalue")
+ }
+}