source: frontend/node_modules/terser/lib/ast.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 100.7 KB
Line 
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
44import {
45 HOP,
46 MAP,
47 noop
48} from "./utils/index.js";
49import { parse } from "./parse.js";
50
51function DEFNODE(type, props, ctor, methods, base = AST_Node) {
52 if (!props) props = [];
53 else props = props.split(/\s+/);
54 var self_props = props;
55 if (base && base.PROPS)
56 props = props.concat(base.PROPS);
57 const proto = base && Object.create(base.prototype);
58 if (proto) {
59 ctor.prototype = proto;
60 ctor.BASE = base;
61 }
62 if (base) base.SUBCLASSES.push(ctor);
63 ctor.prototype.CTOR = ctor;
64 ctor.prototype.constructor = ctor;
65 ctor.PROPS = props || null;
66 ctor.SELF_PROPS = self_props;
67 ctor.SUBCLASSES = [];
68 if (type) {
69 ctor.prototype.TYPE = ctor.TYPE = type;
70 }
71 if (methods) for (let i in methods) if (HOP(methods, i)) {
72 if (i[0] === "$") {
73 ctor[i.substr(1)] = methods[i];
74 } else {
75 ctor.prototype[i] = methods[i];
76 }
77 }
78 ctor.DEFMETHOD = function(name, method) {
79 this.prototype[name] = method;
80 };
81 return ctor;
82}
83
84const has_tok_flag = (tok, flag) => Boolean(tok.flags & flag);
85const set_tok_flag = (tok, flag, truth) => {
86 if (truth) {
87 tok.flags |= flag;
88 } else {
89 tok.flags &= ~flag;
90 }
91};
92
93const TOK_FLAG_NLB = 0b0001;
94const TOK_FLAG_QUOTE_SINGLE = 0b0010;
95const TOK_FLAG_QUOTE_EXISTS = 0b0100;
96const TOK_FLAG_TEMPLATE_END = 0b1000;
97
98class AST_Token {
99 constructor(type, value, line, col, pos, nlb, comments_before, comments_after, file) {
100 this.flags = (nlb ? 1 : 0);
101
102 this.type = type;
103 this.value = value;
104 this.line = line;
105 this.col = col;
106 this.pos = pos;
107 this.comments_before = comments_before;
108 this.comments_after = comments_after;
109 this.file = file;
110
111 Object.seal(this);
112 }
113
114 // Return a string summary of the token for node.js console.log
115 [Symbol.for("nodejs.util.inspect.custom")](_depth, options) {
116 const special = str => options.stylize(str, "special");
117 const quote = typeof this.value === "string" && this.value.includes("`") ? "'" : "`";
118 const value = `${quote}${this.value}${quote}`;
119 return `${special("[AST_Token")} ${value} at ${this.line}:${this.col}${special("]")}`;
120 }
121
122 get nlb() {
123 return has_tok_flag(this, TOK_FLAG_NLB);
124 }
125
126 set nlb(new_nlb) {
127 set_tok_flag(this, TOK_FLAG_NLB, new_nlb);
128 }
129
130 get quote() {
131 return !has_tok_flag(this, TOK_FLAG_QUOTE_EXISTS)
132 ? ""
133 : (has_tok_flag(this, TOK_FLAG_QUOTE_SINGLE) ? "'" : '"');
134 }
135
136 set quote(quote_type) {
137 set_tok_flag(this, TOK_FLAG_QUOTE_SINGLE, quote_type === "'");
138 set_tok_flag(this, TOK_FLAG_QUOTE_EXISTS, !!quote_type);
139 }
140
141 get template_end() {
142 return has_tok_flag(this, TOK_FLAG_TEMPLATE_END);
143 }
144
145 set template_end(new_template_end) {
146 set_tok_flag(this, TOK_FLAG_TEMPLATE_END, new_template_end);
147 }
148}
149
150var AST_Node = DEFNODE("Node", "start end", function AST_Node(props) {
151 if (props) {
152 this.start = props.start;
153 this.end = props.end;
154 }
155
156 this.flags = 0;
157}, {
158 _clone: function(deep) {
159 if (deep) {
160 var self = this.clone();
161 return self.transform(new TreeTransformer(function(node) {
162 if (node !== self) {
163 return node.clone(true);
164 }
165 }));
166 }
167 return new this.CTOR(this);
168 },
169 clone: function(deep) {
170 return this._clone(deep);
171 },
172 $documentation: "Base class of all AST nodes",
173 $propdoc: {
174 start: "[AST_Token] The first token of this node",
175 end: "[AST_Token] The last token of this node"
176 },
177 _walk: function(visitor) {
178 return visitor._visit(this);
179 },
180 walk: function(visitor) {
181 return this._walk(visitor); // not sure the indirection will be any help
182 },
183 _children_backwards: () => {}
184}, null);
185
186/* -----[ statements ]----- */
187
188var AST_Statement = DEFNODE("Statement", null, function AST_Statement(props) {
189 if (props) {
190 this.start = props.start;
191 this.end = props.end;
192 }
193
194 this.flags = 0;
195}, {
196 $documentation: "Base class of all statements",
197});
198
199var AST_Debugger = DEFNODE("Debugger", null, function AST_Debugger(props) {
200 if (props) {
201 this.start = props.start;
202 this.end = props.end;
203 }
204
205 this.flags = 0;
206}, {
207 $documentation: "Represents a debugger statement",
208}, AST_Statement);
209
210var AST_Directive = DEFNODE("Directive", "value quote", function AST_Directive(props) {
211 if (props) {
212 this.value = props.value;
213 this.quote = props.quote;
214 this.start = props.start;
215 this.end = props.end;
216 }
217
218 this.flags = 0;
219}, {
220 $documentation: "Represents a directive, like \"use strict\";",
221 $propdoc: {
222 value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
223 quote: "[string] the original quote character"
224 },
225}, AST_Statement);
226
227var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", function AST_SimpleStatement(props) {
228 if (props) {
229 this.body = props.body;
230 this.start = props.start;
231 this.end = props.end;
232 }
233
234 this.flags = 0;
235}, {
236 $documentation: "A statement consisting of an expression, i.e. a = 1 + 2",
237 $propdoc: {
238 body: "[AST_Node] an expression node (should not be instanceof AST_Statement)"
239 },
240 _walk: function(visitor) {
241 return visitor._visit(this, function() {
242 this.body._walk(visitor);
243 });
244 },
245 _children_backwards(push) {
246 push(this.body);
247 }
248}, AST_Statement);
249
250function walk_body(node, visitor) {
251 const body = node.body;
252 for (var i = 0, len = body.length; i < len; i++) {
253 body[i]._walk(visitor);
254 }
255}
256
257function clone_block_scope(deep) {
258 var clone = this._clone(deep);
259 if (this.block_scope) {
260 clone.block_scope = this.block_scope.clone();
261 }
262 return clone;
263}
264
265var AST_Block = DEFNODE("Block", "body block_scope", function AST_Block(props) {
266 if (props) {
267 this.body = props.body;
268 this.block_scope = props.block_scope;
269 this.start = props.start;
270 this.end = props.end;
271 }
272
273 this.flags = 0;
274}, {
275 $documentation: "A body of statements (usually braced)",
276 $propdoc: {
277 body: "[AST_Statement*] an array of statements",
278 block_scope: "[AST_Scope] the block scope"
279 },
280 _walk: function(visitor) {
281 return visitor._visit(this, function() {
282 walk_body(this, visitor);
283 });
284 },
285 _children_backwards(push) {
286 let i = this.body.length;
287 while (i--) push(this.body[i]);
288 },
289 clone: clone_block_scope
290}, AST_Statement);
291
292var AST_BlockStatement = DEFNODE("BlockStatement", null, function AST_BlockStatement(props) {
293 if (props) {
294 this.body = props.body;
295 this.block_scope = props.block_scope;
296 this.start = props.start;
297 this.end = props.end;
298 }
299
300 this.flags = 0;
301}, {
302 $documentation: "A block statement",
303}, AST_Block);
304
305var AST_EmptyStatement = DEFNODE("EmptyStatement", null, function AST_EmptyStatement(props) {
306 if (props) {
307 this.start = props.start;
308 this.end = props.end;
309 }
310
311 this.flags = 0;
312}, {
313 $documentation: "The empty statement (empty block or simply a semicolon)"
314}, AST_Statement);
315
316var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", function AST_StatementWithBody(props) {
317 if (props) {
318 this.body = props.body;
319 this.start = props.start;
320 this.end = props.end;
321 }
322
323 this.flags = 0;
324}, {
325 $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
326 $propdoc: {
327 body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
328 }
329}, AST_Statement);
330
331var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", function AST_LabeledStatement(props) {
332 if (props) {
333 this.label = props.label;
334 this.body = props.body;
335 this.start = props.start;
336 this.end = props.end;
337 }
338
339 this.flags = 0;
340}, {
341 $documentation: "Statement with a label",
342 $propdoc: {
343 label: "[AST_Label] a label definition"
344 },
345 _walk: function(visitor) {
346 return visitor._visit(this, function() {
347 this.label._walk(visitor);
348 this.body._walk(visitor);
349 });
350 },
351 _children_backwards(push) {
352 push(this.body);
353 push(this.label);
354 },
355 clone: function(deep) {
356 var node = this._clone(deep);
357 if (deep) {
358 var label = node.label;
359 var def = this.label;
360 node.walk(new TreeWalker(function(node) {
361 if (node instanceof AST_LoopControl
362 && node.label && node.label.thedef === def) {
363 node.label.thedef = label;
364 label.references.push(node);
365 }
366 }));
367 }
368 return node;
369 }
370}, AST_StatementWithBody);
371
372var AST_IterationStatement = DEFNODE(
373 "IterationStatement",
374 "block_scope",
375 function AST_IterationStatement(props) {
376 if (props) {
377 this.block_scope = props.block_scope;
378 this.body = props.body;
379 this.start = props.start;
380 this.end = props.end;
381 }
382
383 this.flags = 0;
384 },
385 {
386 $documentation: "Internal class. All loops inherit from it.",
387 $propdoc: {
388 block_scope: "[AST_Scope] the block scope for this iteration statement."
389 },
390 clone: clone_block_scope
391 },
392 AST_StatementWithBody
393);
394
395var AST_DWLoop = DEFNODE("DWLoop", "condition", function AST_DWLoop(props) {
396 if (props) {
397 this.condition = props.condition;
398 this.block_scope = props.block_scope;
399 this.body = props.body;
400 this.start = props.start;
401 this.end = props.end;
402 }
403
404 this.flags = 0;
405}, {
406 $documentation: "Base class for do/while statements",
407 $propdoc: {
408 condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
409 }
410}, AST_IterationStatement);
411
412var AST_Do = DEFNODE("Do", null, function AST_Do(props) {
413 if (props) {
414 this.condition = props.condition;
415 this.block_scope = props.block_scope;
416 this.body = props.body;
417 this.start = props.start;
418 this.end = props.end;
419 }
420
421 this.flags = 0;
422}, {
423 $documentation: "A `do` statement",
424 _walk: function(visitor) {
425 return visitor._visit(this, function() {
426 this.body._walk(visitor);
427 this.condition._walk(visitor);
428 });
429 },
430 _children_backwards(push) {
431 push(this.condition);
432 push(this.body);
433 }
434}, AST_DWLoop);
435
436var AST_While = DEFNODE("While", null, function AST_While(props) {
437 if (props) {
438 this.condition = props.condition;
439 this.block_scope = props.block_scope;
440 this.body = props.body;
441 this.start = props.start;
442 this.end = props.end;
443 }
444
445 this.flags = 0;
446}, {
447 $documentation: "A `while` statement",
448 _walk: function(visitor) {
449 return visitor._visit(this, function() {
450 this.condition._walk(visitor);
451 this.body._walk(visitor);
452 });
453 },
454 _children_backwards(push) {
455 push(this.body);
456 push(this.condition);
457 },
458}, AST_DWLoop);
459
460var AST_For = DEFNODE("For", "init condition step", function AST_For(props) {
461 if (props) {
462 this.init = props.init;
463 this.condition = props.condition;
464 this.step = props.step;
465 this.block_scope = props.block_scope;
466 this.body = props.body;
467 this.start = props.start;
468 this.end = props.end;
469 }
470
471 this.flags = 0;
472}, {
473 $documentation: "A `for` statement",
474 $propdoc: {
475 init: "[AST_Node?] the `for` initialization code, or null if empty",
476 condition: "[AST_Node?] the `for` termination clause, or null if empty",
477 step: "[AST_Node?] the `for` update clause, or null if empty"
478 },
479 _walk: function(visitor) {
480 return visitor._visit(this, function() {
481 if (this.init) this.init._walk(visitor);
482 if (this.condition) this.condition._walk(visitor);
483 if (this.step) this.step._walk(visitor);
484 this.body._walk(visitor);
485 });
486 },
487 _children_backwards(push) {
488 push(this.body);
489 if (this.step) push(this.step);
490 if (this.condition) push(this.condition);
491 if (this.init) push(this.init);
492 },
493}, AST_IterationStatement);
494
495var AST_ForIn = DEFNODE("ForIn", "init object", function AST_ForIn(props) {
496 if (props) {
497 this.init = props.init;
498 this.object = props.object;
499 this.block_scope = props.block_scope;
500 this.body = props.body;
501 this.start = props.start;
502 this.end = props.end;
503 }
504
505 this.flags = 0;
506}, {
507 $documentation: "A `for ... in` statement",
508 $propdoc: {
509 init: "[AST_Node] the `for/in` initialization code",
510 object: "[AST_Node] the object that we're looping through"
511 },
512 _walk: function(visitor) {
513 return visitor._visit(this, function() {
514 this.init._walk(visitor);
515 this.object._walk(visitor);
516 this.body._walk(visitor);
517 });
518 },
519 _children_backwards(push) {
520 push(this.body);
521 if (this.object) push(this.object);
522 if (this.init) push(this.init);
523 },
524}, AST_IterationStatement);
525
526var AST_ForOf = DEFNODE("ForOf", "await", function AST_ForOf(props) {
527 if (props) {
528 this.await = props.await;
529 this.init = props.init;
530 this.object = props.object;
531 this.block_scope = props.block_scope;
532 this.body = props.body;
533 this.start = props.start;
534 this.end = props.end;
535 }
536
537 this.flags = 0;
538}, {
539 $documentation: "A `for ... of` statement",
540}, AST_ForIn);
541
542var AST_With = DEFNODE("With", "expression", function AST_With(props) {
543 if (props) {
544 this.expression = props.expression;
545 this.body = props.body;
546 this.start = props.start;
547 this.end = props.end;
548 }
549
550 this.flags = 0;
551}, {
552 $documentation: "A `with` statement",
553 $propdoc: {
554 expression: "[AST_Node] the `with` expression"
555 },
556 _walk: function(visitor) {
557 return visitor._visit(this, function() {
558 this.expression._walk(visitor);
559 this.body._walk(visitor);
560 });
561 },
562 _children_backwards(push) {
563 push(this.body);
564 push(this.expression);
565 },
566}, AST_StatementWithBody);
567
568/* -----[ scope and functions ]----- */
569
570var AST_Scope = DEFNODE(
571 "Scope",
572 "variables uses_with uses_eval parent_scope enclosed cname",
573 function AST_Scope(props) {
574 if (props) {
575 this.variables = props.variables;
576 this.uses_with = props.uses_with;
577 this.uses_eval = props.uses_eval;
578 this.parent_scope = props.parent_scope;
579 this.enclosed = props.enclosed;
580 this.cname = props.cname;
581 this.body = props.body;
582 this.block_scope = props.block_scope;
583 this.start = props.start;
584 this.end = props.end;
585 }
586
587 this.flags = 0;
588 },
589 {
590 $documentation: "Base class for all statements introducing a lexical scope",
591 $propdoc: {
592 variables: "[Map/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
593 uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
594 uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
595 parent_scope: "[AST_Scope?/S] link to the parent scope",
596 enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
597 cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
598 },
599 get_defun_scope: function() {
600 var self = this;
601 while (self.is_block_scope()) {
602 self = self.parent_scope;
603 }
604 return self;
605 },
606 clone: function(deep, toplevel) {
607 var node = this._clone(deep);
608 if (deep && this.variables && toplevel && !this._block_scope) {
609 node.figure_out_scope({}, {
610 toplevel: toplevel,
611 parent_scope: this.parent_scope
612 });
613 } else {
614 if (this.variables) node.variables = new Map(this.variables);
615 if (this.enclosed) node.enclosed = this.enclosed.slice();
616 if (this._block_scope) node._block_scope = this._block_scope;
617 }
618 return node;
619 },
620 pinned: function() {
621 return this.uses_eval || this.uses_with;
622 }
623 },
624 AST_Block
625);
626
627var AST_Toplevel = DEFNODE("Toplevel", "globals", function AST_Toplevel(props) {
628 if (props) {
629 this.globals = props.globals;
630 this.variables = props.variables;
631 this.uses_with = props.uses_with;
632 this.uses_eval = props.uses_eval;
633 this.parent_scope = props.parent_scope;
634 this.enclosed = props.enclosed;
635 this.cname = props.cname;
636 this.body = props.body;
637 this.block_scope = props.block_scope;
638 this.start = props.start;
639 this.end = props.end;
640 }
641
642 this.flags = 0;
643}, {
644 $documentation: "The toplevel scope",
645 $propdoc: {
646 globals: "[Map/S] a map of name -> SymbolDef for all undeclared names",
647 },
648 wrap_commonjs: function(name) {
649 var body = this.body;
650 var wrapped_tl = "(function(exports){'$ORIG';})(typeof " + name + "=='undefined'?(" + name + "={}):" + name + ");";
651 wrapped_tl = parse(wrapped_tl);
652 wrapped_tl = wrapped_tl.transform(new TreeTransformer(function(node) {
653 if (node instanceof AST_Directive && node.value == "$ORIG") {
654 return MAP.splice(body);
655 }
656 }));
657 return wrapped_tl;
658 },
659 wrap_enclose: function(args_values) {
660 if (typeof args_values != "string") args_values = "";
661 var index = args_values.indexOf(":");
662 if (index < 0) index = args_values.length;
663 var body = this.body;
664 return parse([
665 "(function(",
666 args_values.slice(0, index),
667 '){"$ORIG"})(',
668 args_values.slice(index + 1),
669 ")"
670 ].join("")).transform(new TreeTransformer(function(node) {
671 if (node instanceof AST_Directive && node.value == "$ORIG") {
672 return MAP.splice(body);
673 }
674 }));
675 }
676}, AST_Scope);
677
678var AST_Expansion = DEFNODE("Expansion", "expression", function AST_Expansion(props) {
679 if (props) {
680 this.expression = props.expression;
681 this.start = props.start;
682 this.end = props.end;
683 }
684
685 this.flags = 0;
686}, {
687 $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",
688 $propdoc: {
689 expression: "[AST_Node] the thing to be expanded"
690 },
691 _walk: function(visitor) {
692 return visitor._visit(this, function() {
693 this.expression.walk(visitor);
694 });
695 },
696 _children_backwards(push) {
697 push(this.expression);
698 },
699});
700
701var AST_Lambda = DEFNODE(
702 "Lambda",
703 "name argnames uses_arguments is_generator async",
704 function AST_Lambda(props) {
705 if (props) {
706 this.name = props.name;
707 this.argnames = props.argnames;
708 this.uses_arguments = props.uses_arguments;
709 this.is_generator = props.is_generator;
710 this.async = props.async;
711 this.variables = props.variables;
712 this.uses_with = props.uses_with;
713 this.uses_eval = props.uses_eval;
714 this.parent_scope = props.parent_scope;
715 this.enclosed = props.enclosed;
716 this.cname = props.cname;
717 this.body = props.body;
718 this.block_scope = props.block_scope;
719 this.start = props.start;
720 this.end = props.end;
721 }
722
723 this.flags = 0;
724 },
725 {
726 $documentation: "Base class for functions",
727 $propdoc: {
728 name: "[AST_SymbolDeclaration?] the name of this function",
729 argnames: "[AST_SymbolFunarg|AST_Destructuring|AST_Expansion|AST_DefaultAssign*] array of function arguments, destructurings, or expanding arguments",
730 uses_arguments: "[boolean/S] tells whether this function accesses the arguments array",
731 is_generator: "[boolean] is this a generator method",
732 async: "[boolean] is this method async",
733 },
734 args_as_names: function () {
735 var out = [];
736 for (var i = 0; i < this.argnames.length; i++) {
737 if (this.argnames[i] instanceof AST_Destructuring) {
738 out.push(...this.argnames[i].all_symbols());
739 } else {
740 out.push(this.argnames[i]);
741 }
742 }
743 return out;
744 },
745 _walk: function(visitor) {
746 return visitor._visit(this, function() {
747 if (this.name) this.name._walk(visitor);
748 var argnames = this.argnames;
749 for (var i = 0, len = argnames.length; i < len; i++) {
750 argnames[i]._walk(visitor);
751 }
752 walk_body(this, visitor);
753 });
754 },
755 _children_backwards(push) {
756 let i = this.body.length;
757 while (i--) push(this.body[i]);
758
759 i = this.argnames.length;
760 while (i--) push(this.argnames[i]);
761
762 if (this.name) push(this.name);
763 },
764 is_braceless() {
765 return this.body[0] instanceof AST_Return && this.body[0].value;
766 },
767 // Default args and expansion don't count, so .argnames.length doesn't cut it
768 length_property() {
769 let length = 0;
770
771 for (const arg of this.argnames) {
772 if (arg instanceof AST_SymbolFunarg || arg instanceof AST_Destructuring) {
773 length++;
774 }
775 }
776
777 return length;
778 }
779 },
780 AST_Scope
781);
782
783var AST_Accessor = DEFNODE("Accessor", null, function AST_Accessor(props) {
784 if (props) {
785 this.name = props.name;
786 this.argnames = props.argnames;
787 this.uses_arguments = props.uses_arguments;
788 this.is_generator = props.is_generator;
789 this.async = props.async;
790 this.variables = props.variables;
791 this.uses_with = props.uses_with;
792 this.uses_eval = props.uses_eval;
793 this.parent_scope = props.parent_scope;
794 this.enclosed = props.enclosed;
795 this.cname = props.cname;
796 this.body = props.body;
797 this.block_scope = props.block_scope;
798 this.start = props.start;
799 this.end = props.end;
800 }
801
802 this.flags = 0;
803}, {
804 $documentation: "A setter/getter function. The `name` property is always null."
805}, AST_Lambda);
806
807var AST_Function = DEFNODE("Function", null, function AST_Function(props) {
808 if (props) {
809 this.name = props.name;
810 this.argnames = props.argnames;
811 this.uses_arguments = props.uses_arguments;
812 this.is_generator = props.is_generator;
813 this.async = props.async;
814 this.variables = props.variables;
815 this.uses_with = props.uses_with;
816 this.uses_eval = props.uses_eval;
817 this.parent_scope = props.parent_scope;
818 this.enclosed = props.enclosed;
819 this.cname = props.cname;
820 this.body = props.body;
821 this.block_scope = props.block_scope;
822 this.start = props.start;
823 this.end = props.end;
824 }
825
826 this.flags = 0;
827}, {
828 $documentation: "A function expression"
829}, AST_Lambda);
830
831var AST_Arrow = DEFNODE("Arrow", null, function AST_Arrow(props) {
832 if (props) {
833 this.name = props.name;
834 this.argnames = props.argnames;
835 this.uses_arguments = props.uses_arguments;
836 this.is_generator = props.is_generator;
837 this.async = props.async;
838 this.variables = props.variables;
839 this.uses_with = props.uses_with;
840 this.uses_eval = props.uses_eval;
841 this.parent_scope = props.parent_scope;
842 this.enclosed = props.enclosed;
843 this.cname = props.cname;
844 this.body = props.body;
845 this.block_scope = props.block_scope;
846 this.start = props.start;
847 this.end = props.end;
848 }
849
850 this.flags = 0;
851}, {
852 $documentation: "An ES6 Arrow function ((a) => b)"
853}, AST_Lambda);
854
855var AST_Defun = DEFNODE("Defun", null, function AST_Defun(props) {
856 if (props) {
857 this.name = props.name;
858 this.argnames = props.argnames;
859 this.uses_arguments = props.uses_arguments;
860 this.is_generator = props.is_generator;
861 this.async = props.async;
862 this.variables = props.variables;
863 this.uses_with = props.uses_with;
864 this.uses_eval = props.uses_eval;
865 this.parent_scope = props.parent_scope;
866 this.enclosed = props.enclosed;
867 this.cname = props.cname;
868 this.body = props.body;
869 this.block_scope = props.block_scope;
870 this.start = props.start;
871 this.end = props.end;
872 }
873
874 this.flags = 0;
875}, {
876 $documentation: "A function definition"
877}, AST_Lambda);
878
879/* -----[ DESTRUCTURING ]----- */
880var AST_Destructuring = DEFNODE("Destructuring", "names is_array", function AST_Destructuring(props) {
881 if (props) {
882 this.names = props.names;
883 this.is_array = props.is_array;
884 this.start = props.start;
885 this.end = props.end;
886 }
887
888 this.flags = 0;
889}, {
890 $documentation: "A destructuring of several names. Used in destructuring assignment and with destructuring function argument names",
891 $propdoc: {
892 "names": "[AST_Node*] Array of properties or elements",
893 "is_array": "[Boolean] Whether the destructuring represents an object or array"
894 },
895 _walk: function(visitor) {
896 return visitor._visit(this, function() {
897 this.names.forEach(function(name) {
898 name._walk(visitor);
899 });
900 });
901 },
902 _children_backwards(push) {
903 let i = this.names.length;
904 while (i--) push(this.names[i]);
905 },
906 all_symbols: function() {
907 var out = [];
908 walk(this, node => {
909 if (node instanceof AST_SymbolDeclaration) {
910 out.push(node);
911 }
912 if (node instanceof AST_Lambda) {
913 return true;
914 }
915 });
916 return out;
917 }
918});
919
920var AST_PrefixedTemplateString = DEFNODE(
921 "PrefixedTemplateString",
922 "template_string prefix",
923 function AST_PrefixedTemplateString(props) {
924 if (props) {
925 this.template_string = props.template_string;
926 this.prefix = props.prefix;
927 this.start = props.start;
928 this.end = props.end;
929 }
930
931 this.flags = 0;
932 },
933 {
934 $documentation: "A templatestring with a prefix, such as String.raw`foobarbaz`",
935 $propdoc: {
936 template_string: "[AST_TemplateString] The template string",
937 prefix: "[AST_Node] The prefix, which will get called."
938 },
939 _walk: function(visitor) {
940 return visitor._visit(this, function () {
941 this.prefix._walk(visitor);
942 this.template_string._walk(visitor);
943 });
944 },
945 _children_backwards(push) {
946 push(this.template_string);
947 push(this.prefix);
948 },
949 }
950);
951
952var AST_TemplateString = DEFNODE("TemplateString", "segments", function AST_TemplateString(props) {
953 if (props) {
954 this.segments = props.segments;
955 this.start = props.start;
956 this.end = props.end;
957 }
958
959 this.flags = 0;
960}, {
961 $documentation: "A template string literal",
962 $propdoc: {
963 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."
964 },
965 _walk: function(visitor) {
966 return visitor._visit(this, function() {
967 this.segments.forEach(function(seg) {
968 seg._walk(visitor);
969 });
970 });
971 },
972 _children_backwards(push) {
973 let i = this.segments.length;
974 while (i--) push(this.segments[i]);
975 }
976});
977
978var AST_TemplateSegment = DEFNODE("TemplateSegment", "value raw", function AST_TemplateSegment(props) {
979 if (props) {
980 this.value = props.value;
981 this.raw = props.raw;
982 this.start = props.start;
983 this.end = props.end;
984 }
985
986 this.flags = 0;
987}, {
988 $documentation: "A segment of a template string literal",
989 $propdoc: {
990 value: "Content of the segment",
991 raw: "Raw source of the segment",
992 }
993});
994
995/* -----[ JUMPS ]----- */
996
997var AST_Jump = DEFNODE("Jump", null, function AST_Jump(props) {
998 if (props) {
999 this.start = props.start;
1000 this.end = props.end;
1001 }
1002
1003 this.flags = 0;
1004}, {
1005 $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)"
1006}, AST_Statement);
1007
1008/** Base class for “exits” (`return` and `throw`) */
1009var AST_Exit = DEFNODE("Exit", "value", function AST_Exit(props) {
1010 if (props) {
1011 this.value = props.value;
1012 this.start = props.start;
1013 this.end = props.end;
1014 }
1015
1016 this.flags = 0;
1017}, {
1018 $documentation: "Base class for “exits” (`return` and `throw`)",
1019 $propdoc: {
1020 value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
1021 },
1022 _walk: function(visitor) {
1023 return visitor._visit(this, this.value && function() {
1024 this.value._walk(visitor);
1025 });
1026 },
1027 _children_backwards(push) {
1028 if (this.value) push(this.value);
1029 },
1030}, AST_Jump);
1031
1032var AST_Return = DEFNODE("Return", null, function AST_Return(props) {
1033 if (props) {
1034 this.value = props.value;
1035 this.start = props.start;
1036 this.end = props.end;
1037 }
1038
1039 this.flags = 0;
1040}, {
1041 $documentation: "A `return` statement"
1042}, AST_Exit);
1043
1044var AST_Throw = DEFNODE("Throw", null, function AST_Throw(props) {
1045 if (props) {
1046 this.value = props.value;
1047 this.start = props.start;
1048 this.end = props.end;
1049 }
1050
1051 this.flags = 0;
1052}, {
1053 $documentation: "A `throw` statement"
1054}, AST_Exit);
1055
1056var AST_LoopControl = DEFNODE("LoopControl", "label", function AST_LoopControl(props) {
1057 if (props) {
1058 this.label = props.label;
1059 this.start = props.start;
1060 this.end = props.end;
1061 }
1062
1063 this.flags = 0;
1064}, {
1065 $documentation: "Base class for loop control statements (`break` and `continue`)",
1066 $propdoc: {
1067 label: "[AST_LabelRef?] the label, or null if none",
1068 },
1069 _walk: function(visitor) {
1070 return visitor._visit(this, this.label && function() {
1071 this.label._walk(visitor);
1072 });
1073 },
1074 _children_backwards(push) {
1075 if (this.label) push(this.label);
1076 },
1077}, AST_Jump);
1078
1079var AST_Break = DEFNODE("Break", null, function AST_Break(props) {
1080 if (props) {
1081 this.label = props.label;
1082 this.start = props.start;
1083 this.end = props.end;
1084 }
1085
1086 this.flags = 0;
1087}, {
1088 $documentation: "A `break` statement"
1089}, AST_LoopControl);
1090
1091var AST_Continue = DEFNODE("Continue", null, function AST_Continue(props) {
1092 if (props) {
1093 this.label = props.label;
1094 this.start = props.start;
1095 this.end = props.end;
1096 }
1097
1098 this.flags = 0;
1099}, {
1100 $documentation: "A `continue` statement"
1101}, AST_LoopControl);
1102
1103var AST_Await = DEFNODE("Await", "expression", function AST_Await(props) {
1104 if (props) {
1105 this.expression = props.expression;
1106 this.start = props.start;
1107 this.end = props.end;
1108 }
1109
1110 this.flags = 0;
1111}, {
1112 $documentation: "An `await` statement",
1113 $propdoc: {
1114 expression: "[AST_Node] the mandatory expression being awaited",
1115 },
1116 _walk: function(visitor) {
1117 return visitor._visit(this, function() {
1118 this.expression._walk(visitor);
1119 });
1120 },
1121 _children_backwards(push) {
1122 push(this.expression);
1123 },
1124});
1125
1126var AST_Yield = DEFNODE("Yield", "expression is_star", function AST_Yield(props) {
1127 if (props) {
1128 this.expression = props.expression;
1129 this.is_star = props.is_star;
1130 this.start = props.start;
1131 this.end = props.end;
1132 }
1133
1134 this.flags = 0;
1135}, {
1136 $documentation: "A `yield` statement",
1137 $propdoc: {
1138 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",
1139 is_star: "[Boolean] Whether this is a yield or yield* statement"
1140 },
1141 _walk: function(visitor) {
1142 return visitor._visit(this, this.expression && function() {
1143 this.expression._walk(visitor);
1144 });
1145 },
1146 _children_backwards(push) {
1147 if (this.expression) push(this.expression);
1148 }
1149});
1150
1151/* -----[ IF ]----- */
1152
1153var AST_If = DEFNODE("If", "condition alternative", function AST_If(props) {
1154 if (props) {
1155 this.condition = props.condition;
1156 this.alternative = props.alternative;
1157 this.body = props.body;
1158 this.start = props.start;
1159 this.end = props.end;
1160 }
1161
1162 this.flags = 0;
1163}, {
1164 $documentation: "A `if` statement",
1165 $propdoc: {
1166 condition: "[AST_Node] the `if` condition",
1167 alternative: "[AST_Statement?] the `else` part, or null if not present"
1168 },
1169 _walk: function(visitor) {
1170 return visitor._visit(this, function() {
1171 this.condition._walk(visitor);
1172 this.body._walk(visitor);
1173 if (this.alternative) this.alternative._walk(visitor);
1174 });
1175 },
1176 _children_backwards(push) {
1177 if (this.alternative) {
1178 push(this.alternative);
1179 }
1180 push(this.body);
1181 push(this.condition);
1182 }
1183}, AST_StatementWithBody);
1184
1185/* -----[ SWITCH ]----- */
1186
1187var AST_Switch = DEFNODE("Switch", "expression", function AST_Switch(props) {
1188 if (props) {
1189 this.expression = props.expression;
1190 this.body = props.body;
1191 this.block_scope = props.block_scope;
1192 this.start = props.start;
1193 this.end = props.end;
1194 }
1195
1196 this.flags = 0;
1197}, {
1198 $documentation: "A `switch` statement",
1199 $propdoc: {
1200 expression: "[AST_Node] the `switch` “discriminant”"
1201 },
1202 _walk: function(visitor) {
1203 return visitor._visit(this, function() {
1204 this.expression._walk(visitor);
1205 walk_body(this, visitor);
1206 });
1207 },
1208 _children_backwards(push) {
1209 let i = this.body.length;
1210 while (i--) push(this.body[i]);
1211 push(this.expression);
1212 }
1213}, AST_Block);
1214
1215var AST_SwitchBranch = DEFNODE("SwitchBranch", null, function AST_SwitchBranch(props) {
1216 if (props) {
1217 this.body = props.body;
1218 this.block_scope = props.block_scope;
1219 this.start = props.start;
1220 this.end = props.end;
1221 }
1222
1223 this.flags = 0;
1224}, {
1225 $documentation: "Base class for `switch` branches",
1226}, AST_Block);
1227
1228var AST_Default = DEFNODE("Default", null, function AST_Default(props) {
1229 if (props) {
1230 this.body = props.body;
1231 this.block_scope = props.block_scope;
1232 this.start = props.start;
1233 this.end = props.end;
1234 }
1235
1236 this.flags = 0;
1237}, {
1238 $documentation: "A `default` switch branch",
1239}, AST_SwitchBranch);
1240
1241var AST_Case = DEFNODE("Case", "expression", function AST_Case(props) {
1242 if (props) {
1243 this.expression = props.expression;
1244 this.body = props.body;
1245 this.block_scope = props.block_scope;
1246 this.start = props.start;
1247 this.end = props.end;
1248 }
1249
1250 this.flags = 0;
1251}, {
1252 $documentation: "A `case` switch branch",
1253 $propdoc: {
1254 expression: "[AST_Node] the `case` expression"
1255 },
1256 _walk: function(visitor) {
1257 return visitor._visit(this, function() {
1258 this.expression._walk(visitor);
1259 walk_body(this, visitor);
1260 });
1261 },
1262 _children_backwards(push) {
1263 let i = this.body.length;
1264 while (i--) push(this.body[i]);
1265 push(this.expression);
1266 },
1267}, AST_SwitchBranch);
1268
1269/* -----[ EXCEPTIONS ]----- */
1270
1271var AST_Try = DEFNODE("Try", "body bcatch bfinally", function AST_Try(props) {
1272 if (props) {
1273 this.body = props.body;
1274 this.bcatch = props.bcatch;
1275 this.bfinally = props.bfinally;
1276 this.start = props.start;
1277 this.end = props.end;
1278 }
1279
1280 this.flags = 0;
1281}, {
1282 $documentation: "A `try` statement",
1283 $propdoc: {
1284 body: "[AST_TryBlock] the try block",
1285 bcatch: "[AST_Catch?] the catch block, or null if not present",
1286 bfinally: "[AST_Finally?] the finally block, or null if not present"
1287 },
1288 _walk: function(visitor) {
1289 return visitor._visit(this, function() {
1290 this.body._walk(visitor);
1291 if (this.bcatch) this.bcatch._walk(visitor);
1292 if (this.bfinally) this.bfinally._walk(visitor);
1293 });
1294 },
1295 _children_backwards(push) {
1296 if (this.bfinally) push(this.bfinally);
1297 if (this.bcatch) push(this.bcatch);
1298 push(this.body);
1299 },
1300}, AST_Statement);
1301
1302var AST_TryBlock = DEFNODE("TryBlock", null, function AST_TryBlock(props) {
1303 if (props) {
1304 this.body = props.body;
1305 this.block_scope = props.block_scope;
1306 this.start = props.start;
1307 this.end = props.end;
1308 }
1309
1310 this.flags = 0;
1311}, {
1312 $documentation: "The `try` block of a try statement"
1313}, AST_Block);
1314
1315var AST_Catch = DEFNODE("Catch", "argname", function AST_Catch(props) {
1316 if (props) {
1317 this.argname = props.argname;
1318 this.body = props.body;
1319 this.block_scope = props.block_scope;
1320 this.start = props.start;
1321 this.end = props.end;
1322 }
1323
1324 this.flags = 0;
1325}, {
1326 $documentation: "A `catch` node; only makes sense as part of a `try` statement",
1327 $propdoc: {
1328 argname: "[AST_SymbolCatch|AST_Destructuring|AST_Expansion|AST_DefaultAssign] symbol for the exception"
1329 },
1330 _walk: function(visitor) {
1331 return visitor._visit(this, function() {
1332 if (this.argname) this.argname._walk(visitor);
1333 walk_body(this, visitor);
1334 });
1335 },
1336 _children_backwards(push) {
1337 let i = this.body.length;
1338 while (i--) push(this.body[i]);
1339 if (this.argname) push(this.argname);
1340 },
1341}, AST_Block);
1342
1343var AST_Finally = DEFNODE("Finally", null, function AST_Finally(props) {
1344 if (props) {
1345 this.body = props.body;
1346 this.block_scope = props.block_scope;
1347 this.start = props.start;
1348 this.end = props.end;
1349 }
1350
1351 this.flags = 0;
1352}, {
1353 $documentation: "A `finally` node; only makes sense as part of a `try` statement"
1354}, AST_Block);
1355
1356/* -----[ VAR/CONST ]----- */
1357
1358var AST_DefinitionsLike = DEFNODE("DefinitionsLike", "definitions", function AST_DefinitionsLike(props) {
1359 if (props) {
1360 this.definitions = props.definitions;
1361 this.start = props.start;
1362 this.end = props.end;
1363 }
1364
1365 this.flags = 0;
1366}, {
1367 $documentation: "Base class for variable definitions and `using`",
1368 $propdoc: {
1369 definitions: "[AST_VarDef*|AST_UsingDef*] array of variable definitions"
1370 },
1371 _walk: function(visitor) {
1372 return visitor._visit(this, function() {
1373 var definitions = this.definitions;
1374 for (var i = 0, len = definitions.length; i < len; i++) {
1375 definitions[i]._walk(visitor);
1376 }
1377 });
1378 },
1379 _children_backwards(push) {
1380 let i = this.definitions.length;
1381 while (i--) push(this.definitions[i]);
1382 },
1383}, AST_Statement);
1384
1385var AST_Definitions = DEFNODE("Definitions", null, function AST_Definitions(props) {
1386 if (props) {
1387 this.definitions = props.definitions;
1388 this.start = props.start;
1389 this.end = props.end;
1390 }
1391
1392 this.flags = 0;
1393}, {
1394 $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)",
1395}, AST_DefinitionsLike);
1396
1397var AST_Var = DEFNODE("Var", null, function AST_Var(props) {
1398 if (props) {
1399 this.definitions = props.definitions;
1400 this.start = props.start;
1401 this.end = props.end;
1402 }
1403
1404 this.flags = 0;
1405}, {
1406 $documentation: "A `var` statement"
1407}, AST_Definitions);
1408
1409var AST_Let = DEFNODE("Let", null, function AST_Let(props) {
1410 if (props) {
1411 this.definitions = props.definitions;
1412 this.start = props.start;
1413 this.end = props.end;
1414 }
1415
1416 this.flags = 0;
1417}, {
1418 $documentation: "A `let` statement"
1419}, AST_Definitions);
1420
1421var AST_Const = DEFNODE("Const", null, function AST_Const(props) {
1422 if (props) {
1423 this.definitions = props.definitions;
1424 this.start = props.start;
1425 this.end = props.end;
1426 }
1427
1428 this.flags = 0;
1429}, {
1430 $documentation: "A `const` statement"
1431}, AST_Definitions);
1432
1433var AST_Using = DEFNODE("Using", "await", function AST_Using(props) {
1434 if (props) {
1435 this.await = props.await;
1436 this.definitions = props.definitions;
1437 this.start = props.start;
1438 this.end = props.end;
1439 }
1440
1441 this.flags = 0;
1442}, {
1443 $documentation: "A `using` statement",
1444 $propdoc: {
1445 await: "[boolean] Whether it's `await using`"
1446 },
1447}, AST_DefinitionsLike);
1448
1449var AST_VarDefLike = DEFNODE("VarDefLike", "name value", function AST_VarDefLike(props) {
1450 if (props) {
1451 this.name = props.name;
1452 this.value = props.value;
1453 this.start = props.start;
1454 this.end = props.end;
1455 }
1456
1457 this.flags = 0;
1458}, {
1459 $documentation: "A name=value pair in a variable definition statement or `using`",
1460 $propdoc: {
1461 name: "[AST_Destructuring|AST_SymbolDeclaration] name of the variable",
1462 value: "[AST_Node?] initializer, or null of there's no initializer"
1463 },
1464 _walk: function(visitor) {
1465 return visitor._visit(this, function() {
1466 this.name._walk(visitor);
1467 if (this.value) this.value._walk(visitor);
1468 });
1469 },
1470 _children_backwards(push) {
1471 if (this.value) push(this.value);
1472 push(this.name);
1473 },
1474 declarations_as_names() {
1475 if (this.name instanceof AST_SymbolDeclaration) {
1476 return [this.name];
1477 } else {
1478 return this.name.all_symbols();
1479 }
1480 }
1481});
1482
1483var AST_VarDef = DEFNODE("VarDef", null, function AST_VarDef(props) {
1484 if (props) {
1485 this.name = props.name;
1486 this.value = props.value;
1487 this.start = props.start;
1488 this.end = props.end;
1489 }
1490
1491 this.flags = 0;
1492}, {
1493 $documentation: "A variable declaration; only appears in a AST_Definitions node",
1494}, AST_VarDefLike);
1495
1496var AST_UsingDef = DEFNODE("UsingDef", null, function AST_UsingDef(props) {
1497 if (props) {
1498 this.name = props.name;
1499 this.value = props.value;
1500 this.start = props.start;
1501 this.end = props.end;
1502 }
1503
1504 this.flags = 0;
1505}, {
1506 $documentation: "Like VarDef but specific to AST_Using",
1507}, AST_VarDefLike);
1508
1509var AST_NameMapping = DEFNODE("NameMapping", "foreign_name name", function AST_NameMapping(props) {
1510 if (props) {
1511 this.foreign_name = props.foreign_name;
1512 this.name = props.name;
1513 this.start = props.start;
1514 this.end = props.end;
1515 }
1516
1517 this.flags = 0;
1518}, {
1519 $documentation: "The part of the export/import statement that declare names from a module.",
1520 $propdoc: {
1521 foreign_name: "[AST_SymbolExportForeign|AST_SymbolImportForeign] The name being exported/imported (as specified in the module)",
1522 name: "[AST_SymbolExport|AST_SymbolImport] The name as it is visible to this module."
1523 },
1524 _walk: function (visitor) {
1525 return visitor._visit(this, function() {
1526 this.foreign_name._walk(visitor);
1527 this.name._walk(visitor);
1528 });
1529 },
1530 _children_backwards(push) {
1531 push(this.name);
1532 push(this.foreign_name);
1533 },
1534});
1535
1536var AST_Import = DEFNODE(
1537 "Import",
1538 "phase imported_name imported_names module_name attributes",
1539 function AST_Import(props) {
1540 if (props) {
1541 this.phase = props.phase;
1542 this.imported_name = props.imported_name;
1543 this.imported_names = props.imported_names;
1544 this.module_name = props.module_name;
1545 this.attributes = props.attributes;
1546 this.start = props.start;
1547 this.end = props.end;
1548 }
1549
1550 this.flags = 0;
1551 },
1552 {
1553 $documentation: "An `import` statement",
1554 $propdoc: {
1555 phase: "[string?] Phase keyword: 'source', 'defer', or null.",
1556 imported_name: "[AST_SymbolImport] The name of the variable holding the module's default export.",
1557 imported_names: "[AST_NameMapping*] The names of non-default imported variables",
1558 module_name: "[AST_String] String literal describing where this module came from",
1559 attributes: "[AST_Object?] The import attributes (with {...})"
1560 },
1561 _walk: function(visitor) {
1562 return visitor._visit(this, function() {
1563 if (this.imported_name) {
1564 this.imported_name._walk(visitor);
1565 }
1566 if (this.imported_names) {
1567 this.imported_names.forEach(function(name_import) {
1568 name_import._walk(visitor);
1569 });
1570 }
1571 this.module_name._walk(visitor);
1572 });
1573 },
1574 _children_backwards(push) {
1575 push(this.module_name);
1576 if (this.imported_names) {
1577 let i = this.imported_names.length;
1578 while (i--) push(this.imported_names[i]);
1579 }
1580 if (this.imported_name) push(this.imported_name);
1581 },
1582 }
1583);
1584
1585var AST_ImportMeta = DEFNODE("ImportMeta", null, function AST_ImportMeta(props) {
1586 if (props) {
1587 this.start = props.start;
1588 this.end = props.end;
1589 }
1590
1591 this.flags = 0;
1592}, {
1593 $documentation: "A reference to import.meta",
1594});
1595
1596var AST_DynamicImport = DEFNODE(
1597 "DynamicImport",
1598 "phase args",
1599 function AST_DynamicImport(props) {
1600 if (props) {
1601 this.phase = props.phase;
1602 this.args = props.args;
1603 this.start = props.start;
1604 this.end = props.end;
1605 }
1606
1607 this.flags = 0;
1608 },
1609 {
1610 $documentation: "A phased dynamic import expression: `import.source(specifier [, options])` or `import.defer(specifier [, options])`. Plain `import(x)` continues to be parsed as an AST_Call with a synthetic `import` SymbolRef callee.",
1611 $propdoc: {
1612 phase: "[string] Phase keyword ('source' or 'defer').",
1613 args: "[AST_Node*] specifier followed by optional options argument"
1614 },
1615 _walk: function(visitor) {
1616 return visitor._visit(this, function() {
1617 var args = this.args;
1618 for (var i = 0, len = args.length; i < len; i++) {
1619 args[i]._walk(visitor);
1620 }
1621 });
1622 },
1623 _children_backwards(push) {
1624 let i = this.args.length;
1625 while (i--) push(this.args[i]);
1626 },
1627 }
1628);
1629
1630var AST_Export = DEFNODE(
1631 "Export",
1632 "exported_definition exported_value is_default exported_names module_name attributes",
1633 function AST_Export(props) {
1634 if (props) {
1635 this.exported_definition = props.exported_definition;
1636 this.exported_value = props.exported_value;
1637 this.is_default = props.is_default;
1638 this.exported_names = props.exported_names;
1639 this.module_name = props.module_name;
1640 this.attributes = props.attributes;
1641 this.start = props.start;
1642 this.end = props.end;
1643 }
1644
1645 this.flags = 0;
1646 },
1647 {
1648 $documentation: "An `export` statement",
1649 $propdoc: {
1650 exported_definition: "[AST_Defun|AST_Definitions|AST_DefClass?] An exported definition",
1651 exported_value: "[AST_Node?] An exported value",
1652 exported_names: "[AST_NameMapping*?] List of exported names",
1653 module_name: "[AST_String?] Name of the file to load exports from",
1654 is_default: "[Boolean] Whether this is the default exported value of this module",
1655 attributes: "[AST_Object?] The import attributes"
1656 },
1657 _walk: function (visitor) {
1658 return visitor._visit(this, function () {
1659 if (this.exported_definition) {
1660 this.exported_definition._walk(visitor);
1661 }
1662 if (this.exported_value) {
1663 this.exported_value._walk(visitor);
1664 }
1665 if (this.exported_names) {
1666 this.exported_names.forEach(function(name_export) {
1667 name_export._walk(visitor);
1668 });
1669 }
1670 if (this.module_name) {
1671 this.module_name._walk(visitor);
1672 }
1673 });
1674 },
1675 _children_backwards(push) {
1676 if (this.module_name) push(this.module_name);
1677 if (this.exported_names) {
1678 let i = this.exported_names.length;
1679 while (i--) push(this.exported_names[i]);
1680 }
1681 if (this.exported_value) push(this.exported_value);
1682 if (this.exported_definition) push(this.exported_definition);
1683 }
1684 },
1685 AST_Statement
1686);
1687
1688/* -----[ OTHER ]----- */
1689
1690var AST_Call = DEFNODE(
1691 "Call",
1692 "expression args optional _annotations",
1693 function AST_Call(props) {
1694 if (props) {
1695 this.expression = props.expression;
1696 this.args = props.args;
1697 this.optional = props.optional;
1698 this._annotations = props._annotations;
1699 this.start = props.start;
1700 this.end = props.end;
1701 this.initialize();
1702 }
1703
1704 this.flags = 0;
1705 },
1706 {
1707 $documentation: "A function call expression",
1708 $propdoc: {
1709 expression: "[AST_Node] expression to invoke as function",
1710 args: "[AST_Node*] array of arguments",
1711 optional: "[boolean] whether this is an optional call (IE ?.() )",
1712 _annotations: "[number] bitfield containing information about the call"
1713 },
1714 initialize() {
1715 if (this._annotations == null) this._annotations = 0;
1716 },
1717 _walk(visitor) {
1718 return visitor._visit(this, function() {
1719 var args = this.args;
1720 for (var i = 0, len = args.length; i < len; i++) {
1721 args[i]._walk(visitor);
1722 }
1723 this.expression._walk(visitor); // TODO why do we need to crawl this last?
1724 });
1725 },
1726 _children_backwards(push) {
1727 let i = this.args.length;
1728 while (i--) push(this.args[i]);
1729 push(this.expression);
1730 },
1731 }
1732);
1733
1734var AST_New = DEFNODE("New", null, function AST_New(props) {
1735 if (props) {
1736 this.expression = props.expression;
1737 this.args = props.args;
1738 this.optional = props.optional;
1739 this._annotations = props._annotations;
1740 this.start = props.start;
1741 this.end = props.end;
1742 this.initialize();
1743 }
1744
1745 this.flags = 0;
1746}, {
1747 $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties"
1748}, AST_Call);
1749
1750var AST_Sequence = DEFNODE("Sequence", "expressions", function AST_Sequence(props) {
1751 if (props) {
1752 this.expressions = props.expressions;
1753 this.start = props.start;
1754 this.end = props.end;
1755 }
1756
1757 this.flags = 0;
1758}, {
1759 $documentation: "A sequence expression (comma-separated expressions)",
1760 $propdoc: {
1761 expressions: "[AST_Node*] array of expressions (at least two)"
1762 },
1763 _walk: function(visitor) {
1764 return visitor._visit(this, function() {
1765 this.expressions.forEach(function(node) {
1766 node._walk(visitor);
1767 });
1768 });
1769 },
1770 _children_backwards(push) {
1771 let i = this.expressions.length;
1772 while (i--) push(this.expressions[i]);
1773 },
1774});
1775
1776var AST_PropAccess = DEFNODE(
1777 "PropAccess",
1778 "expression property optional",
1779 function AST_PropAccess(props) {
1780 if (props) {
1781 this.expression = props.expression;
1782 this.property = props.property;
1783 this.optional = props.optional;
1784 this.start = props.start;
1785 this.end = props.end;
1786 }
1787
1788 this.flags = 0;
1789 },
1790 {
1791 $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`",
1792 $propdoc: {
1793 expression: "[AST_Node] the “container” expression",
1794 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",
1795
1796 optional: "[boolean] whether this is an optional property access (IE ?.)"
1797 }
1798 }
1799);
1800
1801var AST_Dot = DEFNODE("Dot", "quote", function AST_Dot(props) {
1802 if (props) {
1803 this.quote = props.quote;
1804 this.expression = props.expression;
1805 this.property = props.property;
1806 this.optional = props.optional;
1807 this._annotations = props._annotations;
1808 this.start = props.start;
1809 this.end = props.end;
1810 }
1811
1812 this.flags = 0;
1813}, {
1814 $documentation: "A dotted property access expression",
1815 $propdoc: {
1816 quote: "[string] the original quote character when transformed from AST_Sub",
1817 },
1818 _walk: function(visitor) {
1819 return visitor._visit(this, function() {
1820 this.expression._walk(visitor);
1821 });
1822 },
1823 _children_backwards(push) {
1824 push(this.expression);
1825 },
1826}, AST_PropAccess);
1827
1828var AST_DotHash = DEFNODE("DotHash", "", function AST_DotHash(props) {
1829 if (props) {
1830 this.expression = props.expression;
1831 this.property = props.property;
1832 this.optional = props.optional;
1833 this.start = props.start;
1834 this.end = props.end;
1835 }
1836
1837 this.flags = 0;
1838}, {
1839 $documentation: "A dotted property access to a private property",
1840 _walk: function(visitor) {
1841 return visitor._visit(this, function() {
1842 this.expression._walk(visitor);
1843 });
1844 },
1845 _children_backwards(push) {
1846 push(this.expression);
1847 },
1848}, AST_PropAccess);
1849
1850var AST_Sub = DEFNODE("Sub", null, function AST_Sub(props) {
1851 if (props) {
1852 this.expression = props.expression;
1853 this.property = props.property;
1854 this.optional = props.optional;
1855 this._annotations = props._annotations;
1856 this.start = props.start;
1857 this.end = props.end;
1858 }
1859
1860 this.flags = 0;
1861}, {
1862 $documentation: "Index-style property access, i.e. `a[\"foo\"]`",
1863 _walk: function(visitor) {
1864 return visitor._visit(this, function() {
1865 this.expression._walk(visitor);
1866 this.property._walk(visitor);
1867 });
1868 },
1869 _children_backwards(push) {
1870 push(this.property);
1871 push(this.expression);
1872 },
1873}, AST_PropAccess);
1874
1875var AST_Chain = DEFNODE("Chain", "expression", function AST_Chain(props) {
1876 if (props) {
1877 this.expression = props.expression;
1878 this.start = props.start;
1879 this.end = props.end;
1880 }
1881
1882 this.flags = 0;
1883}, {
1884 $documentation: "A chain expression like a?.b?.(c)?.[d]",
1885 $propdoc: {
1886 expression: "[AST_Call|AST_Dot|AST_DotHash|AST_Sub] chain element."
1887 },
1888 _walk: function (visitor) {
1889 return visitor._visit(this, function() {
1890 this.expression._walk(visitor);
1891 });
1892 },
1893 _children_backwards(push) {
1894 push(this.expression);
1895 },
1896});
1897
1898var AST_Unary = DEFNODE("Unary", "operator expression", function AST_Unary(props) {
1899 if (props) {
1900 this.operator = props.operator;
1901 this.expression = props.expression;
1902 this.start = props.start;
1903 this.end = props.end;
1904 }
1905
1906 this.flags = 0;
1907}, {
1908 $documentation: "Base class for unary expressions",
1909 $propdoc: {
1910 operator: "[string] the operator",
1911 expression: "[AST_Node] expression that this unary operator applies to"
1912 },
1913 _walk: function(visitor) {
1914 return visitor._visit(this, function() {
1915 this.expression._walk(visitor);
1916 });
1917 },
1918 _children_backwards(push) {
1919 push(this.expression);
1920 },
1921});
1922
1923var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, function AST_UnaryPrefix(props) {
1924 if (props) {
1925 this.operator = props.operator;
1926 this.expression = props.expression;
1927 this.start = props.start;
1928 this.end = props.end;
1929 }
1930
1931 this.flags = 0;
1932}, {
1933 $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`"
1934}, AST_Unary);
1935
1936var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, function AST_UnaryPostfix(props) {
1937 if (props) {
1938 this.operator = props.operator;
1939 this.expression = props.expression;
1940 this.start = props.start;
1941 this.end = props.end;
1942 }
1943
1944 this.flags = 0;
1945}, {
1946 $documentation: "Unary postfix expression, i.e. `i++`"
1947}, AST_Unary);
1948
1949var AST_Binary = DEFNODE("Binary", "operator left right", function AST_Binary(props) {
1950 if (props) {
1951 this.operator = props.operator;
1952 this.left = props.left;
1953 this.right = props.right;
1954 this.start = props.start;
1955 this.end = props.end;
1956 }
1957
1958 this.flags = 0;
1959}, {
1960 $documentation: "Binary expression, i.e. `a + b`",
1961 $propdoc: {
1962 left: "[AST_Node] left-hand side expression",
1963 operator: "[string] the operator",
1964 right: "[AST_Node] right-hand side expression"
1965 },
1966 _walk: function(visitor) {
1967 return visitor._visit(this, function() {
1968 this.left._walk(visitor);
1969 this.right._walk(visitor);
1970 });
1971 },
1972 _children_backwards(push) {
1973 push(this.right);
1974 push(this.left);
1975 },
1976});
1977
1978var AST_Conditional = DEFNODE(
1979 "Conditional",
1980 "condition consequent alternative",
1981 function AST_Conditional(props) {
1982 if (props) {
1983 this.condition = props.condition;
1984 this.consequent = props.consequent;
1985 this.alternative = props.alternative;
1986 this.start = props.start;
1987 this.end = props.end;
1988 }
1989
1990 this.flags = 0;
1991 },
1992 {
1993 $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`",
1994 $propdoc: {
1995 condition: "[AST_Node]",
1996 consequent: "[AST_Node]",
1997 alternative: "[AST_Node]"
1998 },
1999 _walk: function(visitor) {
2000 return visitor._visit(this, function() {
2001 this.condition._walk(visitor);
2002 this.consequent._walk(visitor);
2003 this.alternative._walk(visitor);
2004 });
2005 },
2006 _children_backwards(push) {
2007 push(this.alternative);
2008 push(this.consequent);
2009 push(this.condition);
2010 },
2011 }
2012);
2013
2014var AST_Assign = DEFNODE("Assign", "logical", function AST_Assign(props) {
2015 if (props) {
2016 this.logical = props.logical;
2017 this.operator = props.operator;
2018 this.left = props.left;
2019 this.right = props.right;
2020 this.start = props.start;
2021 this.end = props.end;
2022 }
2023
2024 this.flags = 0;
2025}, {
2026 $documentation: "An assignment expression — `a = b + 5`",
2027 $propdoc: {
2028 logical: "Whether it's a logical assignment"
2029 }
2030}, AST_Binary);
2031
2032var AST_DefaultAssign = DEFNODE("DefaultAssign", null, function AST_DefaultAssign(props) {
2033 if (props) {
2034 this.operator = props.operator;
2035 this.left = props.left;
2036 this.right = props.right;
2037 this.start = props.start;
2038 this.end = props.end;
2039 }
2040
2041 this.flags = 0;
2042}, {
2043 $documentation: "A default assignment expression like in `(a = 3) => a`"
2044}, AST_Binary);
2045
2046/* -----[ LITERALS ]----- */
2047
2048var AST_Array = DEFNODE("Array", "elements", function AST_Array(props) {
2049 if (props) {
2050 this.elements = props.elements;
2051 this.start = props.start;
2052 this.end = props.end;
2053 }
2054
2055 this.flags = 0;
2056}, {
2057 $documentation: "An array literal",
2058 $propdoc: {
2059 elements: "[AST_Node*] array of elements"
2060 },
2061 _walk: function(visitor) {
2062 return visitor._visit(this, function() {
2063 var elements = this.elements;
2064 for (var i = 0, len = elements.length; i < len; i++) {
2065 elements[i]._walk(visitor);
2066 }
2067 });
2068 },
2069 _children_backwards(push) {
2070 let i = this.elements.length;
2071 while (i--) push(this.elements[i]);
2072 },
2073});
2074
2075var AST_Object = DEFNODE("Object", "properties", function AST_Object(props) {
2076 if (props) {
2077 this.properties = props.properties;
2078 this.start = props.start;
2079 this.end = props.end;
2080 }
2081
2082 this.flags = 0;
2083}, {
2084 $documentation: "An object literal",
2085 $propdoc: {
2086 properties: "[AST_ObjectProperty*] array of properties"
2087 },
2088 _walk: function(visitor) {
2089 return visitor._visit(this, function() {
2090 var properties = this.properties;
2091 for (var i = 0, len = properties.length; i < len; i++) {
2092 properties[i]._walk(visitor);
2093 }
2094 });
2095 },
2096 _children_backwards(push) {
2097 let i = this.properties.length;
2098 while (i--) push(this.properties[i]);
2099 },
2100});
2101
2102/* -----[ OBJECT/CLASS PROPERTIES ]----- */
2103
2104/**
2105 * Everything inside the curly braces of an object/class is a subclass of AST_ObjectProperty, except for AST_ClassStaticBlock.
2106 **/
2107var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", function AST_ObjectProperty(props) {
2108 if (props) {
2109 this.key = props.key;
2110 this.value = props.value;
2111 this.start = props.start;
2112 this.end = props.end;
2113 this._annotations = props._annotations;
2114 }
2115
2116 this.flags = 0;
2117}, {
2118 $documentation: "Base class for literal object properties",
2119 $propdoc: {
2120 key: "[string|AST_Node] property name. For ObjectKeyVal this is a string. For getters, setters and computed property this is an AST_Node.",
2121 value: "[AST_Node] property value. For getters, setters and methods this is an AST_Accessor."
2122 },
2123 _walk: function(visitor) {
2124 return visitor._visit(this, function() {
2125 if (this.key instanceof AST_Node)
2126 this.key._walk(visitor);
2127 this.value._walk(visitor);
2128 });
2129 },
2130 _children_backwards(push) {
2131 push(this.value);
2132 if (this.key instanceof AST_Node) push(this.key);
2133 },
2134});
2135
2136var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", function AST_ObjectKeyVal(props) {
2137 if (props) {
2138 this.quote = props.quote;
2139 this.key = props.key;
2140 this.value = props.value;
2141 this.start = props.start;
2142 this.end = props.end;
2143 this._annotations = props._annotations;
2144 }
2145
2146 this.flags = 0;
2147}, {
2148 $documentation: "A key: value object property",
2149 $propdoc: {
2150 quote: "[string] the original quote character"
2151 },
2152 computed_key() {
2153 return this.key instanceof AST_Node;
2154 }
2155}, AST_ObjectProperty);
2156
2157var AST_PrivateSetter = DEFNODE("PrivateSetter", "static", function AST_PrivateSetter(props) {
2158 if (props) {
2159 this.static = props.static;
2160 this.key = props.key;
2161 this.value = props.value;
2162 this.start = props.start;
2163 this.end = props.end;
2164 }
2165
2166 this.flags = 0;
2167}, {
2168 $propdoc: {
2169 static: "[boolean] whether this is a static private setter"
2170 },
2171 $documentation: "A private setter property",
2172 computed_key() {
2173 return false;
2174 }
2175}, AST_ObjectProperty);
2176
2177var AST_PrivateGetter = DEFNODE("PrivateGetter", "static", function AST_PrivateGetter(props) {
2178 if (props) {
2179 this.static = props.static;
2180 this.key = props.key;
2181 this.value = props.value;
2182 this.start = props.start;
2183 this.end = props.end;
2184 }
2185
2186 this.flags = 0;
2187}, {
2188 $propdoc: {
2189 static: "[boolean] whether this is a static private getter"
2190 },
2191 $documentation: "A private getter property",
2192 computed_key() {
2193 return false;
2194 }
2195}, AST_ObjectProperty);
2196
2197var AST_ObjectSetter = DEFNODE("ObjectSetter", "quote static", function AST_ObjectSetter(props) {
2198 if (props) {
2199 this.quote = props.quote;
2200 this.static = props.static;
2201 this.key = props.key;
2202 this.value = props.value;
2203 this.start = props.start;
2204 this.end = props.end;
2205 this._annotations = props._annotations;
2206 }
2207
2208 this.flags = 0;
2209}, {
2210 $propdoc: {
2211 quote: "[string|undefined] the original quote character, if any",
2212 static: "[boolean] whether this is a static setter (classes only)"
2213 },
2214 $documentation: "An object setter property",
2215 computed_key() {
2216 return !(this.key instanceof AST_SymbolMethod);
2217 }
2218}, AST_ObjectProperty);
2219
2220var AST_ObjectGetter = DEFNODE("ObjectGetter", "quote static", function AST_ObjectGetter(props) {
2221 if (props) {
2222 this.quote = props.quote;
2223 this.static = props.static;
2224 this.key = props.key;
2225 this.value = props.value;
2226 this.start = props.start;
2227 this.end = props.end;
2228 this._annotations = props._annotations;
2229 }
2230
2231 this.flags = 0;
2232}, {
2233 $propdoc: {
2234 quote: "[string|undefined] the original quote character, if any",
2235 static: "[boolean] whether this is a static getter (classes only)"
2236 },
2237 $documentation: "An object getter property",
2238 computed_key() {
2239 return !(this.key instanceof AST_SymbolMethod);
2240 }
2241}, AST_ObjectProperty);
2242
2243var AST_ConciseMethod = DEFNODE("ConciseMethod", "quote static", function AST_ConciseMethod(props) {
2244 if (props) {
2245 this.quote = props.quote;
2246 this.static = props.static;
2247 this.key = props.key;
2248 this.value = props.value;
2249 this.start = props.start;
2250 this.end = props.end;
2251 this._annotations = props._annotations;
2252 }
2253
2254 this.flags = 0;
2255}, {
2256 $propdoc: {
2257 quote: "[string|undefined] the original quote character, if any",
2258 static: "[boolean] is this method static (classes only)",
2259 },
2260 $documentation: "An ES6 concise method inside an object or class",
2261 computed_key() {
2262 return !(this.key instanceof AST_SymbolMethod);
2263 }
2264}, AST_ObjectProperty);
2265
2266var AST_PrivateMethod = DEFNODE("PrivateMethod", "static", function AST_PrivateMethod(props) {
2267 if (props) {
2268 this.static = props.static;
2269 this.key = props.key;
2270 this.value = props.value;
2271 this.start = props.start;
2272 this.end = props.end;
2273 }
2274
2275 this.flags = 0;
2276}, {
2277 $documentation: "A private class method inside a class",
2278 $propdoc: {
2279 static: "[boolean] is this a static private method",
2280 },
2281 computed_key() {
2282 return false;
2283 },
2284}, AST_ObjectProperty);
2285
2286var AST_Class = DEFNODE("Class", "name extends properties", function AST_Class(props) {
2287 if (props) {
2288 this.name = props.name;
2289 this.extends = props.extends;
2290 this.properties = props.properties;
2291 this.variables = props.variables;
2292 this.uses_with = props.uses_with;
2293 this.uses_eval = props.uses_eval;
2294 this.parent_scope = props.parent_scope;
2295 this.enclosed = props.enclosed;
2296 this.cname = props.cname;
2297 this.body = props.body;
2298 this.block_scope = props.block_scope;
2299 this.start = props.start;
2300 this.end = props.end;
2301 }
2302
2303 this.flags = 0;
2304}, {
2305 $propdoc: {
2306 name: "[AST_SymbolClass|AST_SymbolDefClass?] optional class name.",
2307 extends: "[AST_Node]? optional parent class",
2308 properties: "[AST_ObjectProperty|AST_ClassStaticBlock]* array of properties or static blocks"
2309 },
2310 $documentation: "An ES6 class",
2311 _walk: function(visitor) {
2312 return visitor._visit(this, function() {
2313 if (this.name) {
2314 this.name._walk(visitor);
2315 }
2316 if (this.extends) {
2317 this.extends._walk(visitor);
2318 }
2319 this.properties.forEach((prop) => prop._walk(visitor));
2320 });
2321 },
2322 _children_backwards(push) {
2323 let i = this.properties.length;
2324 while (i--) push(this.properties[i]);
2325 if (this.extends) push(this.extends);
2326 if (this.name) push(this.name);
2327 },
2328 /** go through the bits that are executed instantly, not when the class is `new`'d. Doesn't walk the name. */
2329 visit_nondeferred_class_parts(visitor) {
2330 if (this.extends) {
2331 this.extends._walk(visitor);
2332 }
2333 this.properties.forEach((prop) => {
2334 if (prop instanceof AST_ClassStaticBlock) {
2335 prop._walk(visitor);
2336 return;
2337 }
2338 if (prop.computed_key()) {
2339 visitor.push(prop);
2340 prop.key._walk(visitor);
2341 visitor.pop();
2342 }
2343 if (
2344 prop instanceof AST_ClassPrivateProperty && prop.static && prop.value
2345 || prop instanceof AST_ClassProperty && prop.static && prop.value
2346 ) {
2347 visitor.push(prop);
2348 prop.value._walk(visitor);
2349 visitor.pop();
2350 }
2351 });
2352 },
2353 /** go through the bits that are executed later, when the class is `new`'d or a static method is called */
2354 visit_deferred_class_parts(visitor) {
2355 this.properties.forEach((prop) => {
2356 if (
2357 prop instanceof AST_ConciseMethod
2358 || prop instanceof AST_PrivateMethod
2359 ) {
2360 prop.walk(visitor);
2361 } else if (
2362 prop instanceof AST_ClassProperty && !prop.static && prop.value
2363 || prop instanceof AST_ClassPrivateProperty && !prop.static && prop.value
2364 ) {
2365 visitor.push(prop);
2366 prop.value._walk(visitor);
2367 visitor.pop();
2368 }
2369 });
2370 },
2371 is_self_referential: function() {
2372 const this_id = this.name && this.name.definition().id;
2373 let found = false;
2374 let class_this = true;
2375 this.visit_nondeferred_class_parts(new TreeWalker((node, descend) => {
2376 if (found) return true;
2377 if (node instanceof AST_This) return (found = class_this);
2378 if (node instanceof AST_SymbolRef) return (found = node.definition().id === this_id);
2379 if (node instanceof AST_Lambda && !(node instanceof AST_Arrow)) {
2380 const class_this_save = class_this;
2381 class_this = false;
2382 descend();
2383 class_this = class_this_save;
2384 return true;
2385 }
2386 }));
2387 return found;
2388 },
2389}, AST_Scope /* TODO a class might have a scope but it's not a scope */);
2390
2391var AST_ClassProperty = DEFNODE("ClassProperty", "static quote", function AST_ClassProperty(props) {
2392 if (props) {
2393 this.static = props.static;
2394 this.quote = props.quote;
2395 this.key = props.key;
2396 this.value = props.value;
2397 this.start = props.start;
2398 this.end = props.end;
2399 this._annotations = props._annotations;
2400 }
2401
2402 this.flags = 0;
2403}, {
2404 $documentation: "A class property",
2405 $propdoc: {
2406 static: "[boolean] whether this is a static key",
2407 quote: "[string] which quote is being used"
2408 },
2409 _walk: function(visitor) {
2410 return visitor._visit(this, function() {
2411 if (this.key instanceof AST_Node)
2412 this.key._walk(visitor);
2413 if (this.value instanceof AST_Node)
2414 this.value._walk(visitor);
2415 });
2416 },
2417 _children_backwards(push) {
2418 if (this.value instanceof AST_Node) push(this.value);
2419 if (this.key instanceof AST_Node) push(this.key);
2420 },
2421 computed_key() {
2422 return !(this.key instanceof AST_SymbolClassProperty);
2423 }
2424}, AST_ObjectProperty);
2425
2426var AST_ClassPrivateProperty = DEFNODE("ClassPrivateProperty", "", function AST_ClassPrivateProperty(props) {
2427 if (props) {
2428 this.static = props.static;
2429 this.key = props.key;
2430 this.value = props.value;
2431 this.start = props.start;
2432 this.end = props.end;
2433 }
2434
2435 this.flags = 0;
2436}, {
2437 $documentation: "A class property for a private property",
2438 _walk: function(visitor) {
2439 return visitor._visit(this, function() {
2440 if (this.value instanceof AST_Node)
2441 this.value._walk(visitor);
2442 });
2443 },
2444 _children_backwards(push) {
2445 if (this.value instanceof AST_Node) push(this.value);
2446 },
2447 computed_key() {
2448 return false;
2449 },
2450}, AST_ObjectProperty);
2451
2452var AST_PrivateIn = DEFNODE("PrivateIn", "key value", function AST_PrivateIn(props) {
2453 if (props) {
2454 this.key = props.key;
2455 this.value = props.value;
2456 this.start = props.start;
2457 this.end = props.end;
2458 }
2459
2460 this.flags = 0;
2461}, {
2462 $documentation: "An `in` binop when the key is private, eg #x in this",
2463 _walk: function(visitor) {
2464 return visitor._visit(this, function() {
2465 this.key._walk(visitor);
2466 this.value._walk(visitor);
2467 });
2468 },
2469 _children_backwards(push) {
2470 push(this.value);
2471 push(this.key);
2472 },
2473});
2474
2475var AST_DefClass = DEFNODE("DefClass", null, function AST_DefClass(props) {
2476 if (props) {
2477 this.name = props.name;
2478 this.extends = props.extends;
2479 this.properties = props.properties;
2480 this.variables = props.variables;
2481 this.uses_with = props.uses_with;
2482 this.uses_eval = props.uses_eval;
2483 this.parent_scope = props.parent_scope;
2484 this.enclosed = props.enclosed;
2485 this.cname = props.cname;
2486 this.body = props.body;
2487 this.block_scope = props.block_scope;
2488 this.start = props.start;
2489 this.end = props.end;
2490 }
2491
2492 this.flags = 0;
2493}, {
2494 $documentation: "A class definition",
2495}, AST_Class);
2496
2497var AST_ClassStaticBlock = DEFNODE("ClassStaticBlock", "body block_scope", function AST_ClassStaticBlock (props) {
2498 this.body = props.body;
2499 this.block_scope = props.block_scope;
2500 this.start = props.start;
2501 this.end = props.end;
2502}, {
2503 $documentation: "A block containing statements to be executed in the context of the class",
2504 $propdoc: {
2505 body: "[AST_Statement*] an array of statements",
2506 },
2507 _walk: function(visitor) {
2508 return visitor._visit(this, function() {
2509 walk_body(this, visitor);
2510 });
2511 },
2512 _children_backwards(push) {
2513 let i = this.body.length;
2514 while (i--) push(this.body[i]);
2515 },
2516 clone: clone_block_scope,
2517 computed_key() {
2518 return false;
2519 },
2520}, AST_Scope);
2521
2522var AST_ClassExpression = DEFNODE("ClassExpression", null, function AST_ClassExpression(props) {
2523 if (props) {
2524 this.name = props.name;
2525 this.extends = props.extends;
2526 this.properties = props.properties;
2527 this.variables = props.variables;
2528 this.uses_with = props.uses_with;
2529 this.uses_eval = props.uses_eval;
2530 this.parent_scope = props.parent_scope;
2531 this.enclosed = props.enclosed;
2532 this.cname = props.cname;
2533 this.body = props.body;
2534 this.block_scope = props.block_scope;
2535 this.start = props.start;
2536 this.end = props.end;
2537 }
2538
2539 this.flags = 0;
2540}, {
2541 $documentation: "A class expression."
2542}, AST_Class);
2543
2544var AST_Symbol = DEFNODE("Symbol", "scope name thedef", function AST_Symbol(props) {
2545 if (props) {
2546 this.scope = props.scope;
2547 this.name = props.name;
2548 this.thedef = props.thedef;
2549 this.start = props.start;
2550 this.end = props.end;
2551 }
2552
2553 this.flags = 0;
2554}, {
2555 $propdoc: {
2556 name: "[string] name of this symbol",
2557 scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
2558 thedef: "[SymbolDef/S] the definition of this symbol"
2559 },
2560 $documentation: "Base class for all symbols"
2561});
2562
2563var AST_NewTarget = DEFNODE("NewTarget", null, function AST_NewTarget(props) {
2564 if (props) {
2565 this.start = props.start;
2566 this.end = props.end;
2567 }
2568
2569 this.flags = 0;
2570}, {
2571 $documentation: "A reference to new.target"
2572});
2573
2574var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", function AST_SymbolDeclaration(props) {
2575 if (props) {
2576 this.init = props.init;
2577 this.scope = props.scope;
2578 this.name = props.name;
2579 this.thedef = props.thedef;
2580 this.start = props.start;
2581 this.end = props.end;
2582 }
2583
2584 this.flags = 0;
2585}, {
2586 $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
2587}, AST_Symbol);
2588
2589var AST_SymbolVar = DEFNODE("SymbolVar", null, function AST_SymbolVar(props) {
2590 if (props) {
2591 this.init = props.init;
2592 this.scope = props.scope;
2593 this.name = props.name;
2594 this.thedef = props.thedef;
2595 this.start = props.start;
2596 this.end = props.end;
2597 }
2598
2599 this.flags = 0;
2600}, {
2601 $documentation: "Symbol defining a variable",
2602}, AST_SymbolDeclaration);
2603
2604var AST_SymbolBlockDeclaration = DEFNODE(
2605 "SymbolBlockDeclaration",
2606 null,
2607 function AST_SymbolBlockDeclaration(props) {
2608 if (props) {
2609 this.init = props.init;
2610 this.scope = props.scope;
2611 this.name = props.name;
2612 this.thedef = props.thedef;
2613 this.start = props.start;
2614 this.end = props.end;
2615 }
2616
2617 this.flags = 0;
2618 },
2619 {
2620 $documentation: "Base class for block-scoped declaration symbols"
2621 },
2622 AST_SymbolDeclaration
2623);
2624
2625var AST_SymbolConst = DEFNODE("SymbolConst", null, function AST_SymbolConst(props) {
2626 if (props) {
2627 this.init = props.init;
2628 this.scope = props.scope;
2629 this.name = props.name;
2630 this.thedef = props.thedef;
2631 this.start = props.start;
2632 this.end = props.end;
2633 }
2634
2635 this.flags = 0;
2636}, {
2637 $documentation: "A constant declaration"
2638}, AST_SymbolBlockDeclaration);
2639
2640var AST_SymbolUsing = DEFNODE("SymbolUsing", null, function AST_SymbolUsing(props) {
2641 if (props) {
2642 this.init = props.init;
2643 this.scope = props.scope;
2644 this.name = props.name;
2645 this.thedef = props.thedef;
2646 this.start = props.start;
2647 this.end = props.end;
2648 }
2649
2650 this.flags = 0;
2651}, {
2652 $documentation: "A `using` declaration"
2653}, AST_SymbolBlockDeclaration);
2654
2655var AST_SymbolLet = DEFNODE("SymbolLet", null, function AST_SymbolLet(props) {
2656 if (props) {
2657 this.init = props.init;
2658 this.scope = props.scope;
2659 this.name = props.name;
2660 this.thedef = props.thedef;
2661 this.start = props.start;
2662 this.end = props.end;
2663 }
2664
2665 this.flags = 0;
2666}, {
2667 $documentation: "A block-scoped `let` declaration"
2668}, AST_SymbolBlockDeclaration);
2669
2670var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, function AST_SymbolFunarg(props) {
2671 if (props) {
2672 this.init = props.init;
2673 this.scope = props.scope;
2674 this.name = props.name;
2675 this.thedef = props.thedef;
2676 this.start = props.start;
2677 this.end = props.end;
2678 }
2679
2680 this.flags = 0;
2681}, {
2682 $documentation: "Symbol naming a function argument",
2683}, AST_SymbolVar);
2684
2685var AST_SymbolDefun = DEFNODE("SymbolDefun", null, function AST_SymbolDefun(props) {
2686 if (props) {
2687 this.init = props.init;
2688 this.scope = props.scope;
2689 this.name = props.name;
2690 this.thedef = props.thedef;
2691 this.start = props.start;
2692 this.end = props.end;
2693 }
2694
2695 this.flags = 0;
2696}, {
2697 $documentation: "Symbol defining a function",
2698}, AST_SymbolDeclaration);
2699
2700var AST_SymbolMethod = DEFNODE("SymbolMethod", null, function AST_SymbolMethod(props) {
2701 if (props) {
2702 this.scope = props.scope;
2703 this.name = props.name;
2704 this.thedef = props.thedef;
2705 this.start = props.start;
2706 this.end = props.end;
2707 }
2708
2709 this.flags = 0;
2710}, {
2711 $documentation: "Symbol in an object defining a method",
2712}, AST_Symbol);
2713
2714var AST_SymbolClassProperty = DEFNODE("SymbolClassProperty", null, function AST_SymbolClassProperty(props) {
2715 if (props) {
2716 this.scope = props.scope;
2717 this.name = props.name;
2718 this.thedef = props.thedef;
2719 this.start = props.start;
2720 this.end = props.end;
2721 }
2722
2723 this.flags = 0;
2724}, {
2725 $documentation: "Symbol for a class property",
2726}, AST_Symbol);
2727
2728var AST_SymbolLambda = DEFNODE("SymbolLambda", null, function AST_SymbolLambda(props) {
2729 if (props) {
2730 this.init = props.init;
2731 this.scope = props.scope;
2732 this.name = props.name;
2733 this.thedef = props.thedef;
2734 this.start = props.start;
2735 this.end = props.end;
2736 }
2737
2738 this.flags = 0;
2739}, {
2740 $documentation: "Symbol naming a function expression",
2741}, AST_SymbolDeclaration);
2742
2743var AST_SymbolDefClass = DEFNODE("SymbolDefClass", null, function AST_SymbolDefClass(props) {
2744 if (props) {
2745 this.init = props.init;
2746 this.scope = props.scope;
2747 this.name = props.name;
2748 this.thedef = props.thedef;
2749 this.start = props.start;
2750 this.end = props.end;
2751 }
2752
2753 this.flags = 0;
2754}, {
2755 $documentation: "Symbol naming a class's name in a class declaration. Lexically scoped to its containing scope, and accessible within the class."
2756}, AST_SymbolBlockDeclaration);
2757
2758var AST_SymbolClass = DEFNODE("SymbolClass", null, function AST_SymbolClass(props) {
2759 if (props) {
2760 this.init = props.init;
2761 this.scope = props.scope;
2762 this.name = props.name;
2763 this.thedef = props.thedef;
2764 this.start = props.start;
2765 this.end = props.end;
2766 }
2767
2768 this.flags = 0;
2769}, {
2770 $documentation: "Symbol naming a class's name. Lexically scoped to the class."
2771}, AST_SymbolDeclaration);
2772
2773var AST_SymbolCatch = DEFNODE("SymbolCatch", null, function AST_SymbolCatch(props) {
2774 if (props) {
2775 this.init = props.init;
2776 this.scope = props.scope;
2777 this.name = props.name;
2778 this.thedef = props.thedef;
2779 this.start = props.start;
2780 this.end = props.end;
2781 }
2782
2783 this.flags = 0;
2784}, {
2785 $documentation: "Symbol naming the exception in catch",
2786}, AST_SymbolBlockDeclaration);
2787
2788var AST_SymbolImport = DEFNODE("SymbolImport", null, function AST_SymbolImport(props) {
2789 if (props) {
2790 this.init = props.init;
2791 this.scope = props.scope;
2792 this.name = props.name;
2793 this.thedef = props.thedef;
2794 this.start = props.start;
2795 this.end = props.end;
2796 }
2797
2798 this.flags = 0;
2799}, {
2800 $documentation: "Symbol referring to an imported name",
2801}, AST_SymbolBlockDeclaration);
2802
2803var AST_SymbolImportForeign = DEFNODE("SymbolImportForeign", "quote", function AST_SymbolImportForeign(props) {
2804 if (props) {
2805 this.quote = props.quote;
2806 this.scope = props.scope;
2807 this.name = props.name;
2808 this.thedef = props.thedef;
2809 this.start = props.start;
2810 this.end = props.end;
2811 }
2812
2813 this.flags = 0;
2814}, {
2815 $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",
2816}, AST_Symbol);
2817
2818var AST_Label = DEFNODE("Label", "references", function AST_Label(props) {
2819 if (props) {
2820 this.references = props.references;
2821 this.scope = props.scope;
2822 this.name = props.name;
2823 this.thedef = props.thedef;
2824 this.start = props.start;
2825 this.end = props.end;
2826 this.initialize();
2827 }
2828
2829 this.flags = 0;
2830}, {
2831 $documentation: "Symbol naming a label (declaration)",
2832 $propdoc: {
2833 references: "[AST_LoopControl*] a list of nodes referring to this label"
2834 },
2835 initialize: function() {
2836 this.references = [];
2837 this.thedef = this;
2838 }
2839}, AST_Symbol);
2840
2841var AST_SymbolRef = DEFNODE("SymbolRef", null, function AST_SymbolRef(props) {
2842 if (props) {
2843 this.scope = props.scope;
2844 this.name = props.name;
2845 this.thedef = props.thedef;
2846 this.start = props.start;
2847 this.end = props.end;
2848 }
2849
2850 this.flags = 0;
2851}, {
2852 $documentation: "Reference to some symbol (not definition/declaration)",
2853}, AST_Symbol);
2854
2855var AST_SymbolExport = DEFNODE("SymbolExport", "quote", function AST_SymbolExport(props) {
2856 if (props) {
2857 this.quote = props.quote;
2858 this.scope = props.scope;
2859 this.name = props.name;
2860 this.thedef = props.thedef;
2861 this.start = props.start;
2862 this.end = props.end;
2863 }
2864
2865 this.flags = 0;
2866}, {
2867 $documentation: "Symbol referring to a name to export",
2868}, AST_SymbolRef);
2869
2870var AST_SymbolExportForeign = DEFNODE("SymbolExportForeign", "quote", function AST_SymbolExportForeign(props) {
2871 if (props) {
2872 this.quote = props.quote;
2873 this.scope = props.scope;
2874 this.name = props.name;
2875 this.thedef = props.thedef;
2876 this.start = props.start;
2877 this.end = props.end;
2878 }
2879
2880 this.flags = 0;
2881}, {
2882 $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",
2883}, AST_Symbol);
2884
2885var AST_LabelRef = DEFNODE("LabelRef", null, function AST_LabelRef(props) {
2886 if (props) {
2887 this.scope = props.scope;
2888 this.name = props.name;
2889 this.thedef = props.thedef;
2890 this.start = props.start;
2891 this.end = props.end;
2892 }
2893
2894 this.flags = 0;
2895}, {
2896 $documentation: "Reference to a label symbol",
2897}, AST_Symbol);
2898
2899var AST_SymbolPrivateProperty = DEFNODE("SymbolPrivateProperty", null, function AST_SymbolPrivateProperty(props) {
2900 if (props) {
2901 this.scope = props.scope;
2902 this.name = props.name;
2903 this.thedef = props.thedef;
2904 this.start = props.start;
2905 this.end = props.end;
2906 }
2907
2908 this.flags = 0;
2909}, {
2910 $documentation: "A symbol that refers to a private property",
2911}, AST_Symbol);
2912
2913var AST_This = DEFNODE("This", null, function AST_This(props) {
2914 if (props) {
2915 this.scope = props.scope;
2916 this.name = props.name;
2917 this.thedef = props.thedef;
2918 this.start = props.start;
2919 this.end = props.end;
2920 }
2921
2922 this.flags = 0;
2923}, {
2924 $documentation: "The `this` symbol",
2925}, AST_Symbol);
2926
2927var AST_Super = DEFNODE("Super", null, function AST_Super(props) {
2928 if (props) {
2929 this.scope = props.scope;
2930 this.name = props.name;
2931 this.thedef = props.thedef;
2932 this.start = props.start;
2933 this.end = props.end;
2934 }
2935
2936 this.flags = 0;
2937}, {
2938 $documentation: "The `super` symbol",
2939}, AST_This);
2940
2941var AST_Constant = DEFNODE("Constant", null, function AST_Constant(props) {
2942 if (props) {
2943 this.start = props.start;
2944 this.end = props.end;
2945 }
2946
2947 this.flags = 0;
2948}, {
2949 $documentation: "Base class for all constants",
2950 getValue: function() {
2951 return this.value;
2952 }
2953});
2954
2955var AST_String = DEFNODE("String", "value quote", function AST_String(props) {
2956 if (props) {
2957 this.value = props.value;
2958 this.quote = props.quote;
2959 this.start = props.start;
2960 this.end = props.end;
2961 this._annotations = props._annotations;
2962 }
2963
2964 this.flags = 0;
2965}, {
2966 $documentation: "A string literal",
2967 $propdoc: {
2968 value: "[string] the contents of this string",
2969 quote: "[string] the original quote character"
2970 }
2971}, AST_Constant);
2972
2973var AST_Number = DEFNODE("Number", "value raw", function AST_Number(props) {
2974 if (props) {
2975 this.value = props.value;
2976 this.raw = props.raw;
2977 this.start = props.start;
2978 this.end = props.end;
2979 }
2980
2981 this.flags = 0;
2982}, {
2983 $documentation: "A number literal",
2984 $propdoc: {
2985 value: "[number] the numeric value",
2986 raw: "[string] numeric value as string"
2987 }
2988}, AST_Constant);
2989
2990var AST_BigInt = DEFNODE("BigInt", "value raw", function AST_BigInt(props) {
2991 if (props) {
2992 this.value = props.value;
2993 this.raw = props.raw;
2994 this.start = props.start;
2995 this.end = props.end;
2996 }
2997
2998 this.flags = 0;
2999}, {
3000 $documentation: "A big int literal",
3001 $propdoc: {
3002 value: "[string] big int value, represented as a string",
3003 raw: "[string] the original format preserved"
3004 }
3005}, AST_Constant);
3006
3007var AST_RegExp = DEFNODE("RegExp", "value", function AST_RegExp(props) {
3008 if (props) {
3009 this.value = props.value;
3010 this.start = props.start;
3011 this.end = props.end;
3012 }
3013
3014 this.flags = 0;
3015}, {
3016 $documentation: "A regexp literal",
3017 $propdoc: {
3018 value: "[RegExp] the actual regexp",
3019 }
3020}, AST_Constant);
3021
3022var AST_Atom = DEFNODE("Atom", null, function AST_Atom(props) {
3023 if (props) {
3024 this.start = props.start;
3025 this.end = props.end;
3026 }
3027
3028 this.flags = 0;
3029}, {
3030 $documentation: "Base class for atoms",
3031}, AST_Constant);
3032
3033var AST_Null = DEFNODE("Null", null, function AST_Null(props) {
3034 if (props) {
3035 this.start = props.start;
3036 this.end = props.end;
3037 }
3038
3039 this.flags = 0;
3040}, {
3041 $documentation: "The `null` atom",
3042 value: null
3043}, AST_Atom);
3044
3045var AST_NaN = DEFNODE("NaN", null, function AST_NaN(props) {
3046 if (props) {
3047 this.start = props.start;
3048 this.end = props.end;
3049 }
3050
3051 this.flags = 0;
3052}, {
3053 $documentation: "The impossible value",
3054 value: 0/0
3055}, AST_Atom);
3056
3057var AST_Undefined = DEFNODE("Undefined", null, function AST_Undefined(props) {
3058 if (props) {
3059 this.start = props.start;
3060 this.end = props.end;
3061 }
3062
3063 this.flags = 0;
3064}, {
3065 $documentation: "The `undefined` value",
3066 value: (function() {}())
3067}, AST_Atom);
3068
3069var AST_Hole = DEFNODE("Hole", null, function AST_Hole(props) {
3070 if (props) {
3071 this.start = props.start;
3072 this.end = props.end;
3073 }
3074
3075 this.flags = 0;
3076}, {
3077 $documentation: "A hole in an array",
3078 value: (function() {}())
3079}, AST_Atom);
3080
3081var AST_Infinity = DEFNODE("Infinity", null, function AST_Infinity(props) {
3082 if (props) {
3083 this.start = props.start;
3084 this.end = props.end;
3085 }
3086
3087 this.flags = 0;
3088}, {
3089 $documentation: "The `Infinity` value",
3090 value: 1/0
3091}, AST_Atom);
3092
3093var AST_Boolean = DEFNODE("Boolean", null, function AST_Boolean(props) {
3094 if (props) {
3095 this.start = props.start;
3096 this.end = props.end;
3097 }
3098
3099 this.flags = 0;
3100}, {
3101 $documentation: "Base class for booleans",
3102}, AST_Atom);
3103
3104var AST_False = DEFNODE("False", null, function AST_False(props) {
3105 if (props) {
3106 this.start = props.start;
3107 this.end = props.end;
3108 }
3109
3110 this.flags = 0;
3111}, {
3112 $documentation: "The `false` atom",
3113 value: false
3114}, AST_Boolean);
3115
3116var AST_True = DEFNODE("True", null, function AST_True(props) {
3117 if (props) {
3118 this.start = props.start;
3119 this.end = props.end;
3120 }
3121
3122 this.flags = 0;
3123}, {
3124 $documentation: "The `true` atom",
3125 value: true
3126}, AST_Boolean);
3127
3128/* -----[ Walk function ]---- */
3129
3130/**
3131 * Walk nodes in depth-first search fashion.
3132 * Callback can return `walk_abort` symbol to stop iteration.
3133 * It can also return `true` to stop iteration just for child nodes.
3134 * Iteration can be stopped and continued by passing the `to_visit` argument,
3135 * which is given to the callback in the second argument.
3136 **/
3137function walk(node, cb, to_visit = [node]) {
3138 const push = to_visit.push.bind(to_visit);
3139 while (to_visit.length) {
3140 const node = to_visit.pop();
3141 const ret = cb(node, to_visit);
3142
3143 if (ret) {
3144 if (ret === walk_abort) return true;
3145 continue;
3146 }
3147
3148 node._children_backwards(push);
3149 }
3150 return false;
3151}
3152
3153/**
3154 * Walks an AST node and its children.
3155 *
3156 * {cb} can return `walk_abort` to interrupt the walk.
3157 *
3158 * @param node
3159 * @param cb {(node, info: { parent: (nth) => any }) => (boolean | undefined)}
3160 *
3161 * @returns {boolean} whether the walk was aborted
3162 *
3163 * @example
3164 * const found_some_cond = walk_parent(my_ast_node, (node, { parent }) => {
3165 * if (some_cond(node, parent())) return walk_abort
3166 * });
3167 */
3168function walk_parent(node, cb, initial_stack) {
3169 const to_visit = [node];
3170 const push = to_visit.push.bind(to_visit);
3171 const stack = initial_stack ? initial_stack.slice() : [];
3172 const parent_pop_indices = [];
3173
3174 let current;
3175
3176 const info = {
3177 parent: (n = 0) => {
3178 if (n === -1) {
3179 return current;
3180 }
3181
3182 // [ p1 p0 ] [ 1 0 ]
3183 if (initial_stack && n >= stack.length) {
3184 n -= stack.length;
3185 return initial_stack[
3186 initial_stack.length - (n + 1)
3187 ];
3188 }
3189
3190 return stack[stack.length - (1 + n)];
3191 },
3192 };
3193
3194 while (to_visit.length) {
3195 current = to_visit.pop();
3196
3197 while (
3198 parent_pop_indices.length &&
3199 to_visit.length == parent_pop_indices[parent_pop_indices.length - 1]
3200 ) {
3201 stack.pop();
3202 parent_pop_indices.pop();
3203 }
3204
3205 const ret = cb(current, info);
3206
3207 if (ret) {
3208 if (ret === walk_abort) return true;
3209 continue;
3210 }
3211
3212 const visit_length = to_visit.length;
3213
3214 current._children_backwards(push);
3215
3216 // Push only if we're going to traverse the children
3217 if (to_visit.length > visit_length) {
3218 stack.push(current);
3219 parent_pop_indices.push(visit_length - 1);
3220 }
3221 }
3222
3223 return false;
3224}
3225
3226const walk_abort = Symbol("abort walk");
3227
3228/* -----[ TreeWalker ]----- */
3229
3230class TreeWalker {
3231 constructor(callback) {
3232 this.visit = callback;
3233 this.stack = [];
3234 this.directives = Object.create(null);
3235 }
3236
3237 _visit(node, descend) {
3238 this.push(node);
3239 var ret = this.visit(node, descend ? function() {
3240 descend.call(node);
3241 } : noop);
3242 if (!ret && descend) {
3243 descend.call(node);
3244 }
3245 this.pop();
3246 return ret;
3247 }
3248
3249 parent(n) {
3250 return this.stack[this.stack.length - 2 - (n || 0)];
3251 }
3252
3253 push(node) {
3254 if (node instanceof AST_Lambda) {
3255 this.directives = Object.create(this.directives);
3256 } else if (node instanceof AST_Directive && !this.directives[node.value]) {
3257 this.directives[node.value] = node;
3258 } else if (node instanceof AST_Class) {
3259 this.directives = Object.create(this.directives);
3260 if (!this.directives["use strict"]) {
3261 this.directives["use strict"] = node;
3262 }
3263 }
3264 this.stack.push(node);
3265 }
3266
3267 pop() {
3268 var node = this.stack.pop();
3269 if (node instanceof AST_Lambda || node instanceof AST_Class) {
3270 this.directives = Object.getPrototypeOf(this.directives);
3271 }
3272 }
3273
3274 self() {
3275 return this.stack[this.stack.length - 1];
3276 }
3277
3278 find_parent(type) {
3279 var stack = this.stack;
3280 for (var i = stack.length; --i >= 0;) {
3281 var x = stack[i];
3282 if (x instanceof type) return x;
3283 }
3284 }
3285
3286 is_within_loop() {
3287 let i = this.stack.length - 1;
3288 let child = this.stack[i];
3289 while (i--) {
3290 const node = this.stack[i];
3291
3292 if (node instanceof AST_Lambda) return false;
3293 if (
3294 node instanceof AST_IterationStatement
3295 // exclude for-loop bits that only run once
3296 && !((node instanceof AST_For) && child === node.init)
3297 && !((node instanceof AST_ForIn || node instanceof AST_ForOf) && child === node.object)
3298 ) {
3299 return true;
3300 }
3301
3302 child = node;
3303 }
3304
3305 return false;
3306 }
3307
3308 find_scope() {
3309 var stack = this.stack;
3310 for (var i = stack.length; --i >= 0;) {
3311 const p = stack[i];
3312 if (p instanceof AST_Toplevel) return p;
3313 if (p instanceof AST_Lambda) return p;
3314 if (p.block_scope) return p.block_scope;
3315 }
3316 }
3317
3318 has_directive(type) {
3319 var dir = this.directives[type];
3320 if (dir) return dir;
3321 var node = this.stack[this.stack.length - 1];
3322 if (node instanceof AST_Scope && node.body) {
3323 for (var i = 0; i < node.body.length; ++i) {
3324 var st = node.body[i];
3325 if (!(st instanceof AST_Directive)) break;
3326 if (st.value == type) return st;
3327 }
3328 }
3329 }
3330
3331 loopcontrol_target(node) {
3332 var stack = this.stack;
3333 if (node.label) for (var i = stack.length; --i >= 0;) {
3334 var x = stack[i];
3335 if (x instanceof AST_LabeledStatement && x.label.name == node.label.name)
3336 return x.body;
3337 } else for (var i = stack.length; --i >= 0;) {
3338 var x = stack[i];
3339 if (x instanceof AST_IterationStatement
3340 || node instanceof AST_Break && x instanceof AST_Switch)
3341 return x;
3342 }
3343 }
3344}
3345
3346// Tree transformer helpers.
3347class TreeTransformer extends TreeWalker {
3348 constructor(before, after) {
3349 super();
3350 this.before = before;
3351 this.after = after;
3352 }
3353}
3354
3355const _PURE = 0b00000001;
3356const _INLINE = 0b00000010;
3357const _NOINLINE = 0b00000100;
3358const _KEY = 0b00001000;
3359const _MANGLEPROP = 0b00010000;
3360
3361export {
3362 AST_Accessor,
3363 AST_Array,
3364 AST_Arrow,
3365 AST_Assign,
3366 AST_Atom,
3367 AST_Await,
3368 AST_BigInt,
3369 AST_Binary,
3370 AST_Block,
3371 AST_BlockStatement,
3372 AST_Boolean,
3373 AST_Break,
3374 AST_Call,
3375 AST_Case,
3376 AST_Catch,
3377 AST_Chain,
3378 AST_Class,
3379 AST_ClassExpression,
3380 AST_ClassPrivateProperty,
3381 AST_PrivateIn,
3382 AST_ClassProperty,
3383 AST_ClassStaticBlock,
3384 AST_ConciseMethod,
3385 AST_Conditional,
3386 AST_Const,
3387 AST_Constant,
3388 AST_Continue,
3389 AST_Debugger,
3390 AST_Default,
3391 AST_DefaultAssign,
3392 AST_DefClass,
3393 AST_Definitions,
3394 AST_DefinitionsLike,
3395 AST_Defun,
3396 AST_Destructuring,
3397 AST_Directive,
3398 AST_Do,
3399 AST_Dot,
3400 AST_DotHash,
3401 AST_DWLoop,
3402 AST_EmptyStatement,
3403 AST_Exit,
3404 AST_Expansion,
3405 AST_Export,
3406 AST_False,
3407 AST_Finally,
3408 AST_For,
3409 AST_ForIn,
3410 AST_ForOf,
3411 AST_Function,
3412 AST_Hole,
3413 AST_If,
3414 AST_DynamicImport,
3415 AST_Import,
3416 AST_ImportMeta,
3417 AST_Infinity,
3418 AST_IterationStatement,
3419 AST_Jump,
3420 AST_Label,
3421 AST_LabeledStatement,
3422 AST_LabelRef,
3423 AST_Lambda,
3424 AST_Let,
3425 AST_LoopControl,
3426 AST_NameMapping,
3427 AST_NaN,
3428 AST_New,
3429 AST_NewTarget,
3430 AST_Node,
3431 AST_Null,
3432 AST_Number,
3433 AST_Object,
3434 AST_ObjectGetter,
3435 AST_ObjectKeyVal,
3436 AST_ObjectProperty,
3437 AST_ObjectSetter,
3438 AST_PrefixedTemplateString,
3439 AST_PrivateGetter,
3440 AST_PrivateMethod,
3441 AST_PrivateSetter,
3442 AST_PropAccess,
3443 AST_RegExp,
3444 AST_Return,
3445 AST_Scope,
3446 AST_Sequence,
3447 AST_SimpleStatement,
3448 AST_Statement,
3449 AST_StatementWithBody,
3450 AST_String,
3451 AST_Sub,
3452 AST_Super,
3453 AST_Switch,
3454 AST_SwitchBranch,
3455 AST_Symbol,
3456 AST_SymbolBlockDeclaration,
3457 AST_SymbolCatch,
3458 AST_SymbolClass,
3459 AST_SymbolClassProperty,
3460 AST_SymbolConst,
3461 AST_SymbolDeclaration,
3462 AST_SymbolDefClass,
3463 AST_SymbolDefun,
3464 AST_SymbolExport,
3465 AST_SymbolExportForeign,
3466 AST_SymbolFunarg,
3467 AST_SymbolImport,
3468 AST_SymbolImportForeign,
3469 AST_SymbolLambda,
3470 AST_SymbolLet,
3471 AST_SymbolMethod,
3472 AST_SymbolRef,
3473 AST_SymbolUsing,
3474 AST_SymbolVar,
3475 AST_TemplateSegment,
3476 AST_TemplateString,
3477 AST_SymbolPrivateProperty,
3478 AST_This,
3479 AST_Throw,
3480 AST_Token,
3481 AST_Toplevel,
3482 AST_True,
3483 AST_Try,
3484 AST_TryBlock,
3485 AST_Unary,
3486 AST_UnaryPostfix,
3487 AST_UnaryPrefix,
3488 AST_Undefined,
3489 AST_Using,
3490 AST_UsingDef,
3491 AST_Var,
3492 AST_VarDef,
3493 AST_VarDefLike,
3494 AST_While,
3495 AST_With,
3496 AST_Yield,
3497
3498 // Walkers
3499 TreeTransformer,
3500 TreeWalker,
3501 walk,
3502 walk_abort,
3503 walk_body,
3504 walk_parent,
3505
3506 // annotations
3507 _INLINE,
3508 _NOINLINE,
3509 _PURE,
3510 _KEY,
3511 _MANGLEPROP,
3512};
Note: See TracBrowser for help on using the repository browser.