UNPKG

8.2 kBJavaScriptView Raw
1/* @flow */
2
3"use strict";
4
5var _getIterator = require("babel-runtime/core-js/get-iterator")["default"];
6
7var _interopRequireDefault = require("babel-runtime/helpers/interop-require-default")["default"];
8
9var _tokenizerTypes = require("../tokenizer/types");
10
11var _index = require("./index");
12
13var _index2 = _interopRequireDefault(_index);
14
15var _utilIdentifier = require("../util/identifier");
16
17var pp = _index2["default"].prototype;
18
19// Convert existing expression atom to assignable pattern
20// if possible.
21
22pp.toAssignable = function (node, isBinding) {
23 if (node) {
24 switch (node.type) {
25 case "Identifier":
26 case "ObjectPattern":
27 case "ArrayPattern":
28 case "AssignmentPattern":
29 break;
30
31 case "ObjectExpression":
32 node.type = "ObjectPattern";
33 for (var _iterator = (node.properties /*: Array<Object>*/), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {
34 var _ref;
35
36 if (_isArray) {
37 if (_i >= _iterator.length) break;
38 _ref = _iterator[_i++];
39 } else {
40 _i = _iterator.next();
41 if (_i.done) break;
42 _ref = _i.value;
43 }
44
45 var prop = _ref;
46
47 if (prop.type === "SpreadProperty") continue;
48
49 if (prop.type === "ObjectMethod") {
50 if (prop.kind === "get" || prop.kind === "set") {
51 this.raise(prop.key.start, "Object pattern can't contain getter or setter");
52 } else {
53 this.raise(prop.key.start, "Object pattern can't contain methods");
54 }
55 }
56
57 if (prop.type === "ObjectProperty") {
58 this.toAssignable(prop.value, isBinding);
59 }
60 }
61 break;
62
63 case "ArrayExpression":
64 node.type = "ArrayPattern";
65 this.toAssignableList(node.elements, isBinding);
66 break;
67
68 case "AssignmentExpression":
69 if (node.operator === "=") {
70 node.type = "AssignmentPattern";
71 delete node.operator;
72 } else {
73 this.raise(node.left.end, "Only '=' operator can be used for specifying default value.");
74 }
75 break;
76
77 case "MemberExpression":
78 if (!isBinding) break;
79
80 default:
81 this.raise(node.start, "Assigning to rvalue");
82 }
83 }
84 return node;
85};
86
87// Convert list of expression atoms to binding list.
88
89pp.toAssignableList = function (exprList, isBinding) {
90 var end = exprList.length;
91 if (end) {
92 var last = exprList[end - 1];
93 if (last && last.type === "RestElement") {
94 --end;
95 } else if (last && last.type === "SpreadElement") {
96 last.type = "RestElement";
97 var arg = last.argument;
98 this.toAssignable(arg, isBinding);
99 if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern") {
100 this.unexpected(arg.start);
101 }
102 --end;
103 }
104 }
105 for (var i = 0; i < end; i++) {
106 var elt = exprList[i];
107 if (elt) this.toAssignable(elt, isBinding);
108 }
109 return exprList;
110};
111
112// Convert list of expression atoms to a list of
113
114pp.toReferencedList = function (exprList) {
115 return exprList;
116};
117
118// Parses spread element.
119
120pp.parseSpread = function (refShorthandDefaultPos) {
121 var node = this.startNode();
122 this.next();
123 node.argument = this.parseMaybeAssign(refShorthandDefaultPos);
124 return this.finishNode(node, "SpreadElement");
125};
126
127pp.parseRest = function () {
128 var node = this.startNode();
129 this.next();
130 node.argument = this.parseBindingIdentifier();
131 return this.finishNode(node, "RestElement");
132};
133
134pp.shouldAllowYieldIdentifier = function () {
135 return this.match(_tokenizerTypes.types._yield) && !this.state.strict && !this.state.inGenerator;
136};
137
138pp.parseBindingIdentifier = function () {
139 return this.parseIdentifier(this.shouldAllowYieldIdentifier());
140};
141
142// Parses lvalue (assignable) atom.
143
144pp.parseBindingAtom = function () {
145 switch (this.state.type) {
146 case _tokenizerTypes.types._yield:
147 if (this.state.strict || this.state.inGenerator) this.unexpected();
148
149 case _tokenizerTypes.types.name:
150 return this.parseIdentifier(true);
151
152 case _tokenizerTypes.types.bracketL:
153 var node = this.startNode();
154 this.next();
155 node.elements = this.parseBindingList(_tokenizerTypes.types.bracketR, true, true);
156 return this.finishNode(node, "ArrayPattern");
157
158 case _tokenizerTypes.types.braceL:
159 return this.parseObj(true);
160
161 default:
162 this.unexpected();
163 }
164};
165
166pp.parseBindingList = function (close, allowEmpty, allowTrailingComma) {
167 var elts = [];
168 var first = true;
169 while (!this.eat(close)) {
170 if (first) {
171 first = false;
172 } else {
173 this.expect(_tokenizerTypes.types.comma);
174 }
175 if (allowEmpty && this.match(_tokenizerTypes.types.comma)) {
176 elts.push(null);
177 } else if (allowTrailingComma && this.eat(close)) {
178 break;
179 } else if (this.match(_tokenizerTypes.types.ellipsis)) {
180 elts.push(this.parseAssignableListItemTypes(this.parseRest()));
181 this.expect(close);
182 break;
183 } else {
184 var left = this.parseMaybeDefault();
185 this.parseAssignableListItemTypes(left);
186 elts.push(this.parseMaybeDefault(null, null, left));
187 }
188 }
189 return elts;
190};
191
192pp.parseAssignableListItemTypes = function (param) {
193 return param;
194};
195
196// Parses assignment pattern around given atom if possible.
197
198pp.parseMaybeDefault = function (startPos, startLoc, left) {
199 startLoc = startLoc || this.state.startLoc;
200 startPos = startPos || this.state.start;
201 left = left || this.parseBindingAtom();
202 if (!this.eat(_tokenizerTypes.types.eq)) return left;
203
204 var node = this.startNodeAt(startPos, startLoc);
205 node.left = left;
206 node.right = this.parseMaybeAssign();
207 return this.finishNode(node, "AssignmentPattern");
208};
209
210// Verify that a node is an lval — something that can be assigned
211// to.
212
213pp.checkLVal = function (expr, isBinding, checkClashes) {
214 switch (expr.type) {
215 case "Identifier":
216 if (this.state.strict && (_utilIdentifier.reservedWords.strictBind(expr.name) || _utilIdentifier.reservedWords.strict(expr.name))) {
217 this.raise(expr.start, (isBinding ? "Binding " : "Assigning to ") + expr.name + " in strict mode");
218 }
219
220 if (checkClashes) {
221 if (checkClashes[expr.name]) {
222 this.raise(expr.start, "Argument name clash in strict mode");
223 } else {
224 checkClashes[expr.name] = true;
225 }
226 }
227 break;
228
229 case "MemberExpression":
230 if (isBinding) this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression");
231 break;
232
233 case "ObjectPattern":
234 for (var _iterator2 = (expr.properties /*: Array<Object>*/), _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {
235 var _ref2;
236
237 if (_isArray2) {
238 if (_i2 >= _iterator2.length) break;
239 _ref2 = _iterator2[_i2++];
240 } else {
241 _i2 = _iterator2.next();
242 if (_i2.done) break;
243 _ref2 = _i2.value;
244 }
245
246 var prop = _ref2;
247
248 if (prop.type === "ObjectProperty") prop = prop.value;
249 this.checkLVal(prop, isBinding, checkClashes);
250 }
251 break;
252
253 case "ArrayPattern":
254 for (var _iterator3 = (expr.elements /*: Array<Object>*/), _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {
255 var _ref3;
256
257 if (_isArray3) {
258 if (_i3 >= _iterator3.length) break;
259 _ref3 = _iterator3[_i3++];
260 } else {
261 _i3 = _iterator3.next();
262 if (_i3.done) break;
263 _ref3 = _i3.value;
264 }
265
266 var elem = _ref3;
267
268 if (elem) this.checkLVal(elem, isBinding, checkClashes);
269 }
270 break;
271
272 case "AssignmentPattern":
273 this.checkLVal(expr.left, isBinding, checkClashes);
274 break;
275
276 case "RestProperty":
277 case "RestElement":
278 this.checkLVal(expr.argument, isBinding, checkClashes);
279 break;
280
281 default:
282 this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue");
283 }
284};
\No newline at end of file