@lewin671/python-vm 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 (144) hide show
  1. package/.claude/settings.local.json +3 -0
  2. package/.prettierrc +7 -0
  3. package/Agents.md +66 -0
  4. package/README.md +93 -0
  5. package/README_zh-CN.md +93 -0
  6. package/SETUP.md +171 -0
  7. package/dist/compiler.d.ts +20 -0
  8. package/dist/compiler.js +91 -0
  9. package/dist/compiler_module/compiler.d.ts +8 -0
  10. package/dist/compiler_module/compiler.js +22 -0
  11. package/dist/compiler_module/index.d.ts +2 -0
  12. package/dist/compiler_module/index.js +6 -0
  13. package/dist/index.d.ts +4 -0
  14. package/dist/index.js +67 -0
  15. package/dist/lexer/index.d.ts +2 -0
  16. package/dist/lexer/index.js +6 -0
  17. package/dist/lexer/lexer.d.ts +16 -0
  18. package/dist/lexer/lexer.js +403 -0
  19. package/dist/parser/expressions.d.ts +30 -0
  20. package/dist/parser/expressions.js +483 -0
  21. package/dist/parser/index.d.ts +2 -0
  22. package/dist/parser/index.js +6 -0
  23. package/dist/parser/parser.d.ts +63 -0
  24. package/dist/parser/parser.js +129 -0
  25. package/dist/parser/statements.d.ts +20 -0
  26. package/dist/parser/statements.js +388 -0
  27. package/dist/parser/targets.d.ts +6 -0
  28. package/dist/parser/targets.js +75 -0
  29. package/dist/types/ast.d.ts +63 -0
  30. package/dist/types/ast.js +60 -0
  31. package/dist/types/bytecode.d.ts +38 -0
  32. package/dist/types/bytecode.js +35 -0
  33. package/dist/types/index.d.ts +4 -0
  34. package/dist/types/index.js +20 -0
  35. package/dist/types/token.d.ts +34 -0
  36. package/dist/types/token.js +39 -0
  37. package/dist/vm/builtins.d.ts +4 -0
  38. package/dist/vm/builtins.js +269 -0
  39. package/dist/vm/callable.d.ts +8 -0
  40. package/dist/vm/callable.js +161 -0
  41. package/dist/vm/execution.d.ts +15 -0
  42. package/dist/vm/execution.js +283 -0
  43. package/dist/vm/expression-generator.d.ts +3 -0
  44. package/dist/vm/expression-generator.js +70 -0
  45. package/dist/vm/expressions.d.ts +13 -0
  46. package/dist/vm/expressions.js +390 -0
  47. package/dist/vm/imports.d.ts +7 -0
  48. package/dist/vm/imports.js +99 -0
  49. package/dist/vm/index.d.ts +3 -0
  50. package/dist/vm/index.js +21 -0
  51. package/dist/vm/operations.d.ts +16 -0
  52. package/dist/vm/operations.js +439 -0
  53. package/dist/vm/runtime-types.d.ts +84 -0
  54. package/dist/vm/runtime-types.js +290 -0
  55. package/dist/vm/statements.d.ts +7 -0
  56. package/dist/vm/statements.js +381 -0
  57. package/dist/vm/truthy.d.ts +4 -0
  58. package/dist/vm/truthy.js +47 -0
  59. package/dist/vm/value-utils.d.ts +28 -0
  60. package/dist/vm/value-utils.js +225 -0
  61. package/dist/vm/vm.d.ts +56 -0
  62. package/dist/vm/vm.js +75 -0
  63. package/examples/assert_testing.py +38 -0
  64. package/examples/big_int_precision.py +2 -0
  65. package/examples/boolean_logic.py +35 -0
  66. package/examples/break_continue.py +43 -0
  67. package/examples/classes_objects.py +43 -0
  68. package/examples/compiler_killer_async.py +6 -0
  69. package/examples/compiler_killer_bigint.py +3 -0
  70. package/examples/compiler_killer_bool_int_dict_key.py +5 -0
  71. package/examples/compiler_killer_bool_len.py +9 -0
  72. package/examples/compiler_killer_floor_division.py +4 -0
  73. package/examples/compiler_killer_is_identity.py +3 -0
  74. package/examples/compiler_killer_list_sort_return.py +3 -0
  75. package/examples/compiler_killer_match.py +13 -0
  76. package/examples/compiler_killer_negative_repeat.py +3 -0
  77. package/examples/compiler_killer_negative_zero_repr.py +3 -0
  78. package/examples/compiler_killer_rounding.py +4 -0
  79. package/examples/compiler_killer_slice_assign.py +3 -0
  80. package/examples/comprehensions.py +28 -0
  81. package/examples/conditions.py +13 -0
  82. package/examples/context_manager.py +35 -0
  83. package/examples/decorators.py +50 -0
  84. package/examples/exceptions.py +40 -0
  85. package/examples/fibonacci.py +10 -0
  86. package/examples/functions.py +38 -0
  87. package/examples/generator.py +51 -0
  88. package/examples/global_nonlocal.py +48 -0
  89. package/examples/hello.py +3 -0
  90. package/examples/itertools_example.py +33 -0
  91. package/examples/lists_dicts.py +29 -0
  92. package/examples/loops.py +19 -0
  93. package/examples/math_ops.py +15 -0
  94. package/examples/nan_set.py +6 -0
  95. package/examples/numbers_operators.py +51 -0
  96. package/examples/sets.py +36 -0
  97. package/examples/slicing.py +29 -0
  98. package/examples/starred_unpacking.py +3 -0
  99. package/examples/string_formatting.py +36 -0
  100. package/examples/strings.py +22 -0
  101. package/examples/tuples.py +45 -0
  102. package/examples/type_conversion.py +41 -0
  103. package/jest.config.js +15 -0
  104. package/notes/iterations/compiler-runtime/compiler-runtime_2025-09-16.md +25 -0
  105. package/notes/iterations/compiler-runtime/compiler-runtime_2026-01-16.md +24 -0
  106. package/notes/iterations/compiler-runtime/compiler-runtime_test_2026-01-16.md +21 -0
  107. package/notes/iterations/floor-division/floor-division_2026-01-16.md +29 -0
  108. package/package.json +36 -0
  109. package/prompts/commit.txt +9 -0
  110. package/prompts/task.txt +21 -0
  111. package/prompts/test.txt +23 -0
  112. package/scripts/codex-loop.js +215 -0
  113. package/scripts/verify.sh +12 -0
  114. package/src/compiler.ts +58 -0
  115. package/src/compiler_module/compiler.ts +19 -0
  116. package/src/compiler_module/index.ts +1 -0
  117. package/src/index.ts +39 -0
  118. package/src/lexer/index.ts +1 -0
  119. package/src/lexer/lexer.ts +402 -0
  120. package/src/parser/expressions.ts +462 -0
  121. package/src/parser/index.ts +1 -0
  122. package/src/parser/parser.ts +102 -0
  123. package/src/parser/statements.ts +366 -0
  124. package/src/parser/targets.ts +71 -0
  125. package/src/types/ast.ts +64 -0
  126. package/src/types/bytecode.ts +50 -0
  127. package/src/types/index.ts +3 -0
  128. package/src/types/token.ts +44 -0
  129. package/src/vm/builtins.ts +237 -0
  130. package/src/vm/callable.ts +154 -0
  131. package/src/vm/execution.ts +251 -0
  132. package/src/vm/expression-generator.ts +65 -0
  133. package/src/vm/expressions.ts +373 -0
  134. package/src/vm/imports.ts +61 -0
  135. package/src/vm/index.ts +2 -0
  136. package/src/vm/operations.ts +414 -0
  137. package/src/vm/runtime-types.ts +292 -0
  138. package/src/vm/statements.ts +358 -0
  139. package/src/vm/truthy.ts +36 -0
  140. package/src/vm/value-utils.ts +173 -0
  141. package/src/vm/vm.ts +80 -0
  142. package/tests/compiler.test.ts +111 -0
  143. package/tsconfig.json +20 -0
  144. package/vitest.config.ts +16 -0
