1/***********************************************************************
2
3  A JavaScript tokenizer / parser / beautifier / compressor.
4  https://github.com/mishoo/UglifyJS
5
6  -------------------------------- (C) ---------------------------------
7
8                           Author: Mihai Bazon
9                         <mihai.bazon@gmail.com>
10                       http://mihai.bazon.net/blog
11
12  Distributed under the BSD license:
13
14    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
15
16    Redistribution and use in source and binary forms, with or without
17    modification, are permitted provided that the following conditions
18    are met:
19
20        * Redistributions of source code must retain the above
21          copyright notice, this list of conditions and the following
22          disclaimer.
23
24        * Redistributions in binary form must reproduce the above
25          copyright notice, this list of conditions and the following
26          disclaimer in the documentation and/or other materials
27          provided with the distribution.
28
29    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
30    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
33    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
34    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
35    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
36    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
38    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
39    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40    SUCH DAMAGE.
41
42 ***********************************************************************/
43
44"use strict";
45
46(function() {
47    var MOZ_TO_ME = {
48        Program: function(M) {
49            return new AST_Toplevel({
50                start: my_start_token(M),
51                end: my_end_token(M),
52                body: normalize_directives(M.body.map(from_moz)),
53            });
54        },
55        ArrowFunctionExpression: function(M) {
56            var argnames = [], rest = null;
57            M.params.forEach(function(param) {
58                if (param.type == "RestElement") {
59                    rest = from_moz(param.argument);
60                } else {
61                    argnames.push(from_moz(param));
62                }
63            });
64            var fn = new (M.async ? AST_AsyncArrow : AST_Arrow)({
65                start: my_start_token(M),
66                end: my_end_token(M),
67                argnames: argnames,
68                rest: rest,
69            });
70            var node = from_moz(M.body);
71            if (node instanceof AST_BlockStatement) {
72                fn.body = normalize_directives(node.body);
73                fn.value = null;
74            } else {
75                fn.body = [];
76                fn.value = node;
77            }
78            return fn;
79        },
80        FunctionDeclaration: function(M) {
81            var ctor;
82            if (M.async) {
83                ctor = M.generator ? AST_AsyncGeneratorDefun : AST_AsyncDefun;
84            } else {
85                ctor = M.generator ? AST_GeneratorDefun : AST_Defun;
86            }
87            var argnames = [], rest = null;
88            M.params.forEach(function(param) {
89                if (param.type == "RestElement") {
90                    rest = from_moz(param.argument);
91                } else {
92                    argnames.push(from_moz(param));
93                }
94            });
95            return new ctor({
96                start: my_start_token(M),
97                end: my_end_token(M),
98                name: from_moz(M.id),
99                argnames: argnames,
100                rest: rest,
101                body: normalize_directives(from_moz(M.body).body),
102            });
103        },
104        FunctionExpression: function(M) {
105            var ctor;
106            if (M.async) {
107                ctor = M.generator ? AST_AsyncGeneratorFunction : AST_AsyncFunction;
108            } else {
109                ctor = M.generator ? AST_GeneratorFunction : AST_Function;
110            }
111            var argnames = [], rest = null;
112            M.params.forEach(function(param) {
113                if (param.type == "RestElement") {
114                    rest = from_moz(param.argument);
115                } else {
116                    argnames.push(from_moz(param));
117                }
118            });
119            return new ctor({
120                start: my_start_token(M),
121                end: my_end_token(M),
122                name: from_moz(M.id),
123                argnames: argnames,
124                rest: rest,
125                body: normalize_directives(from_moz(M.body).body),
126            });
127        },
128        ClassDeclaration: function(M) {
129            return new AST_DefClass({
130                start: my_start_token(M),
131                end: my_end_token(M),
132                name: from_moz(M.id),
133                extends: from_moz(M.superClass),
134                properties: M.body.body.map(from_moz),
135            });
136        },
137        ClassExpression: function(M) {
138            return new AST_ClassExpression({
139                start: my_start_token(M),
140                end: my_end_token(M),
141                name: from_moz(M.id),
142                extends: from_moz(M.superClass),
143                properties: M.body.body.map(from_moz),
144            });
145        },
146        MethodDefinition: function(M) {
147            var key = M.key, internal = false;
148            if (M.computed) {
149                key = from_moz(key);
150            } else if (key.type == "PrivateIdentifier") {
151                internal = true;
152                key = "#" + key.name;
153            } else {
154                key = read_name(key);
155            }
156            var ctor = AST_ClassMethod, value = from_moz(M.value);
157            switch (M.kind) {
158              case "get":
159                ctor = AST_ClassGetter;
160                value = new AST_Accessor(value);
161                break;
162              case "set":
163                ctor = AST_ClassSetter;
164                value = new AST_Accessor(value);
165                break;
166            }
167            return new ctor({
168                start: my_start_token(M),
169                end: my_end_token(M),
170                key: key,
171                private: internal,
172                static: M.static,
173                value: value,
174            });
175        },
176        PropertyDefinition: function(M) {
177            var key = M.key, internal = false;
178            if (M.computed) {
179                key = from_moz(key);
180            } else if (key.type == "PrivateIdentifier") {
181                internal = true;
182                key = "#" + key.name;
183            } else {
184                key = read_name(key);
185            }
186            return new AST_ClassField({
187                start: my_start_token(M),
188                end: my_end_token(M),
189                key: key,
190                private: internal,
191                static: M.static,
192                value: from_moz(M.value),
193            });
194        },
195        StaticBlock: function(M) {
196            var start = my_start_token(M);
197            var end = my_end_token(M);
198            return new AST_ClassInit({
199                start: start,
200                end: end,
201                value: new AST_ClassInitBlock({
202                    start: start,
203                    end: end,
204                    body: normalize_directives(M.body.map(from_moz)),
205                }),
206            });
207        },
208        ForOfStatement: function(M) {
209            return new (M.await ? AST_ForAwaitOf : AST_ForOf)({
210                start: my_start_token(M),
211                end: my_end_token(M),
212                init: from_moz(M.left),
213                object: from_moz(M.right),
214                body: from_moz(M.body),
215            });
216        },
217        TryStatement: function(M) {
218            var handlers = M.handlers || [M.handler];
219            if (handlers.length > 1 || M.guardedHandlers && M.guardedHandlers.length) {
220                throw new Error("Multiple catch clauses are not supported.");
221            }
222            return new AST_Try({
223                start    : my_start_token(M),
224                end      : my_end_token(M),
225                body     : from_moz(M.block).body,
226                bcatch   : from_moz(handlers[0]),
227                bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null,
228            });
229        },
230        Property: function(M) {
231            var key = M.computed ? from_moz(M.key) : read_name(M.key);
232            var args = {
233                start: my_start_token(M),
234                end: my_end_token(M),
235                key: key,
236                value: from_moz(M.value),
237            };
238            if (M.kind == "init") return new (M.method ? AST_ObjectMethod : AST_ObjectKeyVal)(args);
239            args.value = new AST_Accessor(args.value);
240            if (M.kind == "get") return new AST_ObjectGetter(args);
241            if (M.kind == "set") return new AST_ObjectSetter(args);
242        },
243        ArrayExpression: function(M) {
244            return new AST_Array({
245                start: my_start_token(M),
246                end: my_end_token(M),
247                elements: M.elements.map(function(elem) {
248                    return elem === null ? new AST_Hole() : from_moz(elem);
249                }),
250            });
251        },
252        ArrayPattern: function(M) {
253            var elements = [], rest = null;
254            M.elements.forEach(function(el) {
255                if (el === null) {
256                    elements.push(new AST_Hole());
257                } else if (el.type == "RestElement") {
258                    rest = from_moz(el.argument);
259                } else {
260                    elements.push(from_moz(el));
261                }
262            });
263            return new AST_DestructuredArray({
264                start: my_start_token(M),
265                end: my_end_token(M),
266                elements: elements,
267                rest: rest,
268            });
269        },
270        ObjectPattern: function(M) {
271            var props = [], rest = null;
272            M.properties.forEach(function(prop) {
273                if (prop.type == "RestElement") {
274                    rest = from_moz(prop.argument);
275                } else {
276                    props.push(new AST_DestructuredKeyVal(from_moz(prop)));
277                }
278            });
279            return new AST_DestructuredObject({
280                start: my_start_token(M),
281                end: my_end_token(M),
282                properties: props,
283                rest: rest,
284            });
285        },
286        MemberExpression: function(M) {
287            return new (M.computed ? AST_Sub : AST_Dot)({
288                start: my_start_token(M),
289                end: my_end_token(M),
290                optional: M.optional,
291                expression: from_moz(M.object),
292                property: M.computed ? from_moz(M.property) : M.property.name,
293            });
294        },
295        MetaProperty: function(M) {
296            var expr = from_moz(M.meta);
297            var prop = read_name(M.property);
298            if (expr.name == "new" && prop == "target") return new AST_NewTarget({
299                start: my_start_token(M),
300                end: my_end_token(M),
301                name: "new.target",
302            });
303            return new AST_Dot({
304                start: my_start_token(M),
305                end: my_end_token(M),
306                expression: expr,
307                property: prop,
308            });
309        },
310        SwitchCase: function(M) {
311            return new (M.test ? AST_Case : AST_Default)({
312                start      : my_start_token(M),
313                end        : my_end_token(M),
314                expression : from_moz(M.test),
315                body       : M.consequent.map(from_moz),
316            });
317        },
318        ExportAllDeclaration: function(M) {
319            var start = my_start_token(M);
320            var end = my_end_token(M);
321            return new AST_ExportForeign({
322                start: start,
323                end: end,
324                aliases: [ M.exported ? from_moz_alias(M.exported) : new AST_String({
325                    start: start,
326                    value: "*",
327                    end: end,
328                }) ],
329                keys: [ new AST_String({
330                    start: start,
331                    value: "*",
332                    end: end,
333                }) ],
334                path: from_moz(M.source),
335            });
336        },
337        ExportDefaultDeclaration: function(M) {
338            var decl = from_moz(M.declaration);
339            if (!decl.name) switch (decl.CTOR) {
340              case AST_AsyncDefun:
341                decl = new AST_AsyncFunction(decl);
342                break;
343              case AST_AsyncGeneratorDefun:
344                decl = new AST_AsyncGeneratorFunction(decl);
345                break;
346              case AST_DefClass:
347                decl = new AST_ClassExpression(decl);
348                break;
349              case AST_Defun:
350                decl = new AST_Function(decl);
351                break;
352              case AST_GeneratorDefun:
353                decl = new AST_GeneratorFunction(decl);
354                break;
355            }
356            return new AST_ExportDefault({
357                start: my_start_token(M),
358                end: my_end_token(M),
359                body: decl,
360            });
361        },
362        ExportNamedDeclaration: function(M) {
363            if (M.declaration) return new AST_ExportDeclaration({
364                start: my_start_token(M),
365                end: my_end_token(M),
366                body: from_moz(M.declaration),
367            });
368            if (M.source) {
369                var aliases = [], keys = [];
370                M.specifiers.forEach(function(prop) {
371                    aliases.push(from_moz_alias(prop.exported));
372                    keys.push(from_moz_alias(prop.local));
373                });
374                return new AST_ExportForeign({
375                    start: my_start_token(M),
376                    end: my_end_token(M),
377                    aliases: aliases,
378                    keys: keys,
379                    path: from_moz(M.source),
380                });
381            }
382            return new AST_ExportReferences({
383                start: my_start_token(M),
384                end: my_end_token(M),
385                properties: M.specifiers.map(function(prop) {
386                    var sym = new AST_SymbolExport(from_moz(prop.local));
387                    sym.alias = from_moz_alias(prop.exported);
388                    return sym;
389                }),
390            });
391        },
392        ImportDeclaration: function(M) {
393            var start = my_start_token(M);
394            var end = my_end_token(M);
395            var all = null, def = null, props = null;
396            M.specifiers.forEach(function(prop) {
397                var sym = new AST_SymbolImport(from_moz(prop.local));
398                switch (prop.type) {
399                  case "ImportDefaultSpecifier":
400                    def = sym;
401                    def.key = new AST_String({
402                        start: start,
403                        value: "",
404                        end: end,
405                    });
406                    break;
407                  case "ImportNamespaceSpecifier":
408                    all = sym;
409                    all.key = new AST_String({
410                        start: start,
411                        value: "*",
412                        end: end,
413                    });
414                    break;
415                  default:
416                    sym.key = from_moz_alias(prop.imported);
417                    if (!props) props = [];
418                    props.push(sym);
419                    break;
420                }
421            });
422            return new AST_Import({
423                start: start,
424                end: end,
425                all: all,
426                default: def,
427                properties: props,
428                path: from_moz(M.source),
429            });
430        },
431        ImportExpression: function(M) {
432            var start = my_start_token(M);
433            var arg = from_moz(M.source);
434            return new AST_Call({
435                start: start,
436                end: my_end_token(M),
437                expression: new AST_SymbolRef({
438                    start: start,
439                    end: arg.start,
440                    name: "import",
441                }),
442                args: [ arg ],
443            });
444        },
445        VariableDeclaration: function(M) {
446            return new ({
447                const: AST_Const,
448                let: AST_Let,
449            }[M.kind] || AST_Var)({
450                start: my_start_token(M),
451                end: my_end_token(M),
452                definitions: M.declarations.map(from_moz),
453            });
454        },
455        Literal: function(M) {
456            var args = {
457                start: my_start_token(M),
458                end: my_end_token(M),
459            };
460            if (M.bigint) {
461                args.value = M.bigint.toLowerCase() + "n";
462                return new AST_BigInt(args);
463            }
464            var val = M.value;
465            if (val === null) return new AST_Null(args);
466            var rx = M.regex;
467            if (rx && rx.pattern) {
468                // RegExpLiteral as per ESTree AST spec
469                args.value = new RegExp(rx.pattern, rx.flags);
470                args.value.raw_source = rx.pattern;
471                return new AST_RegExp(args);
472            } else if (rx) {
473                // support legacy RegExp
474                args.value = M.regex && M.raw ? M.raw : val;
475                return new AST_RegExp(args);
476            }
477            switch (typeof val) {
478              case "string":
479                args.value = val;
480                return new AST_String(args);
481              case "number":
482                if (isNaN(val)) return new AST_NaN(args);
483                var negate, node;
484                if (isFinite(val)) {
485                    negate = 1 / val < 0;
486                    args.value = negate ? -val : val;
487                    node = new AST_Number(args);
488                } else {
489                    negate = val < 0;
490                    node = new AST_Infinity(args);
491                }
492                return negate ? new AST_UnaryPrefix({
493                    start: args.start,
494                    end: args.end,
495                    operator: "-",
496                    expression: node,
497                }) : node;
498              case "boolean":
499                return new (val ? AST_True : AST_False)(args);
500            }
501        },
502        TemplateLiteral: function(M) {
503            return new AST_Template({
504                start: my_start_token(M),
505                end: my_end_token(M),
506                expressions: M.expressions.map(from_moz),
507                strings: M.quasis.map(function(el) {
508                    return el.value.raw;
509                }),
510            });
511        },
512        TaggedTemplateExpression: function(M) {
513            var tmpl = from_moz(M.quasi);
514            tmpl.start = my_start_token(M);
515            tmpl.end = my_end_token(M);
516            tmpl.tag = from_moz(M.tag);
517            return tmpl;
518        },
519        Identifier: function(M) {
520            var p, level = FROM_MOZ_STACK.length - 1;
521            do {
522                p = FROM_MOZ_STACK[--level];
523            } while (p.type == "ArrayPattern"
524                || p.type == "AssignmentPattern" && p.left === FROM_MOZ_STACK[level + 1]
525                || p.type == "ObjectPattern"
526                || p.type == "Property" && p.value === FROM_MOZ_STACK[level + 1]
527                || p.type == "VariableDeclarator" && p.id === FROM_MOZ_STACK[level + 1]);
528            var ctor = AST_SymbolRef;
529            switch (p.type) {
530              case "ArrowFunctionExpression":
531                if (p.body !== FROM_MOZ_STACK[level + 1]) ctor = AST_SymbolFunarg;
532                break;
533              case "BreakStatement":
534              case "ContinueStatement":
535                ctor = AST_LabelRef;
536                break;
537              case "CatchClause":
538                ctor = AST_SymbolCatch;
539                break;
540              case "ClassDeclaration":
541                if (p.id === FROM_MOZ_STACK[level + 1]) ctor = AST_SymbolDefClass;
542                break;
543              case "ClassExpression":
544                if (p.id === FROM_MOZ_STACK[level + 1]) ctor = AST_SymbolClass;
545                break;
546              case "FunctionDeclaration":
547                ctor = p.id === FROM_MOZ_STACK[level + 1] ? AST_SymbolDefun : AST_SymbolFunarg;
548                break;
549              case "FunctionExpression":
550                ctor = p.id === FROM_MOZ_STACK[level + 1] ? AST_SymbolLambda : AST_SymbolFunarg;
551                break;
552              case "LabeledStatement":
553                ctor = AST_Label;
554                break;
555              case "VariableDeclaration":
556                ctor = {
557                    const: AST_SymbolConst,
558                    let: AST_SymbolLet,
559                }[p.kind] || AST_SymbolVar;
560                break;
561            }
562            return new ctor({
563                start: my_start_token(M),
564                end: my_end_token(M),
565                name: M.name,
566            });
567        },
568        Super: function(M) {
569            return new AST_Super({
570                start: my_start_token(M),
571                end: my_end_token(M),
572                name: "super",
573            });
574        },
575        ThisExpression: function(M) {
576            return new AST_This({
577                start: my_start_token(M),
578                end: my_end_token(M),
579                name: "this",
580            });
581        },
582        ParenthesizedExpression: function(M) {
583            var node = from_moz(M.expression);
584            if (!node.start.parens) node.start.parens = [];
585            node.start.parens.push(my_start_token(M));
586            if (!node.end.parens) node.end.parens = [];
587            node.end.parens.push(my_end_token(M));
588            return node;
589        },
590        ChainExpression: function(M) {
591            var node = from_moz(M.expression);
592            node.terminal = true;
593            return node;
594        },
595    };
596
597    MOZ_TO_ME.UpdateExpression =
598    MOZ_TO_ME.UnaryExpression = function To_Moz_Unary(M) {
599        var prefix = "prefix" in M ? M.prefix
600            : M.type == "UnaryExpression" ? true : false;
601        return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({
602            start      : my_start_token(M),
603            end        : my_end_token(M),
604            operator   : M.operator,
605            expression : from_moz(M.argument)
606        });
607    };
608
609    map("EmptyStatement", AST_EmptyStatement);
610    map("ExpressionStatement", AST_SimpleStatement, "expression>body");
611    map("BlockStatement", AST_BlockStatement, "body@body");
612    map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative");
613    map("LabeledStatement", AST_LabeledStatement, "label>label, body>body");
614    map("BreakStatement", AST_Break, "label>label");
615    map("ContinueStatement", AST_Continue, "label>label");
616    map("WithStatement", AST_With, "object>expression, body>body");
617    map("SwitchStatement", AST_Switch, "discriminant>expression, cases@body");
618    map("ReturnStatement", AST_Return, "argument>value");
619    map("ThrowStatement", AST_Throw, "argument>value");
620    map("WhileStatement", AST_While, "test>condition, body>body");
621    map("DoWhileStatement", AST_Do, "test>condition, body>body");
622    map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body");
623    map("ForInStatement", AST_ForIn, "left>init, right>object, body>body");
624    map("DebuggerStatement", AST_Debugger);
625    map("VariableDeclarator", AST_VarDef, "id>name, init>value");
626    map("CatchClause", AST_Catch, "param>argname, body%body");
627
628    map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right");
629    map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right");
630    map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right");
631    map("AssignmentPattern", AST_DefaultValue, "left>name, right>value");
632    map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative");
633    map("NewExpression", AST_New, "callee>expression, arguments@args, pure=pure");
634    map("CallExpression", AST_Call, "callee>expression, arguments@args, optional=optional, pure=pure");
635    map("SequenceExpression", AST_Sequence, "expressions@expressions");
636    map("SpreadElement", AST_Spread, "argument>expression");
637    map("ObjectExpression", AST_Object, "properties@properties");
638    map("AwaitExpression", AST_Await, "argument>expression");
639    map("YieldExpression", AST_Yield, "argument>expression, delegate=nested");
640
641    def_to_moz(AST_Toplevel, function To_Moz_Program(M) {
642        return to_moz_scope("Program", M);
643    });
644
645    def_to_moz(AST_LambdaDefinition, function To_Moz_FunctionDeclaration(M) {
646        var params = M.argnames.map(to_moz);
647        if (M.rest) params.push({
648            type: "RestElement",
649            argument: to_moz(M.rest),
650        });
651        return {
652            type: "FunctionDeclaration",
653            id: to_moz(M.name),
654            async: is_async(M),
655            generator: is_generator(M),
656            params: params,
657            body: to_moz_scope("BlockStatement", M),
658        };
659    });
660
661    def_to_moz(AST_Lambda, function To_Moz_FunctionExpression(M) {
662        var params = M.argnames.map(to_moz);
663        if (M.rest) params.push({
664            type: "RestElement",
665            argument: to_moz(M.rest),
666        });
667        if (is_arrow(M)) return {
668            type: "ArrowFunctionExpression",
669            async: is_async(M),
670            params: params,
671            body: M.value ? to_moz(M.value) : to_moz_scope("BlockStatement", M),
672        };
673        return {
674            type: "FunctionExpression",
675            id: to_moz(M.name),
676            async: is_async(M),
677            generator: is_generator(M),
678            params: params,
679            body: to_moz_scope("BlockStatement", M),
680        };
681    });
682
683    def_to_moz(AST_DefClass, function To_Moz_ClassDeclaration(M) {
684        return {
685            type: "ClassDeclaration",
686            id: to_moz(M.name),
687            superClass: to_moz(M.extends),
688            body: {
689                type: "ClassBody",
690                body: M.properties.map(to_moz),
691            },
692        };
693    });
694
695    def_to_moz(AST_ClassExpression, function To_Moz_ClassExpression(M) {
696        return {
697            type: "ClassExpression",
698            id: to_moz(M.name),
699            superClass: to_moz(M.extends),
700            body: {
701                type: "ClassBody",
702                body: M.properties.map(to_moz),
703            },
704        };
705    });
706
707    function To_Moz_MethodDefinition(kind) {
708        return function(M) {
709            var computed = M.key instanceof AST_Node;
710            var key = computed ? to_moz(M.key) : M.private ? {
711                type: "PrivateIdentifier",
712                name: M.key.slice(1),
713            } : {
714                type: "Literal",
715                value: M.key,
716            };
717            return {
718                type: "MethodDefinition",
719                kind: kind,
720                computed: computed,
721                key: key,
722                static: M.static,
723                value: to_moz(M.value),
724            };
725        };
726    }
727    def_to_moz(AST_ClassGetter, To_Moz_MethodDefinition("get"));
728    def_to_moz(AST_ClassSetter, To_Moz_MethodDefinition("set"));
729    def_to_moz(AST_ClassMethod, To_Moz_MethodDefinition("method"));
730
731    def_to_moz(AST_ClassField, function To_Moz_PropertyDefinition(M) {
732        var computed = M.key instanceof AST_Node;
733        var key = computed ? to_moz(M.key) : M.private ? {
734            type: "PrivateIdentifier",
735            name: M.key.slice(1),
736        } : {
737            type: "Literal",
738            value: M.key,
739        };
740        return {
741            type: "PropertyDefinition",
742            computed: computed,
743            key: key,
744            static: M.static,
745            value: to_moz(M.value),
746        };
747    });
748
749    def_to_moz(AST_ClassInit, function To_Moz_StaticBlock(M) {
750        return to_moz_scope("StaticBlock", M.value);
751    });
752
753    function To_Moz_ForOfStatement(is_await) {
754        return function(M) {
755            return {
756                type: "ForOfStatement",
757                await: is_await,
758                left: to_moz(M.init),
759                right: to_moz(M.object),
760                body: to_moz(M.body),
761            };
762        };
763    }
764    def_to_moz(AST_ForAwaitOf, To_Moz_ForOfStatement(true));
765    def_to_moz(AST_ForOf, To_Moz_ForOfStatement(false));
766
767    def_to_moz(AST_Directive, function To_Moz_Directive(M) {
768        return {
769            type: "ExpressionStatement",
770            expression: set_moz_loc(M, {
771                type: "Literal",
772                value: M.value,
773            }),
774        };
775    });
776
777    def_to_moz(AST_SwitchBranch, function To_Moz_SwitchCase(M) {
778        return {
779            type: "SwitchCase",
780            test: to_moz(M.expression),
781            consequent: M.body.map(to_moz),
782        };
783    });
784
785    def_to_moz(AST_Try, function To_Moz_TryStatement(M) {
786        return {
787            type: "TryStatement",
788            block: to_moz_block(M),
789            handler: to_moz(M.bcatch),
790            guardedHandlers: [],
791            finalizer: to_moz(M.bfinally),
792        };
793    });
794
795    def_to_moz(AST_Catch, function To_Moz_CatchClause(M) {
796        return {
797            type: "CatchClause",
798            param: to_moz(M.argname),
799            guard: null,
800            body: to_moz_block(M),
801        };
802    });
803
804    def_to_moz(AST_ExportDeclaration, function To_Moz_ExportNamedDeclaration_declaration(M) {
805        return {
806            type: "ExportNamedDeclaration",
807            declaration: to_moz(M.body),
808        };
809    });
810
811    def_to_moz(AST_ExportDefault, function To_Moz_ExportDefaultDeclaration(M) {
812        return {
813            type: "ExportDefaultDeclaration",
814            declaration: to_moz(M.body),
815        };
816    });
817
818    def_to_moz(AST_ExportForeign, function To_Moz_ExportAllDeclaration_ExportNamedDeclaration(M) {
819        if (M.keys[0].value == "*") return {
820            type: "ExportAllDeclaration",
821            exported: M.aliases[0].value == "*" ? null : to_moz_alias(M.aliases[0]),
822            source: to_moz(M.path),
823        };
824        var specifiers = [];
825        for (var i = 0; i < M.aliases.length; i++) {
826            specifiers.push(set_moz_loc({
827                start: M.keys[i].start,
828                end: M.aliases[i].end,
829            }, {
830                type: "ExportSpecifier",
831                local: to_moz_alias(M.keys[i]),
832                exported: to_moz_alias(M.aliases[i]),
833            }));
834        }
835        return {
836            type: "ExportNamedDeclaration",
837            specifiers: specifiers,
838            source: to_moz(M.path),
839        };
840    });
841
842    def_to_moz(AST_ExportReferences, function To_Moz_ExportNamedDeclaration_specifiers(M) {
843        return {
844            type: "ExportNamedDeclaration",
845            specifiers: M.properties.map(function(prop) {
846                return set_moz_loc({
847                    start: prop.start,
848                    end: prop.alias.end,
849                }, {
850                    type: "ExportSpecifier",
851                    local: to_moz(prop),
852                    exported: to_moz_alias(prop.alias),
853                });
854            }),
855        };
856    });
857
858    def_to_moz(AST_Import, function To_Moz_ImportDeclaration(M) {
859        var specifiers = M.properties ? M.properties.map(function(prop) {
860            return set_moz_loc({
861                start: prop.key.start,
862                end: prop.end,
863            }, {
864                type: "ImportSpecifier",
865                local: to_moz(prop),
866                imported: to_moz_alias(prop.key),
867            });
868        }) : [];
869        if (M.all) specifiers.unshift(set_moz_loc(M.all, {
870            type: "ImportNamespaceSpecifier",
871            local: to_moz(M.all),
872        }));
873        if (M.default) specifiers.unshift(set_moz_loc(M.default, {
874            type: "ImportDefaultSpecifier",
875            local: to_moz(M.default),
876        }));
877        return {
878            type: "ImportDeclaration",
879            specifiers: specifiers,
880            source: to_moz(M.path),
881        };
882    });
883
884    def_to_moz(AST_Definitions, function To_Moz_VariableDeclaration(M) {
885        return {
886            type: "VariableDeclaration",
887            kind: M.TYPE.toLowerCase(),
888            declarations: M.definitions.map(to_moz),
889        };
890    });
891
892    def_to_moz(AST_PropAccess, function To_Moz_MemberExpression(M) {
893        var computed = M instanceof AST_Sub;
894        var expr = {
895            type: "MemberExpression",
896            object: to_moz(M.expression),
897            computed: computed,
898            optional: M.optional,
899            property: computed ? to_moz(M.property) : {
900                type: "Identifier",
901                name: M.property,
902            },
903        };
904        return M.terminal ? {
905            type: "ChainExpression",
906            expression: expr,
907        } : expr;
908    });
909
910    def_to_moz(AST_Unary, function To_Moz_Unary(M) {
911        return {
912            type: M.operator == "++" || M.operator == "--" ? "UpdateExpression" : "UnaryExpression",
913            operator: M.operator,
914            prefix: M instanceof AST_UnaryPrefix,
915            argument: to_moz(M.expression)
916        };
917    });
918
919    def_to_moz(AST_Binary, function To_Moz_BinaryExpression(M) {
920        return {
921            type: M.operator == "&&" || M.operator == "||" ? "LogicalExpression" : "BinaryExpression",
922            left: to_moz(M.left),
923            operator: M.operator,
924            right: to_moz(M.right)
925        };
926    });
927
928    def_to_moz(AST_Array, function To_Moz_ArrayExpression(M) {
929        return {
930            type: "ArrayExpression",
931            elements: M.elements.map(to_moz),
932        };
933    });
934
935    def_to_moz(AST_DestructuredArray, function To_Moz_ArrayPattern(M) {
936        var elements = M.elements.map(to_moz);
937        if (M.rest) elements.push({
938            type: "RestElement",
939            argument: to_moz(M.rest),
940        });
941        return {
942            type: "ArrayPattern",
943            elements: elements,
944        };
945    });
946
947    def_to_moz(AST_DestructuredKeyVal, function To_Moz_Property(M) {
948        var computed = M.key instanceof AST_Node;
949        var key = computed ? to_moz(M.key) : {
950            type: "Literal",
951            value: M.key,
952        };
953        return {
954            type: "Property",
955            kind: "init",
956            computed: computed,
957            key: key,
958            value: to_moz(M.value),
959        };
960    });
961
962    def_to_moz(AST_DestructuredObject, function To_Moz_ObjectPattern(M) {
963        var props = M.properties.map(to_moz);
964        if (M.rest) props.push({
965            type: "RestElement",
966            argument: to_moz(M.rest),
967        });
968        return {
969            type: "ObjectPattern",
970            properties: props,
971        };
972    });
973
974    def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
975        var computed = M.key instanceof AST_Node;
976        var key = computed ? to_moz(M.key) : {
977            type: "Literal",
978            value: M.key,
979        };
980        var kind;
981        if (M instanceof AST_ObjectKeyVal) {
982            kind = "init";
983        } else if (M instanceof AST_ObjectGetter) {
984            kind = "get";
985        } else if (M instanceof AST_ObjectSetter) {
986            kind = "set";
987        }
988        return {
989            type: "Property",
990            kind: kind,
991            computed: computed,
992            method: M instanceof AST_ObjectMethod,
993            key: key,
994            value: to_moz(M.value),
995        };
996    });
997
998    def_to_moz(AST_Symbol, function To_Moz_Identifier(M) {
999        var def = M.definition();
1000        return {
1001            type: "Identifier",
1002            name: def && def.mangled_name || M.name,
1003        };
1004    });
1005
1006    def_to_moz(AST_Super, function To_Moz_Super() {
1007        return { type: "Super" };
1008    });
1009
1010    def_to_moz(AST_This, function To_Moz_ThisExpression() {
1011        return { type: "ThisExpression" };
1012    });
1013
1014    def_to_moz(AST_NewTarget, function To_Moz_MetaProperty() {
1015        return {
1016            type: "MetaProperty",
1017            meta: {
1018                type: "Identifier",
1019                name: "new",
1020            },
1021            property: {
1022                type: "Identifier",
1023                name: "target",
1024            },
1025        };
1026    });
1027
1028    def_to_moz(AST_RegExp, function To_Moz_RegExpLiteral(M) {
1029        var flags = M.value.toString().match(/\/([gimuy]*)$/)[1];
1030        var value = "/" + M.value.raw_source + "/" + flags;
1031        return {
1032            type: "Literal",
1033            value: value,
1034            raw: value,
1035            regex: {
1036                pattern: M.value.raw_source,
1037                flags: flags,
1038            },
1039        };
1040    });
1041
1042    def_to_moz(AST_BigInt, function To_Moz_BigInt(M) {
1043        var value = M.value;
1044        return {
1045            type: "Literal",
1046            bigint: value.slice(0, -1),
1047            raw: value,
1048        };
1049    });
1050
1051    function To_Moz_Literal(M) {
1052        var value = M.value;
1053        if (typeof value === "number" && (value < 0 || (value === 0 && 1 / value < 0))) {
1054            return {
1055                type: "UnaryExpression",
1056                operator: "-",
1057                prefix: true,
1058                argument: {
1059                    type: "Literal",
1060                    value: -value,
1061                    raw: M.start.raw,
1062                },
1063            };
1064        }
1065        return {
1066            type: "Literal",
1067            value: value,
1068            raw: M.start.raw,
1069        };
1070    }
1071    def_to_moz(AST_Boolean, To_Moz_Literal);
1072    def_to_moz(AST_Constant, To_Moz_Literal);
1073    def_to_moz(AST_Null, To_Moz_Literal);
1074
1075    def_to_moz(AST_Atom, function To_Moz_Atom(M) {
1076        return {
1077            type: "Identifier",
1078            name: String(M.value),
1079        };
1080    });
1081
1082    def_to_moz(AST_Template, function To_Moz_TemplateLiteral_TaggedTemplateExpression(M) {
1083        var last = M.strings.length - 1;
1084        var tmpl = {
1085            type: "TemplateLiteral",
1086            expressions: M.expressions.map(to_moz),
1087            quasis: M.strings.map(function(str, index) {
1088                return {
1089                    type: "TemplateElement",
1090                    tail: index == last,
1091                    value: { raw: str },
1092                };
1093            }),
1094        };
1095        if (!M.tag) return tmpl;
1096        return {
1097            type: "TaggedTemplateExpression",
1098            tag: to_moz(M.tag),
1099            quasi: tmpl,
1100        };
1101    });
1102
1103    AST_Block.DEFMETHOD("to_mozilla_ast", AST_BlockStatement.prototype.to_mozilla_ast);
1104    AST_Hole.DEFMETHOD("to_mozilla_ast", return_null);
1105    AST_Node.DEFMETHOD("to_mozilla_ast", function() {
1106        throw new Error("Cannot convert AST_" + this.TYPE);
1107    });
1108
1109    /* -----[ tools ]----- */
1110
1111    function normalize_directives(body) {
1112        for (var i = 0; i < body.length; i++) {
1113            var stat = body[i];
1114            if (!(stat instanceof AST_SimpleStatement)) break;
1115            var node = stat.body;
1116            if (!(node instanceof AST_String)) break;
1117            if (stat.start.pos !== node.start.pos) break;
1118            body[i] = new AST_Directive(node);
1119        }
1120        return body;
1121    }
1122
1123    function raw_token(moznode) {
1124        if (moznode.type == "Literal") {
1125            return moznode.raw != null ? moznode.raw : moznode.value + "";
1126        }
1127    }
1128
1129    function my_start_token(moznode) {
1130        var loc = moznode.loc, start = loc && loc.start;
1131        var range = moznode.range;
1132        return new AST_Token({
1133            file    : loc && loc.source,
1134            line    : start && start.line,
1135            col     : start && start.column,
1136            pos     : range ? range[0] : moznode.start,
1137            endline : start && start.line,
1138            endcol  : start && start.column,
1139            endpos  : range ? range[0] : moznode.start,
1140            raw     : raw_token(moznode),
1141        });
1142    }
1143
1144    function my_end_token(moznode) {
1145        var loc = moznode.loc, end = loc && loc.end;
1146        var range = moznode.range;
1147        return new AST_Token({
1148            file    : loc && loc.source,
1149            line    : end && end.line,
1150            col     : end && end.column,
1151            pos     : range ? range[1] : moznode.end,
1152            endline : end && end.line,
1153            endcol  : end && end.column,
1154            endpos  : range ? range[1] : moznode.end,
1155            raw     : raw_token(moznode),
1156        });
1157    }
1158
1159    function read_name(M) {
1160        return "" + M[M.type == "Identifier" ? "name" : "value"];
1161    }
1162
1163    function map(moztype, mytype, propmap) {
1164        var moz_to_me = [
1165            "start: my_start_token(M)",
1166            "end: my_end_token(M)",
1167        ];
1168        var me_to_moz = [
1169            "type: " + JSON.stringify(moztype),
1170        ];
1171
1172        if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop) {
1173            var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop);
1174            if (!m) throw new Error("Can't understand property map: " + prop);
1175            var moz = m[1], how = m[2], my = m[3];
1176            switch (how) {
1177              case "@":
1178                moz_to_me.push(my + ": M." + moz + ".map(from_moz)");
1179                me_to_moz.push(moz + ": M." +  my + ".map(to_moz)");
1180                break;
1181              case ">":
1182                moz_to_me.push(my + ": from_moz(M." + moz + ")");
1183                me_to_moz.push(moz + ": to_moz(M." + my + ")");
1184                break;
1185              case "=":
1186                moz_to_me.push(my + ": M." + moz);
1187                me_to_moz.push(moz + ": M." + my);
1188                break;
1189              case "%":
1190                moz_to_me.push(my + ": from_moz(M." + moz + ").body");
1191                me_to_moz.push(moz + ": to_moz_block(M)");
1192                break;
1193              default:
1194                throw new Error("Can't understand operator in propmap: " + prop);
1195            }
1196        });
1197
1198        MOZ_TO_ME[moztype] = new Function("U2", "my_start_token", "my_end_token", "from_moz", [
1199            "return function From_Moz_" + moztype + "(M) {",
1200            "    return new U2.AST_" + mytype.TYPE + "({",
1201            moz_to_me.join(",\n"),
1202            "    });",
1203            "};",
1204        ].join("\n"))(exports, my_start_token, my_end_token, from_moz);
1205        def_to_moz(mytype, new Function("to_moz", "to_moz_block", "to_moz_scope", [
1206            "return function To_Moz_" + moztype + "(M) {",
1207            "    return {",
1208            me_to_moz.join(",\n"),
1209            "    };",
1210            "};",
1211        ].join("\n"))(to_moz, to_moz_block, to_moz_scope));
1212    }
1213
1214    var FROM_MOZ_STACK = null;
1215
1216    function from_moz(moz) {
1217        FROM_MOZ_STACK.push(moz);
1218        var node = null;
1219        if (moz) {
1220            if (!HOP(MOZ_TO_ME, moz.type)) throw new Error("Unsupported type: " + moz.type);
1221            node = MOZ_TO_ME[moz.type](moz);
1222        }
1223        FROM_MOZ_STACK.pop();
1224        return node;
1225    }
1226
1227    function from_moz_alias(moz) {
1228        return new AST_String({
1229            start: my_start_token(moz),
1230            value: read_name(moz),
1231            end: my_end_token(moz),
1232        });
1233    }
1234
1235    AST_Node.from_mozilla_ast = function(node) {
1236        var save_stack = FROM_MOZ_STACK;
1237        FROM_MOZ_STACK = [];
1238        var ast = from_moz(node);
1239        FROM_MOZ_STACK = save_stack;
1240        ast.walk(new TreeWalker(function(node) {
1241            if (node instanceof AST_LabelRef) {
1242                for (var level = 0, parent; parent = this.parent(level); level++) {
1243                    if (parent instanceof AST_Scope) break;
1244                    if (parent instanceof AST_LabeledStatement && parent.label.name == node.name) {
1245                        node.thedef = parent.label;
1246                        break;
1247                    }
1248                }
1249                if (!node.thedef) {
1250                    var s = node.start;
1251                    js_error("Undefined label " + node.name, s.file, s.line, s.col, s.pos);
1252                }
1253            }
1254        }));
1255        return ast;
1256    };
1257
1258    function set_moz_loc(mynode, moznode) {
1259        var start = mynode.start;
1260        var end = mynode.end;
1261        if (start.pos != null && end.endpos != null) {
1262            moznode.range = [start.pos, end.endpos];
1263        }
1264        if (start.line) {
1265            moznode.loc = {
1266                start: {line: start.line, column: start.col},
1267                end: end.endline ? {line: end.endline, column: end.endcol} : null,
1268            };
1269            if (start.file) {
1270                moznode.loc.source = start.file;
1271            }
1272        }
1273        return moznode;
1274    }
1275
1276    function def_to_moz(mytype, handler) {
1277        mytype.DEFMETHOD("to_mozilla_ast", function() {
1278            return set_moz_loc(this, handler(this));
1279        });
1280    }
1281
1282    function to_moz(node) {
1283        return node != null ? node.to_mozilla_ast() : null;
1284    }
1285
1286    function to_moz_alias(alias) {
1287        return is_identifier_string(alias.value) ? set_moz_loc(alias, {
1288            type: "Identifier",
1289            name: alias.value,
1290        }) : to_moz(alias);
1291    }
1292
1293    function to_moz_block(node) {
1294        return {
1295            type: "BlockStatement",
1296            body: node.body.map(to_moz),
1297        };
1298    }
1299
1300    function to_moz_scope(type, node) {
1301        var body = node.body.map(to_moz);
1302        if (node.body[0] instanceof AST_SimpleStatement && node.body[0].body instanceof AST_String) {
1303            body.unshift(to_moz(new AST_EmptyStatement(node.body[0])));
1304        }
1305        return {
1306            type: type,
1307            body: body,
1308        };
1309    }
1310})();
1311