Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80550 views
1
import {types as tt} from "./tokentype"
2
import {Parser} from "./state"
3
import {reservedWords} from "./identifier"
4
import {has} from "./util"
5
6
const pp = Parser.prototype
7
8
// Convert existing expression atom to assignable pattern
9
// if possible.
10
11
pp.toAssignable = function(node, isBinding) {
12
if (this.options.ecmaVersion >= 6 && node) {
13
switch (node.type) {
14
case "Identifier":
15
case "ObjectPattern":
16
case "ArrayPattern":
17
case "AssignmentPattern":
18
break
19
20
case "ObjectExpression":
21
node.type = "ObjectPattern"
22
for (let i = 0; i < node.properties.length; i++) {
23
let prop = node.properties[i]
24
if (prop.kind !== "init") this.raise(prop.key.start, "Object pattern can't contain getter or setter")
25
this.toAssignable(prop.value, isBinding)
26
}
27
break
28
29
case "ArrayExpression":
30
node.type = "ArrayPattern"
31
this.toAssignableList(node.elements, isBinding)
32
break
33
34
case "AssignmentExpression":
35
if (node.operator === "=") {
36
node.type = "AssignmentPattern"
37
} else {
38
this.raise(node.left.end, "Only '=' operator can be used for specifying default value.")
39
}
40
break
41
42
case "ParenthesizedExpression":
43
node.expression = this.toAssignable(node.expression, isBinding)
44
break
45
46
case "MemberExpression":
47
if (!isBinding) break
48
49
default:
50
this.raise(node.start, "Assigning to rvalue")
51
}
52
}
53
return node
54
}
55
56
// Convert list of expression atoms to binding list.
57
58
pp.toAssignableList = function(exprList, isBinding) {
59
let end = exprList.length
60
if (end) {
61
let last = exprList[end - 1]
62
if (last && last.type == "RestElement") {
63
--end
64
} else if (last && last.type == "SpreadElement") {
65
last.type = "RestElement"
66
let arg = last.argument
67
this.toAssignable(arg, isBinding)
68
if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern")
69
this.unexpected(arg.start)
70
--end
71
}
72
}
73
for (let i = 0; i < end; i++) {
74
let elt = exprList[i]
75
if (elt) this.toAssignable(elt, isBinding)
76
}
77
return exprList
78
}
79
80
// Parses spread element.
81
82
pp.parseSpread = function(refShorthandDefaultPos) {
83
let node = this.startNode()
84
this.next()
85
node.argument = this.parseMaybeAssign(refShorthandDefaultPos)
86
return this.finishNode(node, "SpreadElement")
87
}
88
89
pp.parseRest = function() {
90
let node = this.startNode()
91
this.next()
92
node.argument = this.type === tt.name || this.type === tt.bracketL ? this.parseBindingAtom() : this.unexpected()
93
return this.finishNode(node, "RestElement")
94
}
95
96
// Parses lvalue (assignable) atom.
97
98
pp.parseBindingAtom = function() {
99
if (this.options.ecmaVersion < 6) return this.parseIdent()
100
switch (this.type) {
101
case tt.name:
102
return this.parseIdent()
103
104
case tt.bracketL:
105
let node = this.startNode()
106
this.next()
107
node.elements = this.parseBindingList(tt.bracketR, true, true)
108
return this.finishNode(node, "ArrayPattern")
109
110
case tt.braceL:
111
return this.parseObj(true)
112
113
default:
114
this.unexpected()
115
}
116
}
117
118
pp.parseBindingList = function(close, allowEmpty, allowTrailingComma) {
119
let elts = [], first = true
120
while (!this.eat(close)) {
121
if (first) first = false
122
else this.expect(tt.comma)
123
if (allowEmpty && this.type === tt.comma) {
124
elts.push(null)
125
} else if (allowTrailingComma && this.afterTrailingComma(close)) {
126
break
127
} else if (this.type === tt.ellipsis) {
128
let rest = this.parseRest()
129
this.parseBindingListItem(rest)
130
elts.push(rest)
131
this.expect(close)
132
break
133
} else {
134
let elem = this.parseMaybeDefault(this.start, this.startLoc)
135
this.parseBindingListItem(elem)
136
elts.push(elem)
137
}
138
}
139
return elts
140
}
141
142
pp.parseBindingListItem = function(param) {
143
return param
144
}
145
146
// Parses assignment pattern around given atom if possible.
147
148
pp.parseMaybeDefault = function(startPos, startLoc, left) {
149
if (Array.isArray(startPos)){
150
if (this.options.locations && noCalls === undefined) {
151
// shift arguments to left by one
152
left = startLoc
153
// flatten startPos
154
startLoc = startPos[1]
155
startPos = startPos[0]
156
}
157
}
158
left = left || this.parseBindingAtom()
159
if (!this.eat(tt.eq)) return left
160
let node = this.startNodeAt(startPos, startLoc)
161
node.operator = "="
162
node.left = left
163
node.right = this.parseMaybeAssign()
164
return this.finishNode(node, "AssignmentPattern")
165
}
166
167
// Verify that a node is an lval — something that can be assigned
168
// to.
169
170
pp.checkLVal = function(expr, isBinding, checkClashes) {
171
switch (expr.type) {
172
case "Identifier":
173
if (this.strict && (reservedWords.strictBind(expr.name) || reservedWords.strict(expr.name)))
174
this.raise(expr.start, (isBinding ? "Binding " : "Assigning to ") + expr.name + " in strict mode")
175
if (checkClashes) {
176
if (has(checkClashes, expr.name))
177
this.raise(expr.start, "Argument name clash in strict mode")
178
checkClashes[expr.name] = true
179
}
180
break
181
182
case "MemberExpression":
183
if (isBinding) this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression")
184
break
185
186
case "ObjectPattern":
187
for (let i = 0; i < expr.properties.length; i++)
188
this.checkLVal(expr.properties[i].value, isBinding, checkClashes)
189
break
190
191
case "ArrayPattern":
192
for (let i = 0; i < expr.elements.length; i++) {
193
let elem = expr.elements[i]
194
if (elem) this.checkLVal(elem, isBinding, checkClashes)
195
}
196
break
197
198
case "AssignmentPattern":
199
this.checkLVal(expr.left, isBinding, checkClashes)
200
break
201
202
case "RestElement":
203
this.checkLVal(expr.argument, isBinding, checkClashes)
204
break
205
206
case "ParenthesizedExpression":
207
this.checkLVal(expr.expression, isBinding, checkClashes)
208
break
209
210
default:
211
this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue")
212
}
213
}
214
215