@mirascript/mirascript 0.1.62-alpha.9 → 0.1.63
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/README.md +46 -0
- package/dist/{chunk-6CAGNGY6.js → chunk-5BBTXV5A.js} +270 -269
- package/dist/chunk-5BBTXV5A.js.map +6 -0
- package/dist/{chunk-VRGQ23AK.js → chunk-HZYARHEQ.js} +30 -38
- package/dist/chunk-HZYARHEQ.js.map +6 -0
- package/dist/compiler/emit/consts.d.ts.map +1 -1
- package/dist/compiler/emit-script.d.ts +7 -2
- package/dist/compiler/emit-script.d.ts.map +1 -1
- package/dist/compiler/index.d.ts +2 -0
- package/dist/compiler/index.d.ts.map +1 -1
- package/dist/compiler/worker.js +1 -1
- package/dist/helpers/constants.d.ts +1 -10
- package/dist/helpers/constants.d.ts.map +1 -1
- package/dist/helpers/serialize.d.ts.map +1 -1
- package/dist/helpers/types.d.ts +5 -1
- package/dist/helpers/types.d.ts.map +1 -1
- package/dist/helpers/utils.d.ts +7 -1
- package/dist/helpers/utils.d.ts.map +1 -1
- package/dist/index.js +7 -4
- package/dist/index.js.map +1 -1
- package/dist/subtle.js +3 -3
- package/dist/subtle.js.map +1 -1
- package/dist/vm/checkpoint.d.ts +3 -3
- package/dist/vm/checkpoint.d.ts.map +1 -1
- package/dist/vm/lib/global/debug.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/entries.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/with.d.ts.map +1 -1
- package/dist/vm/operations/array-range.d.ts +6 -0
- package/dist/vm/operations/array-range.d.ts.map +1 -0
- package/dist/vm/operations/call.d.ts.map +1 -1
- package/dist/vm/operations/common.d.ts +1 -1
- package/dist/vm/operations/common.d.ts.map +1 -1
- package/dist/vm/operations/compound.d.ts +10 -10
- package/dist/vm/operations/compound.d.ts.map +1 -1
- package/dist/vm/operations/convert.d.ts +4 -4
- package/dist/vm/operations/convert.d.ts.map +1 -1
- package/dist/vm/operations/helpers.d.ts +7 -13
- package/dist/vm/operations/helpers.d.ts.map +1 -1
- package/dist/vm/operations/index.d.ts +1 -0
- package/dist/vm/operations/index.d.ts.map +1 -1
- package/dist/vm/operations/operator.d.ts +22 -22
- package/dist/vm/operations/operator.d.ts.map +1 -1
- package/dist/vm/operations/slice.d.ts +2 -2
- package/dist/vm/operations/slice.d.ts.map +1 -1
- package/dist/vm/operations/type-check.d.ts +7 -7
- package/dist/vm/operations/type-check.d.ts.map +1 -1
- package/dist/vm/operations/utils.d.ts +2 -2
- package/dist/vm/operations/utils.d.ts.map +1 -1
- package/dist/vm/types/boundary.d.ts +1 -1
- package/dist/vm/types/boundary.d.ts.map +1 -1
- package/dist/vm/types/context.d.ts.map +1 -1
- package/dist/vm/types/function.d.ts +0 -4
- package/dist/vm/types/function.d.ts.map +1 -1
- package/dist/vm/types/index.d.ts +1 -1
- package/dist/vm/types/index.d.ts.map +1 -1
- package/package.json +21 -8
- package/src/compiler/diagnostic.ts +2 -2
- package/src/compiler/emit/consts.ts +1 -0
- package/src/compiler/emit/index.ts +5 -5
- package/src/compiler/emit-script.ts +15 -6
- package/src/compiler/index.ts +3 -2
- package/src/helpers/analyze.ts +1 -1
- package/src/helpers/constants.ts +1 -11
- package/src/helpers/serialize.ts +1 -1
- package/src/helpers/types.ts +16 -0
- package/src/helpers/utils.ts +2 -1
- package/src/vm/checkpoint.ts +6 -6
- package/src/vm/lib/global/debug.ts +0 -1
- package/src/vm/lib/global/sequence/entries.ts +2 -0
- package/src/vm/lib/global/sequence/map-filter.ts +4 -4
- package/src/vm/lib/global/sequence/with.ts +3 -2
- package/src/vm/lib/loader.ts +2 -2
- package/src/vm/operations/array-range.ts +37 -0
- package/src/vm/operations/call.ts +8 -7
- package/src/vm/operations/common.ts +2 -2
- package/src/vm/operations/compound.ts +24 -25
- package/src/vm/operations/convert.ts +8 -8
- package/src/vm/operations/helpers.ts +17 -51
- package/src/vm/operations/index.ts +1 -0
- package/src/vm/operations/operator.ts +64 -54
- package/src/vm/operations/slice.ts +5 -4
- package/src/vm/operations/type-check.ts +16 -19
- package/src/vm/operations/utils.ts +4 -4
- package/src/vm/types/boundary.ts +2 -2
- package/src/vm/types/context.ts +1 -2
- package/src/vm/types/function.ts +2 -21
- package/src/vm/types/index.ts +1 -0
- package/bench/index.ts +0 -45
- package/dist/chunk-6CAGNGY6.js.map +0 -6
- package/dist/chunk-VRGQ23AK.js.map +0 -6
|
@@ -1,86 +1,52 @@
|
|
|
1
|
-
import { create, defineProperty, entries
|
|
2
|
-
import {
|
|
1
|
+
import { create, defineProperty, entries } from '../../helpers/utils.js';
|
|
2
|
+
import { VM_FUNCTION_ANONYMOUS_NAME } from '../../helpers/constants.js';
|
|
3
3
|
import { isVmConst } from '../../helpers/types.js';
|
|
4
4
|
import type { VmFunctionLike } from '../types/function.js';
|
|
5
5
|
import { DefaultVmContext, type VmContext } from '../types/context.js';
|
|
6
|
-
import type { VmConst, VmAny,
|
|
6
|
+
import type { VmConst, VmAny, VmValue, VmImmutable } from '../types/index.js';
|
|
7
7
|
import { VmModule } from '../types/module.js';
|
|
8
8
|
import { VmFunction } from '../types/function.js';
|
|
9
9
|
import { $AssertInit } from './common.js';
|
|
10
|
-
import { $ToNumber } from './convert.js';
|
|
11
10
|
|
|
12
11
|
/** 构造 module */
|
|
13
|
-
export
|
|
12
|
+
export const $Module = <T extends Record<string, () => VmImmutable>>(
|
|
14
13
|
name: string,
|
|
15
14
|
body: T,
|
|
16
|
-
): VmModule<{ [K in keyof T]: ReturnType<T[K]> }> {
|
|
15
|
+
): VmModule<{ [K in keyof T]: ReturnType<T[K]> }> => {
|
|
17
16
|
const mod = create(null) as { [K in keyof T]: ReturnType<T[K]> };
|
|
18
17
|
for (const [key, get] of entries(body)) {
|
|
19
|
-
defineProperty(mod, key, { __proto__: null, get, enumerable: true });
|
|
18
|
+
defineProperty(mod, key, { __proto__: null, get, enumerable: true, configurable: true });
|
|
20
19
|
}
|
|
21
20
|
return new VmModule(name, mod);
|
|
22
|
-
}
|
|
21
|
+
};
|
|
23
22
|
|
|
24
23
|
/** 构造 record | array 元素 */
|
|
25
|
-
export
|
|
24
|
+
export const $El = (value: VmAny): VmConst => {
|
|
26
25
|
$AssertInit(value);
|
|
27
26
|
if (!isVmConst(value)) return null;
|
|
28
27
|
return value;
|
|
29
|
-
}
|
|
28
|
+
};
|
|
30
29
|
|
|
31
30
|
const EMPTY = create(null);
|
|
32
31
|
/** 构造 record 可选元素 */
|
|
33
|
-
export
|
|
32
|
+
export const $ElOpt = (key: string, value: VmAny): VmConst => {
|
|
34
33
|
$AssertInit(value);
|
|
35
34
|
if (value == null || !isVmConst(value)) return EMPTY;
|
|
36
35
|
return { __proto__: null, [key]: value };
|
|
37
|
-
}
|
|
36
|
+
};
|
|
38
37
|
|
|
39
38
|
/** 构造函数和函数表达式 */
|
|
40
|
-
export
|
|
41
|
-
return VmFunction(fn, { isLib: false,
|
|
42
|
-
}
|
|
39
|
+
export const $Fn = <T extends VmFunctionLike>(name: string | null | undefined, fn: T): VmFunction<T> => {
|
|
40
|
+
return VmFunction(fn, { isLib: false, name: name || VM_FUNCTION_ANONYMOUS_NAME });
|
|
41
|
+
};
|
|
43
42
|
|
|
44
43
|
/** 读取闭包上值 */
|
|
45
|
-
export
|
|
44
|
+
export const $Upvalue = <T extends VmValue>(value: T | undefined): T => {
|
|
46
45
|
$AssertInit(value);
|
|
47
46
|
return value;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const assertArrayLength = (len: number) => {
|
|
51
|
-
if (len > VM_ARRAY_MAX_LENGTH) {
|
|
52
|
-
throw new RangeError(`Array length exceeds maximum limit of ${VM_ARRAY_MAX_LENGTH}`);
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
const isEmptyRange = (start: number, end: number) => {
|
|
56
|
-
return !isFinite(start) || !isFinite(end) || start > end;
|
|
57
47
|
};
|
|
58
|
-
/** 构造范围数组 */
|
|
59
|
-
export function $ArrayRange(start: VmAny, end: VmAny): VmArray {
|
|
60
|
-
const s = $ToNumber(start);
|
|
61
|
-
const e = $ToNumber(end);
|
|
62
|
-
if (isEmptyRange(s, e)) return [];
|
|
63
|
-
assertArrayLength(e - s + 1);
|
|
64
|
-
const arr = [];
|
|
65
|
-
for (let i = s; i <= e; i++) {
|
|
66
|
-
arr.push(i);
|
|
67
|
-
}
|
|
68
|
-
return arr;
|
|
69
|
-
}
|
|
70
|
-
/** 构造范围数组(不包含结束值) */
|
|
71
|
-
export function $ArrayRangeExclusive(start: VmAny, end: VmAny): VmArray {
|
|
72
|
-
const s = $ToNumber(start);
|
|
73
|
-
const e = $ToNumber(end);
|
|
74
|
-
if (isEmptyRange(s, e)) return [];
|
|
75
|
-
assertArrayLength(e - s);
|
|
76
|
-
const arr = [];
|
|
77
|
-
for (let i = s; i < e; i++) {
|
|
78
|
-
arr.push(i);
|
|
79
|
-
}
|
|
80
|
-
return arr;
|
|
81
|
-
}
|
|
82
48
|
|
|
83
49
|
/** 默认执行上下文 */
|
|
84
|
-
export
|
|
50
|
+
export const $GlobalFallback = (): VmContext => {
|
|
85
51
|
return DefaultVmContext;
|
|
86
|
-
}
|
|
52
|
+
};
|
|
@@ -7,111 +7,121 @@ import { isSame, overloadNumberString } from './utils.js';
|
|
|
7
7
|
|
|
8
8
|
// String operations
|
|
9
9
|
/** 字符串连接 */
|
|
10
|
-
export function $Concat(...args: readonly
|
|
10
|
+
export function $Concat(...args: readonly VmAny[]): string {
|
|
11
11
|
return args.map((a) => toFormat(a, null)).join('');
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
// Unary operations
|
|
15
15
|
/** 正号 */
|
|
16
|
-
export
|
|
17
|
-
return $ToNumber(a);
|
|
18
|
-
}
|
|
16
|
+
export const $Pos = $ToNumber;
|
|
19
17
|
/** 负号 */
|
|
20
|
-
export
|
|
21
|
-
return -$ToNumber(a);
|
|
22
|
-
}
|
|
18
|
+
export const $Neg = (a: VmAny): number => -$ToNumber(a);
|
|
23
19
|
/** 非 */
|
|
24
|
-
export
|
|
25
|
-
return !$ToBoolean(a);
|
|
26
|
-
}
|
|
20
|
+
export const $Not = (a: VmAny): boolean => !$ToBoolean(a);
|
|
27
21
|
|
|
28
22
|
// Math operations
|
|
23
|
+
const add = (a: VmAny, b: VmAny): number => $ToNumber(a) + $ToNumber(b);
|
|
29
24
|
/** 加法 */
|
|
30
|
-
export
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
export const $Add = (a: VmAny, b: VmAny): number => {
|
|
26
|
+
if (typeof a == 'number' && typeof b == 'number') return a + b;
|
|
27
|
+
return add(a, b);
|
|
28
|
+
};
|
|
29
|
+
const sub = (a: VmAny, b: VmAny): number => $ToNumber(a) - $ToNumber(b);
|
|
33
30
|
/** 减法 */
|
|
34
|
-
export
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
export const $Sub = (a: VmAny, b: VmAny): number => {
|
|
32
|
+
if (typeof a == 'number' && typeof b == 'number') return a - b;
|
|
33
|
+
return sub(a, b);
|
|
34
|
+
};
|
|
35
|
+
const mul = (a: VmAny, b: VmAny): number => $ToNumber(a) * $ToNumber(b);
|
|
37
36
|
/** 乘法 */
|
|
38
|
-
export
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
export const $Mul = (a: VmAny, b: VmAny): number => {
|
|
38
|
+
if (typeof a == 'number' && typeof b == 'number') return a * b;
|
|
39
|
+
return mul(a, b);
|
|
40
|
+
};
|
|
41
|
+
const div = (a: VmAny, b: VmAny): number => $ToNumber(a) / $ToNumber(b);
|
|
41
42
|
/** 除法 */
|
|
42
|
-
export
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
export const $Div = (a: VmAny, b: VmAny): number => {
|
|
44
|
+
if (typeof a == 'number' && typeof b == 'number') return a / b;
|
|
45
|
+
return div(a, b);
|
|
46
|
+
};
|
|
47
|
+
const mod = (a: VmAny, b: VmAny): number => $ToNumber(a) % $ToNumber(b);
|
|
45
48
|
/** 取模 */
|
|
46
|
-
export
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
export const $Mod = (a: VmAny, b: VmAny): number => {
|
|
50
|
+
if (typeof a == 'number' && typeof b == 'number') return a % b;
|
|
51
|
+
return mod(a, b);
|
|
52
|
+
};
|
|
53
|
+
const pow = (a: VmAny, b: VmAny): number => $ToNumber(a) ** $ToNumber(b);
|
|
49
54
|
/** 乘方 */
|
|
50
|
-
export
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
export const $Pow = (a: VmAny, b: VmAny): number => {
|
|
56
|
+
if (typeof a == 'number' && typeof b == 'number') return a ** b;
|
|
57
|
+
return pow(a, b);
|
|
58
|
+
};
|
|
53
59
|
|
|
54
60
|
// Logical operations without short-circuiting
|
|
61
|
+
const and = (a: VmAny, b: VmAny): boolean => $ToBoolean(a) && $ToBoolean(b);
|
|
55
62
|
/** 与 */
|
|
56
|
-
export
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
export const $And = (a: VmAny, b: VmAny): boolean => {
|
|
64
|
+
if (typeof a == 'boolean' && typeof b == 'boolean') return a && b;
|
|
65
|
+
return and(a, b);
|
|
66
|
+
};
|
|
67
|
+
const or = (a: VmAny, b: VmAny): boolean => $ToBoolean(a) || $ToBoolean(b);
|
|
59
68
|
/** 或 */
|
|
60
|
-
export
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
export const $Or = (a: VmAny, b: VmAny): boolean => {
|
|
70
|
+
if (typeof a == 'boolean' && typeof b == 'boolean') return a || b;
|
|
71
|
+
return or(a, b);
|
|
72
|
+
};
|
|
63
73
|
|
|
64
74
|
// Comparison operations
|
|
65
75
|
/** 大于 */
|
|
66
|
-
export
|
|
76
|
+
export const $Gt = (a: VmAny, b: VmAny): boolean => {
|
|
67
77
|
if (overloadNumberString(a, b)) {
|
|
68
78
|
return $ToNumber(a) > $ToNumber(b);
|
|
69
79
|
} else {
|
|
70
80
|
return $ToString(a) > $ToString(b);
|
|
71
81
|
}
|
|
72
|
-
}
|
|
82
|
+
};
|
|
73
83
|
/** 大于等于 */
|
|
74
|
-
export
|
|
84
|
+
export const $Gte = (a: VmAny, b: VmAny): boolean => {
|
|
75
85
|
if (overloadNumberString(a, b)) {
|
|
76
86
|
return $ToNumber(a) >= $ToNumber(b);
|
|
77
87
|
} else {
|
|
78
88
|
return $ToString(a) >= $ToString(b);
|
|
79
89
|
}
|
|
80
|
-
}
|
|
90
|
+
};
|
|
81
91
|
/** 小于 */
|
|
82
|
-
export
|
|
92
|
+
export const $Lt = (a: VmAny, b: VmAny): boolean => {
|
|
83
93
|
if (overloadNumberString(a, b)) {
|
|
84
94
|
return $ToNumber(a) < $ToNumber(b);
|
|
85
95
|
} else {
|
|
86
96
|
return $ToString(a) < $ToString(b);
|
|
87
97
|
}
|
|
88
|
-
}
|
|
98
|
+
};
|
|
89
99
|
/** 小于等于 */
|
|
90
|
-
export
|
|
100
|
+
export const $Lte = (a: VmAny, b: VmAny): boolean => {
|
|
91
101
|
if (overloadNumberString(a, b)) {
|
|
92
102
|
return $ToNumber(a) <= $ToNumber(b);
|
|
93
103
|
} else {
|
|
94
104
|
return $ToString(a) <= $ToString(b);
|
|
95
105
|
}
|
|
96
|
-
}
|
|
106
|
+
};
|
|
97
107
|
|
|
98
108
|
// Equality operations
|
|
99
109
|
/** 等于 */
|
|
100
|
-
export
|
|
110
|
+
export const $Eq = (a: VmAny, b: VmAny): boolean => {
|
|
101
111
|
$AssertInit(a);
|
|
102
112
|
$AssertInit(b);
|
|
103
113
|
// Number comparison is a special case to handle NaN correctly
|
|
104
114
|
if (typeof a == 'number' && typeof b == 'number') return a === b;
|
|
105
115
|
return isSame(a, b);
|
|
106
|
-
}
|
|
116
|
+
};
|
|
107
117
|
/** 不等于 */
|
|
108
|
-
export
|
|
118
|
+
export const $Neq = (a: VmAny, b: VmAny): boolean => {
|
|
109
119
|
return !$Eq(a, b);
|
|
110
|
-
}
|
|
120
|
+
};
|
|
111
121
|
|
|
112
122
|
const { abs, min } = Math;
|
|
113
123
|
/** 近似等于 */
|
|
114
|
-
export
|
|
124
|
+
export const $Aeq = (a: VmAny, b: VmAny): boolean => {
|
|
115
125
|
if (overloadNumberString(a, b)) {
|
|
116
126
|
const an = $ToNumber(a);
|
|
117
127
|
const bn = $ToNumber(b);
|
|
@@ -135,19 +145,19 @@ export function $Aeq(a: VmAny, b: VmAny): boolean {
|
|
|
135
145
|
const bn = bi.normalize('NFC');
|
|
136
146
|
return an === bn;
|
|
137
147
|
}
|
|
138
|
-
}
|
|
148
|
+
};
|
|
139
149
|
/** 不近似等于 */
|
|
140
|
-
export
|
|
150
|
+
export const $Naeq = (a: VmAny, b: VmAny): boolean => {
|
|
141
151
|
return !$Aeq(a, b);
|
|
142
|
-
}
|
|
152
|
+
};
|
|
143
153
|
|
|
144
154
|
/** 全等于 */
|
|
145
|
-
export
|
|
155
|
+
export const $Same = (a: VmAny, b: VmAny): boolean => {
|
|
146
156
|
$AssertInit(a);
|
|
147
157
|
$AssertInit(b);
|
|
148
158
|
return isSame(a, b);
|
|
149
|
-
}
|
|
159
|
+
};
|
|
150
160
|
/** 不全等于 */
|
|
151
|
-
export
|
|
161
|
+
export const $Nsame = (a: VmAny, b: VmAny): boolean => {
|
|
152
162
|
return !$Same(a, b);
|
|
153
|
-
}
|
|
163
|
+
};
|
|
@@ -13,6 +13,7 @@ const sliceCore = (value: VmArray, start: number, end: number, exclusive: boolea
|
|
|
13
13
|
|
|
14
14
|
if (isNaN(start)) start = 0;
|
|
15
15
|
else if (start < 0) start = length + start;
|
|
16
|
+
|
|
16
17
|
if (isNaN(end)) end = exclusive ? length : length - 1;
|
|
17
18
|
else if (end < 0) end = length + end;
|
|
18
19
|
|
|
@@ -26,18 +27,18 @@ const sliceCore = (value: VmArray, start: number, end: number, exclusive: boolea
|
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
/** 获取数组切片 */
|
|
29
|
-
export
|
|
30
|
+
export const $Slice = (value: VmAny, start: VmAny, end: VmAny): VmArray => {
|
|
30
31
|
$AssertInit(value);
|
|
31
32
|
if (!isVmArray(value)) throw new VmError(`Expected array, got ${display(value)}`, []);
|
|
32
33
|
const s = start != null ? $ToNumber(start) : 0;
|
|
33
34
|
const e = end != null ? $ToNumber(end) : value.length - 1;
|
|
34
35
|
return sliceCore(value, s, e, false);
|
|
35
|
-
}
|
|
36
|
+
};
|
|
36
37
|
/** 获取数组切片(不包含结束位置) */
|
|
37
|
-
export
|
|
38
|
+
export const $SliceExclusive = (value: VmAny, start: VmAny, end: VmAny): VmArray => {
|
|
38
39
|
$AssertInit(value);
|
|
39
40
|
if (!isVmArray(value)) throw new VmError(`Expected array, got ${display(value)}`, []);
|
|
40
41
|
const s = start != null ? $ToNumber(start) : 0;
|
|
41
42
|
const e = end != null ? $ToNumber(end) : value.length;
|
|
42
43
|
return sliceCore(value, s, e, true);
|
|
43
|
-
}
|
|
44
|
+
};
|
|
@@ -1,45 +1,42 @@
|
|
|
1
1
|
import { VmError } from '../../helpers/error.js';
|
|
2
|
-
import { isVmArray, isVmRecord
|
|
2
|
+
import { getVmType, isVmArray, isVmRecord } from '../../helpers/types.js';
|
|
3
3
|
import type { VmTypeName, VmAny, VmArray, VmRecord, VmValue } from '../types/index.js';
|
|
4
4
|
import { $AssertInit } from './common.js';
|
|
5
5
|
|
|
6
6
|
/** 获取值的类型名称 */
|
|
7
|
-
export
|
|
7
|
+
export const $Type = (value: VmAny): VmTypeName => {
|
|
8
8
|
// 允许未初始化值通过
|
|
9
9
|
if (value == null) return 'nil';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (typeof value == 'object') return 'record';
|
|
13
|
-
return typeof value as VmTypeName;
|
|
14
|
-
}
|
|
10
|
+
return getVmType(value);
|
|
11
|
+
};
|
|
15
12
|
/** 判断值是否为布尔值 */
|
|
16
|
-
export
|
|
13
|
+
export const $IsBoolean: (value: VmAny) => value is boolean = (value) => {
|
|
17
14
|
$AssertInit(value);
|
|
18
15
|
return typeof value == 'boolean';
|
|
19
|
-
}
|
|
16
|
+
};
|
|
20
17
|
/** 判断值是否为数字 */
|
|
21
|
-
export
|
|
18
|
+
export const $IsNumber: (value: VmAny) => value is number = (value) => {
|
|
22
19
|
$AssertInit(value);
|
|
23
20
|
return typeof value == 'number';
|
|
24
|
-
}
|
|
21
|
+
};
|
|
25
22
|
/** 判断值是否为字符串 */
|
|
26
|
-
export
|
|
23
|
+
export const $IsString: (value: VmAny) => value is string = (value) => {
|
|
27
24
|
$AssertInit(value);
|
|
28
25
|
return typeof value == 'string';
|
|
29
|
-
}
|
|
26
|
+
};
|
|
30
27
|
/** 判断值是否为记录 */
|
|
31
|
-
export
|
|
28
|
+
export const $IsRecord: (value: VmAny) => value is VmRecord = (value) => {
|
|
32
29
|
$AssertInit(value);
|
|
33
30
|
return isVmRecord(value);
|
|
34
|
-
}
|
|
31
|
+
};
|
|
35
32
|
/** 判断值是否为数组 */
|
|
36
|
-
export
|
|
33
|
+
export const $IsArray: (value: VmAny) => value is VmArray = (value) => {
|
|
37
34
|
$AssertInit(value);
|
|
38
35
|
return isVmArray(value);
|
|
39
|
-
}
|
|
36
|
+
};
|
|
40
37
|
/** 断言值非 nil */
|
|
41
|
-
export
|
|
38
|
+
export const $AssertNonNil: <T extends VmValue>(value: T | undefined) => asserts value is NonNullable<T> = (value) => {
|
|
42
39
|
$AssertInit(value);
|
|
43
40
|
if (value !== null) return;
|
|
44
41
|
throw new VmError(`Expected non-nil value`, null);
|
|
45
|
-
}
|
|
42
|
+
};
|
|
@@ -6,16 +6,16 @@ import type { VmAny, VmValue } from '../types/index.js';
|
|
|
6
6
|
* 确定操作的重载
|
|
7
7
|
* @returns 如果应按数字处理则返回 true;如果应按字符串处理则返回 false
|
|
8
8
|
*/
|
|
9
|
-
export
|
|
9
|
+
export const overloadNumberString = (a: VmAny, b: VmAny): boolean => {
|
|
10
10
|
if (typeof a == 'number' || typeof b == 'number') return true;
|
|
11
11
|
if (typeof a == 'string' || typeof b == 'string') return false;
|
|
12
12
|
return true;
|
|
13
|
-
}
|
|
13
|
+
};
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* 检查两个 VmValue 是否相同
|
|
17
17
|
*/
|
|
18
|
-
export
|
|
18
|
+
export const isSame = (a: VmValue, b: VmValue): boolean => {
|
|
19
19
|
// Check for NaN
|
|
20
20
|
if (typeof a == 'number' && typeof b == 'number') {
|
|
21
21
|
return a === b || (isNaN(a) && isNaN(b));
|
|
@@ -63,4 +63,4 @@ export function isSame(a: VmValue, b: VmValue): boolean {
|
|
|
63
63
|
return true;
|
|
64
64
|
}
|
|
65
65
|
return false;
|
|
66
|
-
}
|
|
66
|
+
};
|
package/src/vm/types/boundary.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { defineProperty, apply } from '../../helpers/utils.js';
|
|
2
2
|
import { isVmExtern, isVmFunction, isVmWrapper } from '../../helpers/types.js';
|
|
3
3
|
import { kVmFunctionProxy } from '../../helpers/constants.js';
|
|
4
|
+
import { $Call } from '../operations/call.js';
|
|
5
|
+
import type { VmAny, VmConst, VmModule, VmPrimitive, VmValue } from './index.js';
|
|
4
6
|
import type { VmFunctionLike, VmFunction } from './function.js';
|
|
5
7
|
import { VmExtern } from './extern.js';
|
|
6
|
-
import type { VmAny, VmConst, VmModule, VmPrimitive, VmValue } from './index.js';
|
|
7
|
-
import { $Call } from '../operations/call.js';
|
|
8
8
|
|
|
9
9
|
/** 创建 Mirascript 函数在宿主语言运行的代理 */
|
|
10
10
|
export function toVmFunctionProxy<T extends VmFunctionLike>(fn: VmFunction<T>): T {
|
package/src/vm/types/context.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { create, defineProperty, hasOwn, keys } from '../../helpers/utils.js';
|
|
1
|
+
import { create, defineProperty, hasOwn, keys, freeze } from '../../helpers/utils.js';
|
|
2
2
|
import { VmError } from '../../helpers/error.js';
|
|
3
3
|
import { kVmContext } from '../../helpers/constants.js';
|
|
4
4
|
import type { VmAny, VmImmutable, VmValue } from './index.js';
|
|
5
5
|
import { wrapToVmValue } from './boundary.js';
|
|
6
6
|
import { VmFunction } from './function.js';
|
|
7
|
-
const { freeze } = Object;
|
|
8
7
|
|
|
9
8
|
/** MiraScript 执行上下文 */
|
|
10
9
|
export interface VmContext {
|
package/src/vm/types/function.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { Writable } from 'type-fest';
|
|
2
2
|
import type { DiagnosticCode } from '@mirascript/constants';
|
|
3
|
-
import { defineProperty } from '../../helpers/utils.js';
|
|
3
|
+
import { defineProperty, freeze } from '../../helpers/utils.js';
|
|
4
4
|
import { kVmFunction, VM_FUNCTION_ANONYMOUS_NAME } from '../../helpers/constants.js';
|
|
5
5
|
import { isVmFunction } from '../../helpers/types.js';
|
|
6
6
|
import type { VmAny, VmValue } from './index.js';
|
|
7
7
|
import { fromVmFunctionProxy } from './boundary.js';
|
|
8
|
-
import { CpEnter, CpExit } from '../checkpoint.js';
|
|
9
8
|
import type { VmLib } from '../lib/helpers.js';
|
|
10
9
|
|
|
11
10
|
/**
|
|
@@ -37,8 +36,6 @@ export type VmFunctionInfo = {
|
|
|
37
36
|
readonly returnsType?: string;
|
|
38
37
|
/** 文档字符串 */
|
|
39
38
|
readonly examples?: string[];
|
|
40
|
-
/** 如果添加了包装,返回原函数 */
|
|
41
|
-
readonly original?: VmFunctionLike;
|
|
42
39
|
/** 标记为弃用 */
|
|
43
40
|
readonly deprecated?: { use?: string; message: DiagnosticCode };
|
|
44
41
|
};
|
|
@@ -47,8 +44,6 @@ export type VmFunctionInfo = {
|
|
|
47
44
|
export type VmFunctionOption = Partial<Omit<VmFunctionInfo, 'original'>> & {
|
|
48
45
|
/** 函数名称 */
|
|
49
46
|
readonly name?: string | null | undefined;
|
|
50
|
-
/** 是否注入检查点 */
|
|
51
|
-
readonly injectCp?: boolean;
|
|
52
47
|
};
|
|
53
48
|
|
|
54
49
|
const nameIfNotAnonymous = <T>({ name }: { name: string | undefined }, fallback: T): string | T => {
|
|
@@ -76,7 +71,6 @@ export function VmFunction<T extends VmFunctionLike>(
|
|
|
76
71
|
opt = {
|
|
77
72
|
...option,
|
|
78
73
|
isLib: true,
|
|
79
|
-
injectCp: false,
|
|
80
74
|
name: nameIfNotAnonymous(option, null),
|
|
81
75
|
};
|
|
82
76
|
} else {
|
|
@@ -96,20 +90,7 @@ export function VmFunction<T extends VmFunctionLike>(
|
|
|
96
90
|
deprecated: opt.deprecated ?? undefined,
|
|
97
91
|
};
|
|
98
92
|
const name = opt.name ?? fn.name;
|
|
99
|
-
if (opt.injectCp) {
|
|
100
|
-
const original = fn;
|
|
101
|
-
info.original = original;
|
|
102
|
-
fn = ((...args) => {
|
|
103
|
-
try {
|
|
104
|
-
CpEnter();
|
|
105
|
-
const ret = original(...args);
|
|
106
|
-
return ret;
|
|
107
|
-
} finally {
|
|
108
|
-
CpExit();
|
|
109
|
-
}
|
|
110
|
-
}) as typeof fn;
|
|
111
|
-
}
|
|
112
93
|
defineProperty(fn, 'name', { value: name, configurable: true });
|
|
113
|
-
defineProperty(fn, kVmFunction, { value:
|
|
94
|
+
defineProperty(fn, kVmFunction, { value: freeze(info) });
|
|
114
95
|
return fn as VmFunction<T>;
|
|
115
96
|
}
|
package/src/vm/types/index.ts
CHANGED
package/bench/index.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Bench } from 'tinybench';
|
|
2
|
-
import { compile, compileSync, createVmContext } from '@mirascript/mirascript';
|
|
3
|
-
|
|
4
|
-
const bench = new Bench({ name: 'simple benchmark', time: 100 });
|
|
5
|
-
const source = `sin(x) + cos(y + PI / 2) + `.repeat(1) + '0';
|
|
6
|
-
const env = { x: 1, y: 2 };
|
|
7
|
-
|
|
8
|
-
bench
|
|
9
|
-
.add('compile', async () => {
|
|
10
|
-
await Promise.all(Array.from({ length: 10 }).map(async () => compile(source)));
|
|
11
|
-
})
|
|
12
|
-
.add('compileSync', () => {
|
|
13
|
-
compileSync(source);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
bench.add('createVmContext', () => {
|
|
17
|
-
return createVmContext(env);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const vmContext = createVmContext(env);
|
|
21
|
-
const script = compileSync(source);
|
|
22
|
-
bench.add('run', () => {
|
|
23
|
-
return script(vmContext);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
bench.add('nativeCompile', () => {
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
28
|
-
return new Function('context', `const {sin,cos,PI,x,y} = context; return ${source};`);
|
|
29
|
-
});
|
|
30
|
-
bench.add('nativeCreateContext', () => {
|
|
31
|
-
return { __proto__: Math, ...env };
|
|
32
|
-
});
|
|
33
|
-
const nativeContext = { __proto__: Math, ...env };
|
|
34
|
-
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
35
|
-
const nativeScript = new Function('context', `const {sin,cos,PI,x,y} = context; return ${source};`) as (
|
|
36
|
-
context: Record<string, unknown>,
|
|
37
|
-
) => unknown;
|
|
38
|
-
|
|
39
|
-
bench.add('nativeRun', () => {
|
|
40
|
-
return nativeScript(nativeContext);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
await bench.run();
|
|
44
|
-
// eslint-disable-next-line no-console
|
|
45
|
-
console.table(bench.table());
|