@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.
- package/.claude/settings.local.json +3 -0
- package/.prettierrc +7 -0
- package/Agents.md +66 -0
- package/README.md +93 -0
- package/README_zh-CN.md +93 -0
- package/SETUP.md +171 -0
- package/dist/compiler.d.ts +20 -0
- package/dist/compiler.js +91 -0
- package/dist/compiler_module/compiler.d.ts +8 -0
- package/dist/compiler_module/compiler.js +22 -0
- package/dist/compiler_module/index.d.ts +2 -0
- package/dist/compiler_module/index.js +6 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +67 -0
- package/dist/lexer/index.d.ts +2 -0
- package/dist/lexer/index.js +6 -0
- package/dist/lexer/lexer.d.ts +16 -0
- package/dist/lexer/lexer.js +403 -0
- package/dist/parser/expressions.d.ts +30 -0
- package/dist/parser/expressions.js +483 -0
- package/dist/parser/index.d.ts +2 -0
- package/dist/parser/index.js +6 -0
- package/dist/parser/parser.d.ts +63 -0
- package/dist/parser/parser.js +129 -0
- package/dist/parser/statements.d.ts +20 -0
- package/dist/parser/statements.js +388 -0
- package/dist/parser/targets.d.ts +6 -0
- package/dist/parser/targets.js +75 -0
- package/dist/types/ast.d.ts +63 -0
- package/dist/types/ast.js +60 -0
- package/dist/types/bytecode.d.ts +38 -0
- package/dist/types/bytecode.js +35 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.js +20 -0
- package/dist/types/token.d.ts +34 -0
- package/dist/types/token.js +39 -0
- package/dist/vm/builtins.d.ts +4 -0
- package/dist/vm/builtins.js +269 -0
- package/dist/vm/callable.d.ts +8 -0
- package/dist/vm/callable.js +161 -0
- package/dist/vm/execution.d.ts +15 -0
- package/dist/vm/execution.js +283 -0
- package/dist/vm/expression-generator.d.ts +3 -0
- package/dist/vm/expression-generator.js +70 -0
- package/dist/vm/expressions.d.ts +13 -0
- package/dist/vm/expressions.js +390 -0
- package/dist/vm/imports.d.ts +7 -0
- package/dist/vm/imports.js +99 -0
- package/dist/vm/index.d.ts +3 -0
- package/dist/vm/index.js +21 -0
- package/dist/vm/operations.d.ts +16 -0
- package/dist/vm/operations.js +439 -0
- package/dist/vm/runtime-types.d.ts +84 -0
- package/dist/vm/runtime-types.js +290 -0
- package/dist/vm/statements.d.ts +7 -0
- package/dist/vm/statements.js +381 -0
- package/dist/vm/truthy.d.ts +4 -0
- package/dist/vm/truthy.js +47 -0
- package/dist/vm/value-utils.d.ts +28 -0
- package/dist/vm/value-utils.js +225 -0
- package/dist/vm/vm.d.ts +56 -0
- package/dist/vm/vm.js +75 -0
- package/examples/assert_testing.py +38 -0
- package/examples/big_int_precision.py +2 -0
- package/examples/boolean_logic.py +35 -0
- package/examples/break_continue.py +43 -0
- package/examples/classes_objects.py +43 -0
- package/examples/compiler_killer_async.py +6 -0
- package/examples/compiler_killer_bigint.py +3 -0
- package/examples/compiler_killer_bool_int_dict_key.py +5 -0
- package/examples/compiler_killer_bool_len.py +9 -0
- package/examples/compiler_killer_floor_division.py +4 -0
- package/examples/compiler_killer_is_identity.py +3 -0
- package/examples/compiler_killer_list_sort_return.py +3 -0
- package/examples/compiler_killer_match.py +13 -0
- package/examples/compiler_killer_negative_repeat.py +3 -0
- package/examples/compiler_killer_negative_zero_repr.py +3 -0
- package/examples/compiler_killer_rounding.py +4 -0
- package/examples/compiler_killer_slice_assign.py +3 -0
- package/examples/comprehensions.py +28 -0
- package/examples/conditions.py +13 -0
- package/examples/context_manager.py +35 -0
- package/examples/decorators.py +50 -0
- package/examples/exceptions.py +40 -0
- package/examples/fibonacci.py +10 -0
- package/examples/functions.py +38 -0
- package/examples/generator.py +51 -0
- package/examples/global_nonlocal.py +48 -0
- package/examples/hello.py +3 -0
- package/examples/itertools_example.py +33 -0
- package/examples/lists_dicts.py +29 -0
- package/examples/loops.py +19 -0
- package/examples/math_ops.py +15 -0
- package/examples/nan_set.py +6 -0
- package/examples/numbers_operators.py +51 -0
- package/examples/sets.py +36 -0
- package/examples/slicing.py +29 -0
- package/examples/starred_unpacking.py +3 -0
- package/examples/string_formatting.py +36 -0
- package/examples/strings.py +22 -0
- package/examples/tuples.py +45 -0
- package/examples/type_conversion.py +41 -0
- package/jest.config.js +15 -0
- package/notes/iterations/compiler-runtime/compiler-runtime_2025-09-16.md +25 -0
- package/notes/iterations/compiler-runtime/compiler-runtime_2026-01-16.md +24 -0
- package/notes/iterations/compiler-runtime/compiler-runtime_test_2026-01-16.md +21 -0
- package/notes/iterations/floor-division/floor-division_2026-01-16.md +29 -0
- package/package.json +36 -0
- package/prompts/commit.txt +9 -0
- package/prompts/task.txt +21 -0
- package/prompts/test.txt +23 -0
- package/scripts/codex-loop.js +215 -0
- package/scripts/verify.sh +12 -0
- package/src/compiler.ts +58 -0
- package/src/compiler_module/compiler.ts +19 -0
- package/src/compiler_module/index.ts +1 -0
- package/src/index.ts +39 -0
- package/src/lexer/index.ts +1 -0
- package/src/lexer/lexer.ts +402 -0
- package/src/parser/expressions.ts +462 -0
- package/src/parser/index.ts +1 -0
- package/src/parser/parser.ts +102 -0
- package/src/parser/statements.ts +366 -0
- package/src/parser/targets.ts +71 -0
- package/src/types/ast.ts +64 -0
- package/src/types/bytecode.ts +50 -0
- package/src/types/index.ts +3 -0
- package/src/types/token.ts +44 -0
- package/src/vm/builtins.ts +237 -0
- package/src/vm/callable.ts +154 -0
- package/src/vm/execution.ts +251 -0
- package/src/vm/expression-generator.ts +65 -0
- package/src/vm/expressions.ts +373 -0
- package/src/vm/imports.ts +61 -0
- package/src/vm/index.ts +2 -0
- package/src/vm/operations.ts +414 -0
- package/src/vm/runtime-types.ts +292 -0
- package/src/vm/statements.ts +358 -0
- package/src/vm/truthy.ts +36 -0
- package/src/vm/value-utils.ts +173 -0
- package/src/vm/vm.ts +80 -0
- package/tests/compiler.test.ts +111 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +16 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isTruthy = isTruthy;
|
|
4
|
+
const runtime_types_1 = require("./runtime-types");
|
|
5
|
+
const value_utils_1 = require("./value-utils");
|
|
6
|
+
function isTruthy(value, scope) {
|
|
7
|
+
if (value === null || value === undefined)
|
|
8
|
+
return false;
|
|
9
|
+
if (value instanceof Number)
|
|
10
|
+
return value.valueOf() !== 0;
|
|
11
|
+
if (typeof value === 'boolean')
|
|
12
|
+
return value;
|
|
13
|
+
if (typeof value === 'number')
|
|
14
|
+
return value !== 0;
|
|
15
|
+
if (typeof value === 'bigint')
|
|
16
|
+
return value !== 0n;
|
|
17
|
+
if (typeof value === 'string')
|
|
18
|
+
return value.length > 0;
|
|
19
|
+
if (Array.isArray(value))
|
|
20
|
+
return value.length > 0;
|
|
21
|
+
if (value instanceof runtime_types_1.PyDict)
|
|
22
|
+
return value.size > 0;
|
|
23
|
+
if (value instanceof Set)
|
|
24
|
+
return value.size > 0;
|
|
25
|
+
if (value instanceof runtime_types_1.PyInstance) {
|
|
26
|
+
const boolAttr = this.findClassAttribute(value.klass, '__bool__');
|
|
27
|
+
if (boolAttr !== undefined) {
|
|
28
|
+
const bound = this.getAttribute(value, '__bool__', scope);
|
|
29
|
+
const result = typeof bound === 'function' ? bound() : bound;
|
|
30
|
+
if (typeof result !== 'boolean') {
|
|
31
|
+
throw new runtime_types_1.PyException('TypeError', '__bool__ should return bool');
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
const lenAttr = this.findClassAttribute(value.klass, '__len__');
|
|
36
|
+
if (lenAttr !== undefined) {
|
|
37
|
+
const bound = this.getAttribute(value, '__len__', scope);
|
|
38
|
+
const result = typeof bound === 'function' ? bound() : bound;
|
|
39
|
+
if (!(0, value_utils_1.isNumericLike)(result)) {
|
|
40
|
+
throw new runtime_types_1.PyException('TypeError', '__len__ should return int');
|
|
41
|
+
}
|
|
42
|
+
return (0, value_utils_1.toNumber)(result) !== 0;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=truthy.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const isPyNone: (value: any) => boolean;
|
|
2
|
+
export declare const isBigInt: (value: any) => value is bigint;
|
|
3
|
+
export declare const isIntObject: (value: any) => boolean;
|
|
4
|
+
export declare const isFloatObject: (value: any) => boolean;
|
|
5
|
+
export declare const isFloatLike: (value: any) => boolean;
|
|
6
|
+
export declare const isIntLike: (value: any) => boolean;
|
|
7
|
+
export declare const isNumericLike: (value: any) => boolean;
|
|
8
|
+
export declare const toNumber: (value: any) => number;
|
|
9
|
+
export declare const toBigIntValue: (value: any) => bigint;
|
|
10
|
+
export declare const shouldUseBigInt: (left: any, right: any) => boolean;
|
|
11
|
+
export declare const numericEquals: (left: any, right: any) => boolean;
|
|
12
|
+
export declare const numericCompare: (left: any, right: any) => {
|
|
13
|
+
kind: "float" | "int";
|
|
14
|
+
left: number | bigint;
|
|
15
|
+
right: number | bigint;
|
|
16
|
+
} | null;
|
|
17
|
+
export declare const bigIntFloorDiv: (left: bigint, right: bigint) => bigint;
|
|
18
|
+
export declare const pyTypeName: (value: any) => string;
|
|
19
|
+
export declare const pyRepr: (value: any) => string;
|
|
20
|
+
export declare const pyStr: (value: any) => string;
|
|
21
|
+
export declare const isComplex: (value: any) => any;
|
|
22
|
+
export declare const toComplex: (value: any) => any;
|
|
23
|
+
export declare const pythonModulo: (left: any, right: any) => number | bigint | Number;
|
|
24
|
+
export declare const parseStringToken: (tokenValue: string) => {
|
|
25
|
+
value: string;
|
|
26
|
+
isFString: boolean;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=value-utils.d.ts.map
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseStringToken = exports.pythonModulo = exports.toComplex = exports.isComplex = exports.pyStr = exports.pyRepr = exports.pyTypeName = exports.bigIntFloorDiv = exports.numericCompare = exports.numericEquals = exports.shouldUseBigInt = exports.toBigIntValue = exports.toNumber = exports.isNumericLike = exports.isIntLike = exports.isFloatLike = exports.isFloatObject = exports.isIntObject = exports.isBigInt = exports.isPyNone = void 0;
|
|
4
|
+
const runtime_types_1 = require("./runtime-types");
|
|
5
|
+
const isPyNone = (value) => value === null;
|
|
6
|
+
exports.isPyNone = isPyNone;
|
|
7
|
+
const isBigInt = (value) => typeof value === 'bigint';
|
|
8
|
+
exports.isBigInt = isBigInt;
|
|
9
|
+
const isIntObject = (value) => value instanceof Number && value.__int__ === true;
|
|
10
|
+
exports.isIntObject = isIntObject;
|
|
11
|
+
const isFloatObject = (value) => value instanceof Number && !(0, exports.isIntObject)(value);
|
|
12
|
+
exports.isFloatObject = isFloatObject;
|
|
13
|
+
const isFloatLike = (value) => (0, exports.isFloatObject)(value) || (typeof value === 'number' && !Number.isInteger(value));
|
|
14
|
+
exports.isFloatLike = isFloatLike;
|
|
15
|
+
const isIntLike = (value) => (0, exports.isBigInt)(value) ||
|
|
16
|
+
value === true ||
|
|
17
|
+
value === false ||
|
|
18
|
+
(typeof value === 'number' && Number.isInteger(value)) ||
|
|
19
|
+
(0, exports.isIntObject)(value);
|
|
20
|
+
exports.isIntLike = isIntLike;
|
|
21
|
+
const isNumericLike = (value) => (0, exports.isBigInt)(value) || typeof value === 'number' || value instanceof Number || typeof value === 'boolean';
|
|
22
|
+
exports.isNumericLike = isNumericLike;
|
|
23
|
+
const toNumber = (value) => {
|
|
24
|
+
if (value instanceof Number)
|
|
25
|
+
return value.valueOf();
|
|
26
|
+
if (typeof value === 'boolean')
|
|
27
|
+
return value ? 1 : 0;
|
|
28
|
+
if (typeof value === 'bigint')
|
|
29
|
+
return Number(value);
|
|
30
|
+
return value;
|
|
31
|
+
};
|
|
32
|
+
exports.toNumber = toNumber;
|
|
33
|
+
const toBigIntValue = (value) => {
|
|
34
|
+
if (typeof value === 'bigint')
|
|
35
|
+
return value;
|
|
36
|
+
if (value instanceof Number)
|
|
37
|
+
return BigInt(Math.trunc(value.valueOf()));
|
|
38
|
+
if (typeof value === 'number')
|
|
39
|
+
return BigInt(value);
|
|
40
|
+
return BigInt(value);
|
|
41
|
+
};
|
|
42
|
+
exports.toBigIntValue = toBigIntValue;
|
|
43
|
+
const shouldUseBigInt = (left, right) => ((0, exports.isBigInt)(left) || (0, exports.isBigInt)(right)) && !(0, exports.isFloatLike)(left) && !(0, exports.isFloatLike)(right);
|
|
44
|
+
exports.shouldUseBigInt = shouldUseBigInt;
|
|
45
|
+
const numericEquals = (left, right) => {
|
|
46
|
+
if ((0, exports.isNumericLike)(left) && (0, exports.isNumericLike)(right)) {
|
|
47
|
+
if ((0, exports.isFloatLike)(left) || (0, exports.isFloatLike)(right)) {
|
|
48
|
+
const leftNum = (0, exports.toNumber)(left);
|
|
49
|
+
const rightNum = (0, exports.toNumber)(right);
|
|
50
|
+
return !Number.isNaN(leftNum) && !Number.isNaN(rightNum) && leftNum === rightNum;
|
|
51
|
+
}
|
|
52
|
+
return (0, exports.toBigIntValue)(left) === (0, exports.toBigIntValue)(right);
|
|
53
|
+
}
|
|
54
|
+
return left === right;
|
|
55
|
+
};
|
|
56
|
+
exports.numericEquals = numericEquals;
|
|
57
|
+
const numericCompare = (left, right) => {
|
|
58
|
+
if (!(0, exports.isNumericLike)(left) || !(0, exports.isNumericLike)(right))
|
|
59
|
+
return null;
|
|
60
|
+
if ((0, exports.isFloatLike)(left) || (0, exports.isFloatLike)(right)) {
|
|
61
|
+
return { kind: 'float', left: (0, exports.toNumber)(left), right: (0, exports.toNumber)(right) };
|
|
62
|
+
}
|
|
63
|
+
return { kind: 'int', left: (0, exports.toBigIntValue)(left), right: (0, exports.toBigIntValue)(right) };
|
|
64
|
+
};
|
|
65
|
+
exports.numericCompare = numericCompare;
|
|
66
|
+
const bigIntFloorDiv = (left, right) => {
|
|
67
|
+
const quotient = left / right;
|
|
68
|
+
if (left % right === 0n)
|
|
69
|
+
return quotient;
|
|
70
|
+
if ((left < 0n) !== (right < 0n))
|
|
71
|
+
return quotient - 1n;
|
|
72
|
+
return quotient;
|
|
73
|
+
};
|
|
74
|
+
exports.bigIntFloorDiv = bigIntFloorDiv;
|
|
75
|
+
const pyTypeName = (value) => {
|
|
76
|
+
if (value === null)
|
|
77
|
+
return 'NoneType';
|
|
78
|
+
if ((0, exports.isBigInt)(value))
|
|
79
|
+
return 'int';
|
|
80
|
+
if ((0, exports.isIntObject)(value))
|
|
81
|
+
return 'int';
|
|
82
|
+
if (value instanceof Number)
|
|
83
|
+
return 'float';
|
|
84
|
+
if (typeof value === 'boolean')
|
|
85
|
+
return 'bool';
|
|
86
|
+
if (typeof value === 'number')
|
|
87
|
+
return Number.isInteger(value) ? 'int' : 'float';
|
|
88
|
+
if (typeof value === 'string')
|
|
89
|
+
return 'str';
|
|
90
|
+
if (Array.isArray(value))
|
|
91
|
+
return value.__tuple__ ? 'tuple' : 'list';
|
|
92
|
+
if (value instanceof Set)
|
|
93
|
+
return 'set';
|
|
94
|
+
if (value instanceof runtime_types_1.PyDict)
|
|
95
|
+
return 'dict';
|
|
96
|
+
if (value instanceof runtime_types_1.PyFunction)
|
|
97
|
+
return 'function';
|
|
98
|
+
if (value instanceof runtime_types_1.PyClass)
|
|
99
|
+
return 'type';
|
|
100
|
+
if (value instanceof runtime_types_1.PyInstance)
|
|
101
|
+
return value.klass.name;
|
|
102
|
+
return typeof value;
|
|
103
|
+
};
|
|
104
|
+
exports.pyTypeName = pyTypeName;
|
|
105
|
+
const pyRepr = (value) => {
|
|
106
|
+
if (value === null)
|
|
107
|
+
return 'None';
|
|
108
|
+
if (value instanceof Number) {
|
|
109
|
+
const num = value.valueOf();
|
|
110
|
+
if (Number.isNaN(num))
|
|
111
|
+
return 'nan';
|
|
112
|
+
if (num === Infinity)
|
|
113
|
+
return 'inf';
|
|
114
|
+
if (num === -Infinity)
|
|
115
|
+
return '-inf';
|
|
116
|
+
if ((0, exports.isIntObject)(value))
|
|
117
|
+
return String(num);
|
|
118
|
+
if (Object.is(num, -0))
|
|
119
|
+
return '-0.0';
|
|
120
|
+
return Number.isInteger(num) ? `${num}.0` : String(num);
|
|
121
|
+
}
|
|
122
|
+
if (typeof value === 'boolean')
|
|
123
|
+
return value ? 'True' : 'False';
|
|
124
|
+
if (typeof value === 'number')
|
|
125
|
+
return Number.isNaN(value) ? 'nan' : String(value);
|
|
126
|
+
if (typeof value === 'bigint')
|
|
127
|
+
return value.toString();
|
|
128
|
+
if (value && value.__complex__) {
|
|
129
|
+
const sign = value.im >= 0 ? '+' : '-';
|
|
130
|
+
const imag = Math.abs(value.im);
|
|
131
|
+
return `(${value.re}${sign}${imag}j)`;
|
|
132
|
+
}
|
|
133
|
+
if (typeof value === 'string')
|
|
134
|
+
return `'${value.replace(/'/g, "\\'")}'`;
|
|
135
|
+
if (Array.isArray(value)) {
|
|
136
|
+
const items = value.map((v) => (0, exports.pyRepr)(v)).join(', ');
|
|
137
|
+
if (value.__tuple__) {
|
|
138
|
+
if (value.length === 1)
|
|
139
|
+
return `(${items},)`;
|
|
140
|
+
return `(${items})`;
|
|
141
|
+
}
|
|
142
|
+
return `[${items}]`;
|
|
143
|
+
}
|
|
144
|
+
if (value instanceof Set) {
|
|
145
|
+
const items = Array.from(value.values()).map((v) => (0, exports.pyRepr)(v)).join(', ');
|
|
146
|
+
return `{${items}}`;
|
|
147
|
+
}
|
|
148
|
+
if (value instanceof runtime_types_1.PyDict) {
|
|
149
|
+
const items = Array.from(value.entries()).map(([k, v]) => `${(0, exports.pyRepr)(k)}: ${(0, exports.pyRepr)(v)}`).join(', ');
|
|
150
|
+
return `{${items}}`;
|
|
151
|
+
}
|
|
152
|
+
if (value instanceof runtime_types_1.PyFunction)
|
|
153
|
+
return `<function ${value.name}>`;
|
|
154
|
+
if (value instanceof runtime_types_1.PyClass)
|
|
155
|
+
return `<class '${value.name}'>`;
|
|
156
|
+
if (value instanceof runtime_types_1.PyInstance)
|
|
157
|
+
return `<${value.klass.name} object>`;
|
|
158
|
+
return String(value);
|
|
159
|
+
};
|
|
160
|
+
exports.pyRepr = pyRepr;
|
|
161
|
+
const pyStr = (value) => {
|
|
162
|
+
if (typeof value === 'string')
|
|
163
|
+
return value;
|
|
164
|
+
if (value && value.__complex__)
|
|
165
|
+
return (0, exports.pyRepr)(value);
|
|
166
|
+
if (value && value.__typeName__)
|
|
167
|
+
return `<class '${value.__typeName__}'>`;
|
|
168
|
+
if (value instanceof runtime_types_1.PyException)
|
|
169
|
+
return value.message;
|
|
170
|
+
return (0, exports.pyRepr)(value);
|
|
171
|
+
};
|
|
172
|
+
exports.pyStr = pyStr;
|
|
173
|
+
const isComplex = (value) => value && value.__complex__;
|
|
174
|
+
exports.isComplex = isComplex;
|
|
175
|
+
const toComplex = (value) => {
|
|
176
|
+
if ((0, exports.isComplex)(value))
|
|
177
|
+
return value;
|
|
178
|
+
if ((0, exports.isNumericLike)(value))
|
|
179
|
+
return { __complex__: true, re: (0, exports.toNumber)(value), im: 0 };
|
|
180
|
+
return { __complex__: true, re: 0, im: 0 };
|
|
181
|
+
};
|
|
182
|
+
exports.toComplex = toComplex;
|
|
183
|
+
const pythonModulo = (left, right) => {
|
|
184
|
+
if ((0, exports.shouldUseBigInt)(left, right)) {
|
|
185
|
+
const leftNum = (0, exports.toBigIntValue)(left);
|
|
186
|
+
const rightNum = (0, exports.toBigIntValue)(right);
|
|
187
|
+
if (rightNum === 0n)
|
|
188
|
+
throw new runtime_types_1.PyException('ZeroDivisionError', 'division by zero');
|
|
189
|
+
const remainder = leftNum % rightNum;
|
|
190
|
+
const adjust = remainder !== 0n && (leftNum < 0n) !== (rightNum < 0n);
|
|
191
|
+
const quotient = leftNum / rightNum - (adjust ? 1n : 0n);
|
|
192
|
+
return leftNum - quotient * rightNum;
|
|
193
|
+
}
|
|
194
|
+
const leftNum = (0, exports.toNumber)(left);
|
|
195
|
+
const rightNum = (0, exports.toNumber)(right);
|
|
196
|
+
if (rightNum === 0)
|
|
197
|
+
throw new runtime_types_1.PyException('ZeroDivisionError', 'division by zero');
|
|
198
|
+
const quotient = Math.floor(leftNum / rightNum);
|
|
199
|
+
const result = leftNum - quotient * rightNum;
|
|
200
|
+
if ((0, exports.isFloatObject)(left) || (0, exports.isFloatObject)(right)) {
|
|
201
|
+
return new Number(result);
|
|
202
|
+
}
|
|
203
|
+
return result;
|
|
204
|
+
};
|
|
205
|
+
exports.pythonModulo = pythonModulo;
|
|
206
|
+
const parseStringToken = (tokenValue) => {
|
|
207
|
+
let raw = tokenValue;
|
|
208
|
+
let isFString = false;
|
|
209
|
+
if (raw.startsWith('f') || raw.startsWith('F')) {
|
|
210
|
+
isFString = true;
|
|
211
|
+
raw = raw.slice(1);
|
|
212
|
+
}
|
|
213
|
+
const quote = raw[0];
|
|
214
|
+
if (raw.startsWith(quote.repeat(3))) {
|
|
215
|
+
const inner = raw.slice(3, -3);
|
|
216
|
+
return { value: inner, isFString };
|
|
217
|
+
}
|
|
218
|
+
const inner = raw.slice(1, -1);
|
|
219
|
+
return {
|
|
220
|
+
value: inner.replace(/\\n/g, '\n').replace(/\\t/g, '\t').replace(/\\"/g, '"').replace(/\\'/g, "'"),
|
|
221
|
+
isFString,
|
|
222
|
+
};
|
|
223
|
+
};
|
|
224
|
+
exports.parseStringToken = parseStringToken;
|
|
225
|
+
//# sourceMappingURL=value-utils.js.map
|
package/dist/vm/vm.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
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 { applyFormatSpec, applyWidth, contains, evaluateExpression, evaluateExpressionString, executeExpressionInline, splitFormatSpec } from './expressions';
|
|
7
|
+
import { assignTarget, deleteTarget, executeStatement, toIterableArray } from './statements';
|
|
8
|
+
import { applyBinary, computeSliceBounds, computeSliceIndices, findClassAttribute, formatPercent, getAttribute, getSubscript, normalizeSliceStep, setAttribute } from './operations';
|
|
9
|
+
import { isTruthy } from './truthy';
|
|
10
|
+
export declare class VirtualMachine {
|
|
11
|
+
moduleCache: Map<string, any>;
|
|
12
|
+
moduleSearchPaths: string[];
|
|
13
|
+
constructor(moduleSearchPaths?: string[]);
|
|
14
|
+
execute: typeof execute;
|
|
15
|
+
installBuiltins: typeof installBuiltins;
|
|
16
|
+
importModule: typeof importModule;
|
|
17
|
+
createAsyncioModule: typeof createAsyncioModule;
|
|
18
|
+
loadModuleFromFile: typeof loadModuleFromFile;
|
|
19
|
+
resolveModulePath: typeof resolveModulePath;
|
|
20
|
+
executeBlock: typeof executeBlock;
|
|
21
|
+
iterableToArray: typeof iterableToArray;
|
|
22
|
+
matchValueEquals: typeof matchValueEquals;
|
|
23
|
+
matchPattern: typeof matchPattern;
|
|
24
|
+
applyBindings: typeof applyBindings;
|
|
25
|
+
executeBlockGenerator: typeof executeBlockGenerator;
|
|
26
|
+
executeStatementGenerator: typeof executeStatementGenerator;
|
|
27
|
+
evaluateExpressionGenerator: typeof evaluateExpressionGenerator;
|
|
28
|
+
executeStatement: typeof executeStatement;
|
|
29
|
+
assignTarget: typeof assignTarget;
|
|
30
|
+
toIterableArray: typeof toIterableArray;
|
|
31
|
+
deleteTarget: typeof deleteTarget;
|
|
32
|
+
evaluateExpression: typeof evaluateExpression;
|
|
33
|
+
evaluateExpressionString: typeof evaluateExpressionString;
|
|
34
|
+
executeExpressionInline: typeof executeExpressionInline;
|
|
35
|
+
applyFormatSpec: typeof applyFormatSpec;
|
|
36
|
+
splitFormatSpec: typeof splitFormatSpec;
|
|
37
|
+
applyWidth: typeof applyWidth;
|
|
38
|
+
contains: typeof contains;
|
|
39
|
+
isTruthy: typeof isTruthy;
|
|
40
|
+
applyBinary: typeof applyBinary;
|
|
41
|
+
formatPercent: typeof formatPercent;
|
|
42
|
+
getSubscript: typeof getSubscript;
|
|
43
|
+
computeSliceBounds: typeof computeSliceBounds;
|
|
44
|
+
computeSliceIndices: typeof computeSliceIndices;
|
|
45
|
+
normalizeSliceStep: typeof normalizeSliceStep;
|
|
46
|
+
getAttribute: typeof getAttribute;
|
|
47
|
+
setAttribute: typeof setAttribute;
|
|
48
|
+
findClassAttribute: typeof findClassAttribute;
|
|
49
|
+
callFunction: typeof callFunction;
|
|
50
|
+
containsYield: typeof containsYield;
|
|
51
|
+
evaluateComprehension: typeof evaluateComprehension;
|
|
52
|
+
generateComprehension: typeof generateComprehension;
|
|
53
|
+
expressionHasYield: typeof expressionHasYield;
|
|
54
|
+
}
|
|
55
|
+
export * from './runtime-types';
|
|
56
|
+
//# sourceMappingURL=vm.d.ts.map
|
package/dist/vm/vm.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.VirtualMachine = void 0;
|
|
18
|
+
const builtins_1 = require("./builtins");
|
|
19
|
+
const callable_1 = require("./callable");
|
|
20
|
+
const execution_1 = require("./execution");
|
|
21
|
+
const expression_generator_1 = require("./expression-generator");
|
|
22
|
+
const imports_1 = require("./imports");
|
|
23
|
+
const expressions_1 = require("./expressions");
|
|
24
|
+
const statements_1 = require("./statements");
|
|
25
|
+
const operations_1 = require("./operations");
|
|
26
|
+
const truthy_1 = require("./truthy");
|
|
27
|
+
class VirtualMachine {
|
|
28
|
+
constructor(moduleSearchPaths = [process.cwd()]) {
|
|
29
|
+
this.moduleCache = new Map();
|
|
30
|
+
this.execute = execution_1.execute;
|
|
31
|
+
this.installBuiltins = builtins_1.installBuiltins;
|
|
32
|
+
this.importModule = imports_1.importModule;
|
|
33
|
+
this.createAsyncioModule = imports_1.createAsyncioModule;
|
|
34
|
+
this.loadModuleFromFile = imports_1.loadModuleFromFile;
|
|
35
|
+
this.resolveModulePath = imports_1.resolveModulePath;
|
|
36
|
+
this.executeBlock = execution_1.executeBlock;
|
|
37
|
+
this.iterableToArray = execution_1.iterableToArray;
|
|
38
|
+
this.matchValueEquals = execution_1.matchValueEquals;
|
|
39
|
+
this.matchPattern = execution_1.matchPattern;
|
|
40
|
+
this.applyBindings = execution_1.applyBindings;
|
|
41
|
+
this.executeBlockGenerator = execution_1.executeBlockGenerator;
|
|
42
|
+
this.executeStatementGenerator = execution_1.executeStatementGenerator;
|
|
43
|
+
this.evaluateExpressionGenerator = expression_generator_1.evaluateExpressionGenerator;
|
|
44
|
+
this.executeStatement = statements_1.executeStatement;
|
|
45
|
+
this.assignTarget = statements_1.assignTarget;
|
|
46
|
+
this.toIterableArray = statements_1.toIterableArray;
|
|
47
|
+
this.deleteTarget = statements_1.deleteTarget;
|
|
48
|
+
this.evaluateExpression = expressions_1.evaluateExpression;
|
|
49
|
+
this.evaluateExpressionString = expressions_1.evaluateExpressionString;
|
|
50
|
+
this.executeExpressionInline = expressions_1.executeExpressionInline;
|
|
51
|
+
this.applyFormatSpec = expressions_1.applyFormatSpec;
|
|
52
|
+
this.splitFormatSpec = expressions_1.splitFormatSpec;
|
|
53
|
+
this.applyWidth = expressions_1.applyWidth;
|
|
54
|
+
this.contains = expressions_1.contains;
|
|
55
|
+
this.isTruthy = truthy_1.isTruthy;
|
|
56
|
+
this.applyBinary = operations_1.applyBinary;
|
|
57
|
+
this.formatPercent = operations_1.formatPercent;
|
|
58
|
+
this.getSubscript = operations_1.getSubscript;
|
|
59
|
+
this.computeSliceBounds = operations_1.computeSliceBounds;
|
|
60
|
+
this.computeSliceIndices = operations_1.computeSliceIndices;
|
|
61
|
+
this.normalizeSliceStep = operations_1.normalizeSliceStep;
|
|
62
|
+
this.getAttribute = operations_1.getAttribute;
|
|
63
|
+
this.setAttribute = operations_1.setAttribute;
|
|
64
|
+
this.findClassAttribute = operations_1.findClassAttribute;
|
|
65
|
+
this.callFunction = callable_1.callFunction;
|
|
66
|
+
this.containsYield = callable_1.containsYield;
|
|
67
|
+
this.evaluateComprehension = callable_1.evaluateComprehension;
|
|
68
|
+
this.generateComprehension = callable_1.generateComprehension;
|
|
69
|
+
this.expressionHasYield = callable_1.expressionHasYield;
|
|
70
|
+
this.moduleSearchPaths = moduleSearchPaths;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.VirtualMachine = VirtualMachine;
|
|
74
|
+
__exportStar(require("./runtime-types"), exports);
|
|
75
|
+
//# sourceMappingURL=vm.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Assert 语句进行简单测试
|
|
2
|
+
def test_addition():
|
|
3
|
+
assert 2 + 2 == 4, "Addition failed"
|
|
4
|
+
assert 1 + 1 == 2
|
|
5
|
+
print("Addition tests passed")
|
|
6
|
+
|
|
7
|
+
def test_string():
|
|
8
|
+
assert "hello".upper() == "HELLO"
|
|
9
|
+
assert "hello" == "hello"
|
|
10
|
+
print("String tests passed")
|
|
11
|
+
|
|
12
|
+
def test_list():
|
|
13
|
+
lst = [1, 2, 3]
|
|
14
|
+
assert len(lst) == 3
|
|
15
|
+
assert 2 in lst
|
|
16
|
+
assert 4 not in lst
|
|
17
|
+
print("List tests passed")
|
|
18
|
+
|
|
19
|
+
def test_comparison():
|
|
20
|
+
assert 5 > 3
|
|
21
|
+
assert 2 < 5
|
|
22
|
+
assert 5 >= 5
|
|
23
|
+
print("Comparison tests passed")
|
|
24
|
+
|
|
25
|
+
# 运行测试
|
|
26
|
+
test_addition()
|
|
27
|
+
test_string()
|
|
28
|
+
test_list()
|
|
29
|
+
test_comparison()
|
|
30
|
+
|
|
31
|
+
print("\nAll tests passed!")
|
|
32
|
+
|
|
33
|
+
# 测试失败的示例
|
|
34
|
+
print("\nTesting failure case:")
|
|
35
|
+
try:
|
|
36
|
+
assert 1 == 2, "This assertion will fail"
|
|
37
|
+
except AssertionError as e:
|
|
38
|
+
print(f"Caught AssertionError: {e}")
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# 布尔类型和逻辑运算
|
|
2
|
+
x = True
|
|
3
|
+
y = False
|
|
4
|
+
|
|
5
|
+
print("x and y:", x and y)
|
|
6
|
+
print("x or y:", x or y)
|
|
7
|
+
print("not x:", not x)
|
|
8
|
+
|
|
9
|
+
# 比较运算
|
|
10
|
+
a = 10
|
|
11
|
+
b = 20
|
|
12
|
+
|
|
13
|
+
print(f"{a} == {b}:", a == b)
|
|
14
|
+
print(f"{a} != {b}:", a != b)
|
|
15
|
+
print(f"{a} < {b}:", a < b)
|
|
16
|
+
print(f"{a} > {b}:", a > b)
|
|
17
|
+
print(f"{a} <= {b}:", a <= b)
|
|
18
|
+
print(f"{a} >= {b}:", a >= b)
|
|
19
|
+
|
|
20
|
+
# 链式比较
|
|
21
|
+
c = 15
|
|
22
|
+
print(f"{a} < {c} < {b}:", a < c < b)
|
|
23
|
+
|
|
24
|
+
# 成员运算符
|
|
25
|
+
numbers = [1, 2, 3, 4, 5]
|
|
26
|
+
print("3 in numbers:", 3 in numbers)
|
|
27
|
+
print("6 not in numbers:", 6 not in numbers)
|
|
28
|
+
|
|
29
|
+
# 布尔条件
|
|
30
|
+
if (x or (a < b and not y)):
|
|
31
|
+
print("Complex condition is true")
|
|
32
|
+
|
|
33
|
+
# 三元运算符
|
|
34
|
+
result = "positive" if a > 0 else "non-positive"
|
|
35
|
+
print(f"a is {result}")
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Break 和 Continue 语句
|
|
2
|
+
print("Break example:")
|
|
3
|
+
for i in range(10):
|
|
4
|
+
if i == 5:
|
|
5
|
+
break
|
|
6
|
+
print(i, end=" ")
|
|
7
|
+
print()
|
|
8
|
+
|
|
9
|
+
print("\nContinue example:")
|
|
10
|
+
for i in range(10):
|
|
11
|
+
if i % 2 == 0:
|
|
12
|
+
continue
|
|
13
|
+
print(i, end=" ")
|
|
14
|
+
print()
|
|
15
|
+
|
|
16
|
+
# 嵌套循环中的 break
|
|
17
|
+
print("\nNested loop with break:")
|
|
18
|
+
for i in range(3):
|
|
19
|
+
for j in range(3):
|
|
20
|
+
if j == 1:
|
|
21
|
+
break
|
|
22
|
+
print(f"({i}, {j})", end=" ")
|
|
23
|
+
print()
|
|
24
|
+
|
|
25
|
+
# While 循环中的 break 和 continue
|
|
26
|
+
print("\nWhile with break and continue:")
|
|
27
|
+
count = 0
|
|
28
|
+
while count < 10:
|
|
29
|
+
count += 1
|
|
30
|
+
if count == 3:
|
|
31
|
+
continue
|
|
32
|
+
if count == 8:
|
|
33
|
+
break
|
|
34
|
+
print(count, end=" ")
|
|
35
|
+
print()
|
|
36
|
+
|
|
37
|
+
# Pass 语句
|
|
38
|
+
print("\nPass statement:")
|
|
39
|
+
for i in range(3):
|
|
40
|
+
if i == 1:
|
|
41
|
+
pass # 占位符
|
|
42
|
+
else:
|
|
43
|
+
print(f"i = {i}")
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# 类定义和对象
|
|
2
|
+
class Dog:
|
|
3
|
+
species = "Canis familiaris"
|
|
4
|
+
|
|
5
|
+
def __init__(self, name, age):
|
|
6
|
+
self.name = name
|
|
7
|
+
self.age = age
|
|
8
|
+
|
|
9
|
+
def bark(self):
|
|
10
|
+
return f"{self.name} says: Woof!"
|
|
11
|
+
|
|
12
|
+
def birthday(self):
|
|
13
|
+
self.age += 1
|
|
14
|
+
return f"{self.name} is now {self.age} years old"
|
|
15
|
+
|
|
16
|
+
# 创建对象
|
|
17
|
+
dog1 = Dog("Rex", 3)
|
|
18
|
+
dog2 = Dog("Buddy", 5)
|
|
19
|
+
|
|
20
|
+
print(dog1.bark())
|
|
21
|
+
print(dog2.bark())
|
|
22
|
+
|
|
23
|
+
# 访问属性
|
|
24
|
+
print(f"{dog1.name} is {dog1.age} years old")
|
|
25
|
+
|
|
26
|
+
# 调用方法
|
|
27
|
+
print(dog1.birthday())
|
|
28
|
+
print(f"Species: {dog1.species}")
|
|
29
|
+
|
|
30
|
+
# 继承
|
|
31
|
+
class Animal:
|
|
32
|
+
def __init__(self, name):
|
|
33
|
+
self.name = name
|
|
34
|
+
|
|
35
|
+
def speak(self):
|
|
36
|
+
return f"{self.name} makes a sound"
|
|
37
|
+
|
|
38
|
+
class Cat(Animal):
|
|
39
|
+
def speak(self):
|
|
40
|
+
return f"{self.name} says: Meow!"
|
|
41
|
+
|
|
42
|
+
cat = Cat("Whiskers")
|
|
43
|
+
print(cat.speak())
|