@@ -0,0 +1,290 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.PyFile = exports.PyDict = exports.PyGenerator = exports.PyInstance = exports.PyClass = exports.PyFunction = exports.Scope = exports.PyException = exports.ContinueSignal = exports.BreakSignal = exports.ReturnSignal = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ class ReturnSignal {
39
+ constructor(value) {
40
+ this.value = value;
41
+ }
42
+ }
43
+ exports.ReturnSignal = ReturnSignal;
44
+ class BreakSignal {
45
+ }
46
+ exports.BreakSignal = BreakSignal;
47
+ class ContinueSignal {
48
+ }
49
+ exports.ContinueSignal = ContinueSignal;
50
+ class PyException extends Error {
51
+ constructor(pyType, message, pyValue) {
52
+ super(message || pyType);
53
+ this.pyType = pyType;
54
+ this.pyValue = pyValue;
55
+ }
56
+ }
57
+ exports.PyException = PyException;
58
+ class Scope {
59
+ constructor(parent = null) {
60
+ this.values = new Map();
61
+ this.globals = new Set();
62
+ this.nonlocals = new Set();
63
+ this.parent = parent;
64
+ }
65
+ get(name) {
66
+ if (this.values.has(name)) {
67
+ return this.values.get(name);
68
+ }
69
+ if (this.parent) {
70
+ return this.parent.get(name);
71
+ }
72
+ throw new PyException('NameError', `name '${name}' is not defined`);
73
+ }
74
+ set(name, value) {
75
+ if (this.globals.has(name) && this.parent) {
76
+ this.root().values.set(name, value);
77
+ return;
78
+ }
79
+ if (this.nonlocals.has(name) && this.parent) {
80
+ const scope = this.parent.findScopeWith(name);
81
+ if (!scope) {
82
+ throw new PyException('NameError', `no binding for nonlocal '${name}' found`);
83
+ }
84
+ scope.values.set(name, value);
85
+ return;
86
+ }
87
+ this.values.set(name, value);
88
+ }
89
+ root() {
90
+ let scope = this;
91
+ while (scope.parent) {
92
+ scope = scope.parent;
93
+ }
94
+ return scope;
95
+ }
96
+ findScopeWith(name) {
97
+ let scope = this;
98
+ while (scope) {
99
+ if (scope.values.has(name))
100
+ return scope;
101
+ scope = scope.parent;
102
+ }
103
+ return null;
104
+ }
105
+ }
106
+ exports.Scope = Scope;
107
+ class PyFunction {
108
+ constructor(name, params, body, closure, isGenerator) {
109
+ this.name = name;
110
+ this.params = params;
111
+ this.body = body;
112
+ this.closure = closure;
113
+ this.isGenerator = isGenerator;
114
+ }
115
+ }
116
+ exports.PyFunction = PyFunction;
117
+ class PyClass {
118
+ constructor(name, bases, attributes, isException = false) {
119
+ this.name = name;
120
+ this.bases = bases;
121
+ this.attributes = attributes;
122
+ this.isException = isException;
123
+ }
124
+ }
125
+ exports.PyClass = PyClass;
126
+ class PyInstance {
127
+ constructor(klass) {
128
+ this.klass = klass;
129
+ this.attributes = new Map();
130
+ }
131
+ }
132
+ exports.PyInstance = PyInstance;
133
+ class PyGenerator {
134
+ constructor(iterator) {
135
+ this.iterator = iterator;
136
+ }
137
+ next(value) {
138
+ const result = this.iterator.next(value === undefined ? null : value);
139
+ if (result.done) {
140
+ throw new PyException('StopIteration', 'StopIteration');
141
+ }
142
+ return result.value;
143
+ }
144
+ send(value) {
145
+ const result = this.iterator.next(value === undefined ? null : value);
146
+ if (result.done) {
147
+ throw new PyException('StopIteration', 'StopIteration');
148
+ }
149
+ return result.value;
150
+ }
151
+ [Symbol.iterator]() {
152
+ return this.iterator;
153
+ }
154
+ }
155
+ exports.PyGenerator = PyGenerator;
156
+ class PyDict {
157
+ constructor() {
158
+ this.primitiveStore = new Map();
159
+ this.objectStore = new Map();
160
+ }
161
+ get size() {
162
+ return this.primitiveStore.size + this.objectStore.size;
163
+ }
164
+ set(key, value) {
165
+ const info = this.keyInfo(key);
166
+ const existing = info.store.get(info.id);
167
+ if (existing) {
168
+ existing.value = value;
169
+ return this;
170
+ }
171
+ info.store.set(info.id, { key, value });
172
+ return this;
173
+ }
174
+ get(key) {
175
+ const info = this.keyInfo(key);
176
+ const entry = info.store.get(info.id);
177
+ return entry ? entry.value : undefined;
178
+ }
179
+ has(key) {
180
+ const info = this.keyInfo(key);
181
+ return info.store.has(info.id);
182
+ }
183
+ delete(key) {
184
+ const info = this.keyInfo(key);
185
+ return info.store.delete(info.id);
186
+ }
187
+ *entries() {
188
+ for (const entry of this.primitiveStore.values()) {
189
+ yield [entry.key, entry.value];
190
+ }
191
+ for (const entry of this.objectStore.values()) {
192
+ yield [entry.key, entry.value];
193
+ }
194
+ }
195
+ *keys() {
196
+ for (const entry of this.primitiveStore.values()) {
197
+ yield entry.key;
198
+ }
199
+ for (const entry of this.objectStore.values()) {
200
+ yield entry.key;
201
+ }
202
+ }
203
+ *values() {
204
+ for (const entry of this.primitiveStore.values()) {
205
+ yield entry.value;
206
+ }
207
+ for (const entry of this.objectStore.values()) {
208
+ yield entry.value;
209
+ }
210
+ }
211
+ [Symbol.iterator]() {
212
+ return this.entries();
213
+ }
214
+ keyInfo(key) {
215
+ const numeric = this.normalizeNumericKey(key);
216
+ if (numeric !== null) {
217
+ return { store: this.primitiveStore, id: `n:${String(numeric)}` };
218
+ }
219
+ if (typeof key === 'string') {
220
+ return { store: this.primitiveStore, id: `s:${key}` };
221
+ }
222
+ if (key === null) {
223
+ return { store: this.primitiveStore, id: 'none' };
224
+ }
225
+ if (key === undefined) {
226
+ return { store: this.primitiveStore, id: 'undefined' };
227
+ }
228
+ return { store: this.objectStore, id: key };
229
+ }
230
+ normalizeNumericKey(key) {
231
+ if (typeof key === 'boolean')
232
+ return key ? 1 : 0;
233
+ if (typeof key === 'bigint')
234
+ return key;
235
+ if (typeof key === 'number')
236
+ return key;
237
+ if (key instanceof Number)
238
+ return key.valueOf();
239
+ return null;
240
+ }
241
+ }
242
+ exports.PyDict = PyDict;
243
+ class PyFile {
244
+ constructor(path, mode) {
245
+ this.path = path;
246
+ this.mode = mode;
247
+ this.handle = null;
248
+ }
249
+ open() {
250
+ if (this.handle !== null)
251
+ return;
252
+ if (this.mode.includes('w')) {
253
+ this.handle = fs.openSync(this.path, 'w');
254
+ }
255
+ else if (this.mode.includes('r')) {
256
+ this.handle = fs.openSync(this.path, 'r');
257
+ }
258
+ else {
259
+ this.handle = fs.openSync(this.path, 'r');
260
+ }
261
+ }
262
+ write(data) {
263
+ this.open();
264
+ if (this.handle === null)
265
+ return;
266
+ fs.writeSync(this.handle, data);
267
+ }
268
+ read() {
269
+ if (this.mode.includes('r')) {
270
+ return fs.readFileSync(this.path, 'utf8');
271
+ }
272
+ return '';
273
+ }
274
+ close() {
275
+ if (this.handle !== null) {
276
+ fs.closeSync(this.handle);
277
+ this.handle = null;
278
+ }
279
+ }
280
+ __enter__() {
281
+ this.open();
282
+ return this;
283
+ }
284
+ __exit__() {
285
+ this.close();
286
+ return false;
287
+ }
288
+ }
289
+ exports.PyFile = PyFile;
290
+ //# sourceMappingURL=runtime-types.js.map
@@ -0,0 +1,7 @@
1
+ import type { VirtualMachine } from './vm';
2
+ import { Scope } from './runtime-types';
3
+ export declare function executeStatement(this: VirtualMachine, node: any, scope: Scope): any;
4
+ export declare function assignTarget(this: VirtualMachine, target: any, value: any, scope: Scope): void;
5
+ export declare function toIterableArray(this: VirtualMachine, value: any): any[];
6
+ export declare function deleteTarget(this: VirtualMachine, target: any, scope: Scope): void;
7
+ //# sourceMappingURL=statements.d.ts.map
@@ -0,0 +1,381 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.executeStatement = executeStatement;
4
+ exports.assignTarget = assignTarget;
5
+ exports.toIterableArray = toIterableArray;
6
+ exports.deleteTarget = deleteTarget;
7
+ const types_1 = require("../types");
8
+ const runtime_types_1 = require("./runtime-types");
9
+ const runtime_types_2 = require("./runtime-types");
10
+ function executeStatement(node, scope) {
11
+ switch (node.type) {
12
+ case types_1.ASTNodeType.EXPRESSION_STATEMENT:
13
+ return this.evaluateExpression(node.expression, scope);
14
+ case types_1.ASTNodeType.IMPORT_STATEMENT: {
15
+ for (const entry of node.names) {
16
+ const module = this.importModule(entry.name, scope);
17
+ const bindingName = entry.alias || entry.name.split('.')[0];
18
+ scope.set(bindingName, module);
19
+ }
20
+ return null;
21
+ }
22
+ case types_1.ASTNodeType.ASSIGNMENT: {
23
+ const value = this.evaluateExpression(node.value, scope);
24
+ for (const target of node.targets) {
25
+ this.assignTarget(target, value, scope);
26
+ }
27
+ return null;
28
+ }
29
+ case types_1.ASTNodeType.AUG_ASSIGNMENT: {
30
+ const current = this.evaluateExpression(node.target, scope);
31
+ const value = this.evaluateExpression(node.value, scope);
32
+ const result = this.applyBinary(node.operator.slice(0, -1), current, value);
33
+ this.assignTarget(node.target, result, scope);
34
+ return null;
35
+ }
36
+ case types_1.ASTNodeType.IF_STATEMENT: {
37
+ if (this.isTruthy(this.evaluateExpression(node.test, scope), scope)) {
38
+ return this.executeBlock(node.body, scope);
39
+ }
40
+ for (const branch of node.elifs) {
41
+ if (this.isTruthy(this.evaluateExpression(branch.test, scope), scope)) {
42
+ return this.executeBlock(branch.body, scope);
43
+ }
44
+ }
45
+ if (node.orelse?.length) {
46
+ return this.executeBlock(node.orelse, scope);
47
+ }
48
+ return null;
49
+ }
50
+ case types_1.ASTNodeType.WHILE_STATEMENT: {
51
+ while (this.isTruthy(this.evaluateExpression(node.test, scope), scope)) {
52
+ try {
53
+ this.executeBlock(node.body, scope);
54
+ }
55
+ catch (err) {
56
+ if (err instanceof runtime_types_1.BreakSignal)
57
+ break;
58
+ if (err instanceof runtime_types_1.ContinueSignal)
59
+ continue;
60
+ throw err;
61
+ }
62
+ }
63
+ return null;
64
+ }
65
+ case types_1.ASTNodeType.FOR_STATEMENT: {
66
+ const iterable = this.evaluateExpression(node.iter, scope);
67
+ const items = this.iterableToArray(iterable);
68
+ for (const item of items) {
69
+ this.assignTarget(node.target, item, scope);
70
+ try {
71
+ this.executeBlock(node.body, scope);
72
+ }
73
+ catch (err) {
74
+ if (err instanceof runtime_types_1.BreakSignal)
75
+ break;
76
+ if (err instanceof runtime_types_1.ContinueSignal)
77
+ continue;
78
+ throw err;
79
+ }
80
+ }
81
+ return null;
82
+ }
83
+ case types_1.ASTNodeType.MATCH_STATEMENT: {
84
+ const subject = this.evaluateExpression(node.subject, scope);
85
+ for (const matchCase of node.cases) {
86
+ const result = this.matchPattern(matchCase.pattern, subject, scope);
87
+ if (!result.matched)
88
+ continue;
89
+ if (matchCase.guard) {
90
+ const guardScope = new runtime_types_1.Scope(scope);
91
+ this.applyBindings(result.bindings, guardScope);
92
+ if (!this.isTruthy(this.evaluateExpression(matchCase.guard, guardScope), guardScope))
93
+ continue;
94
+ }
95
+ this.applyBindings(result.bindings, scope);
96
+ return this.executeBlock(matchCase.body, scope);
97
+ }
98
+ return null;
99
+ }
100
+ case types_1.ASTNodeType.FUNCTION_DEF: {
101
+ const params = (node.params || []).map((param) => {
102
+ if (param.type === 'Param' && param.defaultValue) {
103
+ return { ...param, defaultEvaluated: this.evaluateExpression(param.defaultValue, scope) };
104
+ }
105
+ return param;
106
+ });
107
+ const fn = new runtime_types_1.PyFunction(node.name, params, node.body, scope, this.containsYield(node.body));
108
+ scope.set(node.name, fn);
109
+ if (node.decorators && node.decorators.length > 0) {
110
+ let decorated = fn;
111
+ for (const decorator of node.decorators.reverse()) {
112
+ const decFn = this.evaluateExpression(decorator, scope);
113
+ decorated = this.callFunction(decFn, [decorated], scope);
114
+ }
115
+ scope.set(node.name, decorated);
116
+ }
117
+ return null;
118
+ }
119
+ case types_1.ASTNodeType.CLASS_DEF: {
120
+ const bases = node.bases?.map((b) => this.evaluateExpression(b, scope)) || [];
121
+ const classScope = new runtime_types_1.Scope(scope);
122
+ this.executeBlock(node.body, classScope);
123
+ const attributes = new Map(classScope.values.entries());
124
+ const isException = bases.some((b) => b instanceof runtime_types_1.PyClass && b.isException);
125
+ const klass = new runtime_types_1.PyClass(node.name, bases, attributes, isException);
126
+ scope.set(node.name, klass);
127
+ if (node.decorators && node.decorators.length > 0) {
128
+ let decorated = klass;
129
+ for (const decorator of node.decorators.reverse()) {
130
+ const decFn = this.evaluateExpression(decorator, scope);
131
+ decorated = this.callFunction(decFn, [decorated], scope);
132
+ }
133
+ scope.set(node.name, decorated);
134
+ }
135
+ return null;
136
+ }
137
+ case types_1.ASTNodeType.RETURN_STATEMENT:
138
+ throw new runtime_types_1.ReturnSignal(node.value ? this.evaluateExpression(node.value, scope) : null);
139
+ case types_1.ASTNodeType.BREAK_STATEMENT:
140
+ throw new runtime_types_1.BreakSignal();
141
+ case types_1.ASTNodeType.CONTINUE_STATEMENT:
142
+ throw new runtime_types_1.ContinueSignal();
143
+ case types_1.ASTNodeType.PASS_STATEMENT:
144
+ return null;
145
+ case types_1.ASTNodeType.ASSERT_STATEMENT: {
146
+ const test = this.evaluateExpression(node.test, scope);
147
+ if (!this.isTruthy(test, scope)) {
148
+ const message = node.message ? this.evaluateExpression(node.message, scope) : 'Assertion failed';
149
+ throw new runtime_types_1.PyException('AssertionError', String(message));
150
+ }
151
+ return null;
152
+ }
153
+ case types_1.ASTNodeType.RAISE_STATEMENT: {
154
+ const exc = node.exception ? this.evaluateExpression(node.exception, scope) : null;
155
+ if (exc instanceof runtime_types_1.PyException)
156
+ throw exc;
157
+ if (exc instanceof runtime_types_1.PyInstance && exc.klass.isException) {
158
+ const message = exc.attributes.get('message');
159
+ throw new runtime_types_1.PyException(exc.klass.name, message ? String(message) : exc.klass.name, exc);
160
+ }
161
+ if (exc instanceof runtime_types_1.PyClass && exc.isException) {
162
+ throw new runtime_types_1.PyException(exc.name, exc.name);
163
+ }
164
+ throw new runtime_types_1.PyException('Exception', exc ? String(exc) : 'Exception');
165
+ }
166
+ case types_1.ASTNodeType.TRY_STATEMENT: {
167
+ try {
168
+ this.executeBlock(node.body, scope);
169
+ }
170
+ catch (err) {
171
+ let handled = false;
172
+ for (const handler of node.handlers) {
173
+ if (!handler.exceptionType) {
174
+ handled = true;
175
+ }
176
+ else if (err instanceof runtime_types_1.PyException) {
177
+ const expected = this.evaluateExpression(handler.exceptionType, scope);
178
+ if (expected instanceof runtime_types_1.PyClass && expected.isException && err.pyType === expected.name) {
179
+ handled = true;
180
+ }
181
+ else if (expected instanceof runtime_types_1.PyInstance && expected.klass.isException && err.pyType === expected.klass.name) {
182
+ handled = true;
183
+ }
184
+ }
185
+ if (handled) {
186
+ if (handler.name) {
187
+ scope.set(handler.name, err instanceof runtime_types_1.PyException ? err : new runtime_types_1.PyException('Exception', String(err)));
188
+ }
189
+ this.executeBlock(handler.body, scope);
190
+ break;
191
+ }
192
+ }
193
+ if (!handled)
194
+ throw err;
195
+ }
196
+ finally {
197
+ if (node.finalbody?.length) {
198
+ this.executeBlock(node.finalbody, scope);
199
+ }
200
+ }
201
+ if (node.orelse?.length) {
202
+ this.executeBlock(node.orelse, scope);
203
+ }
204
+ return null;
205
+ }
206
+ case types_1.ASTNodeType.WITH_STATEMENT: {
207
+ for (const item of node.items) {
208
+ const ctx = this.evaluateExpression(item.context, scope);
209
+ const enter = this.getAttribute(ctx, '__enter__', scope);
210
+ const exit = this.getAttribute(ctx, '__exit__', scope);
211
+ const value = this.callFunction(enter, [], scope);
212
+ if (item.target) {
213
+ this.assignTarget(item.target, value, scope);
214
+ }
215
+ try {
216
+ this.executeBlock(node.body, scope);
217
+ }
218
+ catch (err) {
219
+ this.callFunction(exit, [err], scope);
220
+ throw err;
221
+ }
222
+ this.callFunction(exit, [null, null, null], scope);
223
+ }
224
+ return null;
225
+ }
226
+ case types_1.ASTNodeType.GLOBAL_STATEMENT:
227
+ for (const name of node.names)
228
+ scope.globals.add(name);
229
+ return null;
230
+ case types_1.ASTNodeType.NONLOCAL_STATEMENT:
231
+ for (const name of node.names)
232
+ scope.nonlocals.add(name);
233
+ return null;
234
+ case types_1.ASTNodeType.DELETE_STATEMENT:
235
+ this.deleteTarget(node.target, scope);
236
+ return null;
237
+ default:
238
+ throw new Error(`Unsupported statement type: ${node.type}`);
239
+ }
240
+ }
241
+ function assignTarget(target, value, scope) {
242
+ if (target.type === types_1.ASTNodeType.IDENTIFIER) {
243
+ scope.set(target.name, value);
244
+ return;
245
+ }
246
+ if (target.type === types_1.ASTNodeType.ATTRIBUTE) {
247
+ const obj = this.evaluateExpression(target.object, scope);
248
+ this.setAttribute(obj, target.name, value);
249
+ return;
250
+ }
251
+ if (target.type === types_1.ASTNodeType.SUBSCRIPT) {
252
+ const obj = this.evaluateExpression(target.object, scope);
253
+ let index;
254
+ if (target.index && target.index.type === types_1.ASTNodeType.SLICE) {
255
+ index = {
256
+ type: types_1.ASTNodeType.SLICE,
257
+ start: target.index.start ? this.evaluateExpression(target.index.start, scope) : null,
258
+ end: target.index.end ? this.evaluateExpression(target.index.end, scope) : null,
259
+ step: target.index.step ? this.evaluateExpression(target.index.step, scope) : null
260
+ };
261
+ }
262
+ else {
263
+ index = this.evaluateExpression(target.index, scope);
264
+ }
265
+ if (Array.isArray(obj)) {
266
+ if (index && index.type === types_1.ASTNodeType.SLICE) {
267
+ const start = index.start !== null ? index.start : null;
268
+ const end = index.end !== null ? index.end : null;
269
+ const step = index.step !== null ? index.step : null;
270
+ const stepValue = step !== null && step !== undefined ? step : 1;
271
+ const values = this.toIterableArray(value);
272
+ if (stepValue === 1) {
273
+ const bounds = this.computeSliceBounds(obj.length, start, end, stepValue);
274
+ obj.splice(bounds.start, bounds.end - bounds.start, ...values);
275
+ }
276
+ else {
277
+ const indices = this.computeSliceIndices(obj.length, start, end, stepValue);
278
+ if (values.length !== indices.length) {
279
+ throw new runtime_types_1.PyException('ValueError', `attempt to assign sequence of size ${values.length} to extended slice of size ${indices.length}`);
280
+ }
281
+ for (let i = 0; i < indices.length; i++) {
282
+ obj[indices[i]] = values[i];
283
+ }
284
+ }
285
+ }
286
+ else {
287
+ obj[index] = value;
288
+ }
289
+ return;
290
+ }
291
+ if (obj instanceof runtime_types_2.PyDict) {
292
+ obj.set(index, value);
293
+ return;
294
+ }
295
+ throw new runtime_types_1.PyException('TypeError', 'unsupported subscript assignment');
296
+ }
297
+ if (target.type === types_1.ASTNodeType.TUPLE_LITERAL || target.type === types_1.ASTNodeType.LIST_LITERAL) {
298
+ const elements = target.elements;
299
+ const unpackValue = this.toIterableArray(value);
300
+ const starIndex = elements.findIndex((el) => el.type === types_1.ASTNodeType.STARRED);
301
+ if (starIndex === -1) {
302
+ for (let i = 0; i < elements.length; i++) {
303
+ this.assignTarget(elements[i], unpackValue[i], scope);
304
+ }
305
+ return;
306
+ }
307
+ const prefixCount = starIndex;
308
+ const suffixCount = elements.length - starIndex - 1;
309
+ if (unpackValue.length < prefixCount + suffixCount) {
310
+ throw new runtime_types_1.PyException('ValueError', 'not enough values to unpack');
311
+ }
312
+ for (let i = 0; i < prefixCount; i++) {
313
+ this.assignTarget(elements[i], unpackValue[i], scope);
314
+ }
315
+ const starTarget = elements[starIndex];
316
+ const middle = unpackValue.slice(prefixCount, unpackValue.length - suffixCount);
317
+ this.assignTarget(starTarget.target, middle, scope);
318
+ for (let i = 0; i < suffixCount; i++) {
319
+ const valueIndex = unpackValue.length - suffixCount + i;
320
+ const elementIndex = starIndex + 1 + i;
321
+ this.assignTarget(elements[elementIndex], unpackValue[valueIndex], scope);
322
+ }
323
+ return;
324
+ }
325
+ throw new runtime_types_1.PyException('TypeError', 'invalid assignment target');
326
+ }
327
+ function toIterableArray(value) {
328
+ if (Array.isArray(value))
329
+ return value;
330
+ if (value && typeof value[Symbol.iterator] === 'function') {
331
+ return Array.from(value);
332
+ }
333
+ throw new runtime_types_1.PyException('TypeError', 'cannot unpack non-iterable');
334
+ }
335
+ function deleteTarget(target, scope) {
336
+ if (target.type === types_1.ASTNodeType.SUBSCRIPT) {
337
+ const obj = this.evaluateExpression(target.object, scope);
338
+ let index;
339
+ if (target.index && target.index.type === types_1.ASTNodeType.SLICE) {
340
+ index = {
341
+ type: types_1.ASTNodeType.SLICE,
342
+ start: target.index.start ? this.evaluateExpression(target.index.start, scope) : null,
343
+ end: target.index.end ? this.evaluateExpression(target.index.end, scope) : null,
344
+ step: target.index.step ? this.evaluateExpression(target.index.step, scope) : null
345
+ };
346
+ }
347
+ else {
348
+ index = this.evaluateExpression(target.index, scope);
349
+ }
350
+ if (Array.isArray(obj)) {
351
+ if (index && index.type === types_1.ASTNodeType.SLICE) {
352
+ const start = index.start !== null ? index.start : null;
353
+ const end = index.end !== null ? index.end : null;
354
+ const step = index.step !== null ? index.step : null;
355
+ const stepValue = step !== null && step !== undefined ? step : 1;
356
+ if (stepValue === 1) {
357
+ const bounds = this.computeSliceBounds(obj.length, start, end, stepValue);
358
+ obj.splice(bounds.start, bounds.end - bounds.start);
359
+ }
360
+ else {
361
+ const indices = this.computeSliceIndices(obj.length, start, end, stepValue);
362
+ indices.sort((a, b) => b - a);
363
+ for (const idx of indices) {
364
+ obj.splice(idx, 1);
365
+ }
366
+ }
367
+ }
368
+ else {
369
+ obj.splice(index, 1);
370
+ }
371
+ return;
372
+ }
373
+ if (obj instanceof runtime_types_2.PyDict) {
374
+ obj.delete(index);
375
+ return;
376
+ }
377
+ throw new runtime_types_1.PyException('TypeError', 'unsupported delete target');
378
+ }
379
+ throw new runtime_types_1.PyException('TypeError', 'unsupported delete target');
380
+ }
381
+ //# sourceMappingURL=statements.js.map
@@ -0,0 +1,4 @@
1
+ import type { VirtualMachine } from './vm';
2
+ import { Scope } from './runtime-types';
3
+ export declare function isTruthy(this: VirtualMachine, value: any, scope: Scope): boolean;
4
+ //# sourceMappingURL=truthy.d.ts.map