@mirascript/mirascript 0.1.12 → 0.1.14
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/dist/chunk-55FKP56O.js +2317 -0
- package/dist/chunk-55FKP56O.js.map +6 -0
- package/dist/{chunk-IKSSUVRE.js → chunk-Q74RKZ7O.js} +73 -1250
- package/dist/chunk-Q74RKZ7O.js.map +6 -0
- package/dist/cli/index.js +8 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/compiler/emit.d.ts.map +1 -1
- package/dist/compiler/worker.js +1 -1
- package/dist/helpers/serialize.d.ts +1 -1
- package/dist/helpers/serialize.d.ts.map +1 -1
- package/dist/index.js +15 -9
- package/dist/subtle.d.ts +1 -1
- package/dist/subtle.d.ts.map +1 -1
- package/dist/subtle.js +7 -7
- package/dist/vm/lib/global/debug.d.ts +1 -1
- package/dist/vm/lib/global/json.d.ts +2 -2
- package/dist/vm/lib/global/json.d.ts.map +1 -1
- package/dist/vm/lib/global/mod/matrix.d.ts +1 -1
- package/dist/vm/lib/global/mod/matrix.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/all-any.d.ts +2 -2
- package/dist/vm/lib/global/sequence/entries.d.ts +4 -4
- package/dist/vm/lib/global/sequence/find.d.ts +2 -2
- package/dist/vm/lib/global/sequence/repeat.d.ts +1 -1
- package/dist/vm/lib/global/sequence/with.d.ts +1 -1
- package/dist/vm/lib/global/sequence/with.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/zip.d.ts +1 -1
- package/dist/vm/operations.d.ts +2 -0
- package/dist/vm/operations.d.ts.map +1 -1
- package/dist/vm/types/any.d.ts +10 -0
- package/dist/vm/types/any.d.ts.map +1 -0
- package/dist/vm/types/array.d.ts +12 -0
- package/dist/vm/types/array.d.ts.map +1 -0
- package/dist/vm/types/callable.d.ts +5 -0
- package/dist/vm/types/callable.d.ts.map +1 -0
- package/dist/vm/types/const.d.ts +15 -0
- package/dist/vm/types/const.d.ts.map +1 -0
- package/dist/vm/types/context.d.ts.map +1 -1
- package/dist/vm/types/extern.d.ts +1 -1
- package/dist/vm/types/extern.d.ts.map +1 -1
- package/dist/vm/types/immutable.d.ts +15 -0
- package/dist/vm/types/immutable.d.ts.map +1 -0
- package/dist/vm/types/index.d.ts +17 -47
- package/dist/vm/types/index.d.ts.map +1 -1
- package/dist/vm/types/primitive.d.ts +7 -0
- package/dist/vm/types/primitive.d.ts.map +1 -0
- package/dist/vm/types/record.d.ts +20 -0
- package/dist/vm/types/record.d.ts.map +1 -0
- package/dist/vm/types/value.d.ts +14 -0
- package/dist/vm/types/value.d.ts.map +1 -0
- package/dist/vm/types/wrapper.d.ts +1 -1
- package/dist/vm/types/wrapper.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/compiler/compile-fast.ts +1 -1
- package/src/compiler/emit.ts +131 -17
- package/src/helpers/serialize.ts +34 -14
- package/src/subtle.ts +1 -1
- package/src/vm/operations.ts +5 -5
- package/src/vm/types/any.ts +33 -0
- package/src/vm/types/array.ts +19 -0
- package/src/vm/types/callable.ts +10 -0
- package/src/vm/types/{checker.ts → const.ts} +7 -55
- package/src/vm/types/context.ts +5 -1
- package/src/vm/types/extern.ts +19 -5
- package/src/vm/types/immutable.ts +22 -0
- package/src/vm/types/index.ts +31 -83
- package/src/vm/types/primitive.ts +14 -0
- package/src/vm/types/record.ts +53 -0
- package/src/vm/types/value.ts +22 -0
- package/src/vm/types/wrapper.ts +1 -1
- package/dist/chunk-AGIXQM52.js +0 -916
- package/dist/chunk-AGIXQM52.js.map +0 -6
- package/dist/chunk-IKSSUVRE.js.map +0 -6
- package/dist/vm/types/checker.d.ts +0 -30
- package/dist/vm/types/checker.d.ts.map +0 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { VmAny } from './any.js';
|
|
2
|
+
import { type VmConst } from './const.js';
|
|
3
|
+
import { type VmFunction } from './function.js';
|
|
4
|
+
import { type VmModule } from './module.js';
|
|
5
|
+
/** Mirascript 虚拟机内的不可变值 */
|
|
6
|
+
export type VmImmutable = VmConst | VmFunction | VmModule;
|
|
7
|
+
/**
|
|
8
|
+
* 检查是否为 Mirascript 不可变值
|
|
9
|
+
*/
|
|
10
|
+
export declare function isVmImmutable(value: VmAny): value is VmImmutable;
|
|
11
|
+
/**
|
|
12
|
+
* 检查是否为 Mirascript 不可变值
|
|
13
|
+
*/
|
|
14
|
+
export declare function isVmImmutable(value: unknown, checkDeep: boolean): value is VmImmutable;
|
|
15
|
+
//# sourceMappingURL=immutable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"immutable.d.ts","sourceRoot":"","sources":["../../../src/vm/types/immutable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAa,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAExD,2BAA2B;AAC3B,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE1D;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,WAAW,CAAC;AAClE;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAAC"}
|
package/dist/vm/types/index.d.ts
CHANGED
|
@@ -1,32 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export type VmPrimitive = null | string | number | boolean;
|
|
7
|
-
/**
|
|
8
|
-
* Mirascript 记录
|
|
9
|
-
* 仅拥有且可枚举的字符串键视作存在
|
|
10
|
-
* 字段值 `undefined` 和 `null` 均视作 `nil`
|
|
11
|
-
*/
|
|
12
|
-
export type VmRecord = {
|
|
13
|
-
readonly [key: string]: VmConst | undefined;
|
|
14
|
-
};
|
|
15
|
-
/**
|
|
16
|
-
* Mirascript 数组
|
|
17
|
-
* 数组中的 `undefined`、`null` 及 <empty slot> 均视作 `nil`
|
|
18
|
-
*/
|
|
19
|
-
export type VmArray = ReadonlyArray<VmConst | undefined>;
|
|
20
|
-
/** Mirascript 虚拟机内的值语义值 */
|
|
21
|
-
export type VmConst = VmPrimitive | VmRecord | VmArray;
|
|
22
|
-
/** Mirascript 虚拟机内的不可变值 */
|
|
23
|
-
export type VmImmutable = VmConst | VmFunction | VmModule;
|
|
24
|
-
/** Mirascript 虚拟机内的合法值 */
|
|
25
|
-
export type VmValue = VmImmutable | VmExtern;
|
|
26
|
-
/** Mirascript 虚拟机内的未初始化变量 */
|
|
27
|
-
export type VmUninitialized = undefined;
|
|
28
|
-
/** Mirascript 虚拟机内的值(包括未初始化变量) */
|
|
29
|
-
export type VmAny = VmValue | VmUninitialized;
|
|
1
|
+
import type { VmArray } from './array.js';
|
|
2
|
+
import type { VmExtern } from './extern.js';
|
|
3
|
+
import type { VmFunction } from './function.js';
|
|
4
|
+
import type { VmModule } from './module.js';
|
|
5
|
+
import type { VmRecord } from './record.js';
|
|
30
6
|
/** 类型名称 */
|
|
31
7
|
export type TypeName = keyof VmValueMap;
|
|
32
8
|
/** 类型名称映射 */
|
|
@@ -50,25 +26,19 @@ export interface VmValueMap {
|
|
|
50
26
|
/** Mirascript 模块 */
|
|
51
27
|
module: VmModule;
|
|
52
28
|
}
|
|
53
|
-
/**
|
|
54
|
-
* 检查值是否为 Mirascript 数组
|
|
55
|
-
*/
|
|
56
|
-
export declare function isVmArray(value: VmAny): value is VmArray;
|
|
57
|
-
/**
|
|
58
|
-
* 检查值是否为 Mirascript 记录
|
|
59
|
-
*/
|
|
60
|
-
export declare function isVmRecord(value: VmAny): value is VmRecord;
|
|
61
|
-
/**
|
|
62
|
-
* 检查值是否为 Mirascript 原始值
|
|
63
|
-
*/
|
|
64
|
-
export declare function isVmPrimitive(value: unknown): value is VmPrimitive;
|
|
65
|
-
export { VmFunction, isVmFunction, VmExtern, isVmExtern, VmModule, isVmModule, isVmWrapper };
|
|
66
29
|
export { wrapToVmValue, unwrapFromVmValue, toVmFunctionProxy, fromVmFunctionProxy } from './boundary.js';
|
|
67
|
-
/** 检查值是否为 Mirascript 可调用值 */
|
|
68
|
-
export declare function isVmCallable(value: unknown): value is VmFunction | VmExtern<Function>;
|
|
69
|
-
export { getVmFunctionInfo, type VmFunctionInfo, type VmFunctionLike, type VmFunctionOption } from './function.js';
|
|
70
30
|
export { type VmContext, type VmSharedContext, isVmContext, defineVmContextValue, createVmContext } from './context.js';
|
|
71
31
|
export { type VmScript, isVmScript } from './script.js';
|
|
72
|
-
export {
|
|
73
|
-
export
|
|
32
|
+
export { isVmCallable } from './callable.js';
|
|
33
|
+
export { type VmArray, VM_ARRAY_MAX_LENGTH, isVmArray } from './array.js';
|
|
34
|
+
export { type VmRecord, isVmRecord, isVmArrayLikeRecord, isVmArrayLikeRecordByEntires, isVmArrayLikeRecordByKeys, } from './record.js';
|
|
35
|
+
export { type VmPrimitive, isVmPrimitive } from './primitive.js';
|
|
36
|
+
export { type VmConst, isVmConst } from './const.js';
|
|
37
|
+
export { type VmImmutable, isVmImmutable } from './immutable.js';
|
|
38
|
+
export { VmExtern, isVmExtern } from './extern.js';
|
|
39
|
+
export { VmFunction, isVmFunction, getVmFunctionInfo, type VmFunctionInfo, type VmFunctionLike, type VmFunctionOption, } from './function.js';
|
|
40
|
+
export { VmModule, isVmModule } from './module.js';
|
|
41
|
+
export { isVmWrapper } from './wrapper.js';
|
|
42
|
+
export { type VmValue, isVmValue } from './value.js';
|
|
43
|
+
export { type VmAny, type VmUninitialized, isVmAny } from './any.js';
|
|
74
44
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/vm/types/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/vm/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,WAAW;AACX,MAAM,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC;AAExC,aAAa;AACb,MAAM,WAAW,UAAU;IACvB,SAAS;IACT,GAAG,EAAE,IAAI,CAAC;IACV,UAAU;IACV,MAAM,EAAE,MAAM,CAAC;IACf,SAAS;IACT,MAAM,EAAE,MAAM,CAAC;IACf,UAAU;IACV,OAAO,EAAE,OAAO,CAAC;IACjB,oBAAoB;IACpB,MAAM,EAAE,QAAQ,CAAC;IACjB,oBAAoB;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,oBAAoB;IACpB,QAAQ,EAAE,UAAU,CAAC;IACrB,aAAa;IACb,MAAM,EAAE,QAAQ,CAAC;IACjB,oBAAoB;IACpB,MAAM,EAAE,QAAQ,CAAC;CACpB;AAED,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACzG,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,eAAe,EAAE,WAAW,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACxH,OAAO,EAAE,KAAK,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,EAAE,KAAK,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EACH,KAAK,QAAQ,EACb,UAAU,EACV,mBAAmB,EACnB,4BAA4B,EAC5B,yBAAyB,GAC5B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,KAAK,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,KAAK,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,KAAK,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EACH,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,gBAAgB,GACxB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,KAAK,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,eAAe,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primitive.d.ts","sourceRoot":"","sources":["../../../src/vm/types/primitive.ts"],"names":[],"mappings":"AAAA,qBAAqB;AACrB,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAOlE"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type VmAny, type VmConst } from './index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Mirascript 记录
|
|
4
|
+
* 仅拥有且可枚举的字符串键视作存在
|
|
5
|
+
* 字段值 `undefined` 和 `null` 均视作 `nil`
|
|
6
|
+
*/
|
|
7
|
+
export type VmRecord = {
|
|
8
|
+
readonly [key: string]: VmConst | undefined;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* 检查值是否为 Mirascript 记录
|
|
12
|
+
*/
|
|
13
|
+
export declare function isVmRecord(value: VmAny): value is VmRecord;
|
|
14
|
+
/** 检查是否为仅包含从 0 开始的连续数字键的 MiraScript 记录 */
|
|
15
|
+
export declare function isVmArrayLikeRecordByEntires(entries: ReadonlyArray<readonly [string, unknown]>): boolean;
|
|
16
|
+
/** 检查是否为仅包含从 0 开始的连续数字键的 MiraScript 记录 */
|
|
17
|
+
export declare function isVmArrayLikeRecordByKeys(keys: readonly string[]): boolean;
|
|
18
|
+
/** 检查是否为仅包含从 0 开始的连续数字键的 MiraScript 记录 */
|
|
19
|
+
export declare function isVmArrayLikeRecord(value: VmRecord): boolean;
|
|
20
|
+
//# sourceMappingURL=record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../src/vm/types/record.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,KAAK,KAAK,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAEnE;;;;GAIG;AAEH,MAAM,MAAM,QAAQ,GAAG;IACnB,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CAC/C,CAAC;AAEF;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,QAAQ,CAM1D;AAED,0CAA0C;AAC1C,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,CASxG;AAED,0CAA0C;AAC1C,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAS1E;AAED,0CAA0C;AAC1C,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAE5D"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type VmAny } from './any.js';
|
|
2
|
+
import type { VmExtern } from './extern.js';
|
|
3
|
+
import type { VmImmutable } from './immutable.js';
|
|
4
|
+
/** Mirascript 虚拟机内的合法值 */
|
|
5
|
+
export type VmValue = VmImmutable | VmExtern;
|
|
6
|
+
/**
|
|
7
|
+
* 检查是否为 Mirascript 合法值
|
|
8
|
+
*/
|
|
9
|
+
export declare function isVmValue(value: VmAny): value is VmValue;
|
|
10
|
+
/**
|
|
11
|
+
* 检查是否为 Mirascript 合法值
|
|
12
|
+
*/
|
|
13
|
+
export declare function isVmValue(value: unknown, checkDeep: boolean): value is VmValue;
|
|
14
|
+
//# sourceMappingURL=value.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"value.d.ts","sourceRoot":"","sources":["../../../src/vm/types/value.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,KAAK,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,0BAA0B;AAC1B,MAAM,MAAM,OAAO,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE7C;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,OAAO,CAAC;AAC1D;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,CAAC"}
|
|
@@ -20,7 +20,7 @@ export declare abstract class VmWrapper<T extends object> {
|
|
|
20
20
|
/** Convert the object to JSON */
|
|
21
21
|
toJSON(): undefined;
|
|
22
22
|
/** 转为字符串 */
|
|
23
|
-
toString(): string;
|
|
23
|
+
toString(useBraces: boolean): string;
|
|
24
24
|
}
|
|
25
25
|
/** 检查值是否为 MiraScript 包装器 */
|
|
26
26
|
export declare function isVmWrapper<T extends object>(value: unknown): value is VmWrapper<T>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../../../src/vm/types/wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAElD;;GAEG;AACH,8BAAsB,SAAS,CAAC,CAAC,SAAS,MAAM;IAChC,QAAQ,CAAC,KAAK,EAAE,CAAC;gBAAR,KAAK,EAAE,CAAC;IAC7B,cAAc;IACd,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAClC,cAAc;IACd,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK;IAChC,WAAW;IACX,QAAQ,CAAC,IAAI,IAAI,MAAM,EAAE;IACzB,aAAa;IACb,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IACpC,WAAW;IACX,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC;IAC9B,WAAW;IACX,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC;IAChC,iCAAiC;IACjC,MAAM,IAAI,SAAS;IAGnB,YAAY;IACZ,QAAQ,
|
|
1
|
+
{"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../../../src/vm/types/wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAElD;;GAEG;AACH,8BAAsB,SAAS,CAAC,CAAC,SAAS,MAAM;IAChC,QAAQ,CAAC,KAAK,EAAE,CAAC;gBAAR,KAAK,EAAE,CAAC;IAC7B,cAAc;IACd,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAClC,cAAc;IACd,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK;IAChC,WAAW;IACX,QAAQ,CAAC,IAAI,IAAI,MAAM,EAAE;IACzB,aAAa;IACb,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IACpC,WAAW;IACX,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC;IAC9B,WAAW;IACX,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC;IAChC,iCAAiC;IACjC,MAAM,IAAI,SAAS;IAGnB,YAAY;IACZ,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM;CAKvC;AAID,4BAA4B;AAC5B,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAAC,CAAC,CAAC,CAEnF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mirascript/mirascript",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"author": "CloudPSS",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "An expression based scripting language.",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"commander": "^14.0.2",
|
|
35
35
|
"source-map-js": "^1.2.1",
|
|
36
36
|
"supports-color": "^10.2.2",
|
|
37
|
-
"@mirascript/bindings": "~0.1.
|
|
37
|
+
"@mirascript/bindings": "~0.1.14"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^24.10.1",
|
|
@@ -46,7 +46,7 @@ function compileScriptFast(code: string, options: TranspileOptions): VmScript |
|
|
|
46
46
|
if (REG_IDENTIFIER_FAST.test(trimmedCode)) {
|
|
47
47
|
// 直接返回标识符
|
|
48
48
|
const id = trimmedCode;
|
|
49
|
-
return wrapScript(code, (global = GlobalFallback()) => global.get(id)
|
|
49
|
+
return wrapScript(code, (global = GlobalFallback()) => global.get(id));
|
|
50
50
|
}
|
|
51
51
|
if (REG_NUMBER_FULL.test(trimmedCode)) {
|
|
52
52
|
const num = Number(trimmedCode);
|
package/src/compiler/emit.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { OpCode } from '@mirascript/bindings';
|
|
2
2
|
import type { VmConst, VmPrimitive } from '../vm/index.js';
|
|
3
|
+
import { $ToString } from '../vm/operations.js';
|
|
3
4
|
import type { ScriptInput, TranspileOptions } from './types.js';
|
|
4
5
|
import type { IRange } from './diagnostic.js';
|
|
5
6
|
import { SourceMapGenerator } from 'source-map-js';
|
|
@@ -76,6 +77,8 @@ function createArray<T>(length: number, fn: (index: number) => T): T[] {
|
|
|
76
77
|
return result;
|
|
77
78
|
}
|
|
78
79
|
|
|
80
|
+
const SCRIPT_PREFIX = `'use strict'; return ((global = GlobalFallback()) => { try { CpEnter();`;
|
|
81
|
+
const GLOBAL_HINT = `/* globals */`;
|
|
79
82
|
/** 代码生成 */
|
|
80
83
|
class Emitter {
|
|
81
84
|
constructor(
|
|
@@ -102,11 +105,13 @@ class Emitter {
|
|
|
102
105
|
private readConsts(): void {
|
|
103
106
|
for (let i = 0, index = 0; i < this.constSize; index++) {
|
|
104
107
|
const [constant, size] = readConst(this.constReader, i);
|
|
105
|
-
this.
|
|
108
|
+
this.constVals.push(constant);
|
|
109
|
+
this.constLits.push(toJavascript(constant));
|
|
106
110
|
i += size;
|
|
107
111
|
}
|
|
108
112
|
}
|
|
109
|
-
readonly
|
|
113
|
+
readonly constVals: VmPrimitive[] = [];
|
|
114
|
+
readonly constLits: string[] = [];
|
|
110
115
|
|
|
111
116
|
readonly constSize: number;
|
|
112
117
|
private readonly codeReader: DataView;
|
|
@@ -120,6 +125,26 @@ class Emitter {
|
|
|
120
125
|
return ' '.repeat(this.identCounter + len);
|
|
121
126
|
}
|
|
122
127
|
|
|
128
|
+
readonly globals = new Map<number, [val: string, lit: string, eager: boolean, expr: string, name: string]>();
|
|
129
|
+
/** 读取全局变量 */
|
|
130
|
+
private rg(constIdx: number, eager: boolean): string {
|
|
131
|
+
const cached = this.globals.get(constIdx);
|
|
132
|
+
if (cached != null) {
|
|
133
|
+
if (eager && !cached[2]) {
|
|
134
|
+
cached[2] = true;
|
|
135
|
+
cached[3] = cached[0];
|
|
136
|
+
}
|
|
137
|
+
return cached[3];
|
|
138
|
+
}
|
|
139
|
+
const constName = this.constVals[constIdx]!;
|
|
140
|
+
const name = $ToString(constName);
|
|
141
|
+
const lit = typeof constName == 'string' ? this.constLits[constIdx]! : JSON.stringify(name);
|
|
142
|
+
const val = `g${this.globals.size + 1}`;
|
|
143
|
+
const expr = eager ? val : `(${val} === undefined ? (${val} = global.get(${lit})) : ${val})`;
|
|
144
|
+
this.globals.set(constIdx, [val, lit, eager, expr, name]);
|
|
145
|
+
return expr;
|
|
146
|
+
}
|
|
147
|
+
|
|
123
148
|
readonly codeLines: string[] = [];
|
|
124
149
|
|
|
125
150
|
/** Read variable */
|
|
@@ -226,7 +251,7 @@ class Emitter {
|
|
|
226
251
|
case OpCode.FieldOpt:
|
|
227
252
|
case OpCode.Field: {
|
|
228
253
|
const field = read();
|
|
229
|
-
const field_name = this.
|
|
254
|
+
const field_name = this.constLits[field];
|
|
230
255
|
/* c8 ignore next 3 */
|
|
231
256
|
if (!field_name) {
|
|
232
257
|
throw new Error(`Unknown field ${field}`);
|
|
@@ -351,7 +376,7 @@ class Emitter {
|
|
|
351
376
|
switch (opcode) {
|
|
352
377
|
case OpCode.FuncVarg:
|
|
353
378
|
case OpCode.Func: {
|
|
354
|
-
const
|
|
379
|
+
const startFunc = this.codeOffset === 1;
|
|
355
380
|
reg = read();
|
|
356
381
|
const varg = opcode === OpCode.FuncVarg;
|
|
357
382
|
const argn = read();
|
|
@@ -367,9 +392,9 @@ class Emitter {
|
|
|
367
392
|
const regs = createArray(regn - argn + 1, (i) => (i ? this.wv(i + argn, -1) : this.wv(0, -1))).join(
|
|
368
393
|
', ',
|
|
369
394
|
);
|
|
395
|
+
const script = startFunc && !varg && argn === 0;
|
|
370
396
|
if (script) {
|
|
371
|
-
|
|
372
|
-
code = `'use strict'; return ((${args.join(', ')}) => { try { CpEnter(); var ${regs};`;
|
|
397
|
+
code = `${SCRIPT_PREFIX} var ${regs};`;
|
|
373
398
|
} else {
|
|
374
399
|
code = `${this.wv(reg)} = Function((${args.join(', ')}) => { try { CpEnter(); var ${regs};`;
|
|
375
400
|
}
|
|
@@ -381,7 +406,7 @@ class Emitter {
|
|
|
381
406
|
case OpCode.Constant: {
|
|
382
407
|
reg = read();
|
|
383
408
|
const i = read();
|
|
384
|
-
const c = this.
|
|
409
|
+
const c = this.constLits[i];
|
|
385
410
|
code = `${this.wv(reg)} = ${c};`;
|
|
386
411
|
break;
|
|
387
412
|
}
|
|
@@ -424,7 +449,7 @@ class Emitter {
|
|
|
424
449
|
case OpCode.InGlobal: {
|
|
425
450
|
reg = read();
|
|
426
451
|
const left = read();
|
|
427
|
-
code = `${this.wv(reg)} = global.has(${this.rv(left)});`;
|
|
452
|
+
code = `${this.wv(reg)} = global.has($ToString(${this.rv(left)}));`;
|
|
428
453
|
break;
|
|
429
454
|
}
|
|
430
455
|
case OpCode.Concat: {
|
|
@@ -439,7 +464,7 @@ class Emitter {
|
|
|
439
464
|
reg = read();
|
|
440
465
|
const value = read();
|
|
441
466
|
const n = read();
|
|
442
|
-
const args = createArray(n, () => this.
|
|
467
|
+
const args = createArray(n, () => this.constLits[read()]!);
|
|
443
468
|
|
|
444
469
|
code = `${this.wv(reg)} = $${OpCode[opcode]}(${this.rv(value)}, [${args.join(', ')}]);`;
|
|
445
470
|
break;
|
|
@@ -452,7 +477,7 @@ class Emitter {
|
|
|
452
477
|
const args = createArray(n, () => read());
|
|
453
478
|
const ns = read();
|
|
454
479
|
const spreads = createArray(ns, () => read());
|
|
455
|
-
const callTarget = opcode === OpCode.Call ?
|
|
480
|
+
const callTarget = opcode === OpCode.Call ? this.rg(func, this.identCounter <= 1) : this.rv(func);
|
|
456
481
|
code = `${this.wv(reg)} = $Call(${callTarget}, [${args
|
|
457
482
|
.map((a, i) => {
|
|
458
483
|
if (spreads.includes(i)) return `...$ArraySpread(${this.rv(a)})`;
|
|
@@ -494,7 +519,7 @@ class Emitter {
|
|
|
494
519
|
case OpCode.Get: {
|
|
495
520
|
reg = read();
|
|
496
521
|
const obj = read();
|
|
497
|
-
const prop = this.
|
|
522
|
+
const prop = this.constLits[read()];
|
|
498
523
|
code = `${this.wv(reg)} = $Get(${this.rv(obj)}, ${prop});`;
|
|
499
524
|
break;
|
|
500
525
|
}
|
|
@@ -515,7 +540,7 @@ class Emitter {
|
|
|
515
540
|
case OpCode.Has: {
|
|
516
541
|
reg = read();
|
|
517
542
|
const obj = read();
|
|
518
|
-
const prop = this.
|
|
543
|
+
const prop = this.constLits[read()];
|
|
519
544
|
code = `${this.wv(reg)} = $Has(${this.rv(obj)}, ${prop});`;
|
|
520
545
|
break;
|
|
521
546
|
}
|
|
@@ -536,7 +561,7 @@ class Emitter {
|
|
|
536
561
|
case OpCode.Set: {
|
|
537
562
|
reg = read();
|
|
538
563
|
const obj = read();
|
|
539
|
-
const prop = this.
|
|
564
|
+
const prop = this.constLits[read()];
|
|
540
565
|
code = `$Set(${this.rv(obj)}, ${prop}, ${this.rv(reg)});`;
|
|
541
566
|
break;
|
|
542
567
|
}
|
|
@@ -557,14 +582,13 @@ class Emitter {
|
|
|
557
582
|
case OpCode.GetGlobal: {
|
|
558
583
|
reg = read();
|
|
559
584
|
const i = read();
|
|
560
|
-
|
|
561
|
-
code = `${this.wv(reg)} = global.get(${c}) ?? null;`;
|
|
585
|
+
code = `${this.wv(reg)} = ${this.rg(i, this.identCounter <= 1)};`;
|
|
562
586
|
break;
|
|
563
587
|
}
|
|
564
588
|
case OpCode.GetGlobalDyn: {
|
|
565
589
|
reg = read();
|
|
566
590
|
const name = read();
|
|
567
|
-
code = `${this.wv(reg)} = global.get(${this.rv(name)})
|
|
591
|
+
code = `${this.wv(reg)} = global.get($ToString(${this.rv(name)}));`;
|
|
568
592
|
break;
|
|
569
593
|
}
|
|
570
594
|
case OpCode.GetUpvalue: {
|
|
@@ -743,6 +767,14 @@ class Emitter {
|
|
|
743
767
|
read(): void {
|
|
744
768
|
this.readConsts();
|
|
745
769
|
this.readCode();
|
|
770
|
+
if (this.globals.size > 0) {
|
|
771
|
+
let globalsInit = '';
|
|
772
|
+
for (const [val, lit, eager] of this.globals.values()) {
|
|
773
|
+
const expr = eager ? `${val} = global.get(${lit})` : val;
|
|
774
|
+
globalsInit += globalsInit ? `, ${expr}` : `var ${GLOBAL_HINT} ${expr}`;
|
|
775
|
+
}
|
|
776
|
+
this.codeLines[0] += globalsInit + ';';
|
|
777
|
+
}
|
|
746
778
|
this.addSourceMap();
|
|
747
779
|
}
|
|
748
780
|
/** 添加源映射 */
|
|
@@ -764,9 +796,13 @@ class Emitter {
|
|
|
764
796
|
if (typeof this.source === 'string') {
|
|
765
797
|
map.setSourceContent(fileName, this.source);
|
|
766
798
|
}
|
|
767
|
-
|
|
799
|
+
let hasStartMap = false;
|
|
800
|
+
for (let i = 1; i < this.sourcemaps.length; i++) {
|
|
768
801
|
const range = this.sourcemaps[i];
|
|
769
802
|
if (!range) break;
|
|
803
|
+
if (!hasStartMap && range.startLineNumber === 1 && range.startColumn === 1) {
|
|
804
|
+
hasStartMap = true;
|
|
805
|
+
}
|
|
770
806
|
map.addMapping({
|
|
771
807
|
generated: {
|
|
772
808
|
// 前两行固定为:
|
|
@@ -782,6 +818,84 @@ class Emitter {
|
|
|
782
818
|
source: fileName,
|
|
783
819
|
});
|
|
784
820
|
}
|
|
821
|
+
if (!hasStartMap) {
|
|
822
|
+
map.addMapping({
|
|
823
|
+
generated: {
|
|
824
|
+
line: 3,
|
|
825
|
+
column: SCRIPT_PREFIX.length - 'CpEnter();'.length,
|
|
826
|
+
},
|
|
827
|
+
original: {
|
|
828
|
+
line: 1,
|
|
829
|
+
column: 0,
|
|
830
|
+
},
|
|
831
|
+
source: fileName,
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
{
|
|
835
|
+
const line0 = this.codeLines[0]!;
|
|
836
|
+
const file = `${fileName} <globals>`;
|
|
837
|
+
let globals = `global;\n`;
|
|
838
|
+
map.addMapping({
|
|
839
|
+
generated: {
|
|
840
|
+
line: 3,
|
|
841
|
+
column: line0.indexOf(`global = `),
|
|
842
|
+
},
|
|
843
|
+
original: {
|
|
844
|
+
line: 1,
|
|
845
|
+
column: 0,
|
|
846
|
+
},
|
|
847
|
+
source: file,
|
|
848
|
+
name: 'global',
|
|
849
|
+
});
|
|
850
|
+
map.addMapping({
|
|
851
|
+
generated: {
|
|
852
|
+
line: 3,
|
|
853
|
+
column: SCRIPT_PREFIX.length,
|
|
854
|
+
},
|
|
855
|
+
original: {
|
|
856
|
+
line: 1,
|
|
857
|
+
column: 7,
|
|
858
|
+
},
|
|
859
|
+
source: file,
|
|
860
|
+
name: '',
|
|
861
|
+
});
|
|
862
|
+
let i = 1;
|
|
863
|
+
let pos = line0.indexOf(GLOBAL_HINT, SCRIPT_PREFIX.length) + GLOBAL_HINT.length;
|
|
864
|
+
for (const p of this.globals.values()) {
|
|
865
|
+
i++;
|
|
866
|
+
if (pos < 0) break;
|
|
867
|
+
const val = p[0];
|
|
868
|
+
pos = line0.indexOf(val, pos);
|
|
869
|
+
if (pos < 0) break;
|
|
870
|
+
const name = p[4];
|
|
871
|
+
map.addMapping({
|
|
872
|
+
generated: {
|
|
873
|
+
line: 3,
|
|
874
|
+
column: pos,
|
|
875
|
+
},
|
|
876
|
+
original: {
|
|
877
|
+
line: i,
|
|
878
|
+
column: 0,
|
|
879
|
+
},
|
|
880
|
+
source: file,
|
|
881
|
+
name,
|
|
882
|
+
});
|
|
883
|
+
globals += `${name};\n`;
|
|
884
|
+
}
|
|
885
|
+
map.addMapping({
|
|
886
|
+
generated: {
|
|
887
|
+
line: 3,
|
|
888
|
+
column: pos,
|
|
889
|
+
},
|
|
890
|
+
original: {
|
|
891
|
+
line: i,
|
|
892
|
+
column: 0,
|
|
893
|
+
},
|
|
894
|
+
source: file,
|
|
895
|
+
name: '',
|
|
896
|
+
});
|
|
897
|
+
map.setSourceContent(file, globals);
|
|
898
|
+
}
|
|
785
899
|
const prefix = '//# ';
|
|
786
900
|
const sourceURL = hasSchema ? fileName : `${ORIGIN}${fileName}`;
|
|
787
901
|
this.codeLines.push(
|
package/src/helpers/serialize.ts
CHANGED
|
@@ -10,9 +10,10 @@ import {
|
|
|
10
10
|
isVmFunction,
|
|
11
11
|
isVmModule,
|
|
12
12
|
isVmExtern,
|
|
13
|
+
isVmArrayLikeRecordByEntires,
|
|
13
14
|
} from '../vm/index.js';
|
|
14
15
|
import { REG_IDENTIFIER, REG_ORDINAL } from './constants.js';
|
|
15
|
-
import { entries, isFinite, isNaN } from '../helpers/utils.js';
|
|
16
|
+
import { entries, hasOwn, isFinite, isNaN } from '../helpers/utils.js';
|
|
16
17
|
|
|
17
18
|
const REG_IDENTIFIER_FULL = new RegExp(`^${REG_IDENTIFIER.source}$`, REG_IDENTIFIER.flags);
|
|
18
19
|
const REG_ORDINAL_FULL = new RegExp(`^${REG_ORDINAL.source}$`, REG_ORDINAL.flags);
|
|
@@ -66,17 +67,23 @@ const DEFAULT_OPTIONS = Object.freeze({
|
|
|
66
67
|
serializeExtern: serializeNil,
|
|
67
68
|
} satisfies SerializeOptions);
|
|
68
69
|
|
|
70
|
+
/** 是否为默认选项 */
|
|
71
|
+
function isDefaultOptions(options: Partial<SerializeOptions> | undefined): boolean {
|
|
72
|
+
return options == null || options === DEFAULT_OPTIONS;
|
|
73
|
+
}
|
|
74
|
+
|
|
69
75
|
/** 获取选项 */
|
|
70
76
|
function getSerializeOptions(options: Partial<SerializeOptions> | undefined): SerializeOptions {
|
|
71
|
-
if (options
|
|
72
|
-
|
|
77
|
+
if (isDefaultOptions(options)) return DEFAULT_OPTIONS;
|
|
78
|
+
let opt: SerializeOptions | null = null;
|
|
73
79
|
for (const key in options) {
|
|
80
|
+
if (!hasOwn(options, key) || !hasOwn(DEFAULT_OPTIONS, key)) continue;
|
|
74
81
|
const el = options[key as keyof SerializeOptions];
|
|
75
|
-
if (el
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
if (el == null) continue;
|
|
83
|
+
opt ??= { ...DEFAULT_OPTIONS };
|
|
84
|
+
opt[key as keyof SerializeOptions] = el as never;
|
|
78
85
|
}
|
|
79
|
-
return Object.freeze(opt);
|
|
86
|
+
return opt ? Object.freeze(opt) : DEFAULT_OPTIONS;
|
|
80
87
|
}
|
|
81
88
|
|
|
82
89
|
/**
|
|
@@ -137,8 +144,19 @@ export function serializeString(value: string, options?: Partial<SerializeOption
|
|
|
137
144
|
return serializeStringImpl(value, getSerializeOptions(options));
|
|
138
145
|
}
|
|
139
146
|
|
|
147
|
+
/** 使用默认选项序列化属性名 */
|
|
148
|
+
function serializeRecordKeyDefault(key: string): string {
|
|
149
|
+
if (REG_ORDINAL_FULL.test(key) || REG_IDENTIFIER_FULL.test(key)) {
|
|
150
|
+
return key;
|
|
151
|
+
}
|
|
152
|
+
return serializeStringImpl(key, DEFAULT_OPTIONS);
|
|
153
|
+
}
|
|
154
|
+
|
|
140
155
|
/** 序列化属性名 */
|
|
141
|
-
function
|
|
156
|
+
function serializeRecordKeyOpt(value: string, options: SerializeOptions): string {
|
|
157
|
+
if (isDefaultOptions(options)) {
|
|
158
|
+
return serializeRecordKeyDefault(value);
|
|
159
|
+
}
|
|
142
160
|
if (REG_ORDINAL_FULL.test(value)) {
|
|
143
161
|
// 合法的数字属性名
|
|
144
162
|
return options.serializePropName(Number(value), options);
|
|
@@ -152,8 +170,11 @@ function serializePropNameImpl(value: string, options: SerializeOptions): string
|
|
|
152
170
|
}
|
|
153
171
|
|
|
154
172
|
/** 序列化属性名 */
|
|
155
|
-
export function
|
|
156
|
-
|
|
173
|
+
export function serializeRecordKey(key: string, options?: Partial<SerializeOptions>): string {
|
|
174
|
+
if (isDefaultOptions(options)) {
|
|
175
|
+
return serializeRecordKeyDefault(key);
|
|
176
|
+
}
|
|
177
|
+
return serializeRecordKeyOpt(key, getSerializeOptions(options));
|
|
157
178
|
}
|
|
158
179
|
|
|
159
180
|
/** 序列化 nil 值 */
|
|
@@ -220,18 +241,17 @@ export function serializeRecord(value: VmRecord, depth: number, options: Seriali
|
|
|
220
241
|
if (k === '0') {
|
|
221
242
|
return `(${serializeImpl(v, depth, options)},)`; // 单个元素数组
|
|
222
243
|
}
|
|
223
|
-
return `(${
|
|
244
|
+
return `(${serializeRecordKeyOpt(k, options)}: ${serializeImpl(v, depth, options)})`;
|
|
224
245
|
}
|
|
225
246
|
|
|
226
|
-
|
|
227
|
-
const omitKey = e.length < 10 && e.every(([key], index) => key === String(index));
|
|
247
|
+
const omitKey = isVmArrayLikeRecordByEntires(e);
|
|
228
248
|
let str = '(';
|
|
229
249
|
for (const [key, val] of e) {
|
|
230
250
|
if (str.length > 1) str += ', ';
|
|
231
251
|
if (omitKey) {
|
|
232
252
|
str += serializeImpl(val, depth, options);
|
|
233
253
|
} else {
|
|
234
|
-
str += `${
|
|
254
|
+
str += `${serializeRecordKeyOpt(key, options)}: ${serializeImpl(val, depth, options)}`;
|
|
235
255
|
}
|
|
236
256
|
}
|
|
237
257
|
str += ')';
|
package/src/subtle.ts
CHANGED
package/src/vm/operations.ts
CHANGED
|
@@ -313,9 +313,9 @@ function numberToString(value: number): string {
|
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
/** 将值转为字符串 */
|
|
316
|
-
function
|
|
316
|
+
export function $InnerToString(value: VmAny, useBraces: boolean): string {
|
|
317
317
|
if (value == null) return 'nil';
|
|
318
|
-
if (isVmWrapper(value)) return value.toString();
|
|
318
|
+
if (isVmWrapper(value)) return value.toString(useBraces);
|
|
319
319
|
if (typeof value == 'function') {
|
|
320
320
|
const name = getVmFunctionInfo(value)?.fullName;
|
|
321
321
|
return name ? `<function ${name}>` : `<function>`;
|
|
@@ -323,7 +323,7 @@ function innerToString(value: VmAny, useBraces: boolean): string {
|
|
|
323
323
|
if (isVmArray(value)) {
|
|
324
324
|
const strings: string[] = [];
|
|
325
325
|
for (const item of value) {
|
|
326
|
-
strings.push(
|
|
326
|
+
strings.push($InnerToString(item, true));
|
|
327
327
|
}
|
|
328
328
|
// 在 join 过程中会自动把 null/undefined 和 empty slot 转为 ''
|
|
329
329
|
// 与 innerToString 行为不一致
|
|
@@ -333,7 +333,7 @@ function innerToString(value: VmAny, useBraces: boolean): string {
|
|
|
333
333
|
}
|
|
334
334
|
if (typeof value == 'object') {
|
|
335
335
|
const entries = keys(value)
|
|
336
|
-
.map((key) => `${key}: ${
|
|
336
|
+
.map((key) => `${key}: ${$InnerToString(value[key], true)}`)
|
|
337
337
|
.join(', ');
|
|
338
338
|
if (!useBraces) return entries;
|
|
339
339
|
return `(${entries})`;
|
|
@@ -347,7 +347,7 @@ export const $ToString = (value: VmAny): string => {
|
|
|
347
347
|
$AssertInit(value);
|
|
348
348
|
if (typeof value == 'string') return value;
|
|
349
349
|
if (value === null) return '';
|
|
350
|
-
return
|
|
350
|
+
return $InnerToString(value, false);
|
|
351
351
|
};
|
|
352
352
|
export const $ToNumber = (value: VmAny): number => {
|
|
353
353
|
$AssertInit(value);
|