swf-toolkit 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +125 -2
  3. package/README.tr.md +126 -0
  4. package/dist/abc/abc-file.d.ts +168 -0
  5. package/dist/abc/abc-file.js +656 -0
  6. package/dist/abc/analysis.d.ts +36 -0
  7. package/dist/abc/analysis.js +213 -0
  8. package/dist/abc/code.d.ts +59 -0
  9. package/dist/abc/code.js +379 -0
  10. package/dist/abc/constants.d.ts +80 -0
  11. package/dist/abc/constants.js +93 -0
  12. package/dist/abc/interner.d.ts +46 -0
  13. package/dist/abc/interner.js +168 -0
  14. package/dist/abc/model.d.ts +40 -0
  15. package/dist/abc/model.js +146 -0
  16. package/dist/abc/opcodes.d.ts +39 -0
  17. package/dist/abc/opcodes.js +196 -0
  18. package/dist/abc/pcode/assembler.d.ts +42 -0
  19. package/dist/abc/pcode/assembler.js +635 -0
  20. package/dist/abc/pcode/disassembler.d.ts +17 -0
  21. package/dist/abc/pcode/disassembler.js +147 -0
  22. package/dist/abc/pcode/format.d.ts +23 -0
  23. package/dist/abc/pcode/format.js +131 -0
  24. package/dist/abc/pcode/lexer.d.ts +34 -0
  25. package/dist/abc/pcode/lexer.js +183 -0
  26. package/dist/assets/assets.d.ts +26 -0
  27. package/dist/assets/assets.js +151 -0
  28. package/dist/assets/images.d.ts +31 -0
  29. package/dist/assets/images.js +238 -0
  30. package/dist/assets/png.d.ts +12 -0
  31. package/dist/assets/png.js +196 -0
  32. package/dist/assets/sounds.d.ts +37 -0
  33. package/dist/assets/sounds.js +236 -0
  34. package/dist/avm1/avm1.d.ts +55 -0
  35. package/dist/avm1/avm1.js +642 -0
  36. package/dist/avm1/project.d.ts +16 -0
  37. package/dist/avm1/project.js +81 -0
  38. package/dist/cjs/abc/abc-file.d.ts +168 -0
  39. package/dist/cjs/abc/abc-file.js +663 -0
  40. package/dist/cjs/abc/analysis.d.ts +36 -0
  41. package/dist/cjs/abc/analysis.js +221 -0
  42. package/dist/cjs/abc/code.d.ts +59 -0
  43. package/dist/cjs/abc/code.js +387 -0
  44. package/dist/cjs/abc/constants.d.ts +80 -0
  45. package/dist/cjs/abc/constants.js +97 -0
  46. package/dist/cjs/abc/interner.d.ts +46 -0
  47. package/dist/cjs/abc/interner.js +172 -0
  48. package/dist/cjs/abc/model.d.ts +40 -0
  49. package/dist/cjs/abc/model.js +155 -0
  50. package/dist/cjs/abc/opcodes.d.ts +39 -0
  51. package/dist/cjs/abc/opcodes.js +201 -0
  52. package/dist/cjs/abc/pcode/assembler.d.ts +42 -0
  53. package/dist/cjs/abc/pcode/assembler.js +640 -0
  54. package/dist/cjs/abc/pcode/disassembler.d.ts +17 -0
  55. package/dist/cjs/abc/pcode/disassembler.js +152 -0
  56. package/dist/cjs/abc/pcode/format.d.ts +23 -0
  57. package/dist/cjs/abc/pcode/format.js +141 -0
  58. package/dist/cjs/abc/pcode/lexer.d.ts +34 -0
  59. package/dist/cjs/abc/pcode/lexer.js +188 -0
  60. package/dist/cjs/assets/assets.d.ts +26 -0
  61. package/dist/cjs/assets/assets.js +159 -0
  62. package/dist/cjs/assets/images.d.ts +31 -0
  63. package/dist/cjs/assets/images.js +246 -0
  64. package/dist/cjs/assets/png.d.ts +12 -0
  65. package/dist/cjs/assets/png.js +202 -0
  66. package/dist/cjs/assets/sounds.d.ts +37 -0
  67. package/dist/cjs/assets/sounds.js +246 -0
  68. package/dist/cjs/avm1/avm1.d.ts +55 -0
  69. package/dist/cjs/avm1/avm1.js +649 -0
  70. package/dist/cjs/avm1/project.d.ts +16 -0
  71. package/dist/cjs/avm1/project.js +88 -0
  72. package/dist/cjs/compiler/ast.d.ts +285 -0
  73. package/dist/cjs/compiler/ast.js +3 -0
  74. package/dist/cjs/compiler/class-compiler.d.ts +34 -0
  75. package/dist/cjs/compiler/class-compiler.js +440 -0
  76. package/dist/cjs/compiler/codegen.d.ts +144 -0
  77. package/dist/cjs/compiler/codegen.js +1589 -0
  78. package/dist/cjs/compiler/lexer.d.ts +27 -0
  79. package/dist/cjs/compiler/lexer.js +254 -0
  80. package/dist/cjs/compiler/parser.d.ts +58 -0
  81. package/dist/cjs/compiler/parser.js +989 -0
  82. package/dist/cjs/compiler/program.d.ts +29 -0
  83. package/dist/cjs/compiler/program.js +36 -0
  84. package/dist/cjs/compiler/scope.d.ts +22 -0
  85. package/dist/cjs/compiler/scope.js +242 -0
  86. package/dist/cjs/compression/lzma.d.ts +37 -0
  87. package/dist/cjs/compression/lzma.js +575 -0
  88. package/dist/cjs/compression/swf-container.d.ts +19 -0
  89. package/dist/cjs/compression/swf-container.js +92 -0
  90. package/dist/cjs/decompiler/ast.d.ts +228 -0
  91. package/dist/cjs/decompiler/ast.js +455 -0
  92. package/dist/cjs/decompiler/cfg.d.ts +40 -0
  93. package/dist/cjs/decompiler/cfg.js +236 -0
  94. package/dist/cjs/decompiler/class-printer.d.ts +9 -0
  95. package/dist/cjs/decompiler/class-printer.js +173 -0
  96. package/dist/cjs/decompiler/method.d.ts +41 -0
  97. package/dist/cjs/decompiler/method.js +436 -0
  98. package/dist/cjs/decompiler/simulate.d.ts +55 -0
  99. package/dist/cjs/decompiler/simulate.js +591 -0
  100. package/dist/cjs/decompiler/structure.d.ts +48 -0
  101. package/dist/cjs/decompiler/structure.js +764 -0
  102. package/dist/cjs/errors.d.ts +11 -0
  103. package/dist/cjs/errors.js +25 -0
  104. package/dist/cjs/index.d.ts +41 -0
  105. package/dist/cjs/index.js +82 -0
  106. package/dist/cjs/io/reader.d.ts +48 -0
  107. package/dist/cjs/io/reader.js +180 -0
  108. package/dist/cjs/io/writer.d.ts +37 -0
  109. package/dist/cjs/io/writer.js +175 -0
  110. package/dist/cjs/package.json +1 -0
  111. package/dist/cjs/project/pcode-project.d.ts +32 -0
  112. package/dist/cjs/project/pcode-project.js +210 -0
  113. package/dist/cjs/project/source-export.d.ts +12 -0
  114. package/dist/cjs/project/source-export.js +51 -0
  115. package/dist/cjs/project/source-import.d.ts +13 -0
  116. package/dist/cjs/project/source-import.js +73 -0
  117. package/dist/cjs/swf/swf.d.ts +63 -0
  118. package/dist/cjs/swf/swf.js +147 -0
  119. package/dist/cjs/swf/tag-codes.d.ts +77 -0
  120. package/dist/cjs/swf/tag-codes.js +109 -0
  121. package/dist/cjs/swf/tags.d.ts +118 -0
  122. package/dist/cjs/swf/tags.js +330 -0
  123. package/dist/cli.d.ts +2 -0
  124. package/dist/cli.js +296 -0
  125. package/dist/compiler/ast.d.ts +285 -0
  126. package/dist/compiler/ast.js +2 -0
  127. package/dist/compiler/class-compiler.d.ts +34 -0
  128. package/dist/compiler/class-compiler.js +437 -0
  129. package/dist/compiler/codegen.d.ts +144 -0
  130. package/dist/compiler/codegen.js +1585 -0
  131. package/dist/compiler/lexer.d.ts +27 -0
  132. package/dist/compiler/lexer.js +249 -0
  133. package/dist/compiler/parser.d.ts +58 -0
  134. package/dist/compiler/parser.js +984 -0
  135. package/dist/compiler/program.d.ts +29 -0
  136. package/dist/compiler/program.js +32 -0
  137. package/dist/compiler/scope.d.ts +22 -0
  138. package/dist/compiler/scope.js +238 -0
  139. package/dist/compression/lzma.d.ts +37 -0
  140. package/dist/compression/lzma.js +569 -0
  141. package/dist/compression/swf-container.d.ts +19 -0
  142. package/dist/compression/swf-container.js +87 -0
  143. package/dist/decompiler/ast.d.ts +228 -0
  144. package/dist/decompiler/ast.js +441 -0
  145. package/dist/decompiler/cfg.d.ts +40 -0
  146. package/dist/decompiler/cfg.js +231 -0
  147. package/dist/decompiler/class-printer.d.ts +9 -0
  148. package/dist/decompiler/class-printer.js +170 -0
  149. package/dist/decompiler/method.d.ts +41 -0
  150. package/dist/decompiler/method.js +427 -0
  151. package/dist/decompiler/simulate.d.ts +55 -0
  152. package/dist/decompiler/simulate.js +586 -0
  153. package/dist/decompiler/structure.d.ts +48 -0
  154. package/dist/decompiler/structure.js +760 -0
  155. package/dist/errors.d.ts +11 -0
  156. package/dist/errors.js +20 -0
  157. package/dist/index.d.ts +41 -0
  158. package/dist/index.js +49 -0
  159. package/dist/io/reader.d.ts +48 -0
  160. package/dist/io/reader.js +176 -0
  161. package/dist/io/writer.d.ts +37 -0
  162. package/dist/io/writer.js +169 -0
  163. package/dist/project/pcode-project.d.ts +32 -0
  164. package/dist/project/pcode-project.js +203 -0
  165. package/dist/project/source-export.d.ts +12 -0
  166. package/dist/project/source-export.js +47 -0
  167. package/dist/project/source-import.d.ts +13 -0
  168. package/dist/project/source-import.js +70 -0
  169. package/dist/swf/swf.d.ts +63 -0
  170. package/dist/swf/swf.js +143 -0
  171. package/dist/swf/tag-codes.d.ts +77 -0
  172. package/dist/swf/tag-codes.js +105 -0
  173. package/dist/swf/tags.d.ts +118 -0
  174. package/dist/swf/tags.js +316 -0
  175. package/package.json +71 -4
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Small ActionScript 3 AST used by the decompiler, plus a precedence-aware printer.
3
+ */
4
+ export type Expr = {
5
+ k: 'lit';
6
+ v: string | number | boolean | null | undefined;
7
+ } | {
8
+ k: 'raw';
9
+ text: string;
10
+ } | {
11
+ k: 'this';
12
+ } | {
13
+ k: 'super';
14
+ } | {
15
+ k: 'global';
16
+ } | {
17
+ k: 'local';
18
+ reg: number;
19
+ } | {
20
+ k: 'name';
21
+ name: string;
22
+ }
23
+ /** Scope object returned by findprop; only meaningful as the target of a member access. */
24
+ | {
25
+ k: 'findprop';
26
+ name: string;
27
+ } | {
28
+ k: 'member';
29
+ obj: Expr;
30
+ name: string;
31
+ attr?: boolean;
32
+ ns?: string;
33
+ } | {
34
+ k: 'index';
35
+ obj: Expr;
36
+ index: Expr;
37
+ attr?: boolean;
38
+ } | {
39
+ k: 'descendants';
40
+ obj: Expr;
41
+ name: string;
42
+ } | {
43
+ k: 'call';
44
+ fn: Expr;
45
+ args: Expr[];
46
+ } | {
47
+ k: 'new';
48
+ ctor: Expr;
49
+ args: Expr[];
50
+ } | {
51
+ k: 'unary';
52
+ op: string;
53
+ e: Expr;
54
+ } | {
55
+ k: 'postfix';
56
+ op: '++' | '--';
57
+ e: Expr;
58
+ } | {
59
+ k: 'binary';
60
+ op: string;
61
+ a: Expr;
62
+ b: Expr;
63
+ } | {
64
+ k: 'cond';
65
+ c: Expr;
66
+ t: Expr;
67
+ f: Expr;
68
+ } | {
69
+ k: 'assign';
70
+ target: Expr;
71
+ v: Expr;
72
+ op?: string;
73
+ } | {
74
+ k: 'array';
75
+ items: Expr[];
76
+ } | {
77
+ k: 'object';
78
+ props: Array<[Expr, Expr]>;
79
+ } | {
80
+ k: 'function';
81
+ methodIndex: number;
82
+ } | {
83
+ k: 'applytype';
84
+ base: Expr;
85
+ params: Expr[];
86
+ } | {
87
+ k: 'coerce';
88
+ type: string;
89
+ e: Expr;
90
+ } | {
91
+ k: 'activation';
92
+ } | {
93
+ k: 'catchscope';
94
+ index: number;
95
+ } | {
96
+ k: 'hasnext2';
97
+ objReg: number;
98
+ idxReg: number;
99
+ } | {
100
+ k: 'next';
101
+ value: boolean;
102
+ obj: Expr;
103
+ idx: Expr;
104
+ } | {
105
+ k: 'hasnext';
106
+ obj: Expr;
107
+ idx: Expr;
108
+ } | {
109
+ k: 'slot';
110
+ obj: Expr;
111
+ slot: number;
112
+ name?: string;
113
+ };
114
+ export interface CatchClause {
115
+ name: string;
116
+ type: string;
117
+ body: Stmt[];
118
+ }
119
+ export interface SwitchCase {
120
+ /** null = default. */
121
+ test: Expr | null;
122
+ body: Stmt[];
123
+ }
124
+ export type Stmt = {
125
+ k: 'expr';
126
+ e: Expr;
127
+ } | {
128
+ k: 'var';
129
+ name: string;
130
+ type?: string;
131
+ init?: Expr;
132
+ } | {
133
+ k: 'return';
134
+ e?: Expr;
135
+ } | {
136
+ k: 'throw';
137
+ e: Expr;
138
+ } | {
139
+ k: 'if';
140
+ c: Expr;
141
+ then: Stmt[];
142
+ else?: Stmt[];
143
+ } | {
144
+ k: 'while';
145
+ c: Expr;
146
+ body: Stmt[];
147
+ label?: string;
148
+ } | {
149
+ k: 'dowhile';
150
+ c: Expr;
151
+ body: Stmt[];
152
+ label?: string;
153
+ } | {
154
+ k: 'for';
155
+ init?: Stmt;
156
+ c?: Expr;
157
+ update?: Expr;
158
+ body: Stmt[];
159
+ label?: string;
160
+ } | {
161
+ k: 'forin';
162
+ each: boolean;
163
+ target: Expr;
164
+ declare?: {
165
+ name: string;
166
+ type?: string;
167
+ };
168
+ obj: Expr;
169
+ body: Stmt[];
170
+ label?: string;
171
+ } | {
172
+ k: 'switch';
173
+ disc: Expr;
174
+ cases: SwitchCase[];
175
+ label?: string;
176
+ } | {
177
+ k: 'try';
178
+ body: Stmt[];
179
+ catches: CatchClause[];
180
+ finally?: Stmt[];
181
+ } | {
182
+ k: 'break';
183
+ label?: string;
184
+ } | {
185
+ k: 'continue';
186
+ label?: string;
187
+ } | {
188
+ k: 'with';
189
+ obj: Expr;
190
+ body: Stmt[];
191
+ } | {
192
+ k: 'comment';
193
+ text: string;
194
+ } | {
195
+ k: 'block';
196
+ body: Stmt[];
197
+ };
198
+ export declare const lit: (v: string | number | boolean | null | undefined) => Expr;
199
+ export declare const raw: (text: string) => Expr;
200
+ /** Logical negation with simplification of comparisons and double negation. */
201
+ export declare function not(e: Expr): Expr;
202
+ export declare function stripCoerce(e: Expr): Expr;
203
+ /** True when evaluating `e` can have side effects (so it must not be dropped or duplicated). */
204
+ export declare function hasSideEffects(e: Expr): boolean;
205
+ /** Structural equality ignoring implicit coercions (used to detect `x = x + 1` → `x++` etc.). */
206
+ export declare function exprEquals(a: Expr, b: Expr): boolean;
207
+ export declare function readsLocal(e: Expr, reg: number): boolean;
208
+ export declare function walkExpr(e: Expr, f: (e: Expr) => void): void;
209
+ /** Visits every statement list recursively (pre-order). */
210
+ export declare function walkStmts(list: Stmt[], f: (s: Stmt, list: Stmt[], index: number) => void): void;
211
+ export declare function childLists(s: Stmt): Stmt[][];
212
+ export interface PrintContext {
213
+ localName(reg: number): string;
214
+ /** Renders a closure (newfunction) body. */
215
+ functionExpr(methodIndex: number, indent: string): string;
216
+ indentUnit: string;
217
+ }
218
+ export declare class Printer {
219
+ readonly ctx: PrintContext;
220
+ constructor(ctx: PrintContext);
221
+ expr(e: Expr, minPrec?: number, indent?: string): string;
222
+ private member;
223
+ private exprInner;
224
+ stmts(list: Stmt[], indent: string): string[];
225
+ private block;
226
+ private labelPrefix;
227
+ stmt(s: Stmt, indent: string): string[];
228
+ }
@@ -0,0 +1,455 @@
1
+ "use strict";
2
+ /**
3
+ * Small ActionScript 3 AST used by the decompiler, plus a precedence-aware printer.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Printer = exports.raw = exports.lit = void 0;
7
+ exports.not = not;
8
+ exports.stripCoerce = stripCoerce;
9
+ exports.hasSideEffects = hasSideEffects;
10
+ exports.exprEquals = exprEquals;
11
+ exports.readsLocal = readsLocal;
12
+ exports.walkExpr = walkExpr;
13
+ exports.walkStmts = walkStmts;
14
+ exports.childLists = childLists;
15
+ // ---------------------------------------------------------------------------
16
+ // Constructors / helpers
17
+ // ---------------------------------------------------------------------------
18
+ const lit = (v) => ({ k: 'lit', v });
19
+ exports.lit = lit;
20
+ const raw = (text) => ({ k: 'raw', text });
21
+ exports.raw = raw;
22
+ /** Logical negation with simplification of comparisons and double negation. */
23
+ function not(e) {
24
+ if (e.k === 'unary' && e.op === '!')
25
+ return e.e;
26
+ if (e.k === 'binary') {
27
+ const inv = { '==': '!=', '!=': '==', '===': '!==', '!==': '===' };
28
+ const o = inv[e.op];
29
+ if (o)
30
+ return { ...e, op: o };
31
+ }
32
+ if (e.k === 'lit' && typeof e.v === 'boolean')
33
+ return (0, exports.lit)(!e.v);
34
+ return { k: 'unary', op: '!', e };
35
+ }
36
+ function stripCoerce(e) {
37
+ while (e.k === 'coerce')
38
+ e = e.e;
39
+ return e;
40
+ }
41
+ /** True when evaluating `e` can have side effects (so it must not be dropped or duplicated). */
42
+ function hasSideEffects(e) {
43
+ switch (e.k) {
44
+ case 'call':
45
+ case 'new':
46
+ case 'assign':
47
+ case 'postfix':
48
+ case 'function':
49
+ return e.k !== 'function';
50
+ case 'unary':
51
+ return e.op === 'delete' || e.op === '++' || e.op === '--' || hasSideEffects(e.e);
52
+ case 'member':
53
+ return hasSideEffects(e.obj);
54
+ case 'index':
55
+ return hasSideEffects(e.obj) || hasSideEffects(e.index);
56
+ case 'binary':
57
+ return hasSideEffects(e.a) || hasSideEffects(e.b);
58
+ case 'cond':
59
+ return hasSideEffects(e.c) || hasSideEffects(e.t) || hasSideEffects(e.f);
60
+ case 'coerce':
61
+ return hasSideEffects(e.e);
62
+ case 'array':
63
+ return e.items.some(hasSideEffects);
64
+ case 'object':
65
+ return e.props.some(([a, b]) => hasSideEffects(a) || hasSideEffects(b));
66
+ default:
67
+ return false;
68
+ }
69
+ }
70
+ /** Structural equality ignoring implicit coercions (used to detect `x = x + 1` → `x++` etc.). */
71
+ function exprEquals(a, b) {
72
+ const canon = (e) => JSON.stringify(e, (_k, v) => {
73
+ let x = v;
74
+ while (x && typeof x === 'object' && x.k === 'coerce')
75
+ x = x.e;
76
+ return x;
77
+ });
78
+ return canon(a) === canon(b);
79
+ }
80
+ function readsLocal(e, reg) {
81
+ let found = false;
82
+ walkExpr(e, (x) => {
83
+ if (x.k === 'local' && x.reg === reg)
84
+ found = true;
85
+ });
86
+ return found;
87
+ }
88
+ function walkExpr(e, f) {
89
+ f(e);
90
+ switch (e.k) {
91
+ case 'member':
92
+ case 'descendants':
93
+ walkExpr(e.obj, f);
94
+ break;
95
+ case 'index':
96
+ walkExpr(e.obj, f);
97
+ walkExpr(e.index, f);
98
+ break;
99
+ case 'call':
100
+ walkExpr(e.fn, f);
101
+ e.args.forEach((x) => walkExpr(x, f));
102
+ break;
103
+ case 'new':
104
+ walkExpr(e.ctor, f);
105
+ e.args.forEach((x) => walkExpr(x, f));
106
+ break;
107
+ case 'unary':
108
+ case 'postfix':
109
+ case 'coerce':
110
+ walkExpr(e.e, f);
111
+ break;
112
+ case 'binary':
113
+ walkExpr(e.a, f);
114
+ walkExpr(e.b, f);
115
+ break;
116
+ case 'cond':
117
+ walkExpr(e.c, f);
118
+ walkExpr(e.t, f);
119
+ walkExpr(e.f, f);
120
+ break;
121
+ case 'assign':
122
+ walkExpr(e.target, f);
123
+ walkExpr(e.v, f);
124
+ break;
125
+ case 'array':
126
+ e.items.forEach((x) => walkExpr(x, f));
127
+ break;
128
+ case 'object':
129
+ e.props.forEach(([a, b]) => {
130
+ walkExpr(a, f);
131
+ walkExpr(b, f);
132
+ });
133
+ break;
134
+ case 'applytype':
135
+ walkExpr(e.base, f);
136
+ e.params.forEach((x) => walkExpr(x, f));
137
+ break;
138
+ case 'next':
139
+ case 'hasnext':
140
+ walkExpr(e.obj, f);
141
+ walkExpr(e.idx, f);
142
+ break;
143
+ case 'slot':
144
+ walkExpr(e.obj, f);
145
+ break;
146
+ }
147
+ }
148
+ /** Visits every statement list recursively (pre-order). */
149
+ function walkStmts(list, f) {
150
+ for (let i = 0; i < list.length; i++) {
151
+ const s = list[i];
152
+ f(s, list, i);
153
+ for (const child of childLists(s))
154
+ walkStmts(child, f);
155
+ }
156
+ }
157
+ function childLists(s) {
158
+ switch (s.k) {
159
+ case 'if':
160
+ return s.else ? [s.then, s.else] : [s.then];
161
+ case 'while':
162
+ case 'dowhile':
163
+ case 'for':
164
+ case 'forin':
165
+ case 'with':
166
+ case 'block':
167
+ return [s.body];
168
+ case 'switch':
169
+ return s.cases.map((c) => c.body);
170
+ case 'try':
171
+ return [s.body, ...s.catches.map((c) => c.body), ...(s.finally ? [s.finally] : [])];
172
+ default:
173
+ return [];
174
+ }
175
+ }
176
+ // ---------------------------------------------------------------------------
177
+ // Printer
178
+ // ---------------------------------------------------------------------------
179
+ const BINARY_PREC = {
180
+ ',': 0,
181
+ '||': 3,
182
+ '&&': 4,
183
+ '|': 5,
184
+ '^': 6,
185
+ '&': 7,
186
+ '==': 8,
187
+ '!=': 8,
188
+ '===': 8,
189
+ '!==': 8,
190
+ '<': 9,
191
+ '>': 9,
192
+ '<=': 9,
193
+ '>=': 9,
194
+ instanceof: 9,
195
+ is: 9,
196
+ as: 9,
197
+ in: 9,
198
+ '<<': 10,
199
+ '>>': 10,
200
+ '>>>': 10,
201
+ '+': 11,
202
+ '-': 11,
203
+ '*': 12,
204
+ '/': 12,
205
+ '%': 12,
206
+ };
207
+ function precOf(e) {
208
+ switch (e.k) {
209
+ case 'assign':
210
+ return 1;
211
+ case 'cond':
212
+ return 2;
213
+ case 'binary':
214
+ return BINARY_PREC[e.op] ?? 9;
215
+ case 'unary':
216
+ return 13;
217
+ case 'postfix':
218
+ return 14;
219
+ case 'new':
220
+ return 15;
221
+ case 'call':
222
+ case 'member':
223
+ case 'index':
224
+ case 'descendants':
225
+ case 'applytype':
226
+ return 16;
227
+ case 'coerce':
228
+ return precOf(e.e);
229
+ case 'function':
230
+ return 0;
231
+ default:
232
+ return 17;
233
+ }
234
+ }
235
+ const IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
236
+ function formatNumber(v) {
237
+ if (Number.isNaN(v))
238
+ return 'NaN';
239
+ if (v === Infinity)
240
+ return 'Infinity';
241
+ if (v === -Infinity)
242
+ return '-Infinity';
243
+ if (Object.is(v, -0))
244
+ return '-0';
245
+ return String(v);
246
+ }
247
+ class Printer {
248
+ ctx;
249
+ constructor(ctx) {
250
+ this.ctx = ctx;
251
+ }
252
+ expr(e, minPrec = 0, indent = '') {
253
+ const s = this.exprInner(e, indent);
254
+ return precOf(e) < minPrec ? `(${s})` : s;
255
+ }
256
+ member(obj, indent) {
257
+ if (obj.k === 'new')
258
+ return `(${this.expr(obj, 0, indent)})`;
259
+ return this.expr(obj, 16, indent);
260
+ }
261
+ exprInner(e, indent) {
262
+ switch (e.k) {
263
+ case 'lit':
264
+ if (typeof e.v === 'string')
265
+ return JSON.stringify(e.v);
266
+ if (typeof e.v === 'number')
267
+ return formatNumber(e.v);
268
+ if (e.v === undefined)
269
+ return 'undefined';
270
+ return String(e.v);
271
+ case 'raw':
272
+ return e.text;
273
+ case 'this':
274
+ return 'this';
275
+ case 'super':
276
+ return 'super';
277
+ case 'global':
278
+ return 'global';
279
+ case 'local':
280
+ return this.ctx.localName(e.reg);
281
+ case 'name':
282
+ return e.name;
283
+ case 'findprop':
284
+ return e.name;
285
+ case 'member': {
286
+ if (e.obj.k === 'findprop' || e.obj.k === 'global' || e.obj.k === 'activation' || e.obj.k === 'catchscope')
287
+ return (e.attr ? '@' : '') + e.name;
288
+ const nsPart = e.ns ? `${e.ns}::` : '';
289
+ if (!e.attr && !nsPart && !IDENT_RE.test(e.name))
290
+ return `${this.member(e.obj, indent)}[${JSON.stringify(e.name)}]`;
291
+ return `${this.member(e.obj, indent)}.${e.attr ? '@' : ''}${nsPart}${e.name}`;
292
+ }
293
+ case 'index':
294
+ return `${this.member(e.obj, indent)}${e.attr ? '.@' : ''}[${this.expr(e.index, 0, indent)}]`;
295
+ case 'descendants':
296
+ return `${this.member(e.obj, indent)}..${e.name}`;
297
+ case 'call':
298
+ return `${this.expr(e.fn, 16, indent)}(${e.args.map((a) => this.expr(a, 2, indent)).join(', ')})`;
299
+ case 'new': {
300
+ const ctor = e.ctor.k === 'call' ? `(${this.expr(e.ctor, 0, indent)})` : this.expr(e.ctor, 16, indent);
301
+ return `new ${ctor}(${e.args.map((a) => this.expr(a, 2, indent)).join(', ')})`;
302
+ }
303
+ case 'unary': {
304
+ const word = /^[a-z]/.test(e.op);
305
+ const inner = this.expr(e.e, 13, indent);
306
+ // Avoid "- -x" / "!-x" ambiguities.
307
+ return word ? `${e.op} ${inner}` : e.op === '-' && inner.startsWith('-') ? `-(${inner})` : `${e.op}${inner}`;
308
+ }
309
+ case 'postfix':
310
+ return `${this.expr(e.e, 14, indent)}${e.op}`;
311
+ case 'binary': {
312
+ const p = BINARY_PREC[e.op] ?? 9;
313
+ if (e.op === ',')
314
+ return `${this.expr(e.a, 1, indent)}, ${this.expr(e.b, 1, indent)}`;
315
+ return `${this.expr(e.a, p, indent)} ${e.op} ${this.expr(e.b, p + 1, indent)}`;
316
+ }
317
+ case 'cond':
318
+ return `${this.expr(e.c, 3, indent)} ? ${this.expr(e.t, 2, indent)} : ${this.expr(e.f, 2, indent)}`;
319
+ case 'assign':
320
+ return `${this.expr(e.target, 16, indent)} ${e.op ?? ''}= ${this.expr(e.v, 1, indent)}`;
321
+ case 'array':
322
+ return `[${e.items.map((a) => this.expr(a, 2, indent)).join(', ')}]`;
323
+ case 'object':
324
+ if (e.props.length === 0)
325
+ return '{}';
326
+ return `{${e.props
327
+ .map(([k, v]) => {
328
+ const key = k.k === 'lit' && typeof k.v === 'string' && IDENT_RE.test(k.v) ? k.v : this.expr(k, 17, indent);
329
+ return `${key}: ${this.expr(v, 2, indent)}`;
330
+ })
331
+ .join(', ')}}`;
332
+ case 'function':
333
+ return this.ctx.functionExpr(e.methodIndex, indent);
334
+ case 'applytype':
335
+ return `${this.expr(e.base, 16, indent)}.<${e.params.map((p) => this.expr(p, 0, indent)).join(', ')}>`;
336
+ case 'coerce':
337
+ return this.exprInner(e.e, indent);
338
+ case 'activation':
339
+ return '/*activation*/';
340
+ case 'catchscope':
341
+ return '/*catch*/';
342
+ case 'hasnext2':
343
+ return `hasnext2(${this.ctx.localName(e.objReg)}, ${this.ctx.localName(e.idxReg)})`;
344
+ case 'next':
345
+ return `${e.value ? 'nextvalue' : 'nextname'}(${this.expr(e.obj, 0, indent)}, ${this.expr(e.idx, 0, indent)})`;
346
+ case 'hasnext':
347
+ return `hasnext(${this.expr(e.obj, 0, indent)}, ${this.expr(e.idx, 0, indent)})`;
348
+ case 'slot':
349
+ return e.name ?? `${this.member(e.obj, indent)}./*slot ${e.slot}*/`;
350
+ }
351
+ }
352
+ stmts(list, indent) {
353
+ const out = [];
354
+ for (const s of list)
355
+ out.push(...this.stmt(s, indent));
356
+ return out;
357
+ }
358
+ block(body, indent) {
359
+ return [`${indent}{`, ...this.stmts(body, indent + this.ctx.indentUnit), `${indent}}`];
360
+ }
361
+ labelPrefix(label, indent, out) {
362
+ if (label)
363
+ out.push(`${indent}${label}:`);
364
+ }
365
+ stmt(s, indent) {
366
+ const I = indent;
367
+ const out = [];
368
+ switch (s.k) {
369
+ case 'expr':
370
+ out.push(`${I}${this.expr(s.e, 0, I)};`);
371
+ break;
372
+ case 'var':
373
+ out.push(`${I}var ${s.name}${s.type ? ':' + s.type : ''}${s.init ? ' = ' + this.expr(s.init, 1, I) : ''};`);
374
+ break;
375
+ case 'return':
376
+ out.push(s.e ? `${I}return ${this.expr(s.e, 0, I)};` : `${I}return;`);
377
+ break;
378
+ case 'throw':
379
+ out.push(`${I}throw ${this.expr(s.e, 0, I)};`);
380
+ break;
381
+ case 'if': {
382
+ out.push(`${I}if(${this.expr(s.c, 0, I)})`, ...this.block(s.then, I));
383
+ let els = s.else;
384
+ while (els && els.length) {
385
+ const only = els.length === 1 ? els[0] : undefined;
386
+ if (only && only.k === 'if') {
387
+ out.push(`${I}else if(${this.expr(only.c, 0, I)})`, ...this.block(only.then, I));
388
+ els = only.else;
389
+ }
390
+ else {
391
+ out.push(`${I}else`, ...this.block(els, I));
392
+ break;
393
+ }
394
+ }
395
+ break;
396
+ }
397
+ case 'while':
398
+ this.labelPrefix(s.label, I, out);
399
+ out.push(`${I}while(${this.expr(s.c, 0, I)})`, ...this.block(s.body, I));
400
+ break;
401
+ case 'dowhile':
402
+ this.labelPrefix(s.label, I, out);
403
+ out.push(`${I}do`, ...this.block(s.body, I), `${I}while(${this.expr(s.c, 0, I)});`);
404
+ break;
405
+ case 'for': {
406
+ this.labelPrefix(s.label, I, out);
407
+ const init = s.init ? this.stmt(s.init, '')[0].replace(/;$/, '') : '';
408
+ out.push(`${I}for(${init}; ${s.c ? this.expr(s.c, 0, I) : ''}; ${s.update ? this.expr(s.update, 0, I) : ''})`, ...this.block(s.body, I));
409
+ break;
410
+ }
411
+ case 'forin': {
412
+ this.labelPrefix(s.label, I, out);
413
+ const target = s.declare ? `var ${s.declare.name}${s.declare.type ? ':' + s.declare.type : ''}` : this.expr(s.target, 0, I);
414
+ out.push(`${I}for${s.each ? ' each' : ''}(${target} in ${this.expr(s.obj, 0, I)})`, ...this.block(s.body, I));
415
+ break;
416
+ }
417
+ case 'switch': {
418
+ this.labelPrefix(s.label, I, out);
419
+ out.push(`${I}switch(${this.expr(s.disc, 0, I)})`, `${I}{`);
420
+ const I2 = I + this.ctx.indentUnit;
421
+ for (const c of s.cases) {
422
+ out.push(c.test ? `${I2}case ${this.expr(c.test, 0, I2)}:` : `${I2}default:`);
423
+ out.push(...this.stmts(c.body, I2 + this.ctx.indentUnit));
424
+ }
425
+ out.push(`${I}}`);
426
+ break;
427
+ }
428
+ case 'try':
429
+ out.push(`${I}try`, ...this.block(s.body, I));
430
+ for (const c of s.catches)
431
+ out.push(`${I}catch(${c.name}:${c.type})`, ...this.block(c.body, I));
432
+ if (s.finally)
433
+ out.push(`${I}finally`, ...this.block(s.finally, I));
434
+ break;
435
+ case 'break':
436
+ out.push(`${I}break${s.label ? ' ' + s.label : ''};`);
437
+ break;
438
+ case 'continue':
439
+ out.push(`${I}continue${s.label ? ' ' + s.label : ''};`);
440
+ break;
441
+ case 'with':
442
+ out.push(`${I}with(${this.expr(s.obj, 0, I)})`, ...this.block(s.body, I));
443
+ break;
444
+ case 'comment':
445
+ for (const line of s.text.split('\n'))
446
+ out.push(`${I}// ${line}`);
447
+ break;
448
+ case 'block':
449
+ out.push(...this.block(s.body, I));
450
+ break;
451
+ }
452
+ return out;
453
+ }
454
+ }
455
+ exports.Printer = Printer;