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,330 @@
1
+ const PycObject = require('../PythonObject').PythonObject;
2
+ const PycDecompiler = require('../PycDecompiler');
3
+ const AST = require('../ast/ast_node');
4
+
5
+ function handleBuildFunction() {
6
+ let functionCode = this.dataStack.pop();
7
+ let functionNode = new AST.ASTFunction(functionCode);
8
+ this.dataStack.push(functionNode);
9
+ }
10
+
11
+ function handleBuildListA() {
12
+ let values = [];
13
+
14
+ for (let idx = this.code.Current.Argument - 1; idx >= 0; idx--) {
15
+ values[idx] = this.dataStack.pop();
16
+ }
17
+
18
+ let listNode = new AST.ASTList(values);
19
+ this.dataStack.push(listNode);
20
+ }
21
+
22
+ function handleBuildSetA() {
23
+ let values = [];
24
+
25
+ for (let idx = this.code.Current.Argument - 1; idx >= 0; idx--) {
26
+ values[idx] = this.dataStack.pop();
27
+ }
28
+
29
+ let listNode = new AST.ASTSet(values);
30
+ this.dataStack.push(listNode);
31
+ if (this.code.Next?.OpCodeID == this.OpCodes.DUP_TOP) {
32
+ this.code.GoNext();
33
+ }
34
+ }
35
+
36
+ function handleBuildClass() {
37
+ let classCode = this.dataStack.pop();
38
+ let bases = this.dataStack.pop();
39
+ let name = this.dataStack.pop();
40
+ let classNode = new AST.ASTClass(classCode, bases, name);
41
+ this.dataStack.push(classNode);
42
+ }
43
+
44
+ function handleLoadBuildClass() {
45
+ let node = new AST.ASTLoadBuildClass (new PycObject());
46
+ node.line = this.code.Current.LineNo;
47
+ this.dataStack.push(node);
48
+ }
49
+
50
+ function handleMakeClosureA() {
51
+ processMakeFunction.call(this);
52
+ }
53
+
54
+ function handleMakeFunction() {
55
+ processMakeFunction.call(this);
56
+ }
57
+
58
+ function handleMakeFunctionA() {
59
+ processMakeFunction.call(this);
60
+ }
61
+
62
+ function handleMakeCellA() {
63
+ const varNames = this.object?.VarNames?.Value || [];
64
+ const name = varNames[this.code.Current.Argument]?.toString?.() || `##cell_${this.code.Current.Argument}##`;
65
+ this.dataStack.push(new AST.ASTName(name));
66
+ }
67
+
68
+ function handleSetFunctionAttributeA() {
69
+ // Stack: [..., func, value]; argument encodes attribute id (annotations/cellvars/etc).
70
+ const value = this.dataStack.pop();
71
+ const func = this.dataStack.pop();
72
+
73
+ // If annotations tuple is paired with a function, attach them to the function.
74
+ const attachAnnotations = (targetFunc, tupleNode) => {
75
+ const annotations = {};
76
+ const pairs = tupleNode?.values || [];
77
+ for (let i = 0; i + 1 < pairs.length; i += 2) {
78
+ const keyNode = pairs[i];
79
+ const valNode = pairs[i + 1];
80
+ let keyStr = keyNode?.object?.Value || keyNode?.name || keyNode?.codeFragment?.()?.toString?.() || keyNode?.toString?.() || '';
81
+ if (typeof keyStr === 'string') {
82
+ keyStr = keyStr.replace(/^['"]|['"]$/g, "");
83
+ }
84
+ if (keyStr) {
85
+ annotations[keyStr] = valNode;
86
+ }
87
+ }
88
+ targetFunc.annotations = annotations;
89
+ };
90
+
91
+ if (func instanceof AST.ASTFunction && value instanceof AST.ASTTuple) {
92
+ attachAnnotations(func, value);
93
+ this.dataStack.push(func);
94
+ } else if (value instanceof AST.ASTFunction && func instanceof AST.ASTTuple) {
95
+ attachAnnotations(value, func);
96
+ this.dataStack.push(value);
97
+ } else if (func instanceof AST.ASTFunction) {
98
+ this.dataStack.push(func);
99
+ } else if (value) {
100
+ this.dataStack.push(value);
101
+ }
102
+
103
+ if (global.g_cliArgs?.debug) {
104
+ console.log(`[SET_FUNCTION_ATTRIBUTE] arg=${this.code.Current.Argument}, func=${func?.constructor?.name}, value=${value?.constructor?.name}`);
105
+ }
106
+ }
107
+
108
+ function processMakeFunction() {
109
+ let func_code = this.dataStack.pop();
110
+
111
+ if (!func_code) {
112
+ if (global.g_cliArgs?.debug) {
113
+ console.error(`[MAKE_FUNCTION] Stack underflow at offset ${this.code.Current.Offset}`);
114
+ }
115
+ return;
116
+ }
117
+
118
+ /* Test for the qualified name of the function (at TOS) */
119
+ let tos_type = func_code.object?.ClassName;
120
+ if (!["Py_CodeObject", "Py_CodeObject2"].includes(tos_type)) {
121
+ func_code = this.dataStack.pop() || func_code; // Try one more slot
122
+ }
123
+
124
+ if (!func_code || !func_code.object || !["Py_CodeObject", "Py_CodeObject2"].includes(func_code.object.ClassName)) {
125
+ // Try to salvage a code object from constants (3.13 specialized bytecode may reorder stack)
126
+ const fallback = (this.object?.Consts?.Value || []).find(c => ["Py_CodeObject","Py_CodeObject2"].includes(c?.ClassName));
127
+ if (fallback) {
128
+ func_code = new (require('../ast/ast_node').ASTObject)(fallback);
129
+ } else {
130
+ // Give up gracefully: emit stub function
131
+ let fnName = this.code.Current?.Name || `__function_${this.code.Current.Offset}__`;
132
+ let stub = new (require('../ast/ast_node').ASTFunction)(fnName, new (require('../ast/ast_node').ASTBlock)());
133
+ stub.line = this.code.Current.LineNo;
134
+ this.dataStack.push(stub);
135
+ return;
136
+ }
137
+ }
138
+
139
+ let decompiler = new PycDecompiler(func_code.object);
140
+ func_code.object.SourceCode = decompiler.decompile();
141
+
142
+ let annotationMap = null;
143
+ // Python 3.11+ MAKE_FUNCTION flag bit 0x4 indicates annotations tuple on stack before code object
144
+ if ((this.object.Reader.versionCompare(3, 11) >= 0) &&
145
+ (this.code.Current.Argument & 0x04) &&
146
+ this.dataStack.top() instanceof AST.ASTTuple) {
147
+ const tupleAnn = this.dataStack.pop();
148
+ const pairs = tupleAnn.values || [];
149
+ annotationMap = {};
150
+ for (let i = 0; i + 1 < pairs.length; i += 2) {
151
+ const keyNode = pairs[i];
152
+ const valNode = pairs[i + 1];
153
+ let keyStr = keyNode?.object?.Value || keyNode?.name || keyNode?.codeFragment?.()?.toString?.() || keyNode?.toString?.() || '';
154
+ if (typeof keyStr === 'string') {
155
+ keyStr = keyStr.replace(/^['"]|['"]$/g, "");
156
+ }
157
+ if (keyStr) {
158
+ annotationMap[keyStr] = valNode;
159
+ }
160
+ }
161
+ }
162
+
163
+ let defArgs = [], kwDefArgs = [], annotations = [];
164
+ const is311Plus = this.object.Reader.versionCompare(3, 11) >= 0;
165
+ if (is311Plus) {
166
+ const flags = this.code.Current.Argument;
167
+ // defaults tuple
168
+ if (flags & 0x01) {
169
+ const defaults = this.dataStack.pop();
170
+ if (defaults instanceof AST.ASTTuple) {
171
+ defArgs = defaults.values;
172
+ }
173
+ }
174
+ // kwdefaults mapping (rare in these fixtures)
175
+ if (flags & 0x02) {
176
+ this.dataStack.pop(); // discard kwdefaults for now
177
+ }
178
+ // annotations handled earlier (0x04)
179
+ if (flags & 0x08) {
180
+ this.dataStack.pop(); // closure tuple
181
+ }
182
+ } else {
183
+ let defCount = this.code.Current.Argument & 0xFF;
184
+ let kwDefCount = (this.code.Current.Argument >> 8) & 0xFF;
185
+ let numAnnotations = (this.code.Current.Argument >> 16) & 0xFF;
186
+
187
+ if (this.object.Reader.versionCompare(3, 0) < 0) {
188
+ for (let idx = 0; idx < defCount; ++idx) {
189
+ defArgs.unshift(this.dataStack.pop());
190
+ }
191
+
192
+ if (kwDefCount > 0) {
193
+ for (let idx = 0; idx < kwDefCount - defCount; ++idx) {
194
+ kwDefArgs.unshift(this.dataStack.pop());
195
+ }
196
+ }
197
+ } else {
198
+ if (numAnnotations > 0) {
199
+ let tuple = this.dataStack.pop();
200
+ while (--numAnnotations > 0) {
201
+ annotations.push({key: tuple[numAnnotations], value: this.dataStack.pop()})
202
+ }
203
+ }
204
+
205
+ if (defCount > 0) {
206
+ while (defCount-- > 0) {
207
+ defArgs.unshift(this.dataStack.pop());
208
+ }
209
+ }
210
+
211
+ if (kwDefCount > 0) {
212
+ while (kwDefCount-- > 0) {
213
+ let value = this.dataStack.pop();
214
+ let name = this.dataStack.pop();
215
+ kwDefArgs.unshift({name, value});
216
+ }
217
+ }
218
+ }
219
+ }
220
+
221
+ let node = new AST.ASTFunction (func_code, defArgs, kwDefArgs, annotations);
222
+ if (annotationMap) {
223
+ node.annotations = annotationMap;
224
+ }
225
+ this.dataStack.push(node);
226
+ }
227
+
228
+ function handleBuildTupleA() {
229
+ if (this.dataStack.top() instanceof AST.ASTLoadBuildClass) {
230
+ return;
231
+ }
232
+
233
+ let values = [];
234
+ for (let idx = this.code.Current.Argument - 1; idx >= 0; idx--) {
235
+ values[idx] = this.dataStack.pop();
236
+ }
237
+
238
+ let tupleNode = new AST.ASTTuple(values);
239
+ tupleNode.line = this.code.Current.LineNo;
240
+ this.dataStack.push(tupleNode);
241
+ }
242
+
243
+ function handleBuildMapA() {
244
+ if (this.object.Reader.versionCompare(3, 5) >= 0) {
245
+ // Collect key-value pairs from stack first
246
+ let pairs = [];
247
+ for (let idx = 0; idx < this.code.Current.Argument; idx++) {
248
+ let value = this.dataStack.pop();
249
+ let key = this.dataStack.pop();
250
+ pairs.push({key, value});
251
+ }
252
+
253
+ // Create map and add pairs in correct order (reverse because we popped)
254
+ let mapNode = new AST.ASTMap();
255
+ mapNode.line = this.code.Current.LineNo;
256
+ for (let i = pairs.length - 1; i >= 0; i--) {
257
+ mapNode.add(pairs[i].key, pairs[i].value);
258
+ }
259
+
260
+ this.dataStack.push(mapNode);
261
+ } else {
262
+ if (this.dataStack.top() instanceof AST.ASTChainStore) {
263
+ this.dataStack.pop();
264
+ }
265
+
266
+ let mapNode = new AST.ASTMap();
267
+ mapNode.line = this.code.Current.LineNo;
268
+ this.dataStack.push(mapNode);
269
+ }
270
+ }
271
+
272
+ function handleBuildConstKeyMapA() {
273
+ let values = [];
274
+ let keys = this.dataStack.pop();
275
+ for (let idx = 0; idx < this.code.Current.Argument; idx++) {
276
+ values.push(this.dataStack.pop());
277
+ }
278
+
279
+ let mapNode = new AST.ASTConstMap(keys, values);
280
+ mapNode.line = this.code.Current.LineNo;
281
+ this.dataStack.push(mapNode);
282
+ }
283
+
284
+ function handleBuildStringA() {
285
+ let values = [];
286
+ for (let idx = 0; idx < this.code.Current.Argument; idx++) {
287
+ values.push(this.dataStack.pop());
288
+ }
289
+
290
+ let stringNode = new AST.ASTJoinedStr(values);
291
+ stringNode.line = this.code.Current.LineNo;
292
+ this.dataStack.push(stringNode);
293
+ }
294
+
295
+ function handleListToTuple() {
296
+ let listNode = this.dataStack.pop();
297
+ if (listNode instanceof AST.ASTList) {
298
+ this.dataStack.push(new AST.ASTTuple(listNode.values));
299
+ } else {
300
+ console.error("Expected ASTList for LIST_TO_TUPLE");
301
+ }
302
+ }
303
+
304
+ function handleLoadClosureA() {
305
+ this.dataStack.push(new AST.ASTName(this.code.Current.FreeName));
306
+ }
307
+
308
+ function handleCopyFreeVarsA() {
309
+ // Python 3.11+ COPY_FREE_VARS: copies free vars for class scopes; no AST impact.
310
+ }
311
+
312
+ module.exports = {
313
+ handleBuildClass,
314
+ handleBuildFunction,
315
+ handleBuildListA,
316
+ handleBuildSetA,
317
+ handleBuildMapA,
318
+ handleBuildConstKeyMapA,
319
+ handleBuildStringA,
320
+ handleBuildTupleA,
321
+ handleLoadBuildClass,
322
+ handleLoadClosureA,
323
+ handleCopyFreeVarsA,
324
+ handleMakeClosureA,
325
+ handleMakeFunction,
326
+ handleMakeFunctionA,
327
+ handleMakeCellA,
328
+ handleSetFunctionAttributeA,
329
+ handleListToTuple
330
+ };
@@ -0,0 +1,172 @@
1
+ const AST = require('../ast/ast_node');
2
+
3
+ function handleInstrumentedYieldValueA() {
4
+ this.handleYieldValue();
5
+ }
6
+
7
+ function handleYieldValueA() {
8
+ // Python 3.12+ YIELD_VALUE with argument
9
+ // Call the actual handleYieldValue function in this context
10
+ handleYieldValue.call(this);
11
+ }
12
+
13
+ function handleYieldValue() {
14
+ let value = this.dataStack.pop();
15
+
16
+ // Skip YIELD_VALUE if we're inside await machinery
17
+ if (this.insideAwait) {
18
+ if (global.g_cliArgs?.debug) {
19
+ console.log(`[YIELD_VALUE] Skipping - inside await machinery`);
20
+ }
21
+ // Put value back on stack for END_SEND
22
+ this.dataStack.push(value);
23
+ return;
24
+ }
25
+
26
+ // Python 3.11+: YIELD_VALUE appears in async for loops as implementation detail
27
+ // Skip if we're inside AsyncFor block and value looks like generator machinery
28
+ if (this.object.Reader.versionCompare(3, 11) >= 0) {
29
+ // Check if we're in an async for loop
30
+ let inAsyncFor = false;
31
+ for (let i = this.blocks.length - 1; i >= 0; i--) {
32
+ if (this.blocks[i].blockType == AST.ASTBlock.BlockType.AsyncFor) {
33
+ inAsyncFor = true;
34
+ break;
35
+ }
36
+ }
37
+
38
+ if (inAsyncFor) {
39
+ // Check if value is generator machinery (call to __anext__, etc.)
40
+ // In async for context, YIELD_VALUE with awaitable is implementation detail
41
+ if (value && (value.constructor.name === 'ASTCall' ||
42
+ value.constructor.name === 'ASTBinary' ||
43
+ value.constructor.name === 'ASTNone')) {
44
+ if (global.g_cliArgs?.debug) {
45
+ console.log(`[YIELD_VALUE] Skipping generator machinery in async for: ${value.constructor.name}`);
46
+ }
47
+ // Don't append - this is implementation detail
48
+ return;
49
+ }
50
+ }
51
+ }
52
+
53
+ let node = new AST.ASTReturn(value, AST.ASTReturn.RetType.Yield);
54
+ node.line = this.code.Current.LineNo;
55
+ this.curBlock.append(node);
56
+ }
57
+
58
+ function handleYieldFrom() {
59
+ let dest = this.dataStack.pop();
60
+ // TODO: Support yielding into a non-null destination
61
+ let valueNode = this.dataStack.top();
62
+ if (valueNode) {
63
+ let node = new AST.ASTReturn(valueNode, AST.ASTReturn.RetType.YieldFrom);
64
+ node.line = this.code.Current.LineNo;
65
+ this.curBlock.append(node);
66
+ }
67
+ }
68
+
69
+ function handleGetAwaitable() {
70
+ let object = this.dataStack.pop();
71
+ let node = new AST.ASTAwaitable (object);
72
+ node.line = this.code.Current.LineNo;
73
+ this.dataStack.push(node);
74
+
75
+ // Set flag: we're inside await machinery
76
+ // SEND/YIELD_VALUE until END_SEND are implementation details
77
+ this.insideAwait = true;
78
+ }
79
+
80
+ function handleGetAwaitableA() {
81
+ // Python 3.11+ GET_AWAITABLE with argument
82
+ handleGetAwaitable.call(this);
83
+ }
84
+
85
+ function handleGenStartA() {
86
+ this.dataStack.pop();
87
+ }
88
+
89
+ function handleEndSend() {
90
+ // Python 3.12+ END_SEND opcode
91
+ // Ends a SEND operation in async generators/await
92
+ // For decompilation: clear await flag, awaitable result is on stack
93
+ if (global.g_cliArgs?.debug) {
94
+ console.log(`[END_SEND] at offset ${this.code.Current.Offset}, insideAwait=${this.insideAwait}`);
95
+ }
96
+
97
+ // Clear await machinery flag
98
+ this.insideAwait = false;
99
+ }
100
+
101
+ function handleInstrumentedEndSendA() {
102
+ // Instrumented variant mirrors END_SEND behavior.
103
+ handleEndSend.call(this);
104
+ }
105
+
106
+ function handleCleanupThrow() {
107
+ // Python 3.12+ CLEANUP_THROW opcode
108
+ // Exception cleanup in async generators
109
+ // For decompilation: no-op, exception handling is implicit
110
+ if (global.g_cliArgs?.debug) {
111
+ console.log(`[CLEANUP_THROW] at offset ${this.code.Current.Offset}`);
112
+ }
113
+ }
114
+
115
+ function handleSendA() {
116
+ // Python 3.11+ SEND opcode
117
+ // Used in async generators to send values into awaitables
118
+ // Stack: TOS = value to send, TOS1 = awaitable
119
+ // In async for context: sends None into __anext__() awaitable
120
+
121
+ if (global.g_cliArgs?.debug) {
122
+ console.log(`[SEND] at offset ${this.code.Current.Offset}, jump_target=${this.code.Current.Argument}`);
123
+ }
124
+
125
+ // For async for loops, SEND is part of iteration machinery
126
+ // The awaitable (__anext__) is already on stack from GET_ANEXT
127
+ // SEND will be followed by YIELD_VALUE (generator mechanics)
128
+ // Result will be stored by subsequent STORE_FAST
129
+
130
+ // Pop the send value (usually None for async for)
131
+ let sendValue = this.dataStack.pop();
132
+
133
+ // Keep awaitable on stack - YIELD_VALUE will handle it
134
+ // Or if we're in a simple async for, it stays for STORE_FAST
135
+
136
+ if (global.g_cliArgs?.debug) {
137
+ console.log(` Send value: ${sendValue?.constructor?.name}, stack depth: ${this.dataStack.length}`);
138
+ }
139
+ }
140
+
141
+ function handleResumeA() {
142
+ // Python 3.11+ RESUME opcode
143
+ // Marks resumption points in generators/coroutines
144
+ // Argument: 0=start, 1=yield, 2=yield from, 3=await
145
+
146
+ if (global.g_cliArgs?.debug) {
147
+ let resumeType = ['start', 'yield', 'yield_from', 'await'][this.code.Current.Argument] || 'unknown';
148
+ console.log(`[RESUME ${resumeType}] at offset ${this.code.Current.Offset}`);
149
+ }
150
+
151
+ // No-op for decompiler - just marks resumption point for runtime optimization
152
+ }
153
+
154
+ function handleInstrumentedResumeA() {
155
+ this.handleResumeA();
156
+ }
157
+
158
+ module.exports = {
159
+ handleGetAwaitable,
160
+ handleGetAwaitableA,
161
+ handleYieldFrom,
162
+ handleInstrumentedYieldValueA,
163
+ handleYieldValueA,
164
+ handleYieldValue,
165
+ handleEndSend,
166
+ handleInstrumentedEndSendA,
167
+ handleCleanupThrow,
168
+ handleSendA,
169
+ handleResumeA,
170
+ handleInstrumentedResumeA,
171
+ handleGenStartA
172
+ };
@@ -0,0 +1,53 @@
1
+ const AST = require('../ast/ast_node');
2
+
3
+ function handleImportNameA() {
4
+ if (this.object.Reader.versionCompare(2, 0) < 0) {
5
+ let node = new AST.ASTImport(new AST.ASTName(this.code.Current.Name), null);
6
+ node.line = this.code.Current.LineNo;
7
+ this.dataStack.push(node);
8
+ } else {
9
+ let fromlist = this.dataStack.pop();
10
+ if (fromlist instanceof AST.ASTNone) {
11
+ fromlist = null;
12
+ }
13
+ let dots = '';
14
+ if (this.object.Reader.versionCompare(2, 5) >= 0) {
15
+ let importLevelNode = this.dataStack.pop(); // Level
16
+ let importLevel = +importLevelNode?.object || -1;
17
+ if (importLevel > 0) {
18
+ dots = Buffer.alloc(importLevel, '.').toString('ascii');
19
+ }
20
+ }
21
+
22
+ let node = new AST.ASTImport (new AST.ASTName(dots + this.code.Current.Name), fromlist);
23
+ node.line = this.code.Current.LineNo;
24
+
25
+ if (this.code.Next?.OpCodeID == this.OpCodes.IMPORT_STAR) {
26
+ node.add_store(new AST.ASTStore(new AST.ASTName("*"), null));
27
+ this.code.GoNext();
28
+ } else if (fromlist?.object?.ClassName == 'Py_Tuple' && fromlist.object.Value.length > 0) {
29
+ this.code.extractImportNames(fromlist.object, (name, alias) => {
30
+ node.add_store(new AST.ASTStore(new AST.ASTName(name), new AST.ASTName(alias)));
31
+ });
32
+ } else if (!fromlist) {
33
+ let aliasNode = this.code.GetOpCodeByName("STORE_*");
34
+ node.alias = new AST.ASTName(aliasNode.Label);
35
+ this.code.GoToOffset(aliasNode.Offset);
36
+ } else {
37
+ console.error('WARNING: Not covered situation in IMPORT_NAME.');
38
+ }
39
+
40
+ this.curBlock.nodes.push(node);
41
+
42
+ }
43
+ }
44
+
45
+ function handleImportFromA() {}
46
+
47
+ function handleImportStar() {}
48
+
49
+ module.exports = {
50
+ handleImportNameA,
51
+ handleImportFromA,
52
+ handleImportStar
53
+ };