@lewin671/python-vm 0.1.0 → 0.1.1

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 (142) hide show
  1. package/dist/compiler.d.ts.map +1 -0
  2. package/dist/compiler.js.map +1 -0
  3. package/dist/compiler_module/compiler.d.ts.map +1 -0
  4. package/dist/compiler_module/compiler.js.map +1 -0
  5. package/dist/compiler_module/index.d.ts.map +1 -0
  6. package/dist/compiler_module/index.js.map +1 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/lexer/index.d.ts.map +1 -0
  10. package/dist/lexer/index.js.map +1 -0
  11. package/dist/lexer/lexer.d.ts.map +1 -0
  12. package/dist/lexer/lexer.js.map +1 -0
  13. package/dist/parser/expressions.d.ts.map +1 -0
  14. package/dist/parser/expressions.js.map +1 -0
  15. package/dist/parser/index.d.ts.map +1 -0
  16. package/dist/parser/index.js.map +1 -0
  17. package/dist/parser/parser.d.ts.map +1 -0
  18. package/dist/parser/parser.js.map +1 -0
  19. package/dist/parser/statements.d.ts.map +1 -0
  20. package/dist/parser/statements.js.map +1 -0
  21. package/dist/parser/targets.d.ts.map +1 -0
  22. package/dist/parser/targets.js.map +1 -0
  23. package/dist/types/ast.d.ts.map +1 -0
  24. package/dist/types/ast.js.map +1 -0
  25. package/dist/types/bytecode.d.ts.map +1 -0
  26. package/dist/types/bytecode.js.map +1 -0
  27. package/dist/types/index.d.ts.map +1 -0
  28. package/dist/types/index.js.map +1 -0
  29. package/dist/types/token.d.ts.map +1 -0
  30. package/dist/types/token.js.map +1 -0
  31. package/dist/vm/builtins.d.ts.map +1 -0
  32. package/dist/vm/builtins.js.map +1 -0
  33. package/dist/vm/callable.d.ts.map +1 -0
  34. package/dist/vm/callable.js.map +1 -0
  35. package/dist/vm/execution.d.ts.map +1 -0
  36. package/dist/vm/execution.js.map +1 -0
  37. package/dist/vm/expression-generator.d.ts.map +1 -0
  38. package/dist/vm/expression-generator.js.map +1 -0
  39. package/dist/vm/expressions.d.ts.map +1 -0
  40. package/dist/vm/expressions.js.map +1 -0
  41. package/dist/vm/imports.d.ts.map +1 -0
  42. package/dist/vm/imports.js.map +1 -0
  43. package/dist/vm/index.d.ts.map +1 -0
  44. package/dist/vm/index.js.map +1 -0
  45. package/dist/vm/operations.d.ts.map +1 -0
  46. package/dist/vm/operations.js.map +1 -0
  47. package/dist/vm/runtime-types.d.ts.map +1 -0
  48. package/dist/vm/runtime-types.js.map +1 -0
  49. package/dist/vm/statements.d.ts.map +1 -0
  50. package/dist/vm/statements.js.map +1 -0
  51. package/dist/vm/truthy.d.ts.map +1 -0
  52. package/dist/vm/truthy.js.map +1 -0
  53. package/dist/vm/value-utils.d.ts.map +1 -0
  54. package/dist/vm/value-utils.js.map +1 -0
  55. package/dist/vm/vm.d.ts.map +1 -0
  56. package/dist/vm/vm.js.map +1 -0
  57. package/package.json +7 -1
  58. package/.claude/settings.local.json +0 -3
  59. package/.prettierrc +0 -7
  60. package/Agents.md +0 -66
  61. package/SETUP.md +0 -171
  62. package/examples/assert_testing.py +0 -38
  63. package/examples/big_int_precision.py +0 -2
  64. package/examples/boolean_logic.py +0 -35
  65. package/examples/break_continue.py +0 -43
  66. package/examples/classes_objects.py +0 -43
  67. package/examples/compiler_killer_async.py +0 -6
  68. package/examples/compiler_killer_bigint.py +0 -3
  69. package/examples/compiler_killer_bool_int_dict_key.py +0 -5
  70. package/examples/compiler_killer_bool_len.py +0 -9
  71. package/examples/compiler_killer_floor_division.py +0 -4
  72. package/examples/compiler_killer_is_identity.py +0 -3
  73. package/examples/compiler_killer_list_sort_return.py +0 -3
  74. package/examples/compiler_killer_match.py +0 -13
  75. package/examples/compiler_killer_negative_repeat.py +0 -3
  76. package/examples/compiler_killer_negative_zero_repr.py +0 -3
  77. package/examples/compiler_killer_rounding.py +0 -4
  78. package/examples/compiler_killer_slice_assign.py +0 -3
  79. package/examples/comprehensions.py +0 -28
  80. package/examples/conditions.py +0 -13
  81. package/examples/context_manager.py +0 -35
  82. package/examples/decorators.py +0 -50
  83. package/examples/exceptions.py +0 -40
  84. package/examples/fibonacci.py +0 -10
  85. package/examples/functions.py +0 -38
  86. package/examples/generator.py +0 -51
  87. package/examples/global_nonlocal.py +0 -48
  88. package/examples/hello.py +0 -3
  89. package/examples/itertools_example.py +0 -33
  90. package/examples/lists_dicts.py +0 -29
  91. package/examples/loops.py +0 -19
  92. package/examples/math_ops.py +0 -15
  93. package/examples/nan_set.py +0 -6
  94. package/examples/numbers_operators.py +0 -51
  95. package/examples/sets.py +0 -36
  96. package/examples/slicing.py +0 -29
  97. package/examples/starred_unpacking.py +0 -3
  98. package/examples/string_formatting.py +0 -36
  99. package/examples/strings.py +0 -22
  100. package/examples/tuples.py +0 -45
  101. package/examples/type_conversion.py +0 -41
  102. package/jest.config.js +0 -15
  103. package/notes/iterations/compiler-runtime/compiler-runtime_2025-09-16.md +0 -25
  104. package/notes/iterations/compiler-runtime/compiler-runtime_2026-01-16.md +0 -24
  105. package/notes/iterations/compiler-runtime/compiler-runtime_test_2026-01-16.md +0 -21
  106. package/notes/iterations/floor-division/floor-division_2026-01-16.md +0 -29
  107. package/prompts/commit.txt +0 -9
  108. package/prompts/task.txt +0 -21
  109. package/prompts/test.txt +0 -23
  110. package/scripts/codex-loop.js +0 -215
  111. package/scripts/verify.sh +0 -12
  112. package/src/compiler.ts +0 -58
  113. package/src/compiler_module/compiler.ts +0 -19
  114. package/src/compiler_module/index.ts +0 -1
  115. package/src/index.ts +0 -39
  116. package/src/lexer/index.ts +0 -1
  117. package/src/lexer/lexer.ts +0 -402
  118. package/src/parser/expressions.ts +0 -462
  119. package/src/parser/index.ts +0 -1
  120. package/src/parser/parser.ts +0 -102
  121. package/src/parser/statements.ts +0 -366
  122. package/src/parser/targets.ts +0 -71
  123. package/src/types/ast.ts +0 -64
  124. package/src/types/bytecode.ts +0 -50
  125. package/src/types/index.ts +0 -3
  126. package/src/types/token.ts +0 -44
  127. package/src/vm/builtins.ts +0 -237
  128. package/src/vm/callable.ts +0 -154
  129. package/src/vm/execution.ts +0 -251
  130. package/src/vm/expression-generator.ts +0 -65
  131. package/src/vm/expressions.ts +0 -373
  132. package/src/vm/imports.ts +0 -61
  133. package/src/vm/index.ts +0 -2
  134. package/src/vm/operations.ts +0 -414
  135. package/src/vm/runtime-types.ts +0 -292
  136. package/src/vm/statements.ts +0 -358
  137. package/src/vm/truthy.ts +0 -36
  138. package/src/vm/value-utils.ts +0 -173
  139. package/src/vm/vm.ts +0 -80
  140. package/tests/compiler.test.ts +0 -111
  141. package/tsconfig.json +0 -20
  142. package/vitest.config.ts +0 -16
