1 |
|
2 |
|
3 | "use strict";
|
4 |
|
5 | var _Object$create = require("babel-runtime/core-js/object/create")["default"];
|
6 |
|
7 | var _getIterator = require("babel-runtime/core-js/get-iterator")["default"];
|
8 |
|
9 | var _interopRequireDefault = require("babel-runtime/helpers/interop-require-default")["default"];
|
10 |
|
11 | var _tokenizerTypes = require("../tokenizer/types");
|
12 |
|
13 | var _index = require("./index");
|
14 |
|
15 | var _index2 = _interopRequireDefault(_index);
|
16 |
|
17 | var _utilWhitespace = require("../util/whitespace");
|
18 |
|
19 | var pp = _index2["default"].prototype;
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 | pp.parseTopLevel = function (file, program) {
|
29 | program.sourceType = this.options.sourceType;
|
30 |
|
31 | this.parseBlockBody(program, true, true, _tokenizerTypes.types.eof);
|
32 |
|
33 | file.program = this.finishNode(program, "Program");
|
34 | file.comments = this.state.comments;
|
35 | file.tokens = this.state.tokens;
|
36 |
|
37 | return this.finishNode(file, "File");
|
38 | };
|
39 |
|
40 | var loopLabel = { kind: "loop" },
|
41 | switchLabel = { kind: "switch" };
|
42 |
|
43 |
|
44 |
|
45 | pp.parseDirective = function () {
|
46 | var directiveLiteral = this.startNode();
|
47 | var directive = this.startNode();
|
48 |
|
49 | var raw = this.input.slice(this.state.start, this.state.end);
|
50 | var val = directiveLiteral.value = raw.slice(1, -1);
|
51 |
|
52 | this.addExtra(directiveLiteral, "raw", raw);
|
53 | this.addExtra(directiveLiteral, "rawValue", val);
|
54 |
|
55 | this.next();
|
56 |
|
57 | directive.value = this.finishNode(directiveLiteral, "DirectiveLiteral");
|
58 |
|
59 | this.semicolon();
|
60 | return this.finishNode(directive, "Directive");
|
61 | };
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 | pp.parseStatement = function (declaration, topLevel) {
|
71 | if (this.match(_tokenizerTypes.types.at)) {
|
72 | this.parseDecorators(true);
|
73 | }
|
74 |
|
75 | var starttype = this.state.type,
|
76 | node = this.startNode();
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 | switch (starttype) {
|
83 | case _tokenizerTypes.types._break:case _tokenizerTypes.types._continue:
|
84 | return this.parseBreakContinueStatement(node, starttype.keyword);
|
85 | case _tokenizerTypes.types._debugger:
|
86 | return this.parseDebuggerStatement(node);
|
87 | case _tokenizerTypes.types._do:
|
88 | return this.parseDoStatement(node);
|
89 | case _tokenizerTypes.types._for:
|
90 | return this.parseForStatement(node);
|
91 | case _tokenizerTypes.types._function:
|
92 | if (!declaration) this.unexpected();
|
93 | return this.parseFunctionStatement(node);
|
94 |
|
95 | case _tokenizerTypes.types._class:
|
96 | if (!declaration) this.unexpected();
|
97 | this.takeDecorators(node);
|
98 | return this.parseClass(node, true);
|
99 |
|
100 | case _tokenizerTypes.types._if:
|
101 | return this.parseIfStatement(node);
|
102 | case _tokenizerTypes.types._return:
|
103 | return this.parseReturnStatement(node);
|
104 | case _tokenizerTypes.types._switch:
|
105 | return this.parseSwitchStatement(node);
|
106 | case _tokenizerTypes.types._throw:
|
107 | return this.parseThrowStatement(node);
|
108 | case _tokenizerTypes.types._try:
|
109 | return this.parseTryStatement(node);
|
110 |
|
111 | case _tokenizerTypes.types._let:
|
112 | case _tokenizerTypes.types._const:
|
113 | if (!declaration) this.unexpected();
|
114 |
|
115 | case _tokenizerTypes.types._var:
|
116 | return this.parseVarStatement(node, starttype);
|
117 |
|
118 | case _tokenizerTypes.types._while:
|
119 | return this.parseWhileStatement(node);
|
120 | case _tokenizerTypes.types._with:
|
121 | return this.parseWithStatement(node);
|
122 | case _tokenizerTypes.types.braceL:
|
123 | return this.parseBlock();
|
124 | case _tokenizerTypes.types.semi:
|
125 | return this.parseEmptyStatement(node);
|
126 | case _tokenizerTypes.types._export:
|
127 | case _tokenizerTypes.types._import:
|
128 | if (!this.options.allowImportExportEverywhere) {
|
129 | if (!topLevel) {
|
130 | this.raise(this.state.start, "'import' and 'export' may only appear at the top level");
|
131 | }
|
132 |
|
133 | if (!this.inModule) {
|
134 | this.raise(this.state.start, "'import' and 'export' may appear only with 'sourceType: module'");
|
135 | }
|
136 | }
|
137 | return starttype === _tokenizerTypes.types._import ? this.parseImport(node) : this.parseExport(node);
|
138 |
|
139 | case _tokenizerTypes.types.name:
|
140 | if (this.hasPlugin("asyncFunctions") && this.state.value === "async") {
|
141 |
|
142 | var state = this.state.clone();
|
143 | this.next();
|
144 | if (this.match(_tokenizerTypes.types._function) && !this.canInsertSemicolon()) {
|
145 | this.expect(_tokenizerTypes.types._function);
|
146 | return this.parseFunction(node, true, false, true);
|
147 | } else {
|
148 | this.state = state;
|
149 | }
|
150 | }
|
151 | }
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 | var maybeName = this.state.value;
|
159 | var expr = this.parseExpression();
|
160 |
|
161 | if (starttype === _tokenizerTypes.types.name && expr.type === "Identifier" && this.eat(_tokenizerTypes.types.colon)) {
|
162 | return this.parseLabeledStatement(node, maybeName, expr);
|
163 | } else {
|
164 | return this.parseExpressionStatement(node, expr);
|
165 | }
|
166 | };
|
167 |
|
168 | pp.takeDecorators = function (node) {
|
169 | if (this.state.decorators.length) {
|
170 | node.decorators = this.state.decorators;
|
171 | this.state.decorators = [];
|
172 | }
|
173 | };
|
174 |
|
175 | pp.parseDecorators = function (allowExport) {
|
176 | while (this.match(_tokenizerTypes.types.at)) {
|
177 | this.state.decorators.push(this.parseDecorator());
|
178 | }
|
179 |
|
180 | if (allowExport && this.match(_tokenizerTypes.types._export)) {
|
181 | return;
|
182 | }
|
183 |
|
184 | if (!this.match(_tokenizerTypes.types._class)) {
|
185 | this.raise(this.state.start, "Leading decorators must be attached to a class declaration");
|
186 | }
|
187 | };
|
188 |
|
189 | pp.parseDecorator = function () {
|
190 | if (!this.hasPlugin("decorators")) {
|
191 | this.unexpected();
|
192 | }
|
193 | var node = this.startNode();
|
194 | this.next();
|
195 | node.expression = this.parseMaybeAssign();
|
196 | return this.finishNode(node, "Decorator");
|
197 | };
|
198 |
|
199 | pp.parseBreakContinueStatement = function (node, keyword) {
|
200 | var isBreak = keyword === "break";
|
201 | this.next();
|
202 |
|
203 | if (this.isLineTerminator()) {
|
204 | node.label = null;
|
205 | } else if (!this.match(_tokenizerTypes.types.name)) {
|
206 | this.unexpected();
|
207 | } else {
|
208 | node.label = this.parseIdentifier();
|
209 | this.semicolon();
|
210 | }
|
211 |
|
212 |
|
213 |
|
214 | var i = undefined;
|
215 | for (i = 0; i < this.state.labels.length; ++i) {
|
216 | var lab = this.state.labels[i];
|
217 | if (node.label == null || lab.name === node.label.name) {
|
218 | if (lab.kind != null && (isBreak || lab.kind === "loop")) break;
|
219 | if (node.label && isBreak) break;
|
220 | }
|
221 | }
|
222 | if (i === this.state.labels.length) this.raise(node.start, "Unsyntactic " + keyword);
|
223 | return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement");
|
224 | };
|
225 |
|
226 | pp.parseDebuggerStatement = function (node) {
|
227 | this.next();
|
228 | this.semicolon();
|
229 | return this.finishNode(node, "DebuggerStatement");
|
230 | };
|
231 |
|
232 | pp.parseDoStatement = function (node) {
|
233 | this.next();
|
234 | this.state.labels.push(loopLabel);
|
235 | node.body = this.parseStatement(false);
|
236 | this.state.labels.pop();
|
237 | this.expect(_tokenizerTypes.types._while);
|
238 | node.test = this.parseParenExpression();
|
239 | this.eat(_tokenizerTypes.types.semi);
|
240 | return this.finishNode(node, "DoWhileStatement");
|
241 | };
|
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 |
|
248 |
|
249 |
|
250 |
|
251 | pp.parseForStatement = function (node) {
|
252 | this.next();
|
253 | this.state.labels.push(loopLabel);
|
254 | this.expect(_tokenizerTypes.types.parenL);
|
255 |
|
256 | if (this.match(_tokenizerTypes.types.semi)) {
|
257 | return this.parseFor(node, null);
|
258 | }
|
259 |
|
260 | if (this.match(_tokenizerTypes.types._var) || this.match(_tokenizerTypes.types._let) || this.match(_tokenizerTypes.types._const)) {
|
261 | var _init = this.startNode(),
|
262 | varKind = this.state.type;
|
263 | this.next();
|
264 | this.parseVar(_init, true, varKind);
|
265 | this.finishNode(_init, "VariableDeclaration");
|
266 |
|
267 | if (this.match(_tokenizerTypes.types._in) || this.isContextual("of")) {
|
268 | if (_init.declarations.length === 1 && !_init.declarations[0].init) {
|
269 | return this.parseForIn(node, _init);
|
270 | }
|
271 | }
|
272 |
|
273 | return this.parseFor(node, _init);
|
274 | }
|
275 |
|
276 | var refShorthandDefaultPos = { start: 0 };
|
277 | var init = this.parseExpression(true, refShorthandDefaultPos);
|
278 | if (this.match(_tokenizerTypes.types._in) || this.isContextual("of")) {
|
279 | this.toAssignable(init);
|
280 | this.checkLVal(init);
|
281 | return this.parseForIn(node, init);
|
282 | } else if (refShorthandDefaultPos.start) {
|
283 | this.unexpected(refShorthandDefaultPos.start);
|
284 | }
|
285 | return this.parseFor(node, init);
|
286 | };
|
287 |
|
288 | pp.parseFunctionStatement = function (node) {
|
289 | this.next();
|
290 | return this.parseFunction(node, true);
|
291 | };
|
292 |
|
293 | pp.parseIfStatement = function (node) {
|
294 | this.next();
|
295 | node.test = this.parseParenExpression();
|
296 | node.consequent = this.parseStatement(false);
|
297 | node.alternate = this.eat(_tokenizerTypes.types._else) ? this.parseStatement(false) : null;
|
298 | return this.finishNode(node, "IfStatement");
|
299 | };
|
300 |
|
301 | pp.parseReturnStatement = function (node) {
|
302 | if (!this.state.inFunction && !this.options.allowReturnOutsideFunction) {
|
303 | this.raise(this.state.start, "'return' outside of function");
|
304 | }
|
305 |
|
306 | this.next();
|
307 |
|
308 |
|
309 |
|
310 |
|
311 |
|
312 | if (this.isLineTerminator()) {
|
313 | node.argument = null;
|
314 | } else {
|
315 | node.argument = this.parseExpression();
|
316 | this.semicolon();
|
317 | }
|
318 |
|
319 | return this.finishNode(node, "ReturnStatement");
|
320 | };
|
321 |
|
322 | pp.parseSwitchStatement = function (node) {
|
323 | this.next();
|
324 | node.discriminant = this.parseParenExpression();
|
325 | node.cases = [];
|
326 | this.expect(_tokenizerTypes.types.braceL);
|
327 | this.state.labels.push(switchLabel);
|
328 |
|
329 |
|
330 |
|
331 |
|
332 |
|
333 | var cur = undefined;
|
334 | for (var sawDefault = undefined; !this.match(_tokenizerTypes.types.braceR);) {
|
335 | if (this.match(_tokenizerTypes.types._case) || this.match(_tokenizerTypes.types._default)) {
|
336 | var isCase = this.match(_tokenizerTypes.types._case);
|
337 | if (cur) this.finishNode(cur, "SwitchCase");
|
338 | node.cases.push(cur = this.startNode());
|
339 | cur.consequent = [];
|
340 | this.next();
|
341 | if (isCase) {
|
342 | cur.test = this.parseExpression();
|
343 | } else {
|
344 | if (sawDefault) this.raise(this.state.lastTokStart, "Multiple default clauses");
|
345 | sawDefault = true;
|
346 | cur.test = null;
|
347 | }
|
348 | this.expect(_tokenizerTypes.types.colon);
|
349 | } else {
|
350 | if (cur) {
|
351 | cur.consequent.push(this.parseStatement(true));
|
352 | } else {
|
353 | this.unexpected();
|
354 | }
|
355 | }
|
356 | }
|
357 | if (cur) this.finishNode(cur, "SwitchCase");
|
358 | this.next();
|
359 | this.state.labels.pop();
|
360 | return this.finishNode(node, "SwitchStatement");
|
361 | };
|
362 |
|
363 | pp.parseThrowStatement = function (node) {
|
364 | this.next();
|
365 | if (_utilWhitespace.lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start))) this.raise(this.state.lastTokEnd, "Illegal newline after throw");
|
366 | node.argument = this.parseExpression();
|
367 | this.semicolon();
|
368 | return this.finishNode(node, "ThrowStatement");
|
369 | };
|
370 |
|
371 |
|
372 |
|
373 | var empty = [];
|
374 |
|
375 | pp.parseTryStatement = function (node) {
|
376 | this.next();
|
377 |
|
378 | node.block = this.parseBlock();
|
379 | node.handler = null;
|
380 |
|
381 | if (this.match(_tokenizerTypes.types._catch)) {
|
382 | var clause = this.startNode();
|
383 | this.next();
|
384 |
|
385 | this.expect(_tokenizerTypes.types.parenL);
|
386 | clause.param = this.parseBindingAtom();
|
387 | this.checkLVal(clause.param, true, _Object$create(null));
|
388 | this.expect(_tokenizerTypes.types.parenR);
|
389 |
|
390 | clause.body = this.parseBlock();
|
391 | node.handler = this.finishNode(clause, "CatchClause");
|
392 | }
|
393 |
|
394 | node.guardedHandlers = empty;
|
395 | node.finalizer = this.eat(_tokenizerTypes.types._finally) ? this.parseBlock() : null;
|
396 |
|
397 | if (!node.handler && !node.finalizer) {
|
398 | this.raise(node.start, "Missing catch or finally clause");
|
399 | }
|
400 |
|
401 | return this.finishNode(node, "TryStatement");
|
402 | };
|
403 |
|
404 | pp.parseVarStatement = function (node, kind) {
|
405 | this.next();
|
406 | this.parseVar(node, false, kind);
|
407 | this.semicolon();
|
408 | return this.finishNode(node, "VariableDeclaration");
|
409 | };
|
410 |
|
411 | pp.parseWhileStatement = function (node) {
|
412 | this.next();
|
413 | node.test = this.parseParenExpression();
|
414 | this.state.labels.push(loopLabel);
|
415 | node.body = this.parseStatement(false);
|
416 | this.state.labels.pop();
|
417 | return this.finishNode(node, "WhileStatement");
|
418 | };
|
419 |
|
420 | pp.parseWithStatement = function (node) {
|
421 | if (this.state.strict) this.raise(this.state.start, "'with' in strict mode");
|
422 | this.next();
|
423 | node.object = this.parseParenExpression();
|
424 | node.body = this.parseStatement(false);
|
425 | return this.finishNode(node, "WithStatement");
|
426 | };
|
427 |
|
428 | pp.parseEmptyStatement = function (node) {
|
429 | this.next();
|
430 | return this.finishNode(node, "EmptyStatement");
|
431 | };
|
432 |
|
433 | pp.parseLabeledStatement = function (node, maybeName, expr) {
|
434 | for (var _iterator = (this.state.labels ), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {
|
435 | var _ref;
|
436 |
|
437 | if (_isArray) {
|
438 | if (_i >= _iterator.length) break;
|
439 | _ref = _iterator[_i++];
|
440 | } else {
|
441 | _i = _iterator.next();
|
442 | if (_i.done) break;
|
443 | _ref = _i.value;
|
444 | }
|
445 |
|
446 | var label = _ref;
|
447 |
|
448 | if (label.name === maybeName) {
|
449 | this.raise(expr.start, "Label '" + maybeName + "' is already declared");
|
450 | }
|
451 | }
|
452 |
|
453 | var kind = this.state.type.isLoop ? "loop" : this.match(_tokenizerTypes.types._switch) ? "switch" : null;
|
454 | for (var i = this.state.labels.length - 1; i >= 0; i--) {
|
455 | var label = this.state.labels[i];
|
456 | if (label.statementStart === node.start) {
|
457 | label.statementStart = this.state.start;
|
458 | label.kind = kind;
|
459 | } else {
|
460 | break;
|
461 | }
|
462 | }
|
463 |
|
464 | this.state.labels.push({ name: maybeName, kind: kind, statementStart: this.state.start });
|
465 | node.body = this.parseStatement(true);
|
466 | this.state.labels.pop();
|
467 | node.label = expr;
|
468 | return this.finishNode(node, "LabeledStatement");
|
469 | };
|
470 |
|
471 | pp.parseExpressionStatement = function (node, expr) {
|
472 | node.expression = expr;
|
473 | this.semicolon();
|
474 | return this.finishNode(node, "ExpressionStatement");
|
475 | };
|
476 |
|
477 |
|
478 |
|
479 |
|
480 |
|
481 | pp.parseBlock = function (allowDirectives /*:: ?*/) {
|
482 | var node = this.startNode();
|
483 | this.expect(_tokenizerTypes.types.braceL);
|
484 | this.parseBlockBody(node, allowDirectives, false, _tokenizerTypes.types.braceR);
|
485 | return this.finishNode(node, "BlockStatement");
|
486 | };
|
487 |
|
488 |
|
489 |
|
490 | pp.parseBlockBody = function (node, allowDirectives, topLevel, end) {
|
491 | node.body = [];
|
492 | node.directives = [];
|
493 |
|
494 | var parsedNonDirective = false;
|
495 | var oldStrict = undefined;
|
496 | var octalPosition = undefined;
|
497 |
|
498 | while (!this.eat(end)) {
|
499 | if (allowDirectives && !parsedNonDirective && this.match(_tokenizerTypes.types.string)) {
|
500 | var oldState = this.state;
|
501 | var lookahead = this.lookahead();
|
502 | this.state = lookahead;
|
503 | var isDirective = this.isLineTerminator();
|
504 | this.state = oldState;
|
505 |
|
506 | if (isDirective) {
|
507 | if (this.state.containsOctal && !octalPosition) {
|
508 | octalPosition = this.state.octalPosition;
|
509 | }
|
510 |
|
511 | var stmt = this.parseDirective();
|
512 | node.directives.push(stmt);
|
513 |
|
514 | if (allowDirectives && stmt.value.value === "use strict") {
|
515 | oldStrict = this.state.strict;
|
516 | this.state.strict = true;
|
517 | this.setStrict(true);
|
518 |
|
519 | if (octalPosition) {
|
520 | this.raise(octalPosition, "Octal literal in strict mode");
|
521 | }
|
522 | }
|
523 |
|
524 | continue;
|
525 | }
|
526 | }
|
527 |
|
528 | parsedNonDirective = true;
|
529 | node.body.push(this.parseStatement(true, topLevel));
|
530 | }
|
531 |
|
532 | if (oldStrict === false) {
|
533 | this.setStrict(false);
|
534 | }
|
535 | };
|
536 |
|
537 |
|
538 |
|
539 |
|
540 |
|
541 | pp.parseFor = function (node, init) {
|
542 | node.init = init;
|
543 | this.expect(_tokenizerTypes.types.semi);
|
544 | node.test = this.match(_tokenizerTypes.types.semi) ? null : this.parseExpression();
|
545 | this.expect(_tokenizerTypes.types.semi);
|
546 | node.update = this.match(_tokenizerTypes.types.parenR) ? null : this.parseExpression();
|
547 | this.expect(_tokenizerTypes.types.parenR);
|
548 | node.body = this.parseStatement(false);
|
549 | this.state.labels.pop();
|
550 | return this.finishNode(node, "ForStatement");
|
551 | };
|
552 |
|
553 |
|
554 |
|
555 |
|
556 | pp.parseForIn = function (node, init) {
|
557 | var type = this.match(_tokenizerTypes.types._in) ? "ForInStatement" : "ForOfStatement";
|
558 | this.next();
|
559 | node.left = init;
|
560 | node.right = this.parseExpression();
|
561 | this.expect(_tokenizerTypes.types.parenR);
|
562 | node.body = this.parseStatement(false);
|
563 | this.state.labels.pop();
|
564 | return this.finishNode(node, type);
|
565 | };
|
566 |
|
567 |
|
568 |
|
569 | pp.parseVar = function (node, isFor, kind) {
|
570 | node.declarations = [];
|
571 | node.kind = kind.keyword;
|
572 | for (;;) {
|
573 | var decl = this.startNode();
|
574 | this.parseVarHead(decl);
|
575 | if (this.eat(_tokenizerTypes.types.eq)) {
|
576 | decl.init = this.parseMaybeAssign(isFor);
|
577 | } else if (kind === _tokenizerTypes.types._const && !(this.match(_tokenizerTypes.types._in) || this.isContextual("of"))) {
|
578 | this.unexpected();
|
579 | } else if (decl.id.type !== "Identifier" && !(isFor && (this.match(_tokenizerTypes.types._in) || this.isContextual("of")))) {
|
580 | this.raise(this.state.lastTokEnd, "Complex binding patterns require an initialization value");
|
581 | } else {
|
582 | decl.init = null;
|
583 | }
|
584 | node.declarations.push(this.finishNode(decl, "VariableDeclarator"));
|
585 | if (!this.eat(_tokenizerTypes.types.comma)) break;
|
586 | }
|
587 | return node;
|
588 | };
|
589 |
|
590 | pp.parseVarHead = function (decl) {
|
591 | decl.id = this.parseBindingAtom();
|
592 | this.checkLVal(decl.id, true);
|
593 | };
|
594 |
|
595 |
|
596 |
|
597 |
|
598 | pp.parseFunction = function (node, isStatement, allowExpressionBody, isAsync, optionalId) {
|
599 | var oldInMethod = this.state.inMethod;
|
600 | this.state.inMethod = false;
|
601 |
|
602 | this.initFunction(node, isAsync);
|
603 |
|
604 | if (this.match(_tokenizerTypes.types.star)) {
|
605 | if (node.async && !this.hasPlugin("asyncGenerators")) {
|
606 | this.unexpected();
|
607 | } else {
|
608 | node.generator = true;
|
609 | this.next();
|
610 | }
|
611 | }
|
612 |
|
613 | if (isStatement && !optionalId && !this.match(_tokenizerTypes.types.name) && !this.match(_tokenizerTypes.types._yield)) {
|
614 | this.unexpected();
|
615 | }
|
616 |
|
617 | if (this.match(_tokenizerTypes.types.name) || this.match(_tokenizerTypes.types._yield)) {
|
618 | node.id = this.parseBindingIdentifier();
|
619 | }
|
620 |
|
621 | this.parseFunctionParams(node);
|
622 | this.parseFunctionBody(node, allowExpressionBody);
|
623 |
|
624 | this.state.inMethod = oldInMethod;
|
625 |
|
626 | return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
|
627 | };
|
628 |
|
629 | pp.parseFunctionParams = function (node) {
|
630 | this.expect(_tokenizerTypes.types.parenL);
|
631 | node.params = this.parseBindingList(_tokenizerTypes.types.parenR, false, this.hasPlugin("trailingFunctionCommas"));
|
632 | };
|
633 |
|
634 |
|
635 |
|
636 |
|
637 | pp.parseClass = function (node, isStatement, optionalId) {
|
638 | this.next();
|
639 | this.parseClassId(node, isStatement, optionalId);
|
640 | this.parseClassSuper(node);
|
641 | this.parseClassBody(node);
|
642 | return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression");
|
643 | };
|
644 |
|
645 | pp.isClassProperty = function () {
|
646 | return this.match(_tokenizerTypes.types.eq) || this.isLineTerminator();
|
647 | };
|
648 |
|
649 | pp.parseClassBody = function (node) {
|
650 |
|
651 | var oldStrict = this.state.strict;
|
652 | this.state.strict = true;
|
653 |
|
654 | var hadConstructorCall = false;
|
655 | var hadConstructor = false;
|
656 | var decorators = [];
|
657 | var classBody = this.startNode();
|
658 |
|
659 | classBody.body = [];
|
660 |
|
661 | this.expect(_tokenizerTypes.types.braceL);
|
662 |
|
663 | while (!this.eat(_tokenizerTypes.types.braceR)) {
|
664 | if (this.eat(_tokenizerTypes.types.semi)) {
|
665 | continue;
|
666 | }
|
667 |
|
668 | if (this.match(_tokenizerTypes.types.at)) {
|
669 | decorators.push(this.parseDecorator());
|
670 | continue;
|
671 | }
|
672 |
|
673 | var method = this.startNode();
|
674 |
|
675 |
|
676 | if (decorators.length) {
|
677 | method.decorators = decorators;
|
678 | decorators = [];
|
679 | }
|
680 |
|
681 | var isConstructorCall = false;
|
682 | var isMaybeStatic = this.match(_tokenizerTypes.types.name) && this.state.value === "static";
|
683 | var isGenerator = this.eat(_tokenizerTypes.types.star);
|
684 | var isGetSet = false;
|
685 | var isAsync = false;
|
686 |
|
687 | this.parsePropertyName(method);
|
688 |
|
689 | method["static"] = isMaybeStatic && !this.match(_tokenizerTypes.types.parenL);
|
690 | if (method["static"]) {
|
691 | if (isGenerator) this.unexpected();
|
692 | isGenerator = this.eat(_tokenizerTypes.types.star);
|
693 | this.parsePropertyName(method);
|
694 | }
|
695 |
|
696 | if (!isGenerator && method.key.type === "Identifier" && !method.computed) {
|
697 | if (this.isClassProperty()) {
|
698 | classBody.body.push(this.parseClassProperty(method));
|
699 | continue;
|
700 | }
|
701 |
|
702 | if (this.hasPlugin("classConstructorCall") && method.key.name === "call" && this.match(_tokenizerTypes.types.name) && this.state.value === "constructor") {
|
703 | isConstructorCall = true;
|
704 | this.parsePropertyName(method);
|
705 | }
|
706 | }
|
707 |
|
708 | var isAsyncMethod = this.hasPlugin("asyncFunctions") && !this.match(_tokenizerTypes.types.parenL) && !method.computed && method.key.type === "Identifier" && method.key.name === "async";
|
709 | if (isAsyncMethod) {
|
710 | if (this.hasPlugin("asyncGenerators") && this.eat(_tokenizerTypes.types.star)) isGenerator = true;
|
711 | isAsync = true;
|
712 | this.parsePropertyName(method);
|
713 | }
|
714 |
|
715 | method.kind = "method";
|
716 |
|
717 | if (!method.computed) {
|
718 | var key = method.key;
|
719 |
|
720 |
|
721 |
|
722 | if (!isAsync && !isGenerator && key.type === "Identifier" && !this.match(_tokenizerTypes.types.parenL) && (key.name === "get" || key.name === "set")) {
|
723 | isGetSet = true;
|
724 | method.kind = key.name;
|
725 | key = this.parsePropertyName(method);
|
726 | }
|
727 |
|
728 |
|
729 | var isConstructor = !isConstructorCall && !method["static"] && (key.type === "Identifier" && key.name === "constructor" || key.type === "StringLiteral" && key.value === "constructor");
|
730 | if (isConstructor) {
|
731 | if (hadConstructor) this.raise(key.start, "Duplicate constructor in the same class");
|
732 | if (isGetSet) this.raise(key.start, "Constructor can't have get/set modifier");
|
733 | if (isGenerator) this.raise(key.start, "Constructor can't be a generator");
|
734 | if (isAsync) this.raise(key.start, "Constructor can't be an async function");
|
735 | method.kind = "constructor";
|
736 | hadConstructor = true;
|
737 | }
|
738 |
|
739 |
|
740 | var isStaticPrototype = method["static"] && (key.type === "Identifier" && key.name === "prototype" || key.type === "StringLiteral" && key.value === "prototype");
|
741 | if (isStaticPrototype) {
|
742 | this.raise(key.start, "Classes may not have static property named prototype");
|
743 | }
|
744 | }
|
745 |
|
746 |
|
747 | if (isConstructorCall) {
|
748 | if (hadConstructorCall) this.raise(method.start, "Duplicate constructor call in the same class");
|
749 | method.kind = "constructorCall";
|
750 | hadConstructorCall = true;
|
751 | }
|
752 |
|
753 |
|
754 | if ((method.kind === "constructor" || method.kind === "constructorCall") && method.decorators) {
|
755 | this.raise(method.start, "You can't attach decorators to a class constructor");
|
756 | }
|
757 |
|
758 | this.parseClassMethod(classBody, method, isGenerator, isAsync);
|
759 |
|
760 |
|
761 |
|
762 | if (isGetSet) {
|
763 | var paramCount = method.kind === "get" ? 0 : 1;
|
764 | if (method.params.length !== paramCount) {
|
765 | var start = method.start;
|
766 | if (method.kind === "get") {
|
767 | this.raise(start, "getter should have no params");
|
768 | } else {
|
769 | this.raise(start, "setter should have exactly one param");
|
770 | }
|
771 | }
|
772 | }
|
773 | }
|
774 |
|
775 | if (decorators.length) {
|
776 | this.raise(this.state.start, "You have trailing decorators with no method");
|
777 | }
|
778 |
|
779 | node.body = this.finishNode(classBody, "ClassBody");
|
780 |
|
781 | this.state.strict = oldStrict;
|
782 | };
|
783 |
|
784 | pp.parseClassProperty = function (node) {
|
785 | if (this.match(_tokenizerTypes.types.eq)) {
|
786 | if (!this.hasPlugin("classProperties")) this.unexpected();
|
787 | this.next();
|
788 | node.value = this.parseMaybeAssign();
|
789 | } else {
|
790 | node.value = null;
|
791 | }
|
792 | this.semicolon();
|
793 | return this.finishNode(node, "ClassProperty");
|
794 | };
|
795 |
|
796 | pp.parseClassMethod = function (classBody, method, isGenerator, isAsync) {
|
797 | this.parseMethod(method, isGenerator, isAsync);
|
798 | classBody.body.push(this.finishNode(method, "ClassMethod"));
|
799 | };
|
800 |
|
801 | pp.parseClassId = function (node, isStatement, optionalId) {
|
802 | if (this.match(_tokenizerTypes.types.name)) {
|
803 | node.id = this.parseIdentifier();
|
804 | } else {
|
805 | if (optionalId || !isStatement) {
|
806 | node.id = null;
|
807 | } else {
|
808 | this.unexpected();
|
809 | }
|
810 | }
|
811 | };
|
812 |
|
813 | pp.parseClassSuper = function (node) {
|
814 | node.superClass = this.eat(_tokenizerTypes.types._extends) ? this.parseExprSubscripts() : null;
|
815 | };
|
816 |
|
817 |
|
818 |
|
819 | pp.parseExport = function (node) {
|
820 | this.next();
|
821 |
|
822 | if (this.match(_tokenizerTypes.types.star)) {
|
823 | var specifier = this.startNode();
|
824 | this.next();
|
825 | if (this.hasPlugin("exportExtensions") && this.eatContextual("as")) {
|
826 | specifier.exported = this.parseIdentifier();
|
827 | node.specifiers = [this.finishNode(specifier, "ExportNamespaceSpecifier")];
|
828 | this.parseExportSpecifiersMaybe(node);
|
829 | this.parseExportFrom(node, true);
|
830 | } else {
|
831 | this.parseExportFrom(node, true);
|
832 | return this.finishNode(node, "ExportAllDeclaration");
|
833 | }
|
834 | } else if (this.hasPlugin("exportExtensions") && this.isExportDefaultSpecifier()) {
|
835 | var specifier = this.startNode();
|
836 | specifier.exported = this.parseIdentifier(true);
|
837 | node.specifiers = [this.finishNode(specifier, "ExportDefaultSpecifier")];
|
838 | if (this.match(_tokenizerTypes.types.comma) && this.lookahead().type === _tokenizerTypes.types.star) {
|
839 | this.expect(_tokenizerTypes.types.comma);
|
840 | var _specifier = this.startNode();
|
841 | this.expect(_tokenizerTypes.types.star);
|
842 | this.expectContextual("as");
|
843 | _specifier.exported = this.parseIdentifier();
|
844 | node.specifiers.push(this.finishNode(_specifier, "ExportNamespaceSpecifier"));
|
845 | } else {
|
846 | this.parseExportSpecifiersMaybe(node);
|
847 | }
|
848 | this.parseExportFrom(node, true);
|
849 | } else if (this.eat(_tokenizerTypes.types._default)) {
|
850 |
|
851 | var expr = this.startNode();
|
852 | var needsSemi = false;
|
853 | if (this.eat(_tokenizerTypes.types._function)) {
|
854 | expr = this.parseFunction(expr, true, false, false, true);
|
855 | } else if (this.match(_tokenizerTypes.types._class)) {
|
856 | expr = this.parseClass(expr, true, true);
|
857 | } else {
|
858 | needsSemi = true;
|
859 | expr = this.parseMaybeAssign();
|
860 | }
|
861 | node.declaration = expr;
|
862 | if (needsSemi) this.semicolon();
|
863 | this.checkExport(node);
|
864 | return this.finishNode(node, "ExportDefaultDeclaration");
|
865 | } else if (this.state.type.keyword || this.shouldParseExportDeclaration()) {
|
866 | node.specifiers = [];
|
867 | node.source = null;
|
868 | node.declaration = this.parseExportDeclaration(node);
|
869 | } else {
|
870 |
|
871 | node.declaration = null;
|
872 | node.specifiers = this.parseExportSpecifiers();
|
873 | this.parseExportFrom(node);
|
874 | }
|
875 | this.checkExport(node);
|
876 | return this.finishNode(node, "ExportNamedDeclaration");
|
877 | };
|
878 |
|
879 | pp.parseExportDeclaration = function () {
|
880 | return this.parseStatement(true);
|
881 | };
|
882 |
|
883 | pp.isExportDefaultSpecifier = function () {
|
884 | if (this.match(_tokenizerTypes.types.name)) {
|
885 | return this.state.value !== "type" && this.state.value !== "async";
|
886 | }
|
887 |
|
888 | if (!this.match(_tokenizerTypes.types._default)) {
|
889 | return false;
|
890 | }
|
891 |
|
892 | var lookahead = this.lookahead();
|
893 | return lookahead.type === _tokenizerTypes.types.comma || lookahead.type === _tokenizerTypes.types.name && lookahead.value === "from";
|
894 | };
|
895 |
|
896 | pp.parseExportSpecifiersMaybe = function (node) {
|
897 | if (this.eat(_tokenizerTypes.types.comma)) {
|
898 | node.specifiers = node.specifiers.concat(this.parseExportSpecifiers());
|
899 | }
|
900 | };
|
901 |
|
902 | pp.parseExportFrom = function (node, expect /*:: ?*/) {
|
903 | if (this.eatContextual("from")) {
|
904 | node.source = this.match(_tokenizerTypes.types.string) ? this.parseExprAtom() : this.unexpected();
|
905 | this.checkExport(node);
|
906 | } else {
|
907 | if (expect) {
|
908 | this.unexpected();
|
909 | } else {
|
910 | node.source = null;
|
911 | }
|
912 | }
|
913 |
|
914 | this.semicolon();
|
915 | };
|
916 |
|
917 | pp.shouldParseExportDeclaration = function () {
|
918 | return this.hasPlugin("asyncFunctions") && this.isContextual("async");
|
919 | };
|
920 |
|
921 | pp.checkExport = function (node) {
|
922 | if (this.state.decorators.length) {
|
923 | var isClass = node.declaration && (node.declaration.type === "ClassDeclaration" || node.declaration.type === "ClassExpression");
|
924 | if (!node.declaration || !isClass) {
|
925 | this.raise(node.start, "You can only use decorators on an export when exporting a class");
|
926 | }
|
927 | this.takeDecorators(node.declaration);
|
928 | }
|
929 | };
|
930 |
|
931 |
|
932 |
|
933 | pp.parseExportSpecifiers = function () {
|
934 | var nodes = [];
|
935 | var first = true;
|
936 | var needsFrom = undefined;
|
937 |
|
938 |
|
939 | this.expect(_tokenizerTypes.types.braceL);
|
940 |
|
941 | while (!this.eat(_tokenizerTypes.types.braceR)) {
|
942 | if (first) {
|
943 | first = false;
|
944 | } else {
|
945 | this.expect(_tokenizerTypes.types.comma);
|
946 | if (this.eat(_tokenizerTypes.types.braceR)) break;
|
947 | }
|
948 |
|
949 | var isDefault = this.match(_tokenizerTypes.types._default);
|
950 | if (isDefault && !needsFrom) needsFrom = true;
|
951 |
|
952 | var node = this.startNode();
|
953 | node.local = this.parseIdentifier(isDefault);
|
954 | node.exported = this.eatContextual("as") ? this.parseIdentifier(true) : node.local.__clone();
|
955 | nodes.push(this.finishNode(node, "ExportSpecifier"));
|
956 | }
|
957 |
|
958 |
|
959 | if (needsFrom && !this.isContextual("from")) {
|
960 | this.unexpected();
|
961 | }
|
962 |
|
963 | return nodes;
|
964 | };
|
965 |
|
966 |
|
967 |
|
968 | pp.parseImport = function (node) {
|
969 | this.next();
|
970 |
|
971 |
|
972 | if (this.match(_tokenizerTypes.types.string)) {
|
973 | node.specifiers = [];
|
974 | node.source = this.parseExprAtom();
|
975 | } else {
|
976 | node.specifiers = [];
|
977 | this.parseImportSpecifiers(node);
|
978 | this.expectContextual("from");
|
979 | node.source = this.match(_tokenizerTypes.types.string) ? this.parseExprAtom() : this.unexpected();
|
980 | }
|
981 | this.semicolon();
|
982 | return this.finishNode(node, "ImportDeclaration");
|
983 | };
|
984 |
|
985 |
|
986 |
|
987 | pp.parseImportSpecifiers = function (node) {
|
988 | var first = true;
|
989 | if (this.match(_tokenizerTypes.types.name)) {
|
990 |
|
991 | var startPos = this.state.start,
|
992 | startLoc = this.state.startLoc;
|
993 | node.specifiers.push(this.parseImportSpecifierDefault(this.parseIdentifier(), startPos, startLoc));
|
994 | if (!this.eat(_tokenizerTypes.types.comma)) return;
|
995 | }
|
996 |
|
997 | if (this.match(_tokenizerTypes.types.star)) {
|
998 | var specifier = this.startNode();
|
999 | this.next();
|
1000 | this.expectContextual("as");
|
1001 | specifier.local = this.parseIdentifier();
|
1002 | this.checkLVal(specifier.local, true);
|
1003 | node.specifiers.push(this.finishNode(specifier, "ImportNamespaceSpecifier"));
|
1004 | return;
|
1005 | }
|
1006 |
|
1007 | this.expect(_tokenizerTypes.types.braceL);
|
1008 | while (!this.eat(_tokenizerTypes.types.braceR)) {
|
1009 | if (first) {
|
1010 | first = false;
|
1011 | } else {
|
1012 | this.expect(_tokenizerTypes.types.comma);
|
1013 | if (this.eat(_tokenizerTypes.types.braceR)) break;
|
1014 | }
|
1015 |
|
1016 | var specifier = this.startNode();
|
1017 | specifier.imported = this.parseIdentifier(true);
|
1018 | specifier.local = this.eatContextual("as") ? this.parseIdentifier() : specifier.imported.__clone();
|
1019 | this.checkLVal(specifier.local, true);
|
1020 | node.specifiers.push(this.finishNode(specifier, "ImportSpecifier"));
|
1021 | }
|
1022 | };
|
1023 |
|
1024 | pp.parseImportSpecifierDefault = function (id, startPos, startLoc) {
|
1025 | var node = this.startNodeAt(startPos, startLoc);
|
1026 | node.local = id;
|
1027 | this.checkLVal(node.local, true);
|
1028 | return this.finishNode(node, "ImportDefaultSpecifier");
|
1029 | }; |
\ | No newline at end of file |