diff options
| author | littleblack111 <littleblack11111@gmail.com> | 2026-05-18 23:10:59 +0800 |
|---|---|---|
| committer | littleblack111 <littleblack11111@gmail.com> | 2026-05-18 23:41:44 +0800 |
| commit | fc87c009806dcc98867f6b58efe29b042aa01dee (patch) | |
| tree | 8f59b3f4a5b66e9dfef2d40c8d318e258a521228 /node_modules/terser/lib/ast.js | |
| parent | 3336b2356ee6152d9c6ae59bd9b87ccbc0958407 (diff) | |
node: updatemain
Diffstat (limited to 'node_modules/terser/lib/ast.js')
| -rw-r--r-- | node_modules/terser/lib/ast.js | 3357 |
1 files changed, 0 insertions, 3357 deletions
diff --git a/node_modules/terser/lib/ast.js b/node_modules/terser/lib/ast.js deleted file mode 100644 index 9f6ff9ad..00000000 --- a/node_modules/terser/lib/ast.js +++ /dev/null @@ -1,3357 +0,0 @@ -/*********************************************************************** - - A JavaScript tokenizer / parser / beautifier / compressor. - https://github.com/mishoo/UglifyJS2 - - -------------------------------- (C) --------------------------------- - - Author: Mihai Bazon - <mihai.bazon@gmail.com> - http://mihai.bazon.net/blog - - Distributed under the BSD license: - - Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com> - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - ***********************************************************************/ - -import { - HOP, - MAP, - noop -} from "./utils/index.js"; -import { parse } from "./parse.js"; - -function DEFNODE(type, props, ctor, methods, base = AST_Node) { - if (!props) props = []; - else props = props.split(/\s+/); - var self_props = props; - if (base && base.PROPS) - props = props.concat(base.PROPS); - const proto = base && Object.create(base.prototype); - if (proto) { - ctor.prototype = proto; - ctor.BASE = base; - } - if (base) base.SUBCLASSES.push(ctor); - ctor.prototype.CTOR = ctor; - ctor.prototype.constructor = ctor; - ctor.PROPS = props || null; - ctor.SELF_PROPS = self_props; - ctor.SUBCLASSES = []; - if (type) { - ctor.prototype.TYPE = ctor.TYPE = type; - } - if (methods) for (let i in methods) if (HOP(methods, i)) { - if (i[0] === "$") { - ctor[i.substr(1)] = methods[i]; - } else { - ctor.prototype[i] = methods[i]; - } - } - ctor.DEFMETHOD = function(name, method) { - this.prototype[name] = method; - }; - return ctor; -} - -const has_tok_flag = (tok, flag) => Boolean(tok.flags & flag); -const set_tok_flag = (tok, flag, truth) => { - if (truth) { - tok.flags |= flag; - } else { - tok.flags &= ~flag; - } -}; - -const TOK_FLAG_NLB = 0b0001; -const TOK_FLAG_QUOTE_SINGLE = 0b0010; -const TOK_FLAG_QUOTE_EXISTS = 0b0100; -const TOK_FLAG_TEMPLATE_END = 0b1000; - -class AST_Token { - constructor(type, value, line, col, pos, nlb, comments_before, comments_after, file) { - this.flags = (nlb ? 1 : 0); - - this.type = type; - this.value = value; - this.line = line; - this.col = col; - this.pos = pos; - this.comments_before = comments_before; - this.comments_after = comments_after; - this.file = file; - - Object.seal(this); - } - - // Return a string summary of the token for node.js console.log - [Symbol.for("nodejs.util.inspect.custom")](_depth, options) { - const special = str => options.stylize(str, "special"); - const quote = typeof this.value === "string" && this.value.includes("`") ? "'" : "`"; - const value = `${quote}${this.value}${quote}`; - return `${special("[AST_Token")} ${value} at ${this.line}:${this.col}${special("]")}`; - } - - get nlb() { - return has_tok_flag(this, TOK_FLAG_NLB); - } - - set nlb(new_nlb) { - set_tok_flag(this, TOK_FLAG_NLB, new_nlb); - } - - get quote() { - return !has_tok_flag(this, TOK_FLAG_QUOTE_EXISTS) - ? "" - : (has_tok_flag(this, TOK_FLAG_QUOTE_SINGLE) ? "'" : '"'); - } - - set quote(quote_type) { - set_tok_flag(this, TOK_FLAG_QUOTE_SINGLE, quote_type === "'"); - set_tok_flag(this, TOK_FLAG_QUOTE_EXISTS, !!quote_type); - } - - get template_end() { - return has_tok_flag(this, TOK_FLAG_TEMPLATE_END); - } - - set template_end(new_template_end) { - set_tok_flag(this, TOK_FLAG_TEMPLATE_END, new_template_end); - } -} - -var AST_Node = DEFNODE("Node", "start end", function AST_Node(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - _clone: function(deep) { - if (deep) { - var self = this.clone(); - return self.transform(new TreeTransformer(function(node) { - if (node !== self) { - return node.clone(true); - } - })); - } - return new this.CTOR(this); - }, - clone: function(deep) { - return this._clone(deep); - }, - $documentation: "Base class of all AST nodes", - $propdoc: { - start: "[AST_Token] The first token of this node", - end: "[AST_Token] The last token of this node" - }, - _walk: function(visitor) { - return visitor._visit(this); - }, - walk: function(visitor) { - return this._walk(visitor); // not sure the indirection will be any help - }, - _children_backwards: () => {} -}, null); - -/* -----[ statements ]----- */ - -var AST_Statement = DEFNODE("Statement", null, function AST_Statement(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Base class of all statements", -}); - -var AST_Debugger = DEFNODE("Debugger", null, function AST_Debugger(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Represents a debugger statement", -}, AST_Statement); - -var AST_Directive = DEFNODE("Directive", "value quote", function AST_Directive(props) { - if (props) { - this.value = props.value; - this.quote = props.quote; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Represents a directive, like \"use strict\";", - $propdoc: { - value: "[string] The value of this directive as a plain string (it's not an AST_String!)", - quote: "[string] the original quote character" - }, -}, AST_Statement); - -var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", function AST_SimpleStatement(props) { - if (props) { - this.body = props.body; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A statement consisting of an expression, i.e. a = 1 + 2", - $propdoc: { - body: "[AST_Node] an expression node (should not be instanceof AST_Statement)" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.body._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.body); - } -}, AST_Statement); - -function walk_body(node, visitor) { - const body = node.body; - for (var i = 0, len = body.length; i < len; i++) { - body[i]._walk(visitor); - } -} - -function clone_block_scope(deep) { - var clone = this._clone(deep); - if (this.block_scope) { - clone.block_scope = this.block_scope.clone(); - } - return clone; -} - -var AST_Block = DEFNODE("Block", "body block_scope", function AST_Block(props) { - if (props) { - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A body of statements (usually braced)", - $propdoc: { - body: "[AST_Statement*] an array of statements", - block_scope: "[AST_Scope] the block scope" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - walk_body(this, visitor); - }); - }, - _children_backwards(push) { - let i = this.body.length; - while (i--) push(this.body[i]); - }, - clone: clone_block_scope -}, AST_Statement); - -var AST_BlockStatement = DEFNODE("BlockStatement", null, function AST_BlockStatement(props) { - if (props) { - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A block statement", -}, AST_Block); - -var AST_EmptyStatement = DEFNODE("EmptyStatement", null, function AST_EmptyStatement(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "The empty statement (empty block or simply a semicolon)" -}, AST_Statement); - -var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", function AST_StatementWithBody(props) { - if (props) { - this.body = props.body; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`", - $propdoc: { - body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement" - } -}, AST_Statement); - -var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", function AST_LabeledStatement(props) { - if (props) { - this.label = props.label; - this.body = props.body; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Statement with a label", - $propdoc: { - label: "[AST_Label] a label definition" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.label._walk(visitor); - this.body._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.body); - push(this.label); - }, - clone: function(deep) { - var node = this._clone(deep); - if (deep) { - var label = node.label; - var def = this.label; - node.walk(new TreeWalker(function(node) { - if (node instanceof AST_LoopControl - && node.label && node.label.thedef === def) { - node.label.thedef = label; - label.references.push(node); - } - })); - } - return node; - } -}, AST_StatementWithBody); - -var AST_IterationStatement = DEFNODE( - "IterationStatement", - "block_scope", - function AST_IterationStatement(props) { - if (props) { - this.block_scope = props.block_scope; - this.body = props.body; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; - }, - { - $documentation: "Internal class. All loops inherit from it.", - $propdoc: { - block_scope: "[AST_Scope] the block scope for this iteration statement." - }, - clone: clone_block_scope - }, - AST_StatementWithBody -); - -var AST_DWLoop = DEFNODE("DWLoop", "condition", function AST_DWLoop(props) { - if (props) { - this.condition = props.condition; - this.block_scope = props.block_scope; - this.body = props.body; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Base class for do/while statements", - $propdoc: { - condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement" - } -}, AST_IterationStatement); - -var AST_Do = DEFNODE("Do", null, function AST_Do(props) { - if (props) { - this.condition = props.condition; - this.block_scope = props.block_scope; - this.body = props.body; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `do` statement", - _walk: function(visitor) { - return visitor._visit(this, function() { - this.body._walk(visitor); - this.condition._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.condition); - push(this.body); - } -}, AST_DWLoop); - -var AST_While = DEFNODE("While", null, function AST_While(props) { - if (props) { - this.condition = props.condition; - this.block_scope = props.block_scope; - this.body = props.body; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `while` statement", - _walk: function(visitor) { - return visitor._visit(this, function() { - this.condition._walk(visitor); - this.body._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.body); - push(this.condition); - }, -}, AST_DWLoop); - -var AST_For = DEFNODE("For", "init condition step", function AST_For(props) { - if (props) { - this.init = props.init; - this.condition = props.condition; - this.step = props.step; - this.block_scope = props.block_scope; - this.body = props.body; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `for` statement", - $propdoc: { - init: "[AST_Node?] the `for` initialization code, or null if empty", - condition: "[AST_Node?] the `for` termination clause, or null if empty", - step: "[AST_Node?] the `for` update clause, or null if empty" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - if (this.init) this.init._walk(visitor); - if (this.condition) this.condition._walk(visitor); - if (this.step) this.step._walk(visitor); - this.body._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.body); - if (this.step) push(this.step); - if (this.condition) push(this.condition); - if (this.init) push(this.init); - }, -}, AST_IterationStatement); - -var AST_ForIn = DEFNODE("ForIn", "init object", function AST_ForIn(props) { - if (props) { - this.init = props.init; - this.object = props.object; - this.block_scope = props.block_scope; - this.body = props.body; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `for ... in` statement", - $propdoc: { - init: "[AST_Node] the `for/in` initialization code", - object: "[AST_Node] the object that we're looping through" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.init._walk(visitor); - this.object._walk(visitor); - this.body._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.body); - if (this.object) push(this.object); - if (this.init) push(this.init); - }, -}, AST_IterationStatement); - -var AST_ForOf = DEFNODE("ForOf", "await", function AST_ForOf(props) { - if (props) { - this.await = props.await; - this.init = props.init; - this.object = props.object; - this.block_scope = props.block_scope; - this.body = props.body; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `for ... of` statement", -}, AST_ForIn); - -var AST_With = DEFNODE("With", "expression", function AST_With(props) { - if (props) { - this.expression = props.expression; - this.body = props.body; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `with` statement", - $propdoc: { - expression: "[AST_Node] the `with` expression" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - this.body._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.body); - push(this.expression); - }, -}, AST_StatementWithBody); - -/* -----[ scope and functions ]----- */ - -var AST_Scope = DEFNODE( - "Scope", - "variables uses_with uses_eval parent_scope enclosed cname", - function AST_Scope(props) { - if (props) { - this.variables = props.variables; - this.uses_with = props.uses_with; - this.uses_eval = props.uses_eval; - this.parent_scope = props.parent_scope; - this.enclosed = props.enclosed; - this.cname = props.cname; - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; - }, - { - $documentation: "Base class for all statements introducing a lexical scope", - $propdoc: { - variables: "[Map/S] a map of name -> SymbolDef for all variables/functions defined in this scope", - uses_with: "[boolean/S] tells whether this scope uses the `with` statement", - uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`", - parent_scope: "[AST_Scope?/S] link to the parent scope", - enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes", - cname: "[integer/S] current index for mangling variables (used internally by the mangler)", - }, - get_defun_scope: function() { - var self = this; - while (self.is_block_scope()) { - self = self.parent_scope; - } - return self; - }, - clone: function(deep, toplevel) { - var node = this._clone(deep); - if (deep && this.variables && toplevel && !this._block_scope) { - node.figure_out_scope({}, { - toplevel: toplevel, - parent_scope: this.parent_scope - }); - } else { - if (this.variables) node.variables = new Map(this.variables); - if (this.enclosed) node.enclosed = this.enclosed.slice(); - if (this._block_scope) node._block_scope = this._block_scope; - } - return node; - }, - pinned: function() { - return this.uses_eval || this.uses_with; - } - }, - AST_Block -); - -var AST_Toplevel = DEFNODE("Toplevel", "globals", function AST_Toplevel(props) { - if (props) { - this.globals = props.globals; - this.variables = props.variables; - this.uses_with = props.uses_with; - this.uses_eval = props.uses_eval; - this.parent_scope = props.parent_scope; - this.enclosed = props.enclosed; - this.cname = props.cname; - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "The toplevel scope", - $propdoc: { - globals: "[Map/S] a map of name -> SymbolDef for all undeclared names", - }, - wrap_commonjs: function(name) { - var body = this.body; - var wrapped_tl = "(function(exports){'$ORIG';})(typeof " + name + "=='undefined'?(" + name + "={}):" + name + ");"; - wrapped_tl = parse(wrapped_tl); - wrapped_tl = wrapped_tl.transform(new TreeTransformer(function(node) { - if (node instanceof AST_Directive && node.value == "$ORIG") { - return MAP.splice(body); - } - })); - return wrapped_tl; - }, - wrap_enclose: function(args_values) { - if (typeof args_values != "string") args_values = ""; - var index = args_values.indexOf(":"); - if (index < 0) index = args_values.length; - var body = this.body; - return parse([ - "(function(", - args_values.slice(0, index), - '){"$ORIG"})(', - args_values.slice(index + 1), - ")" - ].join("")).transform(new TreeTransformer(function(node) { - if (node instanceof AST_Directive && node.value == "$ORIG") { - return MAP.splice(body); - } - })); - } -}, AST_Scope); - -var AST_Expansion = DEFNODE("Expansion", "expression", function AST_Expansion(props) { - if (props) { - this.expression = props.expression; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $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", - $propdoc: { - expression: "[AST_Node] the thing to be expanded" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression.walk(visitor); - }); - }, - _children_backwards(push) { - push(this.expression); - }, -}); - -var AST_Lambda = DEFNODE( - "Lambda", - "name argnames uses_arguments is_generator async", - function AST_Lambda(props) { - if (props) { - this.name = props.name; - this.argnames = props.argnames; - this.uses_arguments = props.uses_arguments; - this.is_generator = props.is_generator; - this.async = props.async; - this.variables = props.variables; - this.uses_with = props.uses_with; - this.uses_eval = props.uses_eval; - this.parent_scope = props.parent_scope; - this.enclosed = props.enclosed; - this.cname = props.cname; - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; - }, - { - $documentation: "Base class for functions", - $propdoc: { - name: "[AST_SymbolDeclaration?] the name of this function", - argnames: "[AST_SymbolFunarg|AST_Destructuring|AST_Expansion|AST_DefaultAssign*] array of function arguments, destructurings, or expanding arguments", - uses_arguments: "[boolean/S] tells whether this function accesses the arguments array", - is_generator: "[boolean] is this a generator method", - async: "[boolean] is this method async", - }, - args_as_names: function () { - var out = []; - for (var i = 0; i < this.argnames.length; i++) { - if (this.argnames[i] instanceof AST_Destructuring) { - out.push(...this.argnames[i].all_symbols()); - } else { - out.push(this.argnames[i]); - } - } - return out; - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - if (this.name) this.name._walk(visitor); - var argnames = this.argnames; - for (var i = 0, len = argnames.length; i < len; i++) { - argnames[i]._walk(visitor); - } - walk_body(this, visitor); - }); - }, - _children_backwards(push) { - let i = this.body.length; - while (i--) push(this.body[i]); - - i = this.argnames.length; - while (i--) push(this.argnames[i]); - - if (this.name) push(this.name); - }, - is_braceless() { - return this.body[0] instanceof AST_Return && this.body[0].value; - }, - // Default args and expansion don't count, so .argnames.length doesn't cut it - length_property() { - let length = 0; - - for (const arg of this.argnames) { - if (arg instanceof AST_SymbolFunarg || arg instanceof AST_Destructuring) { - length++; - } - } - - return length; - } - }, - AST_Scope -); - -var AST_Accessor = DEFNODE("Accessor", null, function AST_Accessor(props) { - if (props) { - this.name = props.name; - this.argnames = props.argnames; - this.uses_arguments = props.uses_arguments; - this.is_generator = props.is_generator; - this.async = props.async; - this.variables = props.variables; - this.uses_with = props.uses_with; - this.uses_eval = props.uses_eval; - this.parent_scope = props.parent_scope; - this.enclosed = props.enclosed; - this.cname = props.cname; - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A setter/getter function. The `name` property is always null." -}, AST_Lambda); - -var AST_Function = DEFNODE("Function", null, function AST_Function(props) { - if (props) { - this.name = props.name; - this.argnames = props.argnames; - this.uses_arguments = props.uses_arguments; - this.is_generator = props.is_generator; - this.async = props.async; - this.variables = props.variables; - this.uses_with = props.uses_with; - this.uses_eval = props.uses_eval; - this.parent_scope = props.parent_scope; - this.enclosed = props.enclosed; - this.cname = props.cname; - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A function expression" -}, AST_Lambda); - -var AST_Arrow = DEFNODE("Arrow", null, function AST_Arrow(props) { - if (props) { - this.name = props.name; - this.argnames = props.argnames; - this.uses_arguments = props.uses_arguments; - this.is_generator = props.is_generator; - this.async = props.async; - this.variables = props.variables; - this.uses_with = props.uses_with; - this.uses_eval = props.uses_eval; - this.parent_scope = props.parent_scope; - this.enclosed = props.enclosed; - this.cname = props.cname; - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "An ES6 Arrow function ((a) => b)" -}, AST_Lambda); - -var AST_Defun = DEFNODE("Defun", null, function AST_Defun(props) { - if (props) { - this.name = props.name; - this.argnames = props.argnames; - this.uses_arguments = props.uses_arguments; - this.is_generator = props.is_generator; - this.async = props.async; - this.variables = props.variables; - this.uses_with = props.uses_with; - this.uses_eval = props.uses_eval; - this.parent_scope = props.parent_scope; - this.enclosed = props.enclosed; - this.cname = props.cname; - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A function definition" -}, AST_Lambda); - -/* -----[ DESTRUCTURING ]----- */ -var AST_Destructuring = DEFNODE("Destructuring", "names is_array", function AST_Destructuring(props) { - if (props) { - this.names = props.names; - this.is_array = props.is_array; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A destructuring of several names. Used in destructuring assignment and with destructuring function argument names", - $propdoc: { - "names": "[AST_Node*] Array of properties or elements", - "is_array": "[Boolean] Whether the destructuring represents an object or array" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.names.forEach(function(name) { - name._walk(visitor); - }); - }); - }, - _children_backwards(push) { - let i = this.names.length; - while (i--) push(this.names[i]); - }, - all_symbols: function() { - var out = []; - walk(this, node => { - if (node instanceof AST_SymbolDeclaration) { - out.push(node); - } - if (node instanceof AST_Lambda) { - return true; - } - }); - return out; - } -}); - -var AST_PrefixedTemplateString = DEFNODE( - "PrefixedTemplateString", - "template_string prefix", - function AST_PrefixedTemplateString(props) { - if (props) { - this.template_string = props.template_string; - this.prefix = props.prefix; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; - }, - { - $documentation: "A templatestring with a prefix, such as String.raw`foobarbaz`", - $propdoc: { - template_string: "[AST_TemplateString] The template string", - prefix: "[AST_Node] The prefix, which will get called." - }, - _walk: function(visitor) { - return visitor._visit(this, function () { - this.prefix._walk(visitor); - this.template_string._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.template_string); - push(this.prefix); - }, - } -); - -var AST_TemplateString = DEFNODE("TemplateString", "segments", function AST_TemplateString(props) { - if (props) { - this.segments = props.segments; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A template string literal", - $propdoc: { - 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." - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.segments.forEach(function(seg) { - seg._walk(visitor); - }); - }); - }, - _children_backwards(push) { - let i = this.segments.length; - while (i--) push(this.segments[i]); - } -}); - -var AST_TemplateSegment = DEFNODE("TemplateSegment", "value raw", function AST_TemplateSegment(props) { - if (props) { - this.value = props.value; - this.raw = props.raw; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A segment of a template string literal", - $propdoc: { - value: "Content of the segment", - raw: "Raw source of the segment", - } -}); - -/* -----[ JUMPS ]----- */ - -var AST_Jump = DEFNODE("Jump", null, function AST_Jump(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)" -}, AST_Statement); - -/** Base class for “exits” (`return` and `throw`) */ -var AST_Exit = DEFNODE("Exit", "value", function AST_Exit(props) { - if (props) { - this.value = props.value; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Base class for “exits” (`return` and `throw`)", - $propdoc: { - value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return" - }, - _walk: function(visitor) { - return visitor._visit(this, this.value && function() { - this.value._walk(visitor); - }); - }, - _children_backwards(push) { - if (this.value) push(this.value); - }, -}, AST_Jump); - -var AST_Return = DEFNODE("Return", null, function AST_Return(props) { - if (props) { - this.value = props.value; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `return` statement" -}, AST_Exit); - -var AST_Throw = DEFNODE("Throw", null, function AST_Throw(props) { - if (props) { - this.value = props.value; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `throw` statement" -}, AST_Exit); - -var AST_LoopControl = DEFNODE("LoopControl", "label", function AST_LoopControl(props) { - if (props) { - this.label = props.label; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Base class for loop control statements (`break` and `continue`)", - $propdoc: { - label: "[AST_LabelRef?] the label, or null if none", - }, - _walk: function(visitor) { - return visitor._visit(this, this.label && function() { - this.label._walk(visitor); - }); - }, - _children_backwards(push) { - if (this.label) push(this.label); - }, -}, AST_Jump); - -var AST_Break = DEFNODE("Break", null, function AST_Break(props) { - if (props) { - this.label = props.label; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `break` statement" -}, AST_LoopControl); - -var AST_Continue = DEFNODE("Continue", null, function AST_Continue(props) { - if (props) { - this.label = props.label; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `continue` statement" -}, AST_LoopControl); - -var AST_Await = DEFNODE("Await", "expression", function AST_Await(props) { - if (props) { - this.expression = props.expression; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "An `await` statement", - $propdoc: { - expression: "[AST_Node] the mandatory expression being awaited", - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.expression); - }, -}); - -var AST_Yield = DEFNODE("Yield", "expression is_star", function AST_Yield(props) { - if (props) { - this.expression = props.expression; - this.is_star = props.is_star; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `yield` statement", - $propdoc: { - 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", - is_star: "[Boolean] Whether this is a yield or yield* statement" - }, - _walk: function(visitor) { - return visitor._visit(this, this.expression && function() { - this.expression._walk(visitor); - }); - }, - _children_backwards(push) { - if (this.expression) push(this.expression); - } -}); - -/* -----[ IF ]----- */ - -var AST_If = DEFNODE("If", "condition alternative", function AST_If(props) { - if (props) { - this.condition = props.condition; - this.alternative = props.alternative; - this.body = props.body; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `if` statement", - $propdoc: { - condition: "[AST_Node] the `if` condition", - alternative: "[AST_Statement?] the `else` part, or null if not present" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.condition._walk(visitor); - this.body._walk(visitor); - if (this.alternative) this.alternative._walk(visitor); - }); - }, - _children_backwards(push) { - if (this.alternative) { - push(this.alternative); - } - push(this.body); - push(this.condition); - } -}, AST_StatementWithBody); - -/* -----[ SWITCH ]----- */ - -var AST_Switch = DEFNODE("Switch", "expression", function AST_Switch(props) { - if (props) { - this.expression = props.expression; - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `switch` statement", - $propdoc: { - expression: "[AST_Node] the `switch` “discriminant”" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - walk_body(this, visitor); - }); - }, - _children_backwards(push) { - let i = this.body.length; - while (i--) push(this.body[i]); - push(this.expression); - } -}, AST_Block); - -var AST_SwitchBranch = DEFNODE("SwitchBranch", null, function AST_SwitchBranch(props) { - if (props) { - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Base class for `switch` branches", -}, AST_Block); - -var AST_Default = DEFNODE("Default", null, function AST_Default(props) { - if (props) { - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `default` switch branch", -}, AST_SwitchBranch); - -var AST_Case = DEFNODE("Case", "expression", function AST_Case(props) { - if (props) { - this.expression = props.expression; - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `case` switch branch", - $propdoc: { - expression: "[AST_Node] the `case` expression" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - walk_body(this, visitor); - }); - }, - _children_backwards(push) { - let i = this.body.length; - while (i--) push(this.body[i]); - push(this.expression); - }, -}, AST_SwitchBranch); - -/* -----[ EXCEPTIONS ]----- */ - -var AST_Try = DEFNODE("Try", "body bcatch bfinally", function AST_Try(props) { - if (props) { - this.body = props.body; - this.bcatch = props.bcatch; - this.bfinally = props.bfinally; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `try` statement", - $propdoc: { - body: "[AST_TryBlock] the try block", - bcatch: "[AST_Catch?] the catch block, or null if not present", - bfinally: "[AST_Finally?] the finally block, or null if not present" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.body._walk(visitor); - if (this.bcatch) this.bcatch._walk(visitor); - if (this.bfinally) this.bfinally._walk(visitor); - }); - }, - _children_backwards(push) { - if (this.bfinally) push(this.bfinally); - if (this.bcatch) push(this.bcatch); - push(this.body); - }, -}, AST_Statement); - -var AST_TryBlock = DEFNODE("TryBlock", null, function AST_TryBlock(props) { - if (props) { - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "The `try` block of a try statement" -}, AST_Block); - -var AST_Catch = DEFNODE("Catch", "argname", function AST_Catch(props) { - if (props) { - this.argname = props.argname; - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `catch` node; only makes sense as part of a `try` statement", - $propdoc: { - argname: "[AST_SymbolCatch|AST_Destructuring|AST_Expansion|AST_DefaultAssign] symbol for the exception" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - if (this.argname) this.argname._walk(visitor); - walk_body(this, visitor); - }); - }, - _children_backwards(push) { - let i = this.body.length; - while (i--) push(this.body[i]); - if (this.argname) push(this.argname); - }, -}, AST_Block); - -var AST_Finally = DEFNODE("Finally", null, function AST_Finally(props) { - if (props) { - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `finally` node; only makes sense as part of a `try` statement" -}, AST_Block); - -/* -----[ VAR/CONST ]----- */ - -var AST_Definitions = DEFNODE("Definitions", "definitions", function AST_Definitions(props) { - if (props) { - this.definitions = props.definitions; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)", - $propdoc: { - definitions: "[AST_VarDef*] array of variable definitions" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - var definitions = this.definitions; - for (var i = 0, len = definitions.length; i < len; i++) { - definitions[i]._walk(visitor); - } - }); - }, - _children_backwards(push) { - let i = this.definitions.length; - while (i--) push(this.definitions[i]); - }, -}, AST_Statement); - -var AST_Var = DEFNODE("Var", null, function AST_Var(props) { - if (props) { - this.definitions = props.definitions; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `var` statement" -}, AST_Definitions); - -var AST_Let = DEFNODE("Let", null, function AST_Let(props) { - if (props) { - this.definitions = props.definitions; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `let` statement" -}, AST_Definitions); - -var AST_Const = DEFNODE("Const", null, function AST_Const(props) { - if (props) { - this.definitions = props.definitions; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A `const` statement" -}, AST_Definitions); - -var AST_VarDef = DEFNODE("VarDef", "name value", function AST_VarDef(props) { - if (props) { - this.name = props.name; - this.value = props.value; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A variable declaration; only appears in a AST_Definitions node", - $propdoc: { - name: "[AST_Destructuring|AST_SymbolConst|AST_SymbolLet|AST_SymbolVar] name of the variable", - value: "[AST_Node?] initializer, or null of there's no initializer" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.name._walk(visitor); - if (this.value) this.value._walk(visitor); - }); - }, - _children_backwards(push) { - if (this.value) push(this.value); - push(this.name); - }, - declarations_as_names() { - if (this.name instanceof AST_SymbolDeclaration) { - return [this]; - } else { - return this.name.all_symbols(); - } - } -}); - -var AST_NameMapping = DEFNODE("NameMapping", "foreign_name name", function AST_NameMapping(props) { - if (props) { - this.foreign_name = props.foreign_name; - this.name = props.name; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "The part of the export/import statement that declare names from a module.", - $propdoc: { - foreign_name: "[AST_SymbolExportForeign|AST_SymbolImportForeign] The name being exported/imported (as specified in the module)", - name: "[AST_SymbolExport|AST_SymbolImport] The name as it is visible to this module." - }, - _walk: function (visitor) { - return visitor._visit(this, function() { - this.foreign_name._walk(visitor); - this.name._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.name); - push(this.foreign_name); - }, -}); - -var AST_Import = DEFNODE( - "Import", - "imported_name imported_names module_name assert_clause", - function AST_Import(props) { - if (props) { - this.imported_name = props.imported_name; - this.imported_names = props.imported_names; - this.module_name = props.module_name; - this.assert_clause = props.assert_clause; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; - }, - { - $documentation: "An `import` statement", - $propdoc: { - imported_name: "[AST_SymbolImport] The name of the variable holding the module's default export.", - imported_names: "[AST_NameMapping*] The names of non-default imported variables", - module_name: "[AST_String] String literal describing where this module came from", - assert_clause: "[AST_Object?] The import assertion" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - if (this.imported_name) { - this.imported_name._walk(visitor); - } - if (this.imported_names) { - this.imported_names.forEach(function(name_import) { - name_import._walk(visitor); - }); - } - this.module_name._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.module_name); - if (this.imported_names) { - let i = this.imported_names.length; - while (i--) push(this.imported_names[i]); - } - if (this.imported_name) push(this.imported_name); - }, - } -); - -var AST_ImportMeta = DEFNODE("ImportMeta", null, function AST_ImportMeta(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A reference to import.meta", -}); - -var AST_Export = DEFNODE( - "Export", - "exported_definition exported_value is_default exported_names module_name assert_clause", - function AST_Export(props) { - if (props) { - this.exported_definition = props.exported_definition; - this.exported_value = props.exported_value; - this.is_default = props.is_default; - this.exported_names = props.exported_names; - this.module_name = props.module_name; - this.assert_clause = props.assert_clause; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; - }, - { - $documentation: "An `export` statement", - $propdoc: { - exported_definition: "[AST_Defun|AST_Definitions|AST_DefClass?] An exported definition", - exported_value: "[AST_Node?] An exported value", - exported_names: "[AST_NameMapping*?] List of exported names", - module_name: "[AST_String?] Name of the file to load exports from", - is_default: "[Boolean] Whether this is the default exported value of this module", - assert_clause: "[AST_Object?] The import assertion" - }, - _walk: function (visitor) { - return visitor._visit(this, function () { - if (this.exported_definition) { - this.exported_definition._walk(visitor); - } - if (this.exported_value) { - this.exported_value._walk(visitor); - } - if (this.exported_names) { - this.exported_names.forEach(function(name_export) { - name_export._walk(visitor); - }); - } - if (this.module_name) { - this.module_name._walk(visitor); - } - }); - }, - _children_backwards(push) { - if (this.module_name) push(this.module_name); - if (this.exported_names) { - let i = this.exported_names.length; - while (i--) push(this.exported_names[i]); - } - if (this.exported_value) push(this.exported_value); - if (this.exported_definition) push(this.exported_definition); - } - }, - AST_Statement -); - -/* -----[ OTHER ]----- */ - -var AST_Call = DEFNODE( - "Call", - "expression args optional _annotations", - function AST_Call(props) { - if (props) { - this.expression = props.expression; - this.args = props.args; - this.optional = props.optional; - this._annotations = props._annotations; - this.start = props.start; - this.end = props.end; - this.initialize(); - } - - this.flags = 0; - }, - { - $documentation: "A function call expression", - $propdoc: { - expression: "[AST_Node] expression to invoke as function", - args: "[AST_Node*] array of arguments", - optional: "[boolean] whether this is an optional call (IE ?.() )", - _annotations: "[number] bitfield containing information about the call" - }, - initialize() { - if (this._annotations == null) this._annotations = 0; - }, - _walk(visitor) { - return visitor._visit(this, function() { - var args = this.args; - for (var i = 0, len = args.length; i < len; i++) { - args[i]._walk(visitor); - } - this.expression._walk(visitor); // TODO why do we need to crawl this last? - }); - }, - _children_backwards(push) { - let i = this.args.length; - while (i--) push(this.args[i]); - push(this.expression); - }, - } -); - -var AST_New = DEFNODE("New", null, function AST_New(props) { - if (props) { - this.expression = props.expression; - this.args = props.args; - this.optional = props.optional; - this._annotations = props._annotations; - this.start = props.start; - this.end = props.end; - this.initialize(); - } - - this.flags = 0; -}, { - $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties" -}, AST_Call); - -var AST_Sequence = DEFNODE("Sequence", "expressions", function AST_Sequence(props) { - if (props) { - this.expressions = props.expressions; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A sequence expression (comma-separated expressions)", - $propdoc: { - expressions: "[AST_Node*] array of expressions (at least two)" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expressions.forEach(function(node) { - node._walk(visitor); - }); - }); - }, - _children_backwards(push) { - let i = this.expressions.length; - while (i--) push(this.expressions[i]); - }, -}); - -var AST_PropAccess = DEFNODE( - "PropAccess", - "expression property optional", - function AST_PropAccess(props) { - if (props) { - this.expression = props.expression; - this.property = props.property; - this.optional = props.optional; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; - }, - { - $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`", - $propdoc: { - expression: "[AST_Node] the “container” expression", - 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", - - optional: "[boolean] whether this is an optional property access (IE ?.)" - } - } -); - -var AST_Dot = DEFNODE("Dot", "quote", function AST_Dot(props) { - if (props) { - this.quote = props.quote; - this.expression = props.expression; - this.property = props.property; - this.optional = props.optional; - this._annotations = props._annotations; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A dotted property access expression", - $propdoc: { - quote: "[string] the original quote character when transformed from AST_Sub", - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.expression); - }, -}, AST_PropAccess); - -var AST_DotHash = DEFNODE("DotHash", "", function AST_DotHash(props) { - if (props) { - this.expression = props.expression; - this.property = props.property; - this.optional = props.optional; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A dotted property access to a private property", - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.expression); - }, -}, AST_PropAccess); - -var AST_Sub = DEFNODE("Sub", null, function AST_Sub(props) { - if (props) { - this.expression = props.expression; - this.property = props.property; - this.optional = props.optional; - this._annotations = props._annotations; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Index-style property access, i.e. `a[\"foo\"]`", - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - this.property._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.property); - push(this.expression); - }, -}, AST_PropAccess); - -var AST_Chain = DEFNODE("Chain", "expression", function AST_Chain(props) { - if (props) { - this.expression = props.expression; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A chain expression like a?.b?.(c)?.[d]", - $propdoc: { - expression: "[AST_Call|AST_Dot|AST_DotHash|AST_Sub] chain element." - }, - _walk: function (visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.expression); - }, -}); - -var AST_Unary = DEFNODE("Unary", "operator expression", function AST_Unary(props) { - if (props) { - this.operator = props.operator; - this.expression = props.expression; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Base class for unary expressions", - $propdoc: { - operator: "[string] the operator", - expression: "[AST_Node] expression that this unary operator applies to" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.expression); - }, -}); - -var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, function AST_UnaryPrefix(props) { - if (props) { - this.operator = props.operator; - this.expression = props.expression; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`" -}, AST_Unary); - -var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, function AST_UnaryPostfix(props) { - if (props) { - this.operator = props.operator; - this.expression = props.expression; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Unary postfix expression, i.e. `i++`" -}, AST_Unary); - -var AST_Binary = DEFNODE("Binary", "operator left right", function AST_Binary(props) { - if (props) { - this.operator = props.operator; - this.left = props.left; - this.right = props.right; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Binary expression, i.e. `a + b`", - $propdoc: { - left: "[AST_Node] left-hand side expression", - operator: "[string] the operator", - right: "[AST_Node] right-hand side expression" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.left._walk(visitor); - this.right._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.right); - push(this.left); - }, -}); - -var AST_Conditional = DEFNODE( - "Conditional", - "condition consequent alternative", - function AST_Conditional(props) { - if (props) { - this.condition = props.condition; - this.consequent = props.consequent; - this.alternative = props.alternative; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; - }, - { - $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`", - $propdoc: { - condition: "[AST_Node]", - consequent: "[AST_Node]", - alternative: "[AST_Node]" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.condition._walk(visitor); - this.consequent._walk(visitor); - this.alternative._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.alternative); - push(this.consequent); - push(this.condition); - }, - } -); - -var AST_Assign = DEFNODE("Assign", "logical", function AST_Assign(props) { - if (props) { - this.logical = props.logical; - this.operator = props.operator; - this.left = props.left; - this.right = props.right; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "An assignment expression — `a = b + 5`", - $propdoc: { - logical: "Whether it's a logical assignment" - } -}, AST_Binary); - -var AST_DefaultAssign = DEFNODE("DefaultAssign", null, function AST_DefaultAssign(props) { - if (props) { - this.operator = props.operator; - this.left = props.left; - this.right = props.right; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A default assignment expression like in `(a = 3) => a`" -}, AST_Binary); - -/* -----[ LITERALS ]----- */ - -var AST_Array = DEFNODE("Array", "elements", function AST_Array(props) { - if (props) { - this.elements = props.elements; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "An array literal", - $propdoc: { - elements: "[AST_Node*] array of elements" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - var elements = this.elements; - for (var i = 0, len = elements.length; i < len; i++) { - elements[i]._walk(visitor); - } - }); - }, - _children_backwards(push) { - let i = this.elements.length; - while (i--) push(this.elements[i]); - }, -}); - -var AST_Object = DEFNODE("Object", "properties", function AST_Object(props) { - if (props) { - this.properties = props.properties; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "An object literal", - $propdoc: { - properties: "[AST_ObjectProperty*] array of properties" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - var properties = this.properties; - for (var i = 0, len = properties.length; i < len; i++) { - properties[i]._walk(visitor); - } - }); - }, - _children_backwards(push) { - let i = this.properties.length; - while (i--) push(this.properties[i]); - }, -}); - -var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", function AST_ObjectProperty(props) { - if (props) { - this.key = props.key; - this.value = props.value; - this.start = props.start; - this.end = props.end; - this._annotations = props._annotations; - } - - this.flags = 0; -}, { - $documentation: "Base class for literal object properties", - $propdoc: { - key: "[string|AST_Node] property name. For ObjectKeyVal this is a string. For getters, setters and computed property this is an AST_Node.", - value: "[AST_Node] property value. For getters and setters this is an AST_Accessor." - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - if (this.key instanceof AST_Node) - this.key._walk(visitor); - this.value._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.value); - if (this.key instanceof AST_Node) push(this.key); - } -}); - -var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", function AST_ObjectKeyVal(props) { - if (props) { - this.quote = props.quote; - this.key = props.key; - this.value = props.value; - this.start = props.start; - this.end = props.end; - this._annotations = props._annotations; - } - - this.flags = 0; -}, { - $documentation: "A key: value object property", - $propdoc: { - quote: "[string] the original quote character" - }, - computed_key() { - return this.key instanceof AST_Node; - } -}, AST_ObjectProperty); - -var AST_PrivateSetter = DEFNODE("PrivateSetter", "static", function AST_PrivateSetter(props) { - if (props) { - this.static = props.static; - this.key = props.key; - this.value = props.value; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $propdoc: { - static: "[boolean] whether this is a static private setter" - }, - $documentation: "A private setter property", - computed_key() { - return false; - } -}, AST_ObjectProperty); - -var AST_PrivateGetter = DEFNODE("PrivateGetter", "static", function AST_PrivateGetter(props) { - if (props) { - this.static = props.static; - this.key = props.key; - this.value = props.value; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $propdoc: { - static: "[boolean] whether this is a static private getter" - }, - $documentation: "A private getter property", - computed_key() { - return false; - } -}, AST_ObjectProperty); - -var AST_ObjectSetter = DEFNODE("ObjectSetter", "quote static", function AST_ObjectSetter(props) { - if (props) { - this.quote = props.quote; - this.static = props.static; - this.key = props.key; - this.value = props.value; - this.start = props.start; - this.end = props.end; - this._annotations = props._annotations; - } - - this.flags = 0; -}, { - $propdoc: { - quote: "[string|undefined] the original quote character, if any", - static: "[boolean] whether this is a static setter (classes only)" - }, - $documentation: "An object setter property", - computed_key() { - return !(this.key instanceof AST_SymbolMethod); - } -}, AST_ObjectProperty); - -var AST_ObjectGetter = DEFNODE("ObjectGetter", "quote static", function AST_ObjectGetter(props) { - if (props) { - this.quote = props.quote; - this.static = props.static; - this.key = props.key; - this.value = props.value; - this.start = props.start; - this.end = props.end; - this._annotations = props._annotations; - } - - this.flags = 0; -}, { - $propdoc: { - quote: "[string|undefined] the original quote character, if any", - static: "[boolean] whether this is a static getter (classes only)" - }, - $documentation: "An object getter property", - computed_key() { - return !(this.key instanceof AST_SymbolMethod); - } -}, AST_ObjectProperty); - -var AST_ConciseMethod = DEFNODE( - "ConciseMethod", - "quote static is_generator async", - function AST_ConciseMethod(props) { - if (props) { - this.quote = props.quote; - this.static = props.static; - this.is_generator = props.is_generator; - this.async = props.async; - this.key = props.key; - this.value = props.value; - this.start = props.start; - this.end = props.end; - this._annotations = props._annotations; - } - - this.flags = 0; - }, - { - $propdoc: { - quote: "[string|undefined] the original quote character, if any", - static: "[boolean] is this method static (classes only)", - is_generator: "[boolean] is this a generator method", - async: "[boolean] is this method async", - }, - $documentation: "An ES6 concise method inside an object or class", - computed_key() { - return !(this.key instanceof AST_SymbolMethod); - } - }, - AST_ObjectProperty -); - -var AST_PrivateMethod = DEFNODE("PrivateMethod", "", function AST_PrivateMethod(props) { - if (props) { - this.quote = props.quote; - this.static = props.static; - this.is_generator = props.is_generator; - this.async = props.async; - this.key = props.key; - this.value = props.value; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A private class method inside a class", -}, AST_ConciseMethod); - -var AST_Class = DEFNODE("Class", "name extends properties", function AST_Class(props) { - if (props) { - this.name = props.name; - this.extends = props.extends; - this.properties = props.properties; - this.variables = props.variables; - this.uses_with = props.uses_with; - this.uses_eval = props.uses_eval; - this.parent_scope = props.parent_scope; - this.enclosed = props.enclosed; - this.cname = props.cname; - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $propdoc: { - name: "[AST_SymbolClass|AST_SymbolDefClass?] optional class name.", - extends: "[AST_Node]? optional parent class", - properties: "[AST_ObjectProperty*] array of properties" - }, - $documentation: "An ES6 class", - _walk: function(visitor) { - return visitor._visit(this, function() { - if (this.name) { - this.name._walk(visitor); - } - if (this.extends) { - this.extends._walk(visitor); - } - this.properties.forEach((prop) => prop._walk(visitor)); - }); - }, - _children_backwards(push) { - let i = this.properties.length; - while (i--) push(this.properties[i]); - if (this.extends) push(this.extends); - if (this.name) push(this.name); - }, - /** go through the bits that are executed instantly, not when the class is `new`'d. Doesn't walk the name. */ - visit_nondeferred_class_parts(visitor) { - if (this.extends) { - this.extends._walk(visitor); - } - this.properties.forEach((prop) => { - if (prop instanceof AST_ClassStaticBlock) { - prop._walk(visitor); - return; - } - if (prop.computed_key()) { - visitor.push(prop); - prop.key._walk(visitor); - visitor.pop(); - } - if ((prop instanceof AST_ClassPrivateProperty || prop instanceof AST_ClassProperty) && prop.static && prop.value) { - visitor.push(prop); - prop.value._walk(visitor); - visitor.pop(); - } - }); - }, - /** go through the bits that are executed later, when the class is `new`'d or a static method is called */ - visit_deferred_class_parts(visitor) { - this.properties.forEach((prop) => { - if (prop instanceof AST_ConciseMethod) { - prop.walk(visitor); - } else if (prop instanceof AST_ClassProperty && !prop.static && prop.value) { - visitor.push(prop); - prop.value._walk(visitor); - visitor.pop(); - } - }); - }, - is_self_referential: function() { - const this_id = this.name && this.name.definition().id; - let found = false; - let class_this = true; - this.visit_nondeferred_class_parts(new TreeWalker((node, descend) => { - if (found) return true; - if (node instanceof AST_This) return (found = class_this); - if (node instanceof AST_SymbolRef) return (found = node.definition().id === this_id); - if (node instanceof AST_Lambda && !(node instanceof AST_Arrow)) { - const class_this_save = class_this; - class_this = false; - descend(); - class_this = class_this_save; - return true; - } - })); - return found; - }, -}, AST_Scope /* TODO a class might have a scope but it's not a scope */); - -var AST_ClassProperty = DEFNODE("ClassProperty", "static quote", function AST_ClassProperty(props) { - if (props) { - this.static = props.static; - this.quote = props.quote; - this.key = props.key; - this.value = props.value; - this.start = props.start; - this.end = props.end; - this._annotations = props._annotations; - } - - this.flags = 0; -}, { - $documentation: "A class property", - $propdoc: { - static: "[boolean] whether this is a static key", - quote: "[string] which quote is being used" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - if (this.key instanceof AST_Node) - this.key._walk(visitor); - if (this.value instanceof AST_Node) - this.value._walk(visitor); - }); - }, - _children_backwards(push) { - if (this.value instanceof AST_Node) push(this.value); - if (this.key instanceof AST_Node) push(this.key); - }, - computed_key() { - return !(this.key instanceof AST_SymbolClassProperty); - } -}, AST_ObjectProperty); - -var AST_ClassPrivateProperty = DEFNODE("ClassPrivateProperty", "", function AST_ClassPrivateProperty(props) { - if (props) { - this.static = props.static; - this.quote = props.quote; - this.key = props.key; - this.value = props.value; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A class property for a private property", -}, AST_ClassProperty); - -var AST_PrivateIn = DEFNODE("PrivateIn", "key value", function AST_PrivateIn(props) { - if (props) { - this.key = props.key; - this.value = props.value; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "An `in` binop when the key is private, eg #x in this", - _walk: function(visitor) { - return visitor._visit(this, function() { - this.key._walk(visitor); - this.value._walk(visitor); - }); - }, - _children_backwards(push) { - push(this.value); - push(this.key); - }, -}); - -var AST_DefClass = DEFNODE("DefClass", null, function AST_DefClass(props) { - if (props) { - this.name = props.name; - this.extends = props.extends; - this.properties = props.properties; - this.variables = props.variables; - this.uses_with = props.uses_with; - this.uses_eval = props.uses_eval; - this.parent_scope = props.parent_scope; - this.enclosed = props.enclosed; - this.cname = props.cname; - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A class definition", -}, AST_Class); - -var AST_ClassStaticBlock = DEFNODE("ClassStaticBlock", "body block_scope", function AST_ClassStaticBlock (props) { - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; -}, { - $documentation: "A block containing statements to be executed in the context of the class", - $propdoc: { - body: "[AST_Statement*] an array of statements", - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - walk_body(this, visitor); - }); - }, - _children_backwards(push) { - let i = this.body.length; - while (i--) push(this.body[i]); - }, - clone: clone_block_scope, - computed_key: () => false -}, AST_Scope); - -var AST_ClassExpression = DEFNODE("ClassExpression", null, function AST_ClassExpression(props) { - if (props) { - this.name = props.name; - this.extends = props.extends; - this.properties = props.properties; - this.variables = props.variables; - this.uses_with = props.uses_with; - this.uses_eval = props.uses_eval; - this.parent_scope = props.parent_scope; - this.enclosed = props.enclosed; - this.cname = props.cname; - this.body = props.body; - this.block_scope = props.block_scope; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A class expression." -}, AST_Class); - -var AST_Symbol = DEFNODE("Symbol", "scope name thedef", function AST_Symbol(props) { - if (props) { - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $propdoc: { - name: "[string] name of this symbol", - scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)", - thedef: "[SymbolDef/S] the definition of this symbol" - }, - $documentation: "Base class for all symbols" -}); - -var AST_NewTarget = DEFNODE("NewTarget", null, function AST_NewTarget(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A reference to new.target" -}); - -var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", function AST_SymbolDeclaration(props) { - if (props) { - this.init = props.init; - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)", -}, AST_Symbol); - -var AST_SymbolVar = DEFNODE("SymbolVar", null, function AST_SymbolVar(props) { - if (props) { - this.init = props.init; - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Symbol defining a variable", -}, AST_SymbolDeclaration); - -var AST_SymbolBlockDeclaration = DEFNODE( - "SymbolBlockDeclaration", - null, - function AST_SymbolBlockDeclaration(props) { - if (props) { - this.init = props.init; - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; - }, - { - $documentation: "Base class for block-scoped declaration symbols" - }, - AST_SymbolDeclaration -); - -var AST_SymbolConst = DEFNODE("SymbolConst", null, function AST_SymbolConst(props) { - if (props) { - this.init = props.init; - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A constant declaration" -}, AST_SymbolBlockDeclaration); - -var AST_SymbolLet = DEFNODE("SymbolLet", null, function AST_SymbolLet(props) { - if (props) { - this.init = props.init; - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A block-scoped `let` declaration" -}, AST_SymbolBlockDeclaration); - -var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, function AST_SymbolFunarg(props) { - if (props) { - this.init = props.init; - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Symbol naming a function argument", -}, AST_SymbolVar); - -var AST_SymbolDefun = DEFNODE("SymbolDefun", null, function AST_SymbolDefun(props) { - if (props) { - this.init = props.init; - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Symbol defining a function", -}, AST_SymbolDeclaration); - -var AST_SymbolMethod = DEFNODE("SymbolMethod", null, function AST_SymbolMethod(props) { - if (props) { - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Symbol in an object defining a method", -}, AST_Symbol); - -var AST_SymbolClassProperty = DEFNODE("SymbolClassProperty", null, function AST_SymbolClassProperty(props) { - if (props) { - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Symbol for a class property", -}, AST_Symbol); - -var AST_SymbolLambda = DEFNODE("SymbolLambda", null, function AST_SymbolLambda(props) { - if (props) { - this.init = props.init; - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Symbol naming a function expression", -}, AST_SymbolDeclaration); - -var AST_SymbolDefClass = DEFNODE("SymbolDefClass", null, function AST_SymbolDefClass(props) { - if (props) { - this.init = props.init; - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Symbol naming a class's name in a class declaration. Lexically scoped to its containing scope, and accessible within the class." -}, AST_SymbolBlockDeclaration); - -var AST_SymbolClass = DEFNODE("SymbolClass", null, function AST_SymbolClass(props) { - if (props) { - this.init = props.init; - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Symbol naming a class's name. Lexically scoped to the class." -}, AST_SymbolDeclaration); - -var AST_SymbolCatch = DEFNODE("SymbolCatch", null, function AST_SymbolCatch(props) { - if (props) { - this.init = props.init; - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Symbol naming the exception in catch", -}, AST_SymbolBlockDeclaration); - -var AST_SymbolImport = DEFNODE("SymbolImport", null, function AST_SymbolImport(props) { - if (props) { - this.init = props.init; - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Symbol referring to an imported name", -}, AST_SymbolBlockDeclaration); - -var AST_SymbolImportForeign = DEFNODE("SymbolImportForeign", null, function AST_SymbolImportForeign(props) { - if (props) { - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.quote = props.quote; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $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", -}, AST_Symbol); - -var AST_Label = DEFNODE("Label", "references", function AST_Label(props) { - if (props) { - this.references = props.references; - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - this.initialize(); - } - - this.flags = 0; -}, { - $documentation: "Symbol naming a label (declaration)", - $propdoc: { - references: "[AST_LoopControl*] a list of nodes referring to this label" - }, - initialize: function() { - this.references = []; - this.thedef = this; - } -}, AST_Symbol); - -var AST_SymbolRef = DEFNODE("SymbolRef", null, function AST_SymbolRef(props) { - if (props) { - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Reference to some symbol (not definition/declaration)", -}, AST_Symbol); - -var AST_SymbolExport = DEFNODE("SymbolExport", null, function AST_SymbolExport(props) { - if (props) { - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.quote = props.quote; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Symbol referring to a name to export", -}, AST_SymbolRef); - -var AST_SymbolExportForeign = DEFNODE("SymbolExportForeign", null, function AST_SymbolExportForeign(props) { - if (props) { - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.quote = props.quote; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $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", -}, AST_Symbol); - -var AST_LabelRef = DEFNODE("LabelRef", null, function AST_LabelRef(props) { - if (props) { - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Reference to a label symbol", -}, AST_Symbol); - -var AST_SymbolPrivateProperty = DEFNODE("SymbolPrivateProperty", null, function AST_SymbolPrivateProperty(props) { - if (props) { - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A symbol that refers to a private property", -}, AST_Symbol); - -var AST_This = DEFNODE("This", null, function AST_This(props) { - if (props) { - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "The `this` symbol", -}, AST_Symbol); - -var AST_Super = DEFNODE("Super", null, function AST_Super(props) { - if (props) { - this.scope = props.scope; - this.name = props.name; - this.thedef = props.thedef; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "The `super` symbol", -}, AST_This); - -var AST_Constant = DEFNODE("Constant", null, function AST_Constant(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Base class for all constants", - getValue: function() { - return this.value; - } -}); - -var AST_String = DEFNODE("String", "value quote", function AST_String(props) { - if (props) { - this.value = props.value; - this.quote = props.quote; - this.start = props.start; - this.end = props.end; - this._annotations = props._annotations; - } - - this.flags = 0; -}, { - $documentation: "A string literal", - $propdoc: { - value: "[string] the contents of this string", - quote: "[string] the original quote character" - } -}, AST_Constant); - -var AST_Number = DEFNODE("Number", "value raw", function AST_Number(props) { - if (props) { - this.value = props.value; - this.raw = props.raw; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A number literal", - $propdoc: { - value: "[number] the numeric value", - raw: "[string] numeric value as string" - } -}, AST_Constant); - -var AST_BigInt = DEFNODE("BigInt", "value", function AST_BigInt(props) { - if (props) { - this.value = props.value; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A big int literal", - $propdoc: { - value: "[string] big int value" - } -}, AST_Constant); - -var AST_RegExp = DEFNODE("RegExp", "value", function AST_RegExp(props) { - if (props) { - this.value = props.value; - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A regexp literal", - $propdoc: { - value: "[RegExp] the actual regexp", - } -}, AST_Constant); - -var AST_Atom = DEFNODE("Atom", null, function AST_Atom(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Base class for atoms", -}, AST_Constant); - -var AST_Null = DEFNODE("Null", null, function AST_Null(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "The `null` atom", - value: null -}, AST_Atom); - -var AST_NaN = DEFNODE("NaN", null, function AST_NaN(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "The impossible value", - value: 0/0 -}, AST_Atom); - -var AST_Undefined = DEFNODE("Undefined", null, function AST_Undefined(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "The `undefined` value", - value: (function() {}()) -}, AST_Atom); - -var AST_Hole = DEFNODE("Hole", null, function AST_Hole(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "A hole in an array", - value: (function() {}()) -}, AST_Atom); - -var AST_Infinity = DEFNODE("Infinity", null, function AST_Infinity(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "The `Infinity` value", - value: 1/0 -}, AST_Atom); - -var AST_Boolean = DEFNODE("Boolean", null, function AST_Boolean(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "Base class for booleans", -}, AST_Atom); - -var AST_False = DEFNODE("False", null, function AST_False(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "The `false` atom", - value: false -}, AST_Boolean); - -var AST_True = DEFNODE("True", null, function AST_True(props) { - if (props) { - this.start = props.start; - this.end = props.end; - } - - this.flags = 0; -}, { - $documentation: "The `true` atom", - value: true -}, AST_Boolean); - -/* -----[ Walk function ]---- */ - -/** - * Walk nodes in depth-first search fashion. - * Callback can return `walk_abort` symbol to stop iteration. - * It can also return `true` to stop iteration just for child nodes. - * Iteration can be stopped and continued by passing the `to_visit` argument, - * which is given to the callback in the second argument. - **/ -function walk(node, cb, to_visit = [node]) { - const push = to_visit.push.bind(to_visit); - while (to_visit.length) { - const node = to_visit.pop(); - const ret = cb(node, to_visit); - - if (ret) { - if (ret === walk_abort) return true; - continue; - } - - node._children_backwards(push); - } - return false; -} - -/** - * Walks an AST node and its children. - * - * {cb} can return `walk_abort` to interrupt the walk. - * - * @param node - * @param cb {(node, info: { parent: (nth) => any }) => (boolean | undefined)} - * - * @returns {boolean} whether the walk was aborted - * - * @example - * const found_some_cond = walk_parent(my_ast_node, (node, { parent }) => { - * if (some_cond(node, parent())) return walk_abort - * }); - */ -function walk_parent(node, cb, initial_stack) { - const to_visit = [node]; - const push = to_visit.push.bind(to_visit); - const stack = initial_stack ? initial_stack.slice() : []; - const parent_pop_indices = []; - - let current; - - const info = { - parent: (n = 0) => { - if (n === -1) { - return current; - } - - // [ p1 p0 ] [ 1 0 ] - if (initial_stack && n >= stack.length) { - n -= stack.length; - return initial_stack[ - initial_stack.length - (n + 1) - ]; - } - - return stack[stack.length - (1 + n)]; - }, - }; - - while (to_visit.length) { - current = to_visit.pop(); - - while ( - parent_pop_indices.length && - to_visit.length == parent_pop_indices[parent_pop_indices.length - 1] - ) { - stack.pop(); - parent_pop_indices.pop(); - } - - const ret = cb(current, info); - - if (ret) { - if (ret === walk_abort) return true; - continue; - } - - const visit_length = to_visit.length; - - current._children_backwards(push); - - // Push only if we're going to traverse the children - if (to_visit.length > visit_length) { - stack.push(current); - parent_pop_indices.push(visit_length - 1); - } - } - - return false; -} - -const walk_abort = Symbol("abort walk"); - -/* -----[ TreeWalker ]----- */ - -class TreeWalker { - constructor(callback) { - this.visit = callback; - this.stack = []; - this.directives = Object.create(null); - } - - _visit(node, descend) { - this.push(node); - var ret = this.visit(node, descend ? function() { - descend.call(node); - } : noop); - if (!ret && descend) { - descend.call(node); - } - this.pop(); - return ret; - } - - parent(n) { - return this.stack[this.stack.length - 2 - (n || 0)]; - } - - push(node) { - if (node instanceof AST_Lambda) { - this.directives = Object.create(this.directives); - } else if (node instanceof AST_Directive && !this.directives[node.value]) { - this.directives[node.value] = node; - } else if (node instanceof AST_Class) { - this.directives = Object.create(this.directives); - if (!this.directives["use strict"]) { - this.directives["use strict"] = node; - } - } - this.stack.push(node); - } - - pop() { - var node = this.stack.pop(); - if (node instanceof AST_Lambda || node instanceof AST_Class) { - this.directives = Object.getPrototypeOf(this.directives); - } - } - - self() { - return this.stack[this.stack.length - 1]; - } - - find_parent(type) { - var stack = this.stack; - for (var i = stack.length; --i >= 0;) { - var x = stack[i]; - if (x instanceof type) return x; - } - } - - find_scope() { - var stack = this.stack; - for (var i = stack.length; --i >= 0;) { - const p = stack[i]; - if (p instanceof AST_Toplevel) return p; - if (p instanceof AST_Lambda) return p; - if (p.block_scope) return p.block_scope; - } - } - - has_directive(type) { - var dir = this.directives[type]; - if (dir) return dir; - var node = this.stack[this.stack.length - 1]; - if (node instanceof AST_Scope && node.body) { - for (var i = 0; i < node.body.length; ++i) { - var st = node.body[i]; - if (!(st instanceof AST_Directive)) break; - if (st.value == type) return st; - } - } - } - - loopcontrol_target(node) { - var stack = this.stack; - if (node.label) for (var i = stack.length; --i >= 0;) { - var x = stack[i]; - if (x instanceof AST_LabeledStatement && x.label.name == node.label.name) - return x.body; - } else for (var i = stack.length; --i >= 0;) { - var x = stack[i]; - if (x instanceof AST_IterationStatement - || node instanceof AST_Break && x instanceof AST_Switch) - return x; - } - } -} - -// Tree transformer helpers. -class TreeTransformer extends TreeWalker { - constructor(before, after) { - super(); - this.before = before; - this.after = after; - } -} - -const _PURE = 0b00000001; -const _INLINE = 0b00000010; -const _NOINLINE = 0b00000100; -const _KEY = 0b00001000; -const _MANGLEPROP = 0b00010000; - -export { - AST_Accessor, - AST_Array, - AST_Arrow, - AST_Assign, - AST_Atom, - AST_Await, - AST_BigInt, - AST_Binary, - AST_Block, - AST_BlockStatement, - AST_Boolean, - AST_Break, - AST_Call, - AST_Case, - AST_Catch, - AST_Chain, - AST_Class, - AST_ClassExpression, - AST_ClassPrivateProperty, - AST_PrivateIn, - AST_ClassProperty, - AST_ClassStaticBlock, - AST_ConciseMethod, - AST_Conditional, - AST_Const, - AST_Constant, - AST_Continue, - AST_Debugger, - AST_Default, - AST_DefaultAssign, - AST_DefClass, - AST_Definitions, - AST_Defun, - AST_Destructuring, - AST_Directive, - AST_Do, - AST_Dot, - AST_DotHash, - AST_DWLoop, - AST_EmptyStatement, - AST_Exit, - AST_Expansion, - AST_Export, - AST_False, - AST_Finally, - AST_For, - AST_ForIn, - AST_ForOf, - AST_Function, - AST_Hole, - AST_If, - AST_Import, - AST_ImportMeta, - AST_Infinity, - AST_IterationStatement, - AST_Jump, - AST_Label, - AST_LabeledStatement, - AST_LabelRef, - AST_Lambda, - AST_Let, - AST_LoopControl, - AST_NameMapping, - AST_NaN, - AST_New, - AST_NewTarget, - AST_Node, - AST_Null, - AST_Number, - AST_Object, - AST_ObjectGetter, - AST_ObjectKeyVal, - AST_ObjectProperty, - AST_ObjectSetter, - AST_PrefixedTemplateString, - AST_PrivateGetter, - AST_PrivateMethod, - AST_PrivateSetter, - AST_PropAccess, - AST_RegExp, - AST_Return, - AST_Scope, - AST_Sequence, - AST_SimpleStatement, - AST_Statement, - AST_StatementWithBody, - AST_String, - AST_Sub, - AST_Super, - AST_Switch, - AST_SwitchBranch, - AST_Symbol, - AST_SymbolBlockDeclaration, - AST_SymbolCatch, - AST_SymbolClass, - AST_SymbolClassProperty, - AST_SymbolConst, - AST_SymbolDeclaration, - AST_SymbolDefClass, - AST_SymbolDefun, - AST_SymbolExport, - AST_SymbolExportForeign, - AST_SymbolFunarg, - AST_SymbolImport, - AST_SymbolImportForeign, - AST_SymbolLambda, - AST_SymbolLet, - AST_SymbolMethod, - AST_SymbolRef, - AST_SymbolVar, - AST_TemplateSegment, - AST_TemplateString, - AST_SymbolPrivateProperty, - AST_This, - AST_Throw, - AST_Token, - AST_Toplevel, - AST_True, - AST_Try, - AST_TryBlock, - AST_Unary, - AST_UnaryPostfix, - AST_UnaryPrefix, - AST_Undefined, - AST_Var, - AST_VarDef, - AST_While, - AST_With, - AST_Yield, - - // Walkers - TreeTransformer, - TreeWalker, - walk, - walk_abort, - walk_body, - walk_parent, - - // annotations - _INLINE, - _NOINLINE, - _PURE, - _KEY, - _MANGLEPROP, -}; |