@@ -1,358 +0,0 @@
1
- import type { VirtualMachine } from './vm';
2
- import { ASTNodeType } from '../types';
3
- import { BreakSignal, ContinueSignal, PyClass, PyException, PyFunction, PyInstance, ReturnSignal, Scope } from './runtime-types';
4
- import { PyDict } from './runtime-types';
5
-
6
- export function executeStatement(this: VirtualMachine, node: any, scope: Scope): any {
7
- switch (node.type) {
8
- case ASTNodeType.EXPRESSION_STATEMENT:
9
- return this.evaluateExpression(node.expression, scope);
10
- case ASTNodeType.IMPORT_STATEMENT: {
11
- for (const entry of node.names) {
12
- const module = this.importModule(entry.name, scope);
13
- const bindingName = entry.alias || entry.name.split('.')[0];
14
- scope.set(bindingName, module);
15
- }
16
- return null;
17
- }
18
- case ASTNodeType.ASSIGNMENT: {
19
- const value = this.evaluateExpression(node.value, scope);
20
- for (const target of node.targets) {
21
- this.assignTarget(target, value, scope);
22
- }
23
- return null;
24
- }
25
- case ASTNodeType.AUG_ASSIGNMENT: {
26
- const current = this.evaluateExpression(node.target, scope);
27
- const value = this.evaluateExpression(node.value, scope);
28
- const result = this.applyBinary(node.operator.slice(0, -1), current, value);
29
- this.assignTarget(node.target, result, scope);
30
- return null;
31
- }
32
- case ASTNodeType.IF_STATEMENT: {
33
- if (this.isTruthy(this.evaluateExpression(node.test, scope), scope)) {
34
- return this.executeBlock(node.body, scope);
35
- }
36
- for (const branch of node.elifs) {
37
- if (this.isTruthy(this.evaluateExpression(branch.test, scope), scope)) {
38
- return this.executeBlock(branch.body, scope);
39
- }
40
- }
41
- if (node.orelse?.length) {
42
- return this.executeBlock(node.orelse, scope);
43
- }
44
- return null;
45
- }
46
- case ASTNodeType.WHILE_STATEMENT: {
47
- while (this.isTruthy(this.evaluateExpression(node.test, scope), scope)) {
48
- try {
49
- this.executeBlock(node.body, scope);
50
- } catch (err) {
51
- if (err instanceof BreakSignal) break;
52
- if (err instanceof ContinueSignal) continue;
53
- throw err;
54
- }
55
- }
56
- return null;
57
- }
58
- case ASTNodeType.FOR_STATEMENT: {
59
- const iterable = this.evaluateExpression(node.iter, scope);
60
- const items = this.iterableToArray(iterable);
61
- for (const item of items) {
62
- this.assignTarget(node.target, item, scope);
63
- try {
64
- this.executeBlock(node.body, scope);
65
- } catch (err) {
66
- if (err instanceof BreakSignal) break;
67
- if (err instanceof ContinueSignal) continue;
68
- throw err;
69
- }
70
- }
71
- return null;
72
- }
73
- case ASTNodeType.MATCH_STATEMENT: {
74
- const subject = this.evaluateExpression(node.subject, scope);
75
- for (const matchCase of node.cases) {
76
- const result = this.matchPattern(matchCase.pattern, subject, scope);
77
- if (!result.matched) continue;
78
- if (matchCase.guard) {
79
- const guardScope = new Scope(scope);
80
- this.applyBindings(result.bindings, guardScope);
81
- if (!this.isTruthy(this.evaluateExpression(matchCase.guard, guardScope), guardScope)) continue;
82
- }
83
- this.applyBindings(result.bindings, scope);
84
- return this.executeBlock(matchCase.body, scope);
85
- }
86
- return null;
87
- }
88
- case ASTNodeType.FUNCTION_DEF: {
89
- const params = (node.params || []).map((param: any) => {
90
- if (param.type === 'Param' && param.defaultValue) {
91
- return { ...param, defaultEvaluated: this.evaluateExpression(param.defaultValue, scope) };
92
- }
93
- return param;
94
- });
95
- const fn = new PyFunction(node.name, params, node.body, scope, this.containsYield(node.body));
96
- scope.set(node.name, fn);
97
- if (node.decorators && node.decorators.length > 0) {
98
- let decorated: any = fn;
99
- for (const decorator of node.decorators.reverse()) {
100
- const decFn = this.evaluateExpression(decorator, scope);
101
- decorated = this.callFunction(decFn, [decorated], scope);
102
- }
103
- scope.set(node.name, decorated);
104
- }
105
- return null;
106
- }
107
- case ASTNodeType.CLASS_DEF: {
108
- const bases = node.bases?.map((b: any) => this.evaluateExpression(b, scope)) || [];
109
- const classScope = new Scope(scope);
110
- this.executeBlock(node.body, classScope);
111
- const attributes = new Map(classScope.values.entries());
112
- const isException = bases.some((b: any) => b instanceof PyClass && b.isException);
113
- const klass = new PyClass(node.name, bases, attributes, isException);
114
- scope.set(node.name, klass);
115
- if (node.decorators && node.decorators.length > 0) {
116
- let decorated: any = klass;
117
- for (const decorator of node.decorators.reverse()) {
118
- const decFn = this.evaluateExpression(decorator, scope);
119
- decorated = this.callFunction(decFn, [decorated], scope);
120
- }
121
- scope.set(node.name, decorated);
122
- }
123
- return null;
124
- }
125
- case ASTNodeType.RETURN_STATEMENT:
126
- throw new ReturnSignal(node.value ? this.evaluateExpression(node.value, scope) : null);
127
- case ASTNodeType.BREAK_STATEMENT:
128
- throw new BreakSignal();
129
- case ASTNodeType.CONTINUE_STATEMENT:
130
- throw new ContinueSignal();
131
- case ASTNodeType.PASS_STATEMENT:
132
- return null;
133
- case ASTNodeType.ASSERT_STATEMENT: {
134
- const test = this.evaluateExpression(node.test, scope);
135
- if (!this.isTruthy(test, scope)) {
136
- const message = node.message ? this.evaluateExpression(node.message, scope) : 'Assertion failed';
137
- throw new PyException('AssertionError', String(message));
138
- }
139
- return null;
140
- }
141
- case ASTNodeType.RAISE_STATEMENT: {
142
- const exc = node.exception ? this.evaluateExpression(node.exception, scope) : null;
143
- if (exc instanceof PyException) throw exc;
144
- if (exc instanceof PyInstance && exc.klass.isException) {
145
- const message = exc.attributes.get('message');
146
- throw new PyException(exc.klass.name, message ? String(message) : exc.klass.name, exc);
147
- }
148
- if (exc instanceof PyClass && exc.isException) {
149
- throw new PyException(exc.name, exc.name);
150
- }
151
- throw new PyException('Exception', exc ? String(exc) : 'Exception');
152
- }
153
- case ASTNodeType.TRY_STATEMENT: {
154
- try {
155
- this.executeBlock(node.body, scope);
156
- } catch (err) {
157
- let handled = false;
158
- for (const handler of node.handlers) {
159
- if (!handler.exceptionType) {
160
- handled = true;
161
- } else if (err instanceof PyException) {
162
- const expected = this.evaluateExpression(handler.exceptionType, scope);
163
- if (expected instanceof PyClass && expected.isException && err.pyType === expected.name) {
164
- handled = true;
165
- } else if (expected instanceof PyInstance && expected.klass.isException && err.pyType === expected.klass.name) {
166
- handled = true;
167
- }
168
- }
169
- if (handled) {
170
- if (handler.name) {
171
- scope.set(handler.name, err instanceof PyException ? err : new PyException('Exception', String(err)));
172
- }
173
- this.executeBlock(handler.body, scope);
174
- break;
175
- }
176
- }
177
- if (!handled) throw err;
178
- } finally {
179
- if (node.finalbody?.length) {
180
- this.executeBlock(node.finalbody, scope);
181
- }
182
- }
183
- if (node.orelse?.length) {
184
- this.executeBlock(node.orelse, scope);
185
- }
186
- return null;
187
- }
188
- case ASTNodeType.WITH_STATEMENT: {
189
- for (const item of node.items) {
190
- const ctx = this.evaluateExpression(item.context, scope);
191
- const enter = this.getAttribute(ctx, '__enter__', scope);
192
- const exit = this.getAttribute(ctx, '__exit__', scope);
193
- const value = this.callFunction(enter, [], scope);
194
- if (item.target) {
195
- this.assignTarget(item.target, value, scope);
196
- }
197
- try {
198
- this.executeBlock(node.body, scope);
199
- } catch (err) {
200
- this.callFunction(exit, [err], scope);
201
- throw err;
202
- }
203
- this.callFunction(exit, [null, null, null], scope);
204
- }
205
- return null;
206
- }
207
- case ASTNodeType.GLOBAL_STATEMENT:
208
- for (const name of node.names) scope.globals.add(name);
209
- return null;
210
- case ASTNodeType.NONLOCAL_STATEMENT:
211
- for (const name of node.names) scope.nonlocals.add(name);
212
- return null;
213
- case ASTNodeType.DELETE_STATEMENT:
214
- this.deleteTarget(node.target, scope);
215
- return null;
216
- default:
217
- throw new Error(`Unsupported statement type: ${node.type}`);
218
- }
219
- }
220
-
221
- export function assignTarget(this: VirtualMachine, target: any, value: any, scope: Scope) {
222
- if (target.type === ASTNodeType.IDENTIFIER) {
223
- scope.set(target.name, value);
224
- return;
225
- }
226
- if (target.type === ASTNodeType.ATTRIBUTE) {
227
- const obj = this.evaluateExpression(target.object, scope);
228
- this.setAttribute(obj, target.name, value);
229
- return;
230
- }
231
- if (target.type === ASTNodeType.SUBSCRIPT) {
232
- const obj = this.evaluateExpression(target.object, scope);
233
- let index: any;
234
- if (target.index && target.index.type === ASTNodeType.SLICE) {
235
- index = {
236
- type: ASTNodeType.SLICE,
237
- start: target.index.start ? this.evaluateExpression(target.index.start, scope) : null,
238
- end: target.index.end ? this.evaluateExpression(target.index.end, scope) : null,
239
- step: target.index.step ? this.evaluateExpression(target.index.step, scope) : null
240
- };
241
- } else {
242
- index = this.evaluateExpression(target.index, scope);
243
- }
244
- if (Array.isArray(obj)) {
245
- if (index && index.type === ASTNodeType.SLICE) {
246
- const start = index.start !== null ? index.start : null;
247
- const end = index.end !== null ? index.end : null;
248
- const step = index.step !== null ? index.step : null;
249
- const stepValue = step !== null && step !== undefined ? step : 1;
250
- const values = this.toIterableArray(value);
251
- if (stepValue === 1) {
252
- const bounds = this.computeSliceBounds(obj.length, start, end, stepValue);
253
- obj.splice(bounds.start, bounds.end - bounds.start, ...values);
254
- } else {
255
- const indices = this.computeSliceIndices(obj.length, start, end, stepValue);
256
- if (values.length !== indices.length) {
257
- throw new PyException(
258
- 'ValueError',
259
- `attempt to assign sequence of size ${values.length} to extended slice of size ${indices.length}`
260
- );
261
- }
262
- for (let i = 0; i < indices.length; i++) {
263
- obj[indices[i]] = values[i];
264
- }
265
- }
266
- } else {
267
- obj[index] = value;
268
- }
269
- return;
270
- }
271
- if (obj instanceof PyDict) {
272
- obj.set(index, value);
273
- return;
274
- }
275
- throw new PyException('TypeError', 'unsupported subscript assignment');
276
- }
277
- if (target.type === ASTNodeType.TUPLE_LITERAL || target.type === ASTNodeType.LIST_LITERAL) {
278
- const elements = target.elements;
279
- const unpackValue = this.toIterableArray(value);
280
- const starIndex = elements.findIndex((el: any) => el.type === ASTNodeType.STARRED);
281
- if (starIndex === -1) {
282
- for (let i = 0; i < elements.length; i++) {
283
- this.assignTarget(elements[i], unpackValue[i], scope);
284
- }
285
- return;
286
- }
287
- const prefixCount = starIndex;
288
- const suffixCount = elements.length - starIndex - 1;
289
- if (unpackValue.length < prefixCount + suffixCount) {
290
- throw new PyException('ValueError', 'not enough values to unpack');
291
- }
292
- for (let i = 0; i < prefixCount; i++) {
293
- this.assignTarget(elements[i], unpackValue[i], scope);
294
- }
295
- const starTarget = elements[starIndex];
296
- const middle = unpackValue.slice(prefixCount, unpackValue.length - suffixCount);
297
- this.assignTarget(starTarget.target, middle, scope);
298
- for (let i = 0; i < suffixCount; i++) {
299
- const valueIndex = unpackValue.length - suffixCount + i;
300
- const elementIndex = starIndex + 1 + i;
301
- this.assignTarget(elements[elementIndex], unpackValue[valueIndex], scope);
302
- }
303
- return;
304
- }
305
- throw new PyException('TypeError', 'invalid assignment target');
306
- }
307
-
308
- export function toIterableArray(this: VirtualMachine, value: any): any[] {
309
- if (Array.isArray(value)) return value;
310
- if (value && typeof value[Symbol.iterator] === 'function') {
311
- return Array.from(value);
312
- }
313
- throw new PyException('TypeError', 'cannot unpack non-iterable');
314
- }
315
-
316
- export function deleteTarget(this: VirtualMachine, target: any, scope: Scope) {
317
- if (target.type === ASTNodeType.SUBSCRIPT) {
318
- const obj = this.evaluateExpression(target.object, scope);
319
- let index: any;
320
- if (target.index && target.index.type === ASTNodeType.SLICE) {
321
- index = {
322
- type: ASTNodeType.SLICE,
323
- start: target.index.start ? this.evaluateExpression(target.index.start, scope) : null,
324
- end: target.index.end ? this.evaluateExpression(target.index.end, scope) : null,
325
- step: target.index.step ? this.evaluateExpression(target.index.step, scope) : null
326
- };
327
- } else {
328
- index = this.evaluateExpression(target.index, scope);
329
- }
330
- if (Array.isArray(obj)) {
331
- if (index && index.type === ASTNodeType.SLICE) {
332
- const start = index.start !== null ? index.start : null;
333
- const end = index.end !== null ? index.end : null;
334
- const step = index.step !== null ? index.step : null;
335
- const stepValue = step !== null && step !== undefined ? step : 1;
336
- if (stepValue === 1) {
337
- const bounds = this.computeSliceBounds(obj.length, start, end, stepValue);
338
- obj.splice(bounds.start, bounds.end - bounds.start);
339
- } else {
340
- const indices = this.computeSliceIndices(obj.length, start, end, stepValue);
341
- indices.sort((a, b) => b - a);
342
- for (const idx of indices) {
343
- obj.splice(idx, 1);
344
- }
345
- }
346
- } else {
347
- obj.splice(index, 1);
348
- }
349
- return;
350
- }
351
- if (obj instanceof PyDict) {
352
- obj.delete(index);
353
- return;
354
- }
355
- throw new PyException('TypeError', 'unsupported delete target');
356
- }
357
- throw new PyException('TypeError', 'unsupported delete target');
358
- }
package/src/vm/truthy.ts DELETED
@@ -1,36 +0,0 @@
1
- import type { VirtualMachine } from './vm';
2
- import { PyDict, PyException, PyInstance, Scope } from './runtime-types';
3
- import { isNumericLike, toNumber } from './value-utils';
4
-
5
- export function isTruthy(this: VirtualMachine, value: any, scope: Scope): boolean {
6
- if (value === null || value === undefined) return false;
7
- if (value instanceof Number) return value.valueOf() !== 0;
8
- if (typeof value === 'boolean') return value;
9
- if (typeof value === 'number') return value !== 0;
10
- if (typeof value === 'bigint') return value !== 0n;
11
- if (typeof value === 'string') return value.length > 0;
12
- if (Array.isArray(value)) return value.length > 0;
13
- if (value instanceof PyDict) return value.size > 0;
14
- if (value instanceof Set) return value.size > 0;
15
- if (value instanceof PyInstance) {
16
- const boolAttr = this.findClassAttribute(value.klass, '__bool__');
17
- if (boolAttr !== undefined) {
18
- const bound = this.getAttribute(value, '__bool__', scope);
19
- const result = typeof bound === 'function' ? bound() : bound;
20
- if (typeof result !== 'boolean') {
21
- throw new PyException('TypeError', '__bool__ should return bool');
22
- }
23
- return result;
24
- }
25
- const lenAttr = this.findClassAttribute(value.klass, '__len__');
26
- if (lenAttr !== undefined) {
27
- const bound = this.getAttribute(value, '__len__', scope);
28
- const result = typeof bound === 'function' ? bound() : bound;
29
- if (!isNumericLike(result)) {
30
- throw new PyException('TypeError', '__len__ should return int');
31
- }
32
- return toNumber(result) !== 0;
33
- }
34
- }
35
- return true;
36
- }
@@ -1,173 +0,0 @@
1
- import { PyClass, PyDict, PyException, PyFunction, PyInstance } from './runtime-types';
2
-
3
- export const isPyNone = (value: any) => value === null;
4
-
5
- export const isBigInt = (value: any): value is bigint => typeof value === 'bigint';
6
- export const isIntObject = (value: any): boolean => value instanceof Number && (value as any).__int__ === true;
7
- export const isFloatObject = (value: any): boolean => value instanceof Number && !isIntObject(value);
8
- export const isFloatLike = (value: any): boolean => isFloatObject(value) || (typeof value === 'number' && !Number.isInteger(value));
9
- export const isIntLike = (value: any): boolean =>
10
- isBigInt(value) ||
11
- value === true ||
12
- value === false ||
13
- (typeof value === 'number' && Number.isInteger(value)) ||
14
- isIntObject(value);
15
- export const isNumericLike = (value: any): boolean =>
16
- isBigInt(value) || typeof value === 'number' || value instanceof Number || typeof value === 'boolean';
17
- export const toNumber = (value: any): number => {
18
- if (value instanceof Number) return value.valueOf();
19
- if (typeof value === 'boolean') return value ? 1 : 0;
20
- if (typeof value === 'bigint') return Number(value);
21
- return value;
22
- };
23
- export const toBigIntValue = (value: any): bigint => {
24
- if (typeof value === 'bigint') return value;
25
- if (value instanceof Number) return BigInt(Math.trunc(value.valueOf()));
26
- if (typeof value === 'number') return BigInt(value);
27
- return BigInt(value);
28
- };
29
- export const shouldUseBigInt = (left: any, right: any): boolean =>
30
- (isBigInt(left) || isBigInt(right)) && !isFloatLike(left) && !isFloatLike(right);
31
- export const numericEquals = (left: any, right: any): boolean => {
32
- if (isNumericLike(left) && isNumericLike(right)) {
33
- if (isFloatLike(left) || isFloatLike(right)) {
34
- const leftNum = toNumber(left);
35
- const rightNum = toNumber(right);
36
- return !Number.isNaN(leftNum) && !Number.isNaN(rightNum) && leftNum === rightNum;
37
- }
38
- return toBigIntValue(left) === toBigIntValue(right);
39
- }
40
- return left === right;
41
- };
42
- export const numericCompare = (
43
- left: any,
44
- right: any
45
- ): { kind: 'float' | 'int'; left: number | bigint; right: number | bigint } | null => {
46
- if (!isNumericLike(left) || !isNumericLike(right)) return null;
47
- if (isFloatLike(left) || isFloatLike(right)) {
48
- return { kind: 'float', left: toNumber(left), right: toNumber(right) };
49
- }
50
- return { kind: 'int', left: toBigIntValue(left), right: toBigIntValue(right) };
51
- };
52
-
53
- export const bigIntFloorDiv = (left: bigint, right: bigint): bigint => {
54
- const quotient = left / right;
55
- if (left % right === 0n) return quotient;
56
- if ((left < 0n) !== (right < 0n)) return quotient - 1n;
57
- return quotient;
58
- };
59
-
60
- export const pyTypeName = (value: any): string => {
61
- if (value === null) return 'NoneType';
62
- if (isBigInt(value)) return 'int';
63
- if (isIntObject(value)) return 'int';
64
- if (value instanceof Number) return 'float';
65
- if (typeof value === 'boolean') return 'bool';
66
- if (typeof value === 'number') return Number.isInteger(value) ? 'int' : 'float';
67
- if (typeof value === 'string') return 'str';
68
- if (Array.isArray(value)) return (value as any).__tuple__ ? 'tuple' : 'list';
69
- if (value instanceof Set) return 'set';
70
- if (value instanceof PyDict) return 'dict';
71
- if (value instanceof PyFunction) return 'function';
72
- if (value instanceof PyClass) return 'type';
73
- if (value instanceof PyInstance) return value.klass.name;
74
- return typeof value;
75
- };
76
-
77
- export const pyRepr = (value: any): string => {
78
- if (value === null) return 'None';
79
- if (value instanceof Number) {
80
- const num = value.valueOf();
81
- if (Number.isNaN(num)) return 'nan';
82
- if (num === Infinity) return 'inf';
83
- if (num === -Infinity) return '-inf';
84
- if (isIntObject(value)) return String(num);
85
- if (Object.is(num, -0)) return '-0.0';
86
- return Number.isInteger(num) ? `${num}.0` : String(num);
87
- }
88
- if (typeof value === 'boolean') return value ? 'True' : 'False';
89
- if (typeof value === 'number') return Number.isNaN(value) ? 'nan' : String(value);
90
- if (typeof value === 'bigint') return value.toString();
91
- if (value && value.__complex__) {
92
- const sign = value.im >= 0 ? '+' : '-';
93
- const imag = Math.abs(value.im);
94
- return `(${value.re}${sign}${imag}j)`;
95
- }
96
- if (typeof value === 'string') return `'${value.replace(/'/g, "\\'")}'`;
97
- if (Array.isArray(value)) {
98
- const items = value.map((v: any) => pyRepr(v)).join(', ');
99
- if ((value as any).__tuple__) {
100
- if (value.length === 1) return `(${items},)`;
101
- return `(${items})`;
102
- }
103
- return `[${items}]`;
104
- }
105
- if (value instanceof Set) {
106
- const items = Array.from(value.values()).map((v) => pyRepr(v)).join(', ');
107
- return `{${items}}`;
108
- }
109
- if (value instanceof PyDict) {
110
- const items = Array.from(value.entries()).map(([k, v]) => `${pyRepr(k)}: ${pyRepr(v)}`).join(', ');
111
- return `{${items}}`;
112
- }
113
- if (value instanceof PyFunction) return `<function ${value.name}>`;
114
- if (value instanceof PyClass) return `<class '${value.name}'>`;
115
- if (value instanceof PyInstance) return `<${value.klass.name} object>`;
116
- return String(value);
117
- };
118
-
119
- export const pyStr = (value: any): string => {
120
- if (typeof value === 'string') return value;
121
- if (value && value.__complex__) return pyRepr(value);
122
- if (value && value.__typeName__) return `<class '${value.__typeName__}'>`;
123
- if (value instanceof PyException) return value.message;
124
- return pyRepr(value);
125
- };
126
-
127
- export const isComplex = (value: any) => value && value.__complex__;
128
-
129
- export const toComplex = (value: any) => {
130
- if (isComplex(value)) return value;
131
- if (isNumericLike(value)) return { __complex__: true, re: toNumber(value), im: 0 };
132
- return { __complex__: true, re: 0, im: 0 };
133
- };
134
-
135
- export const pythonModulo = (left: any, right: any) => {
136
- if (shouldUseBigInt(left, right)) {
137
- const leftNum = toBigIntValue(left);
138
- const rightNum = toBigIntValue(right);
139
- if (rightNum === 0n) throw new PyException('ZeroDivisionError', 'division by zero');
140
- const remainder = leftNum % rightNum;
141
- const adjust = remainder !== 0n && (leftNum < 0n) !== (rightNum < 0n);
142
- const quotient = leftNum / rightNum - (adjust ? 1n : 0n);
143
- return leftNum - quotient * rightNum;
144
- }
145
- const leftNum = toNumber(left);
146
- const rightNum = toNumber(right);
147
- if (rightNum === 0) throw new PyException('ZeroDivisionError', 'division by zero');
148
- const quotient = Math.floor(leftNum / rightNum);
149
- const result = leftNum - quotient * rightNum;
150
- if (isFloatObject(left) || isFloatObject(right)) {
151
- return new Number(result);
152
- }
153
- return result;
154
- };
155
-
156
- export const parseStringToken = (tokenValue: string): { value: string; isFString: boolean } => {
157
- let raw = tokenValue;
158
- let isFString = false;
159
- if (raw.startsWith('f') || raw.startsWith('F')) {
160
- isFString = true;
161
- raw = raw.slice(1);
162
- }
163
- const quote = raw[0];
164
- if (raw.startsWith(quote.repeat(3))) {
165
- const inner = raw.slice(3, -3);
166
- return { value: inner, isFString };
167
- }
168
- const inner = raw.slice(1, -1);
169
- return {
170
- value: inner.replace(/\\n/g, '\n').replace(/\\t/g, '\t').replace(/\\"/g, '"').replace(/\\'/g, "'"),
171
- isFString,
172
- };
173
- };
package/src/vm/vm.ts DELETED
@@ -1,80 +0,0 @@
1
- import { installBuiltins } from './builtins';
2
- import { callFunction, containsYield, evaluateComprehension, expressionHasYield, generateComprehension } from './callable';
3
- import { execute, executeBlock, executeBlockGenerator, executeStatementGenerator, iterableToArray, matchPattern, matchValueEquals, applyBindings } from './execution';
4
- import { evaluateExpressionGenerator } from './expression-generator';
5
- import { createAsyncioModule, importModule, loadModuleFromFile, resolveModulePath } from './imports';
6
- import {
7
- applyFormatSpec,
8
- applyWidth,
9
- contains,
10
- evaluateExpression,
11
- evaluateExpressionString,
12
- executeExpressionInline,
13
- splitFormatSpec,
14
- } from './expressions';
15
- import { assignTarget, deleteTarget, executeStatement, toIterableArray } from './statements';
16
- import {
17
- applyBinary,
18
- computeSliceBounds,
19
- computeSliceIndices,
20
- findClassAttribute,
21
- formatPercent,
22
- getAttribute,
23
- getSubscript,
24
- normalizeSliceStep,
25
- setAttribute,
26
- } from './operations';
27
- import { isTruthy } from './truthy';
28
- import { Scope } from './runtime-types';
29
-
30
- export class VirtualMachine {
31
- public moduleCache: Map<string, any> = new Map();
32
- public moduleSearchPaths: string[];
33
-
34
- constructor(moduleSearchPaths: string[] = [process.cwd()]) {
35
- this.moduleSearchPaths = moduleSearchPaths;
36
- }
37
-
38
- execute = execute;
39
- installBuiltins = installBuiltins;
40
- importModule = importModule;
41
- createAsyncioModule = createAsyncioModule;
42
- loadModuleFromFile = loadModuleFromFile;
43
- resolveModulePath = resolveModulePath;
44
- executeBlock = executeBlock;
45
- iterableToArray = iterableToArray;
46
- matchValueEquals = matchValueEquals;
47
- matchPattern = matchPattern;
48
- applyBindings = applyBindings;
49
- executeBlockGenerator = executeBlockGenerator;
50
- executeStatementGenerator = executeStatementGenerator;
51
- evaluateExpressionGenerator = evaluateExpressionGenerator;
52
- executeStatement = executeStatement;
53
- assignTarget = assignTarget;
54
- toIterableArray = toIterableArray;
55
- deleteTarget = deleteTarget;
56
- evaluateExpression = evaluateExpression;
57
- evaluateExpressionString = evaluateExpressionString;
58
- executeExpressionInline = executeExpressionInline;
59
- applyFormatSpec = applyFormatSpec;
60
- splitFormatSpec = splitFormatSpec;
61
- applyWidth = applyWidth;
62
- contains = contains;
63
- isTruthy = isTruthy;
64
- applyBinary = applyBinary;
65
- formatPercent = formatPercent;
66
- getSubscript = getSubscript;
67
- computeSliceBounds = computeSliceBounds;
68
- computeSliceIndices = computeSliceIndices;
69
- normalizeSliceStep = normalizeSliceStep;
70
- getAttribute = getAttribute;
71
- setAttribute = setAttribute;
72
- findClassAttribute = findClassAttribute;
73
- callFunction = callFunction;
74
- containsYield = containsYield;
75
- evaluateComprehension = evaluateComprehension;
76
- generateComprehension = generateComprehension;
77
- expressionHasYield = expressionHasYield;
78
- }
79
-
80
- export * from './runtime-types';