source: trip-planner-front/node_modules/terser/lib/ast.js@ 6fe77af

Last change on this file since 6fe77af was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 56.9 KB
RevLine 
[6a3a178]1/***********************************************************************
2
3 A JavaScript tokenizer / parser / beautifier / compressor.
4 https://github.com/mishoo/UglifyJS2
5
6 -------------------------------- (C) ---------------------------------
7
8 Author: Mihai Bazon
9 <mihai.bazon@gmail.com>
10 http://mihai.bazon.net/blog
11
12 Distributed under the BSD license:
13
14 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
15
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions
18 are met:
19
20 * Redistributions of source code must retain the above
21 copyright notice, this list of conditions and the following
22 disclaimer.
23
24 * Redistributions in binary form must reproduce the above
25 copyright notice, this list of conditions and the following
26 disclaimer in the documentation and/or other materials
27 provided with the distribution.
28
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
30 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
33 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
34 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
35 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
36 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
38 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
39 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 SUCH DAMAGE.
41
42 ***********************************************************************/
43
44"use strict";
45
46import {
47 HOP,
48 MAP,
49 noop
50} from "./utils/index.js";
51import { parse } from "./parse.js";
52
53function DEFNODE(type, props, methods, base = AST_Node) {
54 if (!props) props = [];
55 else props = props.split(/\s+/);
56 var self_props = props;
57 if (base && base.PROPS)
58 props = props.concat(base.PROPS);
59 var code = "return function AST_" + type + "(props){ if (props) { ";
60 for (var i = props.length; --i >= 0;) {
61 code += "this." + props[i] + " = props." + props[i] + ";";
62 }
63 const proto = base && Object.create(base.prototype);
64 if (proto && proto.initialize || (methods && methods.initialize))
65 code += "this.initialize();";
66 code += "}";
67 code += "this.flags = 0;";
68 code += "}";
69 var ctor = new Function(code)();
70 if (proto) {
71 ctor.prototype = proto;
72 ctor.BASE = base;
73 }
74 if (base) base.SUBCLASSES.push(ctor);
75 ctor.prototype.CTOR = ctor;
76 ctor.prototype.constructor = ctor;
77 ctor.PROPS = props || null;
78 ctor.SELF_PROPS = self_props;
79 ctor.SUBCLASSES = [];
80 if (type) {
81 ctor.prototype.TYPE = ctor.TYPE = type;
82 }
83 if (methods) for (i in methods) if (HOP(methods, i)) {
84 if (i[0] === "$") {
85 ctor[i.substr(1)] = methods[i];
86 } else {
87 ctor.prototype[i] = methods[i];
88 }
89 }
90 ctor.DEFMETHOD = function(name, method) {
91 this.prototype[name] = method;
92 };
93 return ctor;
94}
95
96const has_tok_flag = (tok, flag) => Boolean(tok.flags & flag);
97const set_tok_flag = (tok, flag, truth) => {
98 if (truth) {
99 tok.flags |= flag;
100 } else {
101 tok.flags &= ~flag;
102 }
103};
104
105const TOK_FLAG_NLB = 0b0001;
106const TOK_FLAG_QUOTE_SINGLE = 0b0010;
107const TOK_FLAG_QUOTE_EXISTS = 0b0100;
108
109class AST_Token {
110 constructor(type, value, line, col, pos, nlb, comments_before, comments_after, file) {
111 this.flags = (nlb ? 1 : 0);
112
113 this.type = type;
114 this.value = value;
115 this.line = line;
116 this.col = col;
117 this.pos = pos;
118 this.comments_before = comments_before;
119 this.comments_after = comments_after;
120 this.file = file;
121
122 Object.seal(this);
123 }
124
125 get nlb() {
126 return has_tok_flag(this, TOK_FLAG_NLB);
127 }
128
129 set nlb(new_nlb) {
130 set_tok_flag(this, TOK_FLAG_NLB, new_nlb);
131 }
132
133 get quote() {
134 return !has_tok_flag(this, TOK_FLAG_QUOTE_EXISTS)
135 ? ""
136 : (has_tok_flag(this, TOK_FLAG_QUOTE_SINGLE) ? "'" : '"');
137 }
138
139 set quote(quote_type) {
140 set_tok_flag(this, TOK_FLAG_QUOTE_SINGLE, quote_type === "'");
141 set_tok_flag(this, TOK_FLAG_QUOTE_EXISTS, !!quote_type);
142 }
143}
144
145var AST_Node = DEFNODE("Node", "start end", {
146 _clone: function(deep) {
147 if (deep) {
148 var self = this.clone();
149 return self.transform(new TreeTransformer(function(node) {
150 if (node !== self) {
151 return node.clone(true);
152 }
153 }));
154 }
155 return new this.CTOR(this);
156 },
157 clone: function(deep) {
158 return this._clone(deep);
159 },
160 $documentation: "Base class of all AST nodes",
161 $propdoc: {
162 start: "[AST_Token] The first token of this node",
163 end: "[AST_Token] The last token of this node"
164 },
165 _walk: function(visitor) {
166 return visitor._visit(this);
167 },
168 walk: function(visitor) {
169 return this._walk(visitor); // not sure the indirection will be any help
170 },
171 _children_backwards: () => {}
172}, null);
173
174/* -----[ statements ]----- */
175
176var AST_Statement = DEFNODE("Statement", null, {
177 $documentation: "Base class of all statements",
178});
179
180var AST_Debugger = DEFNODE("Debugger", null, {
181 $documentation: "Represents a debugger statement",
182}, AST_Statement);
183
184var AST_Directive = DEFNODE("Directive", "value quote", {
185 $documentation: "Represents a directive, like \"use strict\";",
186 $propdoc: {
187 value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
188 quote: "[string] the original quote character"
189 },
190}, AST_Statement);
191
192var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
193 $documentation: "A statement consisting of an expression, i.e. a = 1 + 2",
194 $propdoc: {
195 body: "[AST_Node] an expression node (should not be instanceof AST_Statement)"
196 },
197 _walk: function(visitor) {
198 return visitor._visit(this, function() {
199 this.body._walk(visitor);
200 });
201 },
202 _children_backwards(push) {
203 push(this.body);
204 }
205}, AST_Statement);
206
207function walk_body(node, visitor) {
208 const body = node.body;
209 for (var i = 0, len = body.length; i < len; i++) {
210 body[i]._walk(visitor);
211 }
212}
213
214function clone_block_scope(deep) {
215 var clone = this._clone(deep);
216 if (this.block_scope) {
217 clone.block_scope = this.block_scope.clone();
218 }
219 return clone;
220}
221
222var AST_Block = DEFNODE("Block", "body block_scope", {
223 $documentation: "A body of statements (usually braced)",
224 $propdoc: {
225 body: "[AST_Statement*] an array of statements",
226 block_scope: "[AST_Scope] the block scope"
227 },
228 _walk: function(visitor) {
229 return visitor._visit(this, function() {
230 walk_body(this, visitor);
231 });
232 },
233 _children_backwards(push) {
234 let i = this.body.length;
235 while (i--) push(this.body[i]);
236 },
237 clone: clone_block_scope
238}, AST_Statement);
239
240var AST_BlockStatement = DEFNODE("BlockStatement", null, {
241 $documentation: "A block statement",
242}, AST_Block);
243
244var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
245 $documentation: "The empty statement (empty block or simply a semicolon)"
246}, AST_Statement);
247
248var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
249 $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
250 $propdoc: {
251 body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
252 }
253}, AST_Statement);
254
255var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
256 $documentation: "Statement with a label",
257 $propdoc: {
258 label: "[AST_Label] a label definition"
259 },
260 _walk: function(visitor) {
261 return visitor._visit(this, function() {
262 this.label._walk(visitor);
263 this.body._walk(visitor);
264 });
265 },
266 _children_backwards(push) {
267 push(this.body);
268 push(this.label);
269 },
270 clone: function(deep) {
271 var node = this._clone(deep);
272 if (deep) {
273 var label = node.label;
274 var def = this.label;
275 node.walk(new TreeWalker(function(node) {
276 if (node instanceof AST_LoopControl
277 && node.label && node.label.thedef === def) {
278 node.label.thedef = label;
279 label.references.push(node);
280 }
281 }));
282 }
283 return node;
284 }
285}, AST_StatementWithBody);
286
287var AST_IterationStatement = DEFNODE("IterationStatement", "block_scope", {
288 $documentation: "Internal class. All loops inherit from it.",
289 $propdoc: {
290 block_scope: "[AST_Scope] the block scope for this iteration statement."
291 },
292 clone: clone_block_scope
293}, AST_StatementWithBody);
294
295var AST_DWLoop = DEFNODE("DWLoop", "condition", {
296 $documentation: "Base class for do/while statements",
297 $propdoc: {
298 condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
299 }
300}, AST_IterationStatement);
301
302var AST_Do = DEFNODE("Do", null, {
303 $documentation: "A `do` statement",
304 _walk: function(visitor) {
305 return visitor._visit(this, function() {
306 this.body._walk(visitor);
307 this.condition._walk(visitor);
308 });
309 },
310 _children_backwards(push) {
311 push(this.condition);
312 push(this.body);
313 }
314}, AST_DWLoop);
315
316var AST_While = DEFNODE("While", null, {
317 $documentation: "A `while` statement",
318 _walk: function(visitor) {
319 return visitor._visit(this, function() {
320 this.condition._walk(visitor);
321 this.body._walk(visitor);
322 });
323 },
324 _children_backwards(push) {
325 push(this.body);
326 push(this.condition);
327 },
328}, AST_DWLoop);
329
330var AST_For = DEFNODE("For", "init condition step", {
331 $documentation: "A `for` statement",
332 $propdoc: {
333 init: "[AST_Node?] the `for` initialization code, or null if empty",
334 condition: "[AST_Node?] the `for` termination clause, or null if empty",
335 step: "[AST_Node?] the `for` update clause, or null if empty"
336 },
337 _walk: function(visitor) {
338 return visitor._visit(this, function() {
339 if (this.init) this.init._walk(visitor);
340 if (this.condition) this.condition._walk(visitor);
341 if (this.step) this.step._walk(visitor);
342 this.body._walk(visitor);
343 });
344 },
345 _children_backwards(push) {
346 push(this.body);
347 if (this.step) push(this.step);
348 if (this.condition) push(this.condition);
349 if (this.init) push(this.init);
350 },
351}, AST_IterationStatement);
352
353var AST_ForIn = DEFNODE("ForIn", "init object", {
354 $documentation: "A `for ... in` statement",
355 $propdoc: {
356 init: "[AST_Node] the `for/in` initialization code",
357 object: "[AST_Node] the object that we're looping through"
358 },
359 _walk: function(visitor) {
360 return visitor._visit(this, function() {
361 this.init._walk(visitor);
362 this.object._walk(visitor);
363 this.body._walk(visitor);
364 });
365 },
366 _children_backwards(push) {
367 push(this.body);
368 if (this.object) push(this.object);
369 if (this.init) push(this.init);
370 },
371}, AST_IterationStatement);
372
373var AST_ForOf = DEFNODE("ForOf", "await", {
374 $documentation: "A `for ... of` statement",
375}, AST_ForIn);
376
377var AST_With = DEFNODE("With", "expression", {
378 $documentation: "A `with` statement",
379 $propdoc: {
380 expression: "[AST_Node] the `with` expression"
381 },
382 _walk: function(visitor) {
383 return visitor._visit(this, function() {
384 this.expression._walk(visitor);
385 this.body._walk(visitor);
386 });
387 },
388 _children_backwards(push) {
389 push(this.body);
390 push(this.expression);
391 },
392}, AST_StatementWithBody);
393
394/* -----[ scope and functions ]----- */
395
396var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
397 $documentation: "Base class for all statements introducing a lexical scope",
398 $propdoc: {
399 variables: "[Map/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
400 uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
401 uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
402 parent_scope: "[AST_Scope?/S] link to the parent scope",
403 enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
404 cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
405 },
406 get_defun_scope: function() {
407 var self = this;
408 while (self.is_block_scope()) {
409 self = self.parent_scope;
410 }
411 return self;
412 },
413 clone: function(deep, toplevel) {
414 var node = this._clone(deep);
415 if (deep && this.variables && toplevel && !this._block_scope) {
416 node.figure_out_scope({}, {
417 toplevel: toplevel,
418 parent_scope: this.parent_scope
419 });
420 } else {
421 if (this.variables) node.variables = new Map(this.variables);
422 if (this.enclosed) node.enclosed = this.enclosed.slice();
423 if (this._block_scope) node._block_scope = this._block_scope;
424 }
425 return node;
426 },
427 pinned: function() {
428 return this.uses_eval || this.uses_with;
429 }
430}, AST_Block);
431
432var AST_Toplevel = DEFNODE("Toplevel", "globals", {
433 $documentation: "The toplevel scope",
434 $propdoc: {
435 globals: "[Map/S] a map of name -> SymbolDef for all undeclared names",
436 },
437 wrap_commonjs: function(name) {
438 var body = this.body;
439 var wrapped_tl = "(function(exports){'$ORIG';})(typeof " + name + "=='undefined'?(" + name + "={}):" + name + ");";
440 wrapped_tl = parse(wrapped_tl);
441 wrapped_tl = wrapped_tl.transform(new TreeTransformer(function(node) {
442 if (node instanceof AST_Directive && node.value == "$ORIG") {
443 return MAP.splice(body);
444 }
445 }));
446 return wrapped_tl;
447 },
448 wrap_enclose: function(args_values) {
449 if (typeof args_values != "string") args_values = "";
450 var index = args_values.indexOf(":");
451 if (index < 0) index = args_values.length;
452 var body = this.body;
453 return parse([
454 "(function(",
455 args_values.slice(0, index),
456 '){"$ORIG"})(',
457 args_values.slice(index + 1),
458 ")"
459 ].join("")).transform(new TreeTransformer(function(node) {
460 if (node instanceof AST_Directive && node.value == "$ORIG") {
461 return MAP.splice(body);
462 }
463 }));
464 }
465}, AST_Scope);
466
467var AST_Expansion = DEFNODE("Expansion", "expression", {
468 $documentation: "An expandible argument, such as ...rest, a splat, such as [1,2,...all], or an expansion in a variable declaration, such as var [first, ...rest] = list",
469 $propdoc: {
470 expression: "[AST_Node] the thing to be expanded"
471 },
472 _walk: function(visitor) {
473 return visitor._visit(this, function() {
474 this.expression.walk(visitor);
475 });
476 },
477 _children_backwards(push) {
478 push(this.expression);
479 },
480});
481
482var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments is_generator async", {
483 $documentation: "Base class for functions",
484 $propdoc: {
485 name: "[AST_SymbolDeclaration?] the name of this function",
486 argnames: "[AST_SymbolFunarg|AST_Destructuring|AST_Expansion|AST_DefaultAssign*] array of function arguments, destructurings, or expanding arguments",
487 uses_arguments: "[boolean/S] tells whether this function accesses the arguments array",
488 is_generator: "[boolean] is this a generator method",
489 async: "[boolean] is this method async",
490 },
491 args_as_names: function () {
492 var out = [];
493 for (var i = 0; i < this.argnames.length; i++) {
494 if (this.argnames[i] instanceof AST_Destructuring) {
495 out.push(...this.argnames[i].all_symbols());
496 } else {
497 out.push(this.argnames[i]);
498 }
499 }
500 return out;
501 },
502 _walk: function(visitor) {
503 return visitor._visit(this, function() {
504 if (this.name) this.name._walk(visitor);
505 var argnames = this.argnames;
506 for (var i = 0, len = argnames.length; i < len; i++) {
507 argnames[i]._walk(visitor);
508 }
509 walk_body(this, visitor);
510 });
511 },
512 _children_backwards(push) {
513 let i = this.body.length;
514 while (i--) push(this.body[i]);
515
516 i = this.argnames.length;
517 while (i--) push(this.argnames[i]);
518
519 if (this.name) push(this.name);
520 },
521 is_braceless() {
522 return this.body[0] instanceof AST_Return && this.body[0].value;
523 },
524 // Default args and expansion don't count, so .argnames.length doesn't cut it
525 length_property() {
526 let length = 0;
527
528 for (const arg of this.argnames) {
529 if (arg instanceof AST_SymbolFunarg || arg instanceof AST_Destructuring) {
530 length++;
531 }
532 }
533
534 return length;
535 }
536}, AST_Scope);
537
538var AST_Accessor = DEFNODE("Accessor", null, {
539 $documentation: "A setter/getter function. The `name` property is always null."
540}, AST_Lambda);
541
542var AST_Function = DEFNODE("Function", null, {
543 $documentation: "A function expression"
544}, AST_Lambda);
545
546var AST_Arrow = DEFNODE("Arrow", null, {
547 $documentation: "An ES6 Arrow function ((a) => b)"
548}, AST_Lambda);
549
550var AST_Defun = DEFNODE("Defun", null, {
551 $documentation: "A function definition"
552}, AST_Lambda);
553
554/* -----[ DESTRUCTURING ]----- */
555var AST_Destructuring = DEFNODE("Destructuring", "names is_array", {
556 $documentation: "A destructuring of several names. Used in destructuring assignment and with destructuring function argument names",
557 $propdoc: {
558 "names": "[AST_Node*] Array of properties or elements",
559 "is_array": "[Boolean] Whether the destructuring represents an object or array"
560 },
561 _walk: function(visitor) {
562 return visitor._visit(this, function() {
563 this.names.forEach(function(name) {
564 name._walk(visitor);
565 });
566 });
567 },
568 _children_backwards(push) {
569 let i = this.names.length;
570 while (i--) push(this.names[i]);
571 },
572 all_symbols: function() {
573 var out = [];
574 this.walk(new TreeWalker(function (node) {
575 if (node instanceof AST_Symbol) {
576 out.push(node);
577 }
578 }));
579 return out;
580 }
581});
582
583var AST_PrefixedTemplateString = DEFNODE("PrefixedTemplateString", "template_string prefix", {
584 $documentation: "A templatestring with a prefix, such as String.raw`foobarbaz`",
585 $propdoc: {
586 template_string: "[AST_TemplateString] The template string",
587 prefix: "[AST_Node] The prefix, which will get called."
588 },
589 _walk: function(visitor) {
590 return visitor._visit(this, function () {
591 this.prefix._walk(visitor);
592 this.template_string._walk(visitor);
593 });
594 },
595 _children_backwards(push) {
596 push(this.template_string);
597 push(this.prefix);
598 },
599});
600
601var AST_TemplateString = DEFNODE("TemplateString", "segments", {
602 $documentation: "A template string literal",
603 $propdoc: {
604 segments: "[AST_Node*] One or more segments, starting with AST_TemplateSegment. AST_Node may follow AST_TemplateSegment, but each AST_Node must be followed by AST_TemplateSegment."
605 },
606 _walk: function(visitor) {
607 return visitor._visit(this, function() {
608 this.segments.forEach(function(seg) {
609 seg._walk(visitor);
610 });
611 });
612 },
613 _children_backwards(push) {
614 let i = this.segments.length;
615 while (i--) push(this.segments[i]);
616 }
617});
618
619var AST_TemplateSegment = DEFNODE("TemplateSegment", "value raw", {
620 $documentation: "A segment of a template string literal",
621 $propdoc: {
622 value: "Content of the segment",
623 raw: "Raw source of the segment",
624 }
625});
626
627/* -----[ JUMPS ]----- */
628
629var AST_Jump = DEFNODE("Jump", null, {
630 $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)"
631}, AST_Statement);
632
633var AST_Exit = DEFNODE("Exit", "value", {
634 $documentation: "Base class for “exits” (`return` and `throw`)",
635 $propdoc: {
636 value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
637 },
638 _walk: function(visitor) {
639 return visitor._visit(this, this.value && function() {
640 this.value._walk(visitor);
641 });
642 },
643 _children_backwards(push) {
644 if (this.value) push(this.value);
645 },
646}, AST_Jump);
647
648var AST_Return = DEFNODE("Return", null, {
649 $documentation: "A `return` statement"
650}, AST_Exit);
651
652var AST_Throw = DEFNODE("Throw", null, {
653 $documentation: "A `throw` statement"
654}, AST_Exit);
655
656var AST_LoopControl = DEFNODE("LoopControl", "label", {
657 $documentation: "Base class for loop control statements (`break` and `continue`)",
658 $propdoc: {
659 label: "[AST_LabelRef?] the label, or null if none",
660 },
661 _walk: function(visitor) {
662 return visitor._visit(this, this.label && function() {
663 this.label._walk(visitor);
664 });
665 },
666 _children_backwards(push) {
667 if (this.label) push(this.label);
668 },
669}, AST_Jump);
670
671var AST_Break = DEFNODE("Break", null, {
672 $documentation: "A `break` statement"
673}, AST_LoopControl);
674
675var AST_Continue = DEFNODE("Continue", null, {
676 $documentation: "A `continue` statement"
677}, AST_LoopControl);
678
679var AST_Await = DEFNODE("Await", "expression", {
680 $documentation: "An `await` statement",
681 $propdoc: {
682 expression: "[AST_Node] the mandatory expression being awaited",
683 },
684 _walk: function(visitor) {
685 return visitor._visit(this, function() {
686 this.expression._walk(visitor);
687 });
688 },
689 _children_backwards(push) {
690 push(this.expression);
691 },
692});
693
694var AST_Yield = DEFNODE("Yield", "expression is_star", {
695 $documentation: "A `yield` statement",
696 $propdoc: {
697 expression: "[AST_Node?] the value returned or thrown by this statement; could be null (representing undefined) but only when is_star is set to false",
698 is_star: "[Boolean] Whether this is a yield or yield* statement"
699 },
700 _walk: function(visitor) {
701 return visitor._visit(this, this.expression && function() {
702 this.expression._walk(visitor);
703 });
704 },
705 _children_backwards(push) {
706 if (this.expression) push(this.expression);
707 }
708});
709
710/* -----[ IF ]----- */
711
712var AST_If = DEFNODE("If", "condition alternative", {
713 $documentation: "A `if` statement",
714 $propdoc: {
715 condition: "[AST_Node] the `if` condition",
716 alternative: "[AST_Statement?] the `else` part, or null if not present"
717 },
718 _walk: function(visitor) {
719 return visitor._visit(this, function() {
720 this.condition._walk(visitor);
721 this.body._walk(visitor);
722 if (this.alternative) this.alternative._walk(visitor);
723 });
724 },
725 _children_backwards(push) {
726 if (this.alternative) {
727 push(this.alternative);
728 }
729 push(this.body);
730 push(this.condition);
731 }
732}, AST_StatementWithBody);
733
734/* -----[ SWITCH ]----- */
735
736var AST_Switch = DEFNODE("Switch", "expression", {
737 $documentation: "A `switch` statement",
738 $propdoc: {
739 expression: "[AST_Node] the `switch` “discriminant”"
740 },
741 _walk: function(visitor) {
742 return visitor._visit(this, function() {
743 this.expression._walk(visitor);
744 walk_body(this, visitor);
745 });
746 },
747 _children_backwards(push) {
748 let i = this.body.length;
749 while (i--) push(this.body[i]);
750 push(this.expression);
751 }
752}, AST_Block);
753
754var AST_SwitchBranch = DEFNODE("SwitchBranch", null, {
755 $documentation: "Base class for `switch` branches",
756}, AST_Block);
757
758var AST_Default = DEFNODE("Default", null, {
759 $documentation: "A `default` switch branch",
760}, AST_SwitchBranch);
761
762var AST_Case = DEFNODE("Case", "expression", {
763 $documentation: "A `case` switch branch",
764 $propdoc: {
765 expression: "[AST_Node] the `case` expression"
766 },
767 _walk: function(visitor) {
768 return visitor._visit(this, function() {
769 this.expression._walk(visitor);
770 walk_body(this, visitor);
771 });
772 },
773 _children_backwards(push) {
774 let i = this.body.length;
775 while (i--) push(this.body[i]);
776 push(this.expression);
777 },
778}, AST_SwitchBranch);
779
780/* -----[ EXCEPTIONS ]----- */
781
782var AST_Try = DEFNODE("Try", "bcatch bfinally", {
783 $documentation: "A `try` statement",
784 $propdoc: {
785 bcatch: "[AST_Catch?] the catch block, or null if not present",
786 bfinally: "[AST_Finally?] the finally block, or null if not present"
787 },
788 _walk: function(visitor) {
789 return visitor._visit(this, function() {
790 walk_body(this, visitor);
791 if (this.bcatch) this.bcatch._walk(visitor);
792 if (this.bfinally) this.bfinally._walk(visitor);
793 });
794 },
795 _children_backwards(push) {
796 if (this.bfinally) push(this.bfinally);
797 if (this.bcatch) push(this.bcatch);
798 let i = this.body.length;
799 while (i--) push(this.body[i]);
800 },
801}, AST_Block);
802
803var AST_Catch = DEFNODE("Catch", "argname", {
804 $documentation: "A `catch` node; only makes sense as part of a `try` statement",
805 $propdoc: {
806 argname: "[AST_SymbolCatch|AST_Destructuring|AST_Expansion|AST_DefaultAssign] symbol for the exception"
807 },
808 _walk: function(visitor) {
809 return visitor._visit(this, function() {
810 if (this.argname) this.argname._walk(visitor);
811 walk_body(this, visitor);
812 });
813 },
814 _children_backwards(push) {
815 let i = this.body.length;
816 while (i--) push(this.body[i]);
817 if (this.argname) push(this.argname);
818 },
819}, AST_Block);
820
821var AST_Finally = DEFNODE("Finally", null, {
822 $documentation: "A `finally` node; only makes sense as part of a `try` statement"
823}, AST_Block);
824
825/* -----[ VAR/CONST ]----- */
826
827var AST_Definitions = DEFNODE("Definitions", "definitions", {
828 $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)",
829 $propdoc: {
830 definitions: "[AST_VarDef*] array of variable definitions"
831 },
832 _walk: function(visitor) {
833 return visitor._visit(this, function() {
834 var definitions = this.definitions;
835 for (var i = 0, len = definitions.length; i < len; i++) {
836 definitions[i]._walk(visitor);
837 }
838 });
839 },
840 _children_backwards(push) {
841 let i = this.definitions.length;
842 while (i--) push(this.definitions[i]);
843 },
844}, AST_Statement);
845
846var AST_Var = DEFNODE("Var", null, {
847 $documentation: "A `var` statement"
848}, AST_Definitions);
849
850var AST_Let = DEFNODE("Let", null, {
851 $documentation: "A `let` statement"
852}, AST_Definitions);
853
854var AST_Const = DEFNODE("Const", null, {
855 $documentation: "A `const` statement"
856}, AST_Definitions);
857
858var AST_VarDef = DEFNODE("VarDef", "name value", {
859 $documentation: "A variable declaration; only appears in a AST_Definitions node",
860 $propdoc: {
861 name: "[AST_Destructuring|AST_SymbolConst|AST_SymbolLet|AST_SymbolVar] name of the variable",
862 value: "[AST_Node?] initializer, or null of there's no initializer"
863 },
864 _walk: function(visitor) {
865 return visitor._visit(this, function() {
866 this.name._walk(visitor);
867 if (this.value) this.value._walk(visitor);
868 });
869 },
870 _children_backwards(push) {
871 if (this.value) push(this.value);
872 push(this.name);
873 },
874});
875
876var AST_NameMapping = DEFNODE("NameMapping", "foreign_name name", {
877 $documentation: "The part of the export/import statement that declare names from a module.",
878 $propdoc: {
879 foreign_name: "[AST_SymbolExportForeign|AST_SymbolImportForeign] The name being exported/imported (as specified in the module)",
880 name: "[AST_SymbolExport|AST_SymbolImport] The name as it is visible to this module."
881 },
882 _walk: function (visitor) {
883 return visitor._visit(this, function() {
884 this.foreign_name._walk(visitor);
885 this.name._walk(visitor);
886 });
887 },
888 _children_backwards(push) {
889 push(this.name);
890 push(this.foreign_name);
891 },
892});
893
894var AST_Import = DEFNODE("Import", "imported_name imported_names module_name", {
895 $documentation: "An `import` statement",
896 $propdoc: {
897 imported_name: "[AST_SymbolImport] The name of the variable holding the module's default export.",
898 imported_names: "[AST_NameMapping*] The names of non-default imported variables",
899 module_name: "[AST_String] String literal describing where this module came from",
900 },
901 _walk: function(visitor) {
902 return visitor._visit(this, function() {
903 if (this.imported_name) {
904 this.imported_name._walk(visitor);
905 }
906 if (this.imported_names) {
907 this.imported_names.forEach(function(name_import) {
908 name_import._walk(visitor);
909 });
910 }
911 this.module_name._walk(visitor);
912 });
913 },
914 _children_backwards(push) {
915 push(this.module_name);
916 if (this.imported_names) {
917 let i = this.imported_names.length;
918 while (i--) push(this.imported_names[i]);
919 }
920 if (this.imported_name) push(this.imported_name);
921 },
922});
923
924var AST_ImportMeta = DEFNODE("ImportMeta", null, {
925 $documentation: "A reference to import.meta",
926});
927
928var AST_Export = DEFNODE("Export", "exported_definition exported_value is_default exported_names module_name", {
929 $documentation: "An `export` statement",
930 $propdoc: {
931 exported_definition: "[AST_Defun|AST_Definitions|AST_DefClass?] An exported definition",
932 exported_value: "[AST_Node?] An exported value",
933 exported_names: "[AST_NameMapping*?] List of exported names",
934 module_name: "[AST_String?] Name of the file to load exports from",
935 is_default: "[Boolean] Whether this is the default exported value of this module"
936 },
937 _walk: function (visitor) {
938 return visitor._visit(this, function () {
939 if (this.exported_definition) {
940 this.exported_definition._walk(visitor);
941 }
942 if (this.exported_value) {
943 this.exported_value._walk(visitor);
944 }
945 if (this.exported_names) {
946 this.exported_names.forEach(function(name_export) {
947 name_export._walk(visitor);
948 });
949 }
950 if (this.module_name) {
951 this.module_name._walk(visitor);
952 }
953 });
954 },
955 _children_backwards(push) {
956 if (this.module_name) push(this.module_name);
957 if (this.exported_names) {
958 let i = this.exported_names.length;
959 while (i--) push(this.exported_names[i]);
960 }
961 if (this.exported_value) push(this.exported_value);
962 if (this.exported_definition) push(this.exported_definition);
963 }
964}, AST_Statement);
965
966/* -----[ OTHER ]----- */
967
968var AST_Call = DEFNODE("Call", "expression args optional _annotations", {
969 $documentation: "A function call expression",
970 $propdoc: {
971 expression: "[AST_Node] expression to invoke as function",
972 args: "[AST_Node*] array of arguments",
973 optional: "[boolean] whether this is an optional call (IE ?.() )",
974 _annotations: "[number] bitfield containing information about the call"
975 },
976 initialize() {
977 if (this._annotations == null) this._annotations = 0;
978 },
979 _walk(visitor) {
980 return visitor._visit(this, function() {
981 var args = this.args;
982 for (var i = 0, len = args.length; i < len; i++) {
983 args[i]._walk(visitor);
984 }
985 this.expression._walk(visitor); // TODO why do we need to crawl this last?
986 });
987 },
988 _children_backwards(push) {
989 let i = this.args.length;
990 while (i--) push(this.args[i]);
991 push(this.expression);
992 },
993});
994
995var AST_New = DEFNODE("New", null, {
996 $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties"
997}, AST_Call);
998
999var AST_Sequence = DEFNODE("Sequence", "expressions", {
1000 $documentation: "A sequence expression (comma-separated expressions)",
1001 $propdoc: {
1002 expressions: "[AST_Node*] array of expressions (at least two)"
1003 },
1004 _walk: function(visitor) {
1005 return visitor._visit(this, function() {
1006 this.expressions.forEach(function(node) {
1007 node._walk(visitor);
1008 });
1009 });
1010 },
1011 _children_backwards(push) {
1012 let i = this.expressions.length;
1013 while (i--) push(this.expressions[i]);
1014 },
1015});
1016
1017var AST_PropAccess = DEFNODE("PropAccess", "expression property optional", {
1018 $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`",
1019 $propdoc: {
1020 expression: "[AST_Node] the “container” expression",
1021 property: "[AST_Node|string] the property to access. For AST_Dot & AST_DotHash this is always a plain string, while for AST_Sub it's an arbitrary AST_Node",
1022
1023 optional: "[boolean] whether this is an optional property access (IE ?.)"
1024 }
1025});
1026
1027var AST_Dot = DEFNODE("Dot", "quote", {
1028 $documentation: "A dotted property access expression",
1029 $propdoc: {
1030 quote: "[string] the original quote character when transformed from AST_Sub",
1031 },
1032 _walk: function(visitor) {
1033 return visitor._visit(this, function() {
1034 this.expression._walk(visitor);
1035 });
1036 },
1037 _children_backwards(push) {
1038 push(this.expression);
1039 },
1040}, AST_PropAccess);
1041
1042var AST_DotHash = DEFNODE("DotHash", "", {
1043 $documentation: "A dotted property access to a private property",
1044 _walk: function(visitor) {
1045 return visitor._visit(this, function() {
1046 this.expression._walk(visitor);
1047 });
1048 },
1049 _children_backwards(push) {
1050 push(this.expression);
1051 },
1052}, AST_PropAccess);
1053
1054var AST_Sub = DEFNODE("Sub", null, {
1055 $documentation: "Index-style property access, i.e. `a[\"foo\"]`",
1056 _walk: function(visitor) {
1057 return visitor._visit(this, function() {
1058 this.expression._walk(visitor);
1059 this.property._walk(visitor);
1060 });
1061 },
1062 _children_backwards(push) {
1063 push(this.property);
1064 push(this.expression);
1065 },
1066}, AST_PropAccess);
1067
1068var AST_Chain = DEFNODE("Chain", "expression", {
1069 $documentation: "A chain expression like a?.b?.(c)?.[d]",
1070 $propdoc: {
1071 expression: "[AST_Call|AST_Dot|AST_DotHash|AST_Sub] chain element."
1072 },
1073 _walk: function (visitor) {
1074 return visitor._visit(this, function() {
1075 this.expression._walk(visitor);
1076 });
1077 },
1078 _children_backwards(push) {
1079 push(this.expression);
1080 },
1081});
1082
1083var AST_Unary = DEFNODE("Unary", "operator expression", {
1084 $documentation: "Base class for unary expressions",
1085 $propdoc: {
1086 operator: "[string] the operator",
1087 expression: "[AST_Node] expression that this unary operator applies to"
1088 },
1089 _walk: function(visitor) {
1090 return visitor._visit(this, function() {
1091 this.expression._walk(visitor);
1092 });
1093 },
1094 _children_backwards(push) {
1095 push(this.expression);
1096 },
1097});
1098
1099var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, {
1100 $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`"
1101}, AST_Unary);
1102
1103var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, {
1104 $documentation: "Unary postfix expression, i.e. `i++`"
1105}, AST_Unary);
1106
1107var AST_Binary = DEFNODE("Binary", "operator left right", {
1108 $documentation: "Binary expression, i.e. `a + b`",
1109 $propdoc: {
1110 left: "[AST_Node] left-hand side expression",
1111 operator: "[string] the operator",
1112 right: "[AST_Node] right-hand side expression"
1113 },
1114 _walk: function(visitor) {
1115 return visitor._visit(this, function() {
1116 this.left._walk(visitor);
1117 this.right._walk(visitor);
1118 });
1119 },
1120 _children_backwards(push) {
1121 push(this.right);
1122 push(this.left);
1123 },
1124});
1125
1126var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", {
1127 $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`",
1128 $propdoc: {
1129 condition: "[AST_Node]",
1130 consequent: "[AST_Node]",
1131 alternative: "[AST_Node]"
1132 },
1133 _walk: function(visitor) {
1134 return visitor._visit(this, function() {
1135 this.condition._walk(visitor);
1136 this.consequent._walk(visitor);
1137 this.alternative._walk(visitor);
1138 });
1139 },
1140 _children_backwards(push) {
1141 push(this.alternative);
1142 push(this.consequent);
1143 push(this.condition);
1144 },
1145});
1146
1147var AST_Assign = DEFNODE("Assign", "logical", {
1148 $documentation: "An assignment expression — `a = b + 5`",
1149 $propdoc: {
1150 logical: "Whether it's a logical assignment"
1151 }
1152}, AST_Binary);
1153
1154var AST_DefaultAssign = DEFNODE("DefaultAssign", null, {
1155 $documentation: "A default assignment expression like in `(a = 3) => a`"
1156}, AST_Binary);
1157
1158/* -----[ LITERALS ]----- */
1159
1160var AST_Array = DEFNODE("Array", "elements", {
1161 $documentation: "An array literal",
1162 $propdoc: {
1163 elements: "[AST_Node*] array of elements"
1164 },
1165 _walk: function(visitor) {
1166 return visitor._visit(this, function() {
1167 var elements = this.elements;
1168 for (var i = 0, len = elements.length; i < len; i++) {
1169 elements[i]._walk(visitor);
1170 }
1171 });
1172 },
1173 _children_backwards(push) {
1174 let i = this.elements.length;
1175 while (i--) push(this.elements[i]);
1176 },
1177});
1178
1179var AST_Object = DEFNODE("Object", "properties", {
1180 $documentation: "An object literal",
1181 $propdoc: {
1182 properties: "[AST_ObjectProperty*] array of properties"
1183 },
1184 _walk: function(visitor) {
1185 return visitor._visit(this, function() {
1186 var properties = this.properties;
1187 for (var i = 0, len = properties.length; i < len; i++) {
1188 properties[i]._walk(visitor);
1189 }
1190 });
1191 },
1192 _children_backwards(push) {
1193 let i = this.properties.length;
1194 while (i--) push(this.properties[i]);
1195 },
1196});
1197
1198var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
1199 $documentation: "Base class for literal object properties",
1200 $propdoc: {
1201 key: "[string|AST_Node] property name. For ObjectKeyVal this is a string. For getters, setters and computed property this is an AST_Node.",
1202 value: "[AST_Node] property value. For getters and setters this is an AST_Accessor."
1203 },
1204 _walk: function(visitor) {
1205 return visitor._visit(this, function() {
1206 if (this.key instanceof AST_Node)
1207 this.key._walk(visitor);
1208 this.value._walk(visitor);
1209 });
1210 },
1211 _children_backwards(push) {
1212 push(this.value);
1213 if (this.key instanceof AST_Node) push(this.key);
1214 }
1215});
1216
1217var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
1218 $documentation: "A key: value object property",
1219 $propdoc: {
1220 quote: "[string] the original quote character"
1221 },
1222 computed_key() {
1223 return this.key instanceof AST_Node;
1224 }
1225}, AST_ObjectProperty);
1226
1227var AST_PrivateSetter = DEFNODE("PrivateSetter", "static", {
1228 $propdoc: {
1229 static: "[boolean] whether this is a static private setter"
1230 },
1231 $documentation: "A private setter property",
1232 computed_key() {
1233 return false;
1234 }
1235}, AST_ObjectProperty);
1236
1237var AST_PrivateGetter = DEFNODE("PrivateGetter", "static", {
1238 $propdoc: {
1239 static: "[boolean] whether this is a static private getter"
1240 },
1241 $documentation: "A private getter property",
1242 computed_key() {
1243 return false;
1244 }
1245}, AST_ObjectProperty);
1246
1247var AST_ObjectSetter = DEFNODE("ObjectSetter", "quote static", {
1248 $propdoc: {
1249 quote: "[string|undefined] the original quote character, if any",
1250 static: "[boolean] whether this is a static setter (classes only)"
1251 },
1252 $documentation: "An object setter property",
1253 computed_key() {
1254 return !(this.key instanceof AST_SymbolMethod);
1255 }
1256}, AST_ObjectProperty);
1257
1258var AST_ObjectGetter = DEFNODE("ObjectGetter", "quote static", {
1259 $propdoc: {
1260 quote: "[string|undefined] the original quote character, if any",
1261 static: "[boolean] whether this is a static getter (classes only)"
1262 },
1263 $documentation: "An object getter property",
1264 computed_key() {
1265 return !(this.key instanceof AST_SymbolMethod);
1266 }
1267}, AST_ObjectProperty);
1268
1269var AST_ConciseMethod = DEFNODE("ConciseMethod", "quote static is_generator async", {
1270 $propdoc: {
1271 quote: "[string|undefined] the original quote character, if any",
1272 static: "[boolean] is this method static (classes only)",
1273 is_generator: "[boolean] is this a generator method",
1274 async: "[boolean] is this method async",
1275 },
1276 $documentation: "An ES6 concise method inside an object or class",
1277 computed_key() {
1278 return !(this.key instanceof AST_SymbolMethod);
1279 }
1280}, AST_ObjectProperty);
1281
1282var AST_PrivateMethod = DEFNODE("PrivateMethod", "", {
1283 $documentation: "A private class method inside a class",
1284}, AST_ConciseMethod);
1285
1286var AST_Class = DEFNODE("Class", "name extends properties", {
1287 $propdoc: {
1288 name: "[AST_SymbolClass|AST_SymbolDefClass?] optional class name.",
1289 extends: "[AST_Node]? optional parent class",
1290 properties: "[AST_ObjectProperty*] array of properties"
1291 },
1292 $documentation: "An ES6 class",
1293 _walk: function(visitor) {
1294 return visitor._visit(this, function() {
1295 if (this.name) {
1296 this.name._walk(visitor);
1297 }
1298 if (this.extends) {
1299 this.extends._walk(visitor);
1300 }
1301 this.properties.forEach((prop) => prop._walk(visitor));
1302 });
1303 },
1304 _children_backwards(push) {
1305 let i = this.properties.length;
1306 while (i--) push(this.properties[i]);
1307 if (this.extends) push(this.extends);
1308 if (this.name) push(this.name);
1309 },
1310}, AST_Scope /* TODO a class might have a scope but it's not a scope */);
1311
1312var AST_ClassProperty = DEFNODE("ClassProperty", "static quote", {
1313 $documentation: "A class property",
1314 $propdoc: {
1315 static: "[boolean] whether this is a static key",
1316 quote: "[string] which quote is being used"
1317 },
1318 _walk: function(visitor) {
1319 return visitor._visit(this, function() {
1320 if (this.key instanceof AST_Node)
1321 this.key._walk(visitor);
1322 if (this.value instanceof AST_Node)
1323 this.value._walk(visitor);
1324 });
1325 },
1326 _children_backwards(push) {
1327 if (this.value instanceof AST_Node) push(this.value);
1328 if (this.key instanceof AST_Node) push(this.key);
1329 },
1330 computed_key() {
1331 return !(this.key instanceof AST_SymbolClassProperty);
1332 }
1333}, AST_ObjectProperty);
1334
1335var AST_ClassPrivateProperty = DEFNODE("ClassProperty", "", {
1336 $documentation: "A class property for a private property",
1337}, AST_ClassProperty);
1338
1339var AST_DefClass = DEFNODE("DefClass", null, {
1340 $documentation: "A class definition",
1341}, AST_Class);
1342
1343var AST_ClassExpression = DEFNODE("ClassExpression", null, {
1344 $documentation: "A class expression."
1345}, AST_Class);
1346
1347var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
1348 $propdoc: {
1349 name: "[string] name of this symbol",
1350 scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
1351 thedef: "[SymbolDef/S] the definition of this symbol"
1352 },
1353 $documentation: "Base class for all symbols"
1354});
1355
1356var AST_NewTarget = DEFNODE("NewTarget", null, {
1357 $documentation: "A reference to new.target"
1358});
1359
1360var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
1361 $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
1362}, AST_Symbol);
1363
1364var AST_SymbolVar = DEFNODE("SymbolVar", null, {
1365 $documentation: "Symbol defining a variable",
1366}, AST_SymbolDeclaration);
1367
1368var AST_SymbolBlockDeclaration = DEFNODE("SymbolBlockDeclaration", null, {
1369 $documentation: "Base class for block-scoped declaration symbols"
1370}, AST_SymbolDeclaration);
1371
1372var AST_SymbolConst = DEFNODE("SymbolConst", null, {
1373 $documentation: "A constant declaration"
1374}, AST_SymbolBlockDeclaration);
1375
1376var AST_SymbolLet = DEFNODE("SymbolLet", null, {
1377 $documentation: "A block-scoped `let` declaration"
1378}, AST_SymbolBlockDeclaration);
1379
1380var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
1381 $documentation: "Symbol naming a function argument",
1382}, AST_SymbolVar);
1383
1384var AST_SymbolDefun = DEFNODE("SymbolDefun", null, {
1385 $documentation: "Symbol defining a function",
1386}, AST_SymbolDeclaration);
1387
1388var AST_SymbolMethod = DEFNODE("SymbolMethod", null, {
1389 $documentation: "Symbol in an object defining a method",
1390}, AST_Symbol);
1391
1392var AST_SymbolClassProperty = DEFNODE("SymbolClassProperty", null, {
1393 $documentation: "Symbol for a class property",
1394}, AST_Symbol);
1395
1396var AST_SymbolLambda = DEFNODE("SymbolLambda", null, {
1397 $documentation: "Symbol naming a function expression",
1398}, AST_SymbolDeclaration);
1399
1400var AST_SymbolDefClass = DEFNODE("SymbolDefClass", null, {
1401 $documentation: "Symbol naming a class's name in a class declaration. Lexically scoped to its containing scope, and accessible within the class."
1402}, AST_SymbolBlockDeclaration);
1403
1404var AST_SymbolClass = DEFNODE("SymbolClass", null, {
1405 $documentation: "Symbol naming a class's name. Lexically scoped to the class."
1406}, AST_SymbolDeclaration);
1407
1408var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
1409 $documentation: "Symbol naming the exception in catch",
1410}, AST_SymbolBlockDeclaration);
1411
1412var AST_SymbolImport = DEFNODE("SymbolImport", null, {
1413 $documentation: "Symbol referring to an imported name",
1414}, AST_SymbolBlockDeclaration);
1415
1416var AST_SymbolImportForeign = DEFNODE("SymbolImportForeign", null, {
1417 $documentation: "A symbol imported from a module, but it is defined in the other module, and its real name is irrelevant for this module's purposes",
1418}, AST_Symbol);
1419
1420var AST_Label = DEFNODE("Label", "references", {
1421 $documentation: "Symbol naming a label (declaration)",
1422 $propdoc: {
1423 references: "[AST_LoopControl*] a list of nodes referring to this label"
1424 },
1425 initialize: function() {
1426 this.references = [];
1427 this.thedef = this;
1428 }
1429}, AST_Symbol);
1430
1431var AST_SymbolRef = DEFNODE("SymbolRef", null, {
1432 $documentation: "Reference to some symbol (not definition/declaration)",
1433}, AST_Symbol);
1434
1435var AST_SymbolExport = DEFNODE("SymbolExport", null, {
1436 $documentation: "Symbol referring to a name to export",
1437}, AST_SymbolRef);
1438
1439var AST_SymbolExportForeign = DEFNODE("SymbolExportForeign", null, {
1440 $documentation: "A symbol exported from this module, but it is used in the other module, and its real name is irrelevant for this module's purposes",
1441}, AST_Symbol);
1442
1443var AST_LabelRef = DEFNODE("LabelRef", null, {
1444 $documentation: "Reference to a label symbol",
1445}, AST_Symbol);
1446
1447var AST_This = DEFNODE("This", null, {
1448 $documentation: "The `this` symbol",
1449}, AST_Symbol);
1450
1451var AST_Super = DEFNODE("Super", null, {
1452 $documentation: "The `super` symbol",
1453}, AST_This);
1454
1455var AST_Constant = DEFNODE("Constant", null, {
1456 $documentation: "Base class for all constants",
1457 getValue: function() {
1458 return this.value;
1459 }
1460});
1461
1462var AST_String = DEFNODE("String", "value quote", {
1463 $documentation: "A string literal",
1464 $propdoc: {
1465 value: "[string] the contents of this string",
1466 quote: "[string] the original quote character"
1467 }
1468}, AST_Constant);
1469
1470var AST_Number = DEFNODE("Number", "value raw", {
1471 $documentation: "A number literal",
1472 $propdoc: {
1473 value: "[number] the numeric value",
1474 raw: "[string] numeric value as string"
1475 }
1476}, AST_Constant);
1477
1478var AST_BigInt = DEFNODE("BigInt", "value", {
1479 $documentation: "A big int literal",
1480 $propdoc: {
1481 value: "[string] big int value"
1482 }
1483}, AST_Constant);
1484
1485var AST_RegExp = DEFNODE("RegExp", "value", {
1486 $documentation: "A regexp literal",
1487 $propdoc: {
1488 value: "[RegExp] the actual regexp",
1489 }
1490}, AST_Constant);
1491
1492var AST_Atom = DEFNODE("Atom", null, {
1493 $documentation: "Base class for atoms",
1494}, AST_Constant);
1495
1496var AST_Null = DEFNODE("Null", null, {
1497 $documentation: "The `null` atom",
1498 value: null
1499}, AST_Atom);
1500
1501var AST_NaN = DEFNODE("NaN", null, {
1502 $documentation: "The impossible value",
1503 value: 0/0
1504}, AST_Atom);
1505
1506var AST_Undefined = DEFNODE("Undefined", null, {
1507 $documentation: "The `undefined` value",
1508 value: (function() {}())
1509}, AST_Atom);
1510
1511var AST_Hole = DEFNODE("Hole", null, {
1512 $documentation: "A hole in an array",
1513 value: (function() {}())
1514}, AST_Atom);
1515
1516var AST_Infinity = DEFNODE("Infinity", null, {
1517 $documentation: "The `Infinity` value",
1518 value: 1/0
1519}, AST_Atom);
1520
1521var AST_Boolean = DEFNODE("Boolean", null, {
1522 $documentation: "Base class for booleans",
1523}, AST_Atom);
1524
1525var AST_False = DEFNODE("False", null, {
1526 $documentation: "The `false` atom",
1527 value: false
1528}, AST_Boolean);
1529
1530var AST_True = DEFNODE("True", null, {
1531 $documentation: "The `true` atom",
1532 value: true
1533}, AST_Boolean);
1534
1535/* -----[ Walk function ]---- */
1536
1537/**
1538 * Walk nodes in depth-first search fashion.
1539 * Callback can return `walk_abort` symbol to stop iteration.
1540 * It can also return `true` to stop iteration just for child nodes.
1541 * Iteration can be stopped and continued by passing the `to_visit` argument,
1542 * which is given to the callback in the second argument.
1543 **/
1544function walk(node, cb, to_visit = [node]) {
1545 const push = to_visit.push.bind(to_visit);
1546 while (to_visit.length) {
1547 const node = to_visit.pop();
1548 const ret = cb(node, to_visit);
1549
1550 if (ret) {
1551 if (ret === walk_abort) return true;
1552 continue;
1553 }
1554
1555 node._children_backwards(push);
1556 }
1557 return false;
1558}
1559
1560function walk_parent(node, cb, initial_stack) {
1561 const to_visit = [node];
1562 const push = to_visit.push.bind(to_visit);
1563 const stack = initial_stack ? initial_stack.slice() : [];
1564 const parent_pop_indices = [];
1565
1566 let current;
1567
1568 const info = {
1569 parent: (n = 0) => {
1570 if (n === -1) {
1571 return current;
1572 }
1573
1574 // [ p1 p0 ] [ 1 0 ]
1575 if (initial_stack && n >= stack.length) {
1576 n -= stack.length;
1577 return initial_stack[
1578 initial_stack.length - (n + 1)
1579 ];
1580 }
1581
1582 return stack[stack.length - (1 + n)];
1583 },
1584 };
1585
1586 while (to_visit.length) {
1587 current = to_visit.pop();
1588
1589 while (
1590 parent_pop_indices.length &&
1591 to_visit.length == parent_pop_indices[parent_pop_indices.length - 1]
1592 ) {
1593 stack.pop();
1594 parent_pop_indices.pop();
1595 }
1596
1597 const ret = cb(current, info);
1598
1599 if (ret) {
1600 if (ret === walk_abort) return true;
1601 continue;
1602 }
1603
1604 const visit_length = to_visit.length;
1605
1606 current._children_backwards(push);
1607
1608 // Push only if we're going to traverse the children
1609 if (to_visit.length > visit_length) {
1610 stack.push(current);
1611 parent_pop_indices.push(visit_length - 1);
1612 }
1613 }
1614
1615 return false;
1616}
1617
1618const walk_abort = Symbol("abort walk");
1619
1620/* -----[ TreeWalker ]----- */
1621
1622class TreeWalker {
1623 constructor(callback) {
1624 this.visit = callback;
1625 this.stack = [];
1626 this.directives = Object.create(null);
1627 }
1628
1629 _visit(node, descend) {
1630 this.push(node);
1631 var ret = this.visit(node, descend ? function() {
1632 descend.call(node);
1633 } : noop);
1634 if (!ret && descend) {
1635 descend.call(node);
1636 }
1637 this.pop();
1638 return ret;
1639 }
1640
1641 parent(n) {
1642 return this.stack[this.stack.length - 2 - (n || 0)];
1643 }
1644
1645 push(node) {
1646 if (node instanceof AST_Lambda) {
1647 this.directives = Object.create(this.directives);
1648 } else if (node instanceof AST_Directive && !this.directives[node.value]) {
1649 this.directives[node.value] = node;
1650 } else if (node instanceof AST_Class) {
1651 this.directives = Object.create(this.directives);
1652 if (!this.directives["use strict"]) {
1653 this.directives["use strict"] = node;
1654 }
1655 }
1656 this.stack.push(node);
1657 }
1658
1659 pop() {
1660 var node = this.stack.pop();
1661 if (node instanceof AST_Lambda || node instanceof AST_Class) {
1662 this.directives = Object.getPrototypeOf(this.directives);
1663 }
1664 }
1665
1666 self() {
1667 return this.stack[this.stack.length - 1];
1668 }
1669
1670 find_parent(type) {
1671 var stack = this.stack;
1672 for (var i = stack.length; --i >= 0;) {
1673 var x = stack[i];
1674 if (x instanceof type) return x;
1675 }
1676 }
1677
1678 has_directive(type) {
1679 var dir = this.directives[type];
1680 if (dir) return dir;
1681 var node = this.stack[this.stack.length - 1];
1682 if (node instanceof AST_Scope && node.body) {
1683 for (var i = 0; i < node.body.length; ++i) {
1684 var st = node.body[i];
1685 if (!(st instanceof AST_Directive)) break;
1686 if (st.value == type) return st;
1687 }
1688 }
1689 }
1690
1691 loopcontrol_target(node) {
1692 var stack = this.stack;
1693 if (node.label) for (var i = stack.length; --i >= 0;) {
1694 var x = stack[i];
1695 if (x instanceof AST_LabeledStatement && x.label.name == node.label.name)
1696 return x.body;
1697 } else for (var i = stack.length; --i >= 0;) {
1698 var x = stack[i];
1699 if (x instanceof AST_IterationStatement
1700 || node instanceof AST_Break && x instanceof AST_Switch)
1701 return x;
1702 }
1703 }
1704}
1705
1706// Tree transformer helpers.
1707class TreeTransformer extends TreeWalker {
1708 constructor(before, after) {
1709 super();
1710 this.before = before;
1711 this.after = after;
1712 }
1713}
1714
1715const _PURE = 0b00000001;
1716const _INLINE = 0b00000010;
1717const _NOINLINE = 0b00000100;
1718
1719export {
1720 AST_Accessor,
1721 AST_Array,
1722 AST_Arrow,
1723 AST_Assign,
1724 AST_Atom,
1725 AST_Await,
1726 AST_BigInt,
1727 AST_Binary,
1728 AST_Block,
1729 AST_BlockStatement,
1730 AST_Boolean,
1731 AST_Break,
1732 AST_Call,
1733 AST_Case,
1734 AST_Catch,
1735 AST_Chain,
1736 AST_Class,
1737 AST_ClassExpression,
1738 AST_ClassPrivateProperty,
1739 AST_ClassProperty,
1740 AST_ConciseMethod,
1741 AST_Conditional,
1742 AST_Const,
1743 AST_Constant,
1744 AST_Continue,
1745 AST_Debugger,
1746 AST_Default,
1747 AST_DefaultAssign,
1748 AST_DefClass,
1749 AST_Definitions,
1750 AST_Defun,
1751 AST_Destructuring,
1752 AST_Directive,
1753 AST_Do,
1754 AST_Dot,
1755 AST_DotHash,
1756 AST_DWLoop,
1757 AST_EmptyStatement,
1758 AST_Exit,
1759 AST_Expansion,
1760 AST_Export,
1761 AST_False,
1762 AST_Finally,
1763 AST_For,
1764 AST_ForIn,
1765 AST_ForOf,
1766 AST_Function,
1767 AST_Hole,
1768 AST_If,
1769 AST_Import,
1770 AST_ImportMeta,
1771 AST_Infinity,
1772 AST_IterationStatement,
1773 AST_Jump,
1774 AST_Label,
1775 AST_LabeledStatement,
1776 AST_LabelRef,
1777 AST_Lambda,
1778 AST_Let,
1779 AST_LoopControl,
1780 AST_NameMapping,
1781 AST_NaN,
1782 AST_New,
1783 AST_NewTarget,
1784 AST_Node,
1785 AST_Null,
1786 AST_Number,
1787 AST_Object,
1788 AST_ObjectGetter,
1789 AST_ObjectKeyVal,
1790 AST_ObjectProperty,
1791 AST_ObjectSetter,
1792 AST_PrefixedTemplateString,
1793 AST_PrivateGetter,
1794 AST_PrivateMethod,
1795 AST_PrivateSetter,
1796 AST_PropAccess,
1797 AST_RegExp,
1798 AST_Return,
1799 AST_Scope,
1800 AST_Sequence,
1801 AST_SimpleStatement,
1802 AST_Statement,
1803 AST_StatementWithBody,
1804 AST_String,
1805 AST_Sub,
1806 AST_Super,
1807 AST_Switch,
1808 AST_SwitchBranch,
1809 AST_Symbol,
1810 AST_SymbolBlockDeclaration,
1811 AST_SymbolCatch,
1812 AST_SymbolClass,
1813 AST_SymbolClassProperty,
1814 AST_SymbolConst,
1815 AST_SymbolDeclaration,
1816 AST_SymbolDefClass,
1817 AST_SymbolDefun,
1818 AST_SymbolExport,
1819 AST_SymbolExportForeign,
1820 AST_SymbolFunarg,
1821 AST_SymbolImport,
1822 AST_SymbolImportForeign,
1823 AST_SymbolLambda,
1824 AST_SymbolLet,
1825 AST_SymbolMethod,
1826 AST_SymbolRef,
1827 AST_SymbolVar,
1828 AST_TemplateSegment,
1829 AST_TemplateString,
1830 AST_This,
1831 AST_Throw,
1832 AST_Token,
1833 AST_Toplevel,
1834 AST_True,
1835 AST_Try,
1836 AST_Unary,
1837 AST_UnaryPostfix,
1838 AST_UnaryPrefix,
1839 AST_Undefined,
1840 AST_Var,
1841 AST_VarDef,
1842 AST_While,
1843 AST_With,
1844 AST_Yield,
1845
1846 // Walkers
1847 TreeTransformer,
1848 TreeWalker,
1849 walk,
1850 walk_abort,
1851 walk_body,
1852 walk_parent,
1853
1854 // annotations
1855 _INLINE,
1856 _NOINLINE,
1857 _PURE,
1858};
Note: See TracBrowser for help on using the repository browser.