depyo 1.0.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 (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +97 -0
  3. package/depyo.js +213 -0
  4. package/lib/BinaryReader.js +153 -0
  5. package/lib/OpCode.js +90 -0
  6. package/lib/OpCodes.js +940 -0
  7. package/lib/PycDecompiler.js +2031 -0
  8. package/lib/PycDisassembler.js +55 -0
  9. package/lib/PycReader.js +905 -0
  10. package/lib/PycResult.js +82 -0
  11. package/lib/PythonObject.js +242 -0
  12. package/lib/Unpickle.js +173 -0
  13. package/lib/ast/ast_node.js +3442 -0
  14. package/lib/bytecode/python_1_0.js +116 -0
  15. package/lib/bytecode/python_1_1.js +116 -0
  16. package/lib/bytecode/python_1_3.js +119 -0
  17. package/lib/bytecode/python_1_4.js +121 -0
  18. package/lib/bytecode/python_1_5.js +120 -0
  19. package/lib/bytecode/python_1_6.js +124 -0
  20. package/lib/bytecode/python_2_0.js +137 -0
  21. package/lib/bytecode/python_2_1.js +142 -0
  22. package/lib/bytecode/python_2_2.js +147 -0
  23. package/lib/bytecode/python_2_3.js +145 -0
  24. package/lib/bytecode/python_2_4.js +147 -0
  25. package/lib/bytecode/python_2_5.js +147 -0
  26. package/lib/bytecode/python_2_6.js +147 -0
  27. package/lib/bytecode/python_2_7.js +151 -0
  28. package/lib/bytecode/python_3_0.js +132 -0
  29. package/lib/bytecode/python_3_1.js +135 -0
  30. package/lib/bytecode/python_3_10.js +312 -0
  31. package/lib/bytecode/python_3_11.js +284 -0
  32. package/lib/bytecode/python_3_12.js +327 -0
  33. package/lib/bytecode/python_3_13.js +173 -0
  34. package/lib/bytecode/python_3_14.js +177 -0
  35. package/lib/bytecode/python_3_2.js +136 -0
  36. package/lib/bytecode/python_3_3.js +136 -0
  37. package/lib/bytecode/python_3_4.js +137 -0
  38. package/lib/bytecode/python_3_5.js +149 -0
  39. package/lib/bytecode/python_3_6.js +153 -0
  40. package/lib/bytecode/python_3_7.js +292 -0
  41. package/lib/bytecode/python_3_8.js +294 -0
  42. package/lib/bytecode/python_3_9.js +296 -0
  43. package/lib/code_reader.js +146 -0
  44. package/lib/handlers/binary_ops.js +174 -0
  45. package/lib/handlers/collections_update.js +239 -0
  46. package/lib/handlers/comparisons.js +95 -0
  47. package/lib/handlers/context_managers.js +250 -0
  48. package/lib/handlers/control_flow_jumps.js +954 -0
  49. package/lib/handlers/exceptions_blocks.js +952 -0
  50. package/lib/handlers/formatting.js +31 -0
  51. package/lib/handlers/function_calls.js +496 -0
  52. package/lib/handlers/function_class_build.js +330 -0
  53. package/lib/handlers/generators_async.js +172 -0
  54. package/lib/handlers/imports.js +53 -0
  55. package/lib/handlers/load_store_names.js +711 -0
  56. package/lib/handlers/loop_iterator.js +318 -0
  57. package/lib/handlers/misc_other.js +1201 -0
  58. package/lib/handlers/pattern_matching.js +226 -0
  59. package/lib/handlers/stack_ops.js +280 -0
  60. package/lib/handlers/subscript_slice.js +394 -0
  61. package/lib/handlers/unary_ops.js +91 -0
  62. package/lib/handlers/unpack.js +141 -0
  63. package/lib/stack_history.js +63 -0
  64. package/lib/zip_reader.js +217 -0
  65. package/package.json +35 -0
@@ -0,0 +1,394 @@
1
+ const AST = require('../ast/ast_node');
2
+
3
+ function handleBinarySubscr()
4
+ {
5
+ let subscr = this.dataStack.pop();
6
+ let src = this.dataStack.pop();
7
+ let node = new AST.ASTSubscr(src, subscr);
8
+ node.line = this.code.Current.LineNo;
9
+ this.dataStack.push(node);
10
+ }
11
+
12
+ function handleMapAddA() {
13
+ // MAP_ADD: add key/value pair to dict under construction
14
+ // Stack (TOS at right): ... , map, key, value
15
+ let value = this.dataStack.pop();
16
+ let key = this.dataStack.pop();
17
+
18
+ // Check if this is a dict comprehension
19
+ if (this.curBlock.blockType == AST.ASTBlock.BlockType.For && this.curBlock.comprehension) {
20
+ this.dataStack.pop(); // Pop the empty map
21
+ let node = new AST.ASTComprehension(value, key);
22
+ node.line = this.code.Current.LineNo;
23
+ node.kind = AST.ASTComprehension.DICT;
24
+ this.dataStack.push(node);
25
+ return;
26
+ }
27
+
28
+ let mapNode = this.dataStack.pop();
29
+
30
+ if (!(mapNode instanceof AST.ASTMap)) {
31
+ // Initialize a map literal if we didn't have one
32
+ mapNode = new AST.ASTMap([]);
33
+ }
34
+
35
+ mapNode.add(key, value);
36
+ mapNode.line = this.code.Current.LineNo;
37
+ this.dataStack.push(mapNode);
38
+ }
39
+
40
+ function handleStoreMap() {
41
+ handleBuildSliceA.call(this);
42
+ }
43
+
44
+ function handleBuildSliceA() {
45
+ if (this.code.Current.Argument == 2) {
46
+ let end = this.dataStack.pop();
47
+ let start = this.dataStack.pop();
48
+
49
+ if (start instanceof AST.ASTObject && (start.object == null || start.object.ClassName == 'Py_None')) {
50
+ start = null;
51
+ }
52
+
53
+ if (end instanceof AST.ASTObject && (end.object == null || end.object.ClassName == 'Py_None')) {
54
+ end = null;
55
+ }
56
+
57
+ let sliceOp = null;
58
+ if (!start && !end) {
59
+ sliceOp = AST.ASTSlice.SliceOp.Slice0;
60
+ } else if (!start) {
61
+ sliceOp = AST.ASTSlice.SliceOp.Slice2;
62
+ } else if (!end) {
63
+ sliceOp = AST.ASTSlice.SliceOp.Slice1;
64
+ } else {
65
+ sliceOp = AST.ASTSlice.SliceOp.Slice3;
66
+ }
67
+
68
+ let mapNode = new AST.ASTSlice(sliceOp, start || new AST.ASTNone(), end || new AST.ASTNone());
69
+ mapNode.line = this.code.Current.LineNo;
70
+ this.dataStack.push(mapNode);
71
+ } else if (this.code.Current.Argument == 3) {
72
+ let step = this.dataStack.pop();
73
+ let end = this.dataStack.pop();
74
+ let start = this.dataStack.pop();
75
+
76
+ if (start instanceof AST.ASTObject && (start.object == null || start.object.ClassName == 'Py_None')) {
77
+ start = null;
78
+ }
79
+
80
+ if (end instanceof AST.ASTObject && (end.object == null || end.object.ClassName == 'Py_None')) {
81
+ end = null;
82
+ }
83
+
84
+ if (step instanceof AST.ASTObject && (step.object == null || step.object.ClassName == 'Py_None')) {
85
+ step = null;
86
+ }
87
+
88
+ let sliceOp = null;
89
+ if (!start && !end) {
90
+ sliceOp = AST.ASTSlice.SliceOp.Slice0;
91
+ } else if (!start) {
92
+ sliceOp = AST.ASTSlice.SliceOp.Slice2;
93
+ } else if (!end) {
94
+ sliceOp = AST.ASTSlice.SliceOp.Slice1;
95
+ } else {
96
+ sliceOp = AST.ASTSlice.SliceOp.Slice3;
97
+ }
98
+
99
+ let lhs = new AST.ASTSlice(sliceOp, start || new AST.ASTNone(), end || new AST.ASTNone());
100
+ lhs.line = this.code.Current.LineNo;
101
+
102
+ if (!step) {
103
+ sliceOp = AST.ASTSlice.SliceOp.Slice1;
104
+ } else {
105
+ sliceOp = AST.ASTSlice.SliceOp.Slice3;
106
+ }
107
+
108
+ let sliceNode = new AST.ASTSlice(sliceOp, start || new AST.ASTNone(), end || new AST.ASTNone());
109
+ sliceNode.line = this.code.Current.LineNo;
110
+ this.dataStack.push(sliceNode);
111
+ }
112
+ }
113
+
114
+ function handleDeleteSlice0() {
115
+ if (this.code.Current?.InstructionName === 'NOT_TAKEN') {
116
+ if (global.g_cliArgs?.debug) {
117
+ console.log(`[NOT_TAKEN] skipping instrumentation hint at offset ${this.code.Current.Offset}`);
118
+ }
119
+ return;
120
+ }
121
+ let name = this.dataStack.pop();
122
+ let node = new AST.ASTDelete(new AST.ASTSubscr(name, new AST.ASTSlice(AST.ASTSlice.SliceOp.Slice0)));
123
+ node.line = this.code.Current.LineNo;
124
+ this.curBlock.nodes.push(node);
125
+ }
126
+
127
+ function handleDeleteSlice1() {
128
+ let upper = this.dataStack.pop();
129
+ let name = this.dataStack.pop();
130
+
131
+ let node = new AST.ASTDelete(new AST.ASTSubscr(name, new AST.ASTSlice(AST.ASTSlice.SliceOp.Slice1, upper)));
132
+ node.line = this.code.Current.LineNo;
133
+ this.curBlock.nodes.push(node);
134
+ }
135
+
136
+ function handleDeleteSlice2() {
137
+ let lower = this.dataStack.pop();
138
+ let name = this.dataStack.pop();
139
+
140
+ let node = new AST.ASTDelete(new AST.ASTSubscr(name, new AST.ASTSlice(AST.ASTSlice.SliceOp.Slice2, lower)));
141
+ node.line = this.code.Current.LineNo;
142
+ this.curBlock.nodes.push(node);
143
+ }
144
+
145
+ function handleDeleteSlice3() {
146
+ let lower = this.dataStack.pop();
147
+ let upper = this.dataStack.pop();
148
+ let name = this.dataStack.pop();
149
+
150
+ let node = new AST.ASTDelete(new AST.ASTSubscr(name, new AST.ASTSlice(AST.ASTSlice.SliceOp.Slice3, upper, lower)));
151
+ node.line = this.code.Current.LineNo;
152
+ this.curBlock.nodes.push(node);
153
+ }
154
+
155
+ function handleDeleteSubscr() {
156
+ let key = this.dataStack.pop();
157
+ let name = this.dataStack.pop();
158
+
159
+ let node = new AST.ASTDelete(new AST.ASTSubscr(name, key));
160
+ node.line = this.code.Current.LineNo;
161
+ this.curBlock.nodes.push(node);
162
+ }
163
+
164
+ function handleSlice0() {
165
+ let name = this.dataStack.pop();
166
+ if (name instanceof AST.ASTChainStore) {
167
+ name = name.source;
168
+ }
169
+
170
+ let sliceNode = new AST.ASTSlice (AST.ASTSlice.SliceOp.Slice0);
171
+ let node = new AST.ASTSubscr (name, sliceNode);
172
+ node.line = this.code.Current.LineNo;
173
+ this.dataStack.push(node);
174
+ }
175
+
176
+ function handleSlice1() {
177
+ let lower = this.dataStack.pop();
178
+ let name = this.dataStack.pop();
179
+
180
+ let sliceNode = new AST.ASTSlice(AST.ASTSlice.SliceOp.Slice1, lower);
181
+ let node = new AST.ASTSubscr(name, sliceNode);
182
+ node.line = this.code.Current.LineNo;
183
+ this.dataStack.push(node);
184
+ }
185
+
186
+ function handleSlice2() {
187
+ let upper = this.dataStack.pop();
188
+ let name = this.dataStack.pop();
189
+
190
+ let sliceNode = new AST.ASTSlice(AST.ASTSlice.SliceOp.Slice2, null, upper);
191
+ let node = new AST.ASTSubscr(name, sliceNode);
192
+ node.line = this.code.Current.LineNo;
193
+ this.dataStack.push(node);
194
+ }
195
+
196
+ function handleSlice3() {
197
+ let upper = this.dataStack.pop();
198
+ let lower = this.dataStack.pop();
199
+ let name = this.dataStack.pop();
200
+
201
+ let sliceNode = new AST.ASTSlice(AST.ASTSlice.SliceOp.Slice3, lower, upper);
202
+ let node = new AST.ASTSubscr(name, sliceNode);
203
+ node.line = this.code.Current.LineNo;
204
+ this.dataStack.push(node);
205
+ }
206
+
207
+ function handleStoreSlice0() {
208
+ let destNode = this.dataStack.pop();
209
+ let valueNode = this.dataStack.pop();
210
+ let node = new AST.ASTStore(valueNode,
211
+ new AST.ASTSubscr(destNode,
212
+ new AST.ASTSlice(AST.ASTSlice.SliceOp.Slice0)
213
+ )
214
+ );
215
+ node.line = this.code.Current.LineNo;
216
+ this.curBlock.append(node);
217
+ }
218
+
219
+ function handleStoreSlice1() {
220
+ let upper = this.dataStack.pop();
221
+ let dest = this.dataStack.pop();
222
+ let value = this.dataStack.pop();
223
+ let node = new AST.ASTStore(value,
224
+ new AST.ASTSubscr(dest,
225
+ new AST.ASTSlice(AST.ASTSlice.SliceOp.Slice1, upper)
226
+ )
227
+ );
228
+ node.line = this.code.Current.LineNo;
229
+ this.curBlock.append(node);
230
+ }
231
+
232
+ function handleStoreSlice2() {
233
+ let lowerNode = this.dataStack.pop();
234
+ let destNode = this.dataStack.pop();
235
+ let valueNode = this.dataStack.pop();
236
+ let node = new AST.ASTStore(valueNode,
237
+ new AST.ASTSubscr(destNode,
238
+ new AST.ASTSlice(AST.ASTSlice.SliceOp.Slice2, null, lowerNode)));
239
+ node.line = this.code.Current.LineNo;
240
+ this.curBlock.append(node);
241
+ }
242
+
243
+ function handleStoreSlice3() {
244
+ let lowerNode = this.dataStack.pop();
245
+ let upperNode = this.dataStack.pop();
246
+ let destNode = this.dataStack.pop();
247
+ let valueNode = this.dataStack.pop();
248
+ let node = new AST.ASTStore(valueNode,
249
+ new AST.ASTSubscr(destNode,
250
+ new AST.ASTSlice(AST.ASTSlice.SliceOp.Slice3, upperNode, lowerNode)));
251
+ node.line = this.code.Current.LineNo;
252
+ this.curBlock.append(node);
253
+ }
254
+
255
+ function getAnnotationTargetName(node) {
256
+ if (!node) {
257
+ return null;
258
+ }
259
+ if (node instanceof AST.ASTName) {
260
+ return node.name;
261
+ }
262
+ if (node instanceof AST.ASTObject) {
263
+ let value = node.object?.Value;
264
+ if (value !== undefined && value !== null) {
265
+ return value.toString();
266
+ }
267
+ }
268
+ let fragment = node.codeFragment?.();
269
+ if (!fragment) {
270
+ return null;
271
+ }
272
+ fragment = fragment.toString ? fragment.toString() : fragment;
273
+ if (typeof fragment !== 'string') {
274
+ return null;
275
+ }
276
+ const trimmed = fragment.trim();
277
+ if ((trimmed.startsWith("'") && trimmed.endsWith("'")) ||
278
+ (trimmed.startsWith('"') && trimmed.endsWith('"'))) {
279
+ return trimmed.substring(1, trimmed.length - 1);
280
+ }
281
+ return trimmed;
282
+ }
283
+
284
+ function storeMatchesAnnotation(storeNode, annotationKeyNode) {
285
+ if (!(storeNode instanceof AST.ASTStore)) {
286
+ return false;
287
+ }
288
+ const annotationName = getAnnotationTargetName(annotationKeyNode);
289
+ if (!annotationName) {
290
+ return false;
291
+ }
292
+
293
+ const dest = storeNode.dest;
294
+ if (dest instanceof AST.ASTName) {
295
+ return dest.name === annotationName;
296
+ }
297
+ return false;
298
+ }
299
+
300
+ function handleStoreSubscr() {
301
+ if (this.unpack) {
302
+ let subscrNode = this.dataStack.pop();
303
+ let destNode = this.dataStack.pop();
304
+
305
+ let saveNode = new AST.ASTSubscr(destNode, subscrNode);
306
+
307
+ let tupleNode = this.dataStack.top();
308
+ if (tupleNode instanceof AST.ASTTuple)
309
+ tupleNode.add(saveNode);
310
+ else if (global.g_cliArgs?.debug)
311
+ console.error("Something TERRIBLE happened!\n");
312
+
313
+ if (--this.unpack <= 0) {
314
+ this.dataStack.pop();
315
+ let seqNode = this.dataStack.pop();
316
+ if (seqNode instanceof AST.ASTChainStore) {
317
+ seqNode.line = this.code.Current.LineNo;
318
+ this.append_to_chain_store(seqNode, tupleNode);
319
+ } else {
320
+ let node = new AST.ASTStore(seqNode, tupleNode);
321
+ node.line = this.code.Current.LineNo;
322
+ this.curBlock.append(node);
323
+ }
324
+ }
325
+ } else {
326
+ let subscrNode = this.dataStack.pop();
327
+ let destNode = this.dataStack.pop();
328
+ let srcNode = this.dataStack.pop();
329
+
330
+ // If variable annotations are enabled, we'll need to check for them here.
331
+ // Python handles a varaible annotation by setting:
332
+ // __annotations__['var-name'] = type
333
+ let found_annotated_var = (this.variable_annotations && destNode instanceof AST.ASTName
334
+ && destNode.name == "__annotations__");
335
+
336
+ if (found_annotated_var) {
337
+ // Annotations can be done alone or as part of an assignment.
338
+ // In the case of an assignment, we'll see a NODE_STORE on the this.dataStack.
339
+ if (!this.curBlock.nodes.empty()) {
340
+ // Replace the existing NODE_STORE with a new one that includes the annotation.
341
+ let store = this.curBlock.nodes.top();
342
+ if (store instanceof AST.ASTStore && storeMatchesAnnotation(store, subscrNode)) {
343
+ this.curBlock.removeLast();
344
+ let node = new AST.ASTStore(store.src,
345
+ new AST.ASTAnnotatedVar(subscrNode, srcNode)
346
+ );
347
+ node.line = this.code.Current.LineNo;
348
+ this.curBlock.append(node);
349
+ } else {
350
+ let node = new AST.ASTAnnotatedVar(subscrNode, srcNode);
351
+ node.line = this.code.Current.LineNo;
352
+ this.curBlock.append(node);
353
+ }
354
+ } else {
355
+ let node = new AST.ASTAnnotatedVar(subscrNode, srcNode);
356
+ node.line = this.code.Current.LineNo;
357
+ this.curBlock.append(node);
358
+ }
359
+ } else {
360
+ if (destNode instanceof AST.ASTMap) {
361
+ destNode.add(subscrNode, srcNode);
362
+ } else if (srcNode instanceof AST.ASTChainStore) {
363
+ this.append_to_chain_store(srcNode, new AST.ASTSubscr(destNode, subscrNode));
364
+ } else {
365
+ let node = new AST.ASTStore(srcNode,
366
+ new AST.ASTSubscr(destNode, subscrNode)
367
+ );
368
+ node.line = this.code.Current.LineNo;
369
+ this.curBlock.append(node);
370
+ }
371
+ }
372
+ }
373
+ }
374
+
375
+ module.exports = {
376
+ handleBinarySubscr,
377
+ handleMapAddA,
378
+ handleStoreMap,
379
+ handleBuildSliceA,
380
+ handleDeleteSlice0,
381
+ handleDeleteSlice1,
382
+ handleDeleteSlice2,
383
+ handleDeleteSlice3,
384
+ handleDeleteSubscr,
385
+ handleSlice0,
386
+ handleSlice1,
387
+ handleSlice2,
388
+ handleSlice3,
389
+ handleStoreSlice0,
390
+ handleStoreSlice1,
391
+ handleStoreSlice2,
392
+ handleStoreSlice3,
393
+ handleStoreSubscr,
394
+ };
@@ -0,0 +1,91 @@
1
+ const AST = require('../ast/ast_node');
2
+
3
+ function handleUnaryCall() {
4
+ let funcNode = this.dataStack.pop();
5
+ let node = new AST.ASTCall(funcNode, [], []);
6
+ node.line = this.code.Current.LineNo;
7
+ this.dataStack.push(node);
8
+ }
9
+
10
+ function handleConvertValueA() {
11
+ // Python 3.14 CONVERT_VALUE: capture requested conversion for upcoming FORMAT_*.
12
+ const val = this.dataStack.pop();
13
+ const flag = this.code.Current.Argument;
14
+ let conversion = AST.ASTFormattedValue.ConversionFlag.None;
15
+
16
+ if (flag === 1) {
17
+ conversion = AST.ASTFormattedValue.ConversionFlag.Str;
18
+ } else if (flag === 2) {
19
+ conversion = AST.ASTFormattedValue.ConversionFlag.Repr;
20
+ } else if (flag === 3) {
21
+ conversion = AST.ASTFormattedValue.ConversionFlag.ASCII;
22
+ }
23
+
24
+ let node;
25
+ if (val instanceof AST.ASTFormattedValue) {
26
+ val.m_conversion = conversion;
27
+ node = val;
28
+ } else {
29
+ node = new AST.ASTFormattedValue(val, conversion, null);
30
+ node.line = this.code.Current.LineNo;
31
+ }
32
+ this.dataStack.push(node);
33
+ }
34
+
35
+ function handleUnaryConvert() {
36
+ let name = this.dataStack.pop();
37
+ let node = new AST.ASTConvert(name);
38
+ node.line = this.code.Current.LineNo;
39
+ this.dataStack.push(node);
40
+ }
41
+
42
+ function handleUnaryInvert() {
43
+ let arg = this.dataStack.pop();
44
+ let node = new AST.ASTUnary(arg, AST.ASTUnary.UnaryOp.Invert);
45
+ node.line = this.code.Current.LineNo;
46
+ this.dataStack.push(node);
47
+ }
48
+
49
+ function handleUnaryNegative() {
50
+ let arg = this.dataStack.pop();
51
+ let node = new AST.ASTUnary(arg, AST.ASTUnary.UnaryOp.Negative);
52
+ node.line = this.code.Current.LineNo;
53
+ this.dataStack.push(node);
54
+ }
55
+
56
+ function handleUnaryNot() {
57
+ let arg = this.dataStack.pop();
58
+ let node = new AST.ASTUnary(arg, AST.ASTUnary.UnaryOp.Not);
59
+ node.line = this.code.Current.LineNo;
60
+ this.dataStack.push(node);
61
+ }
62
+
63
+ function handleUnaryPositive() {
64
+ let arg = this.dataStack.pop();
65
+ let node = new AST.ASTUnary(arg, AST.ASTUnary.UnaryOp.Positive);
66
+ node.line = this.code.Current.LineNo;
67
+ this.dataStack.push(node);
68
+ }
69
+
70
+ function handleToBool() {
71
+ // Python 3.13+ TO_BOOL: normalize truthiness. Preserve stack value.
72
+ const arg = this.dataStack.pop();
73
+ this.dataStack.push(arg);
74
+ }
75
+
76
+ function handleExitInitCheck() {
77
+ // Python 3.14 EXIT_INIT_CHECK: no-op for decompiler.
78
+ }
79
+
80
+
81
+ module.exports = {
82
+ handleUnaryCall,
83
+ handleConvertValueA,
84
+ handleUnaryConvert,
85
+ handleUnaryInvert,
86
+ handleUnaryNegative,
87
+ handleUnaryNot,
88
+ handleUnaryPositive,
89
+ handleToBool,
90
+ handleExitInitCheck
91
+ };
@@ -0,0 +1,141 @@
1
+ const PycObject = require('../PythonObject').PythonObject;
2
+ const AST = require('../ast/ast_node');
3
+
4
+ function handleUnpackListA() {
5
+ processUnpack.call(this);
6
+ }
7
+
8
+ function handleUnpackTupleA() {
9
+ processUnpack.call(this);
10
+ }
11
+
12
+ function handleUnpackSequenceA() {
13
+ processUnpack.call(this);
14
+ }
15
+
16
+ function processUnpack() {
17
+ this.unpack = this.code.Current.Argument;
18
+
19
+ // Record pattern operation if in pattern matching
20
+ if (this.inMatchPattern) {
21
+ this.patternOps.push({
22
+ type: 'UNPACK_SEQUENCE',
23
+ count: this.unpack
24
+ });
25
+ }
26
+
27
+ if (this.unpack > 0) {
28
+ let node = new AST.ASTTuple([]);
29
+ node.line = this.code.Current.LineNo;
30
+ this.dataStack.push(node);
31
+ } else {
32
+ // Unpack zero values and assign it to top of stack or for loop variable.
33
+ // E.g. [] = TOS / for [] in X
34
+ let tupleNode = new AST.ASTTuple([]);
35
+ if (this.curBlock.blockType == AST.ASTBlock.BlockType.For
36
+ && !this.curBlock.inited) {
37
+ tupleNode.requireParens = true;
38
+ this.curBlock.index = tupleNode;
39
+ } else if (this.dataStack.top() instanceof AST.ASTChainStore) {
40
+ let chainStore = this.dataStack.pop();
41
+ chainStore.line = this.code.Current.LineNo;
42
+ this.append_to_chain_store(chainStore, tupleNode);
43
+ } else {
44
+ let node = new AST.ASTStore(this.dataStack.pop(), tupleNode);
45
+ node.line = this.code.Current.LineNo;
46
+ this.curBlock.append(node);
47
+ }
48
+ }
49
+ }
50
+
51
+ function handleUnpackArgA() {
52
+ let data = this.dataStack.pop();
53
+ this.object.ArgCount = this.code.Current.Argument;
54
+ for (let idx = 0; idx < this.code.Current.Argument; idx++) {
55
+ this.object.VarNames.Value.push(data[idx]);
56
+ }
57
+ this.code.GoNext(this.code.Current.Argument);
58
+ }
59
+
60
+ function handleUnpackExA() {
61
+ this.unpack = (this.code.Current.Argument & 0xFF);
62
+ this.starPos = this.unpack;
63
+ this.unpack += 1 + (this.code.Current.Argument >> 8) & 0xFF;
64
+
65
+ let source = this.dataStack.pop();
66
+ let tuple = new AST.ASTTuple([]);
67
+ tuple.requireParens = false;
68
+ this.dataStack.push(new PycObject("Py_Null"));
69
+ this.dataStack.push(new AST.ASTChainStore([], source));
70
+ this.dataStack.push(tuple);
71
+ }
72
+
73
+ function handleBuildListUnpackA() {
74
+ processBuild.call(this);
75
+ }
76
+
77
+ function handleBuildTupleUnpackA() {
78
+ processBuild.call(this);
79
+ }
80
+
81
+ function handleBuildTupleUnpackWithCallA() {
82
+ // Python 3.6+ - same as BUILD_TUPLE_UNPACK but with better error messages
83
+ processBuild.call(this);
84
+ }
85
+
86
+ function processBuild() {
87
+ let values = [];
88
+ for (let idx = 0; idx < this.code.Current.Argument; idx++) {
89
+ values.unshift(this.dataStack.pop());
90
+ }
91
+ let listNode = new AST.ASTList(values); // Or ASTTuple based on opcode
92
+ this.dataStack.push(listNode);
93
+ }
94
+
95
+ function handleBuildSetUnpackA() {
96
+ let values = [];
97
+ for (let idx = 0; idx < this.code.Current.Argument; idx++) {
98
+ values.unshift(this.dataStack.pop());
99
+ }
100
+ let setNode = new AST.ASTSet(values);
101
+ this.dataStack.push(setNode);
102
+ }
103
+
104
+ function handleBuildMapUnpackA() {
105
+ processBuildMapUnpack.call(this);
106
+ }
107
+
108
+ function handleBuildMapUnpackWithCallA() {
109
+ processBuildMapUnpack.call(this);
110
+ }
111
+
112
+ function processBuildMapUnpack() {
113
+ let mapNode = new AST.ASTMap();
114
+ for (let idx = 0; idx < this.code.Current.Argument; idx++) {
115
+ let pair = this.dataStack.pop(); // Should be a dictionary
116
+ if (pair instanceof AST.ASTMap) {
117
+ for (const entry of pair.values) {
118
+ mapNode.add(entry.key, entry.value);
119
+ }
120
+ } else {
121
+ if (global.g_cliArgs?.debug) {
122
+ console.error("Expected a map for BUILD_MAP_UNPACK");
123
+ }
124
+ }
125
+ }
126
+ this.dataStack.push(mapNode);
127
+ }
128
+
129
+ module.exports = {
130
+ handleUnpackListA,
131
+ handleUnpackTupleA,
132
+ handleUnpackSequenceA,
133
+ handleUnpackArgA,
134
+ handleUnpackExA,
135
+ handleBuildListUnpackA,
136
+ handleBuildTupleUnpackA,
137
+ handleBuildTupleUnpackWithCallA,
138
+ handleBuildSetUnpackA,
139
+ handleBuildMapUnpackA,
140
+ handleBuildMapUnpackWithCallA
141
+ };
@@ -0,0 +1,63 @@
1
+
2
+ function classSaver(key, value) {
3
+ if (value && typeof(value) == "object") {
4
+ value.___serialized__class_name = value.constructor.name;
5
+ return value;
6
+ }
7
+ return value;
8
+ }
9
+
10
+ function restoreObjectPrototype(obj) {
11
+ if (obj) {
12
+ for (let subObject of Object.values(obj)) {
13
+ if (subObject && typeof(subObject) == "object") {
14
+ restoreObjectPrototype(subObject);
15
+ if (subObject.___serialized__class_name) {
16
+ Object.setPrototypeOf(subObject, global[subObject.___serialized__class_name]);
17
+ delete subObject.___serialized__class_name;
18
+ subObject = subObject;
19
+ }
20
+ }
21
+ }
22
+ }
23
+ }
24
+
25
+ class StackHistory {
26
+ history = [];
27
+
28
+ push(historyElement) {
29
+ this.history.push(JSON.stringify(historyElement, classSaver));
30
+ }
31
+
32
+ top() {
33
+ if (this.history.length == 0) {
34
+ return [];
35
+ }
36
+ try {
37
+ let value = JSON.parse(this.history[this.history.length - 1]);
38
+ restoreObjectPrototype(value);
39
+ return value;
40
+ } catch (ex) {
41
+ return [];
42
+ }
43
+ }
44
+
45
+ pop() {
46
+ let stack = this.top();
47
+ this.history.pop();
48
+ return stack;
49
+ }
50
+ get length() {
51
+ return this.history.length;
52
+ }
53
+
54
+ set length(value) {
55
+ this.history.length = value;
56
+ }
57
+
58
+ empty() {
59
+ return this.history.length == 0;
60
+ }
61
+ }
62
+
63
+ module.exports = StackHistory;