@mirascript/mirascript 0.1.78 → 0.1.80
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-VNQQF2W7.js → chunk-BPFOJ4Q6.js} +381 -432
- package/dist/chunk-BPFOJ4Q6.js.map +6 -0
- package/dist/{chunk-BITOQYYQ.js → chunk-LSPCAN32.js} +204 -149
- package/dist/chunk-LSPCAN32.js.map +6 -0
- package/dist/compiler/emit/constants.d.ts +1 -1
- package/dist/compiler/emit/constants.d.ts.map +1 -1
- package/dist/compiler/emit/consts.d.ts.map +1 -1
- package/dist/compiler/worker.js +1 -1
- package/dist/helpers/convert/{to-boolean.d.ts → boolean.d.ts} +1 -1
- package/dist/helpers/convert/boolean.d.ts.map +1 -0
- package/dist/helpers/convert/{to-format.d.ts → format.d.ts} +1 -1
- package/dist/helpers/convert/format.d.ts.map +1 -0
- package/dist/helpers/convert/index.d.ts +4 -4
- package/dist/helpers/convert/index.d.ts.map +1 -1
- package/dist/helpers/convert/{to-number.d.ts → number.d.ts} +1 -1
- package/dist/helpers/convert/number.d.ts.map +1 -0
- package/dist/helpers/convert/{to-string.d.ts → string.d.ts} +1 -1
- package/dist/helpers/convert/string.d.ts.map +1 -0
- package/dist/helpers/serialize.d.ts.map +1 -1
- package/dist/helpers/types/array-like.d.ts +8 -0
- package/dist/helpers/types/array-like.d.ts.map +1 -0
- package/dist/helpers/types/basic.d.ts +26 -0
- package/dist/helpers/types/basic.d.ts.map +1 -0
- package/dist/helpers/types/composed.d.ts +12 -0
- package/dist/helpers/types/composed.d.ts.map +1 -0
- package/dist/helpers/types/const.d.ts +6 -0
- package/dist/helpers/types/const.d.ts.map +1 -0
- package/dist/helpers/types/get-type.d.ts +6 -0
- package/dist/helpers/types/get-type.d.ts.map +1 -0
- package/dist/helpers/types/index.d.ts +6 -0
- package/dist/helpers/types/index.d.ts.map +1 -0
- package/dist/helpers/types/proto.d.ts +5 -0
- package/dist/helpers/types/proto.d.ts.map +1 -0
- package/dist/helpers/utils.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/subtle.js +3 -3
- package/dist/vm/lib/global/json.d.ts +1 -1
- package/dist/vm/lib/global/json.d.ts.map +1 -1
- package/dist/vm/lib/helpers.d.ts.map +1 -1
- package/dist/vm/lib/mod/index.d.ts +1 -1
- package/dist/vm/lib/mod/index.d.ts.map +1 -1
- package/dist/vm/lib/mod/matrix/bin-ops.d.ts +8 -0
- package/dist/vm/lib/mod/matrix/bin-ops.d.ts.map +1 -0
- package/dist/vm/lib/mod/matrix/fill.d.ts +6 -0
- package/dist/vm/lib/mod/matrix/fill.d.ts.map +1 -0
- package/dist/vm/lib/mod/matrix/helpers.d.ts +6 -0
- package/dist/vm/lib/mod/matrix/helpers.d.ts.map +1 -0
- package/dist/vm/lib/mod/matrix/index.d.ts +6 -0
- package/dist/vm/lib/mod/matrix/index.d.ts.map +1 -0
- package/dist/vm/lib/mod/matrix/invert.d.ts +3 -0
- package/dist/vm/lib/mod/matrix/invert.d.ts.map +1 -0
- package/dist/vm/lib/mod/matrix/size.d.ts +2 -0
- package/dist/vm/lib/mod/matrix/size.d.ts.map +1 -0
- package/dist/vm/lib/mod/matrix/transpose.d.ts +2 -0
- package/dist/vm/lib/mod/matrix/transpose.d.ts.map +1 -0
- package/dist/vm/operations/array-range.d.ts +3 -3
- package/dist/vm/operations/array-range.d.ts.map +1 -1
- package/dist/vm/operations/call.d.ts +1 -1
- package/dist/vm/operations/call.d.ts.map +1 -1
- package/dist/vm/operations/compound.d.ts +1 -13
- package/dist/vm/operations/compound.d.ts.map +1 -1
- package/dist/vm/operations/index.d.ts +3 -0
- package/dist/vm/operations/index.d.ts.map +1 -1
- package/dist/vm/operations/iterable.d.ts +6 -0
- package/dist/vm/operations/iterable.d.ts.map +1 -0
- package/dist/vm/operations/record.d.ts +6 -0
- package/dist/vm/operations/record.d.ts.map +1 -0
- package/dist/vm/operations/slice.d.ts.map +1 -1
- package/dist/vm/operations/spread.d.ts +6 -0
- package/dist/vm/operations/spread.d.ts.map +1 -0
- package/dist/vm/operations/utils.d.ts.map +1 -1
- package/dist/vm/types/extern/access.d.ts +5 -0
- package/dist/vm/types/extern/access.d.ts.map +1 -0
- package/dist/vm/types/{extern.d.ts → extern/index.d.ts} +3 -3
- package/dist/vm/types/extern/index.d.ts.map +1 -0
- package/dist/vm/types/extern/tag.d.ts +3 -0
- package/dist/vm/types/extern/tag.d.ts.map +1 -0
- package/dist/vm/types/extern/utils.d.ts +13 -0
- package/dist/vm/types/extern/utils.d.ts.map +1 -0
- package/dist/vm/types/index.d.ts +3 -3
- package/dist/vm/types/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/compiler/diagnostic.ts +2 -2
- package/src/compiler/emit/constants.ts +1 -1
- package/src/compiler/emit/consts.ts +0 -1
- package/src/compiler/emit/index.ts +1 -1
- package/src/compiler/emit/sourcemap.ts +1 -1
- package/src/compiler/load-module.ts +5 -1
- package/src/helpers/convert/{to-boolean.ts → boolean.ts} +1 -1
- package/src/helpers/convert/{to-format.ts → format.ts} +1 -1
- package/src/helpers/convert/index.ts +4 -4
- package/src/helpers/convert/{to-number.ts → number.ts} +15 -26
- package/src/helpers/convert/{to-string.ts → string.ts} +2 -2
- package/src/helpers/serialize.ts +42 -36
- package/src/helpers/types/array-like.ts +32 -0
- package/src/helpers/types/basic.ts +82 -0
- package/src/helpers/types/composed.ts +27 -0
- package/src/helpers/types/const.ts +44 -0
- package/src/helpers/types/get-type.ts +16 -0
- package/src/helpers/types/index.ts +5 -0
- package/src/helpers/types/proto.ts +21 -0
- package/src/helpers/utils.ts +7 -1
- package/src/vm/lib/global/sequence/all-any.ts +1 -1
- package/src/vm/lib/global/sequence/find.ts +1 -1
- package/src/vm/lib/global/sequence/group.ts +1 -1
- package/src/vm/lib/global/sequence/map-filter.ts +1 -1
- package/src/vm/lib/global/sequence/new.ts +1 -1
- package/src/vm/lib/global/sequence/sort.ts +1 -1
- package/src/vm/lib/global/sequence/unique.ts +1 -1
- package/src/vm/lib/global/sequence/with.ts +1 -1
- package/src/vm/lib/global/time.ts +1 -1
- package/src/vm/lib/helpers.ts +8 -1
- package/src/vm/lib/mod/index.ts +1 -1
- package/src/vm/lib/mod/matrix/bin-ops.ts +291 -0
- package/src/vm/lib/mod/matrix/fill.ts +109 -0
- package/src/vm/lib/mod/matrix/helpers.ts +26 -0
- package/src/vm/lib/mod/matrix/index.ts +5 -0
- package/src/vm/lib/mod/matrix/invert.ts +122 -0
- package/src/vm/lib/mod/matrix/size.ts +15 -0
- package/src/vm/lib/mod/matrix/transpose.ts +32 -0
- package/src/vm/operations/array-range.ts +15 -27
- package/src/vm/operations/call.ts +2 -2
- package/src/vm/operations/compound.ts +4 -131
- package/src/vm/operations/helpers.ts +1 -1
- package/src/vm/operations/index.ts +3 -0
- package/src/vm/operations/iterable.ts +40 -0
- package/src/vm/operations/record.ts +33 -0
- package/src/vm/operations/slice.ts +23 -22
- package/src/vm/operations/spread.ts +57 -0
- package/src/vm/operations/type-check.ts +1 -1
- package/src/vm/operations/utils.ts +45 -37
- package/src/vm/types/boundary.ts +2 -2
- package/src/vm/types/extern/access.ts +24 -0
- package/src/vm/types/extern/index.ts +124 -0
- package/src/vm/types/extern/tag.ts +58 -0
- package/src/vm/types/extern/utils.ts +55 -0
- package/src/vm/types/function.ts +1 -1
- package/src/vm/types/index.ts +3 -3
- package/dist/chunk-BITOQYYQ.js.map +0 -6
- package/dist/chunk-VNQQF2W7.js.map +0 -6
- package/dist/helpers/convert/to-boolean.d.ts.map +0 -1
- package/dist/helpers/convert/to-format.d.ts.map +0 -1
- package/dist/helpers/convert/to-number.d.ts.map +0 -1
- package/dist/helpers/convert/to-string.d.ts.map +0 -1
- package/dist/helpers/types.d.ts +0 -58
- package/dist/helpers/types.d.ts.map +0 -1
- package/dist/vm/lib/mod/matrix.d.ts +0 -15
- package/dist/vm/lib/mod/matrix.d.ts.map +0 -1
- package/dist/vm/types/extern.d.ts.map +0 -1
- package/src/helpers/types.ts +0 -283
- package/src/vm/lib/mod/matrix.ts +0 -590
- package/src/vm/types/extern.ts +0 -197
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OpCode } from '@mirascript/constants';
|
|
2
|
-
import { toString } from '../../helpers/convert/
|
|
2
|
+
import { toString } from '../../helpers/convert/index.js';
|
|
3
3
|
import type { VmPrimitive } from '../../vm/index.js';
|
|
4
4
|
import type { ScriptInput, TranspileOptions } from '../types.js';
|
|
5
5
|
import type { IRange } from '../diagnostic.js';
|
|
@@ -20,7 +20,7 @@ const { SOURCE_URL, SOURCE_MAPPING_URL } = ((source, mapping, url) => {
|
|
|
20
20
|
const SOURCE_OFFSET = 4;
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* Node.js Buffer
|
|
23
|
+
* Node.js Buffer 类型的简易声明,浏览器调试环境下会直接加载此文件
|
|
24
24
|
*/
|
|
25
25
|
declare class Buffer {
|
|
26
26
|
/** @inheritdoc */
|
|
@@ -4,7 +4,7 @@ import { display } from '../serialize.js';
|
|
|
4
4
|
|
|
5
5
|
/** 转换为 boolean */
|
|
6
6
|
export function toBoolean<F = undefined>(value: VmAny, fallback?: F): boolean | Exclude<F, undefined> {
|
|
7
|
-
if (typeof value
|
|
7
|
+
if (typeof value == 'boolean') return value;
|
|
8
8
|
if (fallback === undefined) {
|
|
9
9
|
throw new VmError(`Failed to convert value to boolean: ${display(value)}`, false);
|
|
10
10
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { toNumber } from './
|
|
2
|
-
export { toString } from './
|
|
3
|
-
export { toFormat } from './
|
|
4
|
-
export { toBoolean } from './
|
|
1
|
+
export { toNumber } from './number.js';
|
|
2
|
+
export { toString } from './string.js';
|
|
3
|
+
export { toFormat } from './format.js';
|
|
4
|
+
export { toBoolean } from './boolean.js';
|
|
@@ -3,28 +3,22 @@ import { VmError } from '../error.js';
|
|
|
3
3
|
import { display } from '../serialize.js';
|
|
4
4
|
import { NegativeInfinity, NotNumber, PositiveInfinity } from '../utils.js';
|
|
5
5
|
|
|
6
|
+
const parseInt = (value: string, radix: number): number => Number.parseInt(value.slice(2), radix);
|
|
7
|
+
|
|
6
8
|
/** 将字符串转换为数字 */
|
|
7
9
|
function parseNumericLiteral(value: string): number | null {
|
|
8
10
|
const ch0 = value.charAt(0);
|
|
9
|
-
if (ch0 < '0' || ch0 > '9')
|
|
10
|
-
|
|
11
|
-
}
|
|
11
|
+
if (ch0 < '0' || ch0 > '9') return null;
|
|
12
|
+
|
|
12
13
|
// 二进制
|
|
13
|
-
if (/^0[bB][01]+$/.test(value))
|
|
14
|
-
return Number.parseInt(value.slice(2), 2);
|
|
15
|
-
}
|
|
14
|
+
if (/^0[bB][01]+$/.test(value)) return parseInt(value, 2);
|
|
16
15
|
// 八进制
|
|
17
|
-
if (/^0[oO][0-7]+$/.test(value))
|
|
18
|
-
return Number.parseInt(value.slice(2), 8);
|
|
19
|
-
}
|
|
16
|
+
if (/^0[oO][0-7]+$/.test(value)) return parseInt(value, 8);
|
|
20
17
|
// 十六进制
|
|
21
|
-
if (/^0[xX][0-9a-fA-F]+$/.test(value))
|
|
22
|
-
return Number.parseInt(value.slice(2), 16);
|
|
23
|
-
}
|
|
18
|
+
if (/^0[xX][0-9a-fA-F]+$/.test(value)) return parseInt(value, 16);
|
|
24
19
|
// 十进制/科学计数法
|
|
25
|
-
if (/^[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?$/.test(value))
|
|
26
|
-
|
|
27
|
-
}
|
|
20
|
+
if (/^[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?$/.test(value)) return Number.parseFloat(value);
|
|
21
|
+
|
|
28
22
|
return null;
|
|
29
23
|
}
|
|
30
24
|
|
|
@@ -32,18 +26,13 @@ function parseNumericLiteral(value: string): number | null {
|
|
|
32
26
|
function stringToNumber(value: string): number | null {
|
|
33
27
|
value = value.trim();
|
|
34
28
|
if (value === '') return null;
|
|
35
|
-
if (value === 'inf' || value === '+inf' || value === 'Infinity' || value === '+Infinity')
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return NegativeInfinity;
|
|
40
|
-
}
|
|
41
|
-
if (value === 'nan' || value === 'NaN') {
|
|
42
|
-
return NotNumber;
|
|
43
|
-
}
|
|
29
|
+
if (value === 'inf' || value === '+inf' || value === 'Infinity' || value === '+Infinity') return PositiveInfinity;
|
|
30
|
+
if (value === '-inf' || value === '-Infinity') return NegativeInfinity;
|
|
31
|
+
if (value === 'nan' || value === 'NaN') return NotNumber;
|
|
32
|
+
|
|
44
33
|
if (value.startsWith('-')) {
|
|
45
34
|
const num = parseNumericLiteral(value.slice(1));
|
|
46
|
-
if (num
|
|
35
|
+
if (num != null) return -num;
|
|
47
36
|
return null;
|
|
48
37
|
} else if (value.startsWith('+')) {
|
|
49
38
|
return parseNumericLiteral(value.slice(1));
|
|
@@ -54,7 +43,7 @@ function stringToNumber(value: string): number | null {
|
|
|
54
43
|
|
|
55
44
|
/** 转换为 number */
|
|
56
45
|
export function toNumber<F = undefined>(value: VmAny, fallback?: F): number | Exclude<F, undefined> {
|
|
57
|
-
if (typeof value
|
|
46
|
+
if (typeof value == 'number') return value;
|
|
58
47
|
if (typeof value == 'boolean') return value ? 1 : 0;
|
|
59
48
|
if (typeof value == 'string') {
|
|
60
49
|
const num = stringToNumber(value);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { VmAny, VmRecord } from '../../vm/index.js';
|
|
2
|
-
import { isVmArray, isVmWrapper } from '../types.js';
|
|
2
|
+
import { isVmArray, isVmWrapper } from '../types/index.js';
|
|
3
3
|
import { VmError } from '../error.js';
|
|
4
4
|
import { display, displayFunction } from '../serialize.js';
|
|
5
5
|
import { keys, isNaN } from '../utils.js';
|
|
@@ -41,7 +41,7 @@ export function innerToString(value: VmAny, useBraces: boolean): string {
|
|
|
41
41
|
|
|
42
42
|
/** 转换为 string */
|
|
43
43
|
export function toString<F = undefined>(value: VmAny, fallback?: F): string | Exclude<F, undefined> {
|
|
44
|
-
if (typeof value
|
|
44
|
+
if (typeof value == 'string') return value;
|
|
45
45
|
if (value == null) return '';
|
|
46
46
|
try {
|
|
47
47
|
return innerToString(value, false);
|
package/src/helpers/serialize.ts
CHANGED
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
isVmFunction,
|
|
10
10
|
isVmModule,
|
|
11
11
|
isVmRecord,
|
|
12
|
-
} from './types.js';
|
|
13
|
-
import { numberToString } from './convert/
|
|
12
|
+
} from './types/index.js';
|
|
13
|
+
import { numberToString } from './convert/string.js';
|
|
14
14
|
|
|
15
15
|
/** 序列化 nil 值 */
|
|
16
16
|
export function serializeNil(): string {
|
|
@@ -44,6 +44,44 @@ function serializeStringContent(value: string, options: Readonly<SerializeOption
|
|
|
44
44
|
const STRING_QUOTE = `'`;
|
|
45
45
|
const STRING_REG = new RegExp(String.raw`[${STRING_QUOTE}\\\$\p{C}\u2028\u2029]`, 'gu');
|
|
46
46
|
const STRING_MARK = /^[\p{M}]$/u;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 序列化为特殊字符
|
|
50
|
+
*/
|
|
51
|
+
function serializeSpecialChar(char: string, options: Readonly<SerializeOptions>): string {
|
|
52
|
+
if (char === STRING_QUOTE) {
|
|
53
|
+
return serializeStringEscaped(STRING_QUOTE, options);
|
|
54
|
+
} else if (char === '\0') {
|
|
55
|
+
return serializeStringEscaped(`0`, options);
|
|
56
|
+
} else if (char === '\n') {
|
|
57
|
+
return serializeStringEscaped(`n`, options);
|
|
58
|
+
} else if (char === '\r') {
|
|
59
|
+
return serializeStringEscaped(`r`, options);
|
|
60
|
+
} else if (char === '\t') {
|
|
61
|
+
return serializeStringEscaped(`t`, options);
|
|
62
|
+
} else if (char === '\b') {
|
|
63
|
+
return serializeStringEscaped(`b`, options);
|
|
64
|
+
} else if (char === '\f') {
|
|
65
|
+
return serializeStringEscaped(`f`, options);
|
|
66
|
+
} else if (char === '\v') {
|
|
67
|
+
return serializeStringEscaped(`v`, options);
|
|
68
|
+
} else if (char === '\\') {
|
|
69
|
+
return serializeStringEscaped(`\\`, options);
|
|
70
|
+
} else if (char === '$') {
|
|
71
|
+
return serializeStringEscaped(`$`, options);
|
|
72
|
+
} else {
|
|
73
|
+
const code = char.codePointAt(0)!;
|
|
74
|
+
if (code <= 0x7f) {
|
|
75
|
+
return serializeStringEscaped(`x${code.toString(16).padStart(2, '0')}`, options);
|
|
76
|
+
} else if (code >= 0xd800 && code <= 0xdfff) {
|
|
77
|
+
// 无效的代理对
|
|
78
|
+
return serializeStringContent('�', options);
|
|
79
|
+
} else {
|
|
80
|
+
return serializeStringEscaped(`u{${code.toString(16)}}`, options);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
47
85
|
/**
|
|
48
86
|
* 将 MiraScript 字符串序列化为 MiraScript 字面量。
|
|
49
87
|
*/
|
|
@@ -62,8 +100,7 @@ function serializeStringImpl(value: string, options: Readonly<SerializeOptions>)
|
|
|
62
100
|
const cp = value.codePointAt(lastIndex)!;
|
|
63
101
|
const ch = String.fromCodePoint(cp);
|
|
64
102
|
if (!STRING_MARK.test(ch)) break;
|
|
65
|
-
|
|
66
|
-
ret += c;
|
|
103
|
+
ret += serializeStringEscaped(`u{${cp.toString(16)}}`, options);
|
|
67
104
|
lastIndex += ch.length;
|
|
68
105
|
}
|
|
69
106
|
|
|
@@ -71,40 +108,9 @@ function serializeStringImpl(value: string, options: Readonly<SerializeOptions>)
|
|
|
71
108
|
STRING_REG.lastIndex = lastIndex;
|
|
72
109
|
let match: RegExpExecArray | null;
|
|
73
110
|
while ((match = STRING_REG.exec(value)) !== null) {
|
|
74
|
-
const char = match[0];
|
|
75
111
|
ret += serializeStringContent(value.slice(lastIndex, match.index), options);
|
|
76
112
|
lastIndex = STRING_REG.lastIndex;
|
|
77
|
-
|
|
78
|
-
ret += serializeStringEscaped(STRING_QUOTE, options);
|
|
79
|
-
} else if (char === '\0') {
|
|
80
|
-
ret += serializeStringEscaped(`0`, options);
|
|
81
|
-
} else if (char === '\n') {
|
|
82
|
-
ret += serializeStringEscaped(`n`, options);
|
|
83
|
-
} else if (char === '\r') {
|
|
84
|
-
ret += serializeStringEscaped(`r`, options);
|
|
85
|
-
} else if (char === '\t') {
|
|
86
|
-
ret += serializeStringEscaped(`t`, options);
|
|
87
|
-
} else if (char === '\b') {
|
|
88
|
-
ret += serializeStringEscaped(`b`, options);
|
|
89
|
-
} else if (char === '\f') {
|
|
90
|
-
ret += serializeStringEscaped(`f`, options);
|
|
91
|
-
} else if (char === '\v') {
|
|
92
|
-
ret += serializeStringEscaped(`v`, options);
|
|
93
|
-
} else if (char === '\\') {
|
|
94
|
-
ret += serializeStringEscaped(`\\`, options);
|
|
95
|
-
} else if (char === '$') {
|
|
96
|
-
ret += serializeStringEscaped(`$`, options);
|
|
97
|
-
} else {
|
|
98
|
-
const code = char.codePointAt(0)!;
|
|
99
|
-
if (code <= 0x7f) {
|
|
100
|
-
ret += serializeStringEscaped(`x${code.toString(16).padStart(2, '0')}`, options);
|
|
101
|
-
} else if (code >= 0xd800 && code <= 0xdfff) {
|
|
102
|
-
// 无效的代理对
|
|
103
|
-
ret += serializeStringContent('�', options);
|
|
104
|
-
} else {
|
|
105
|
-
ret += serializeStringEscaped(`u{${code.toString(16)}}`, options);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
113
|
+
ret += serializeSpecialChar(match[0], options);
|
|
108
114
|
}
|
|
109
115
|
ret += serializeStringContent(value.slice(lastIndex), options);
|
|
110
116
|
ret += cq;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { VmRecord } from '../../vm/types/index.js';
|
|
2
|
+
import { VM_ARRAY_MAX_LENGTH } from '../constants.js';
|
|
3
|
+
import { keys } from '../utils.js';
|
|
4
|
+
|
|
5
|
+
/** 检查是否为仅包含从 0 开始的连续数字键的 MiraScript 记录 */
|
|
6
|
+
export function isVmArrayLikeRecordByEntries(entries: ReadonlyArray<readonly [string, unknown]>): boolean {
|
|
7
|
+
const { length } = entries;
|
|
8
|
+
if (length === 0) return true;
|
|
9
|
+
if (length > VM_ARRAY_MAX_LENGTH) return false;
|
|
10
|
+
const firstKey = entries[0]![0];
|
|
11
|
+
if (firstKey !== '0') return false;
|
|
12
|
+
const lastKey = entries[length - 1]![0];
|
|
13
|
+
if (lastKey !== String(length - 1)) return false;
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** 检查是否为仅包含从 0 开始的连续数字键的 MiraScript 记录 */
|
|
18
|
+
export function isVmArrayLikeRecordByKeys(keys: readonly string[]): boolean {
|
|
19
|
+
const { length } = keys;
|
|
20
|
+
if (length === 0) return true;
|
|
21
|
+
if (length > VM_ARRAY_MAX_LENGTH) return false;
|
|
22
|
+
const firstKey = keys[0]!;
|
|
23
|
+
if (firstKey !== '0') return false;
|
|
24
|
+
const lastKey = keys[length - 1]!;
|
|
25
|
+
if (lastKey !== String(length - 1)) return false;
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** 检查是否为仅包含从 0 开始的连续数字键的 MiraScript 记录 */
|
|
30
|
+
export function isVmArrayLikeRecord(value: VmRecord): boolean {
|
|
31
|
+
return isVmArrayLikeRecordByKeys(keys(value));
|
|
32
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { VmScript } from '../../compiler/index.js';
|
|
2
|
+
import type {
|
|
3
|
+
VmAny,
|
|
4
|
+
VmArray,
|
|
5
|
+
VmContext,
|
|
6
|
+
VmExtern,
|
|
7
|
+
VmFunction,
|
|
8
|
+
VmFunctionInfo,
|
|
9
|
+
VmFunctionLike,
|
|
10
|
+
VmImmutable,
|
|
11
|
+
VmModule,
|
|
12
|
+
VmPrimitive,
|
|
13
|
+
VmRecord,
|
|
14
|
+
} from '../../vm/types/index.js';
|
|
15
|
+
import type { VmWrapper } from '../../vm/types/wrapper.js';
|
|
16
|
+
import { kVmContext, kVmExtern, kVmFunction, kVmModule, kVmScript, kVmWrapper } from '../constants.js';
|
|
17
|
+
import { isArray } from '../utils.js';
|
|
18
|
+
|
|
19
|
+
/** 检查是否为 Mirascript 脚本 */
|
|
20
|
+
export function isVmScript(value: unknown): value is VmScript {
|
|
21
|
+
return typeof value === 'function' && kVmScript in value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** 检查是否为执行上下文 */
|
|
25
|
+
export function isVmContext(context: unknown): context is VmContext {
|
|
26
|
+
return context != null && typeof context == 'object' && kVmContext in context;
|
|
27
|
+
}
|
|
28
|
+
/** 检查是否为 Mirascript 函数 */
|
|
29
|
+
export function isVmFunction<T extends VmFunctionLike>(value: unknown): value is VmFunction<T> {
|
|
30
|
+
return typeof value == 'function' && kVmFunction in value;
|
|
31
|
+
}
|
|
32
|
+
/** 检查是否为 Mirascript 函数,并获取其信息 */
|
|
33
|
+
export function getVmFunctionInfo(value: unknown): VmFunctionInfo | undefined {
|
|
34
|
+
if (typeof value != 'function') return undefined;
|
|
35
|
+
return (value as VmFunction)[kVmFunction];
|
|
36
|
+
}
|
|
37
|
+
/** 检查值是否为 MiraScript 包装器 */
|
|
38
|
+
export function isVmWrapper<T extends object>(value: unknown): value is VmWrapper<T> {
|
|
39
|
+
return value != null && typeof value == 'object' && kVmWrapper in value;
|
|
40
|
+
}
|
|
41
|
+
/** 检查值是否为 Mirascript 模块 */
|
|
42
|
+
export function isVmModule<T extends Record<string, VmImmutable>>(value: unknown): value is VmModule<T> {
|
|
43
|
+
return value != null && typeof value == 'object' && kVmModule in value;
|
|
44
|
+
}
|
|
45
|
+
/** 检查值是否为 Mirascript 外部值 */
|
|
46
|
+
export function isVmExtern<T extends object>(value: unknown): value is VmExtern<T> {
|
|
47
|
+
return value != null && typeof value == 'object' && kVmExtern in value;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** 检查值是否为 Mirascript 可调用值 */
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
52
|
+
export function isVmCallable<E extends Function, F extends VmFunctionLike>(
|
|
53
|
+
value: unknown,
|
|
54
|
+
): value is VmFunction<F> | VmExtern<E> {
|
|
55
|
+
return isVmFunction<F>(value) || (isVmExtern<E>(value) && typeof value.value == 'function');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** 检查值是否为 Mirascript 原始值 */
|
|
59
|
+
export function isVmPrimitive(value: unknown): value is VmPrimitive {
|
|
60
|
+
if (value === null || typeof value == 'number' || typeof value == 'string' || typeof value == 'boolean') {
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
62
|
+
value as VmPrimitive satisfies typeof value;
|
|
63
|
+
value satisfies VmPrimitive;
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** 检查值是否为 Mirascript 数组 */
|
|
70
|
+
export function isVmArray(value: VmAny): value is VmArray {
|
|
71
|
+
if (!isArray(value)) return false;
|
|
72
|
+
value as VmArray satisfies VmArray;
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** 检查值是否为 Mirascript 记录 */
|
|
77
|
+
export function isVmRecord(value: VmAny): value is VmRecord {
|
|
78
|
+
if (value == null || typeof value != 'object') return false;
|
|
79
|
+
if (isVmWrapper(value) || isVmArray(value)) return false;
|
|
80
|
+
value satisfies VmRecord;
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { VmAny, VmImmutable, VmValue } from '../../vm/types/index.js';
|
|
2
|
+
import { isVmFunction, isVmModule, isVmWrapper } from './basic.js';
|
|
3
|
+
import { isVmConst } from './const.js';
|
|
4
|
+
|
|
5
|
+
/** 检查是否为 Mirascript 不可变值 */
|
|
6
|
+
export function isVmImmutable(value: VmAny): value is VmImmutable;
|
|
7
|
+
/** 检查是否为 Mirascript 不可变值 */
|
|
8
|
+
export function isVmImmutable(value: unknown, checkDeep: boolean): value is VmImmutable;
|
|
9
|
+
/** 检查是否为 Mirascript 不可变值 */
|
|
10
|
+
export function isVmImmutable(value: unknown, checkDeep = false): value is VmImmutable {
|
|
11
|
+
return isVmModule(value) || isVmFunction(value) || isVmConst(value, checkDeep);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** 检查是否为 Mirascript 合法值 */
|
|
15
|
+
export function isVmValue(value: VmAny): value is VmValue;
|
|
16
|
+
/** 检查是否为 Mirascript 合法值 */
|
|
17
|
+
export function isVmValue(value: unknown, checkDeep: boolean): value is VmValue;
|
|
18
|
+
/** 检查是否为 Mirascript 合法值 */
|
|
19
|
+
export function isVmValue(value: unknown, checkDeep = false): value is VmValue {
|
|
20
|
+
return isVmWrapper(value) || isVmFunction(value) || isVmConst(value, checkDeep);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** 检查是否为 Mirascript 值 */
|
|
24
|
+
export function isVmAny(value: unknown, checkDeep: boolean): value is VmAny {
|
|
25
|
+
if (value == null) return true;
|
|
26
|
+
return isVmValue(value, checkDeep);
|
|
27
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { VmAny, VmArray, VmConst, VmRecord } from '../../vm/types/index.js';
|
|
2
|
+
import { isArray, values } from '../utils.js';
|
|
3
|
+
import { isVmWrapper } from './basic.js';
|
|
4
|
+
import { isPlainArray, isPlainObject } from './proto.js';
|
|
5
|
+
|
|
6
|
+
const MAX_DEPTH = 16;
|
|
7
|
+
/** 检查是否为 Mirascript 数组 */
|
|
8
|
+
function isVmArrayDeep(value: readonly unknown[], depth: number): value is VmArray {
|
|
9
|
+
if (!isPlainArray(value)) return false;
|
|
10
|
+
if (depth <= 0) return true;
|
|
11
|
+
const inner_depth = depth - 1;
|
|
12
|
+
return value.every((item) => isVmConstInner(item, inner_depth));
|
|
13
|
+
}
|
|
14
|
+
/** 检查是否为 Mirascript 记录 */
|
|
15
|
+
function isVmRecordDeep(value: object, depth: number): value is VmRecord {
|
|
16
|
+
if (!isPlainObject(value)) return false;
|
|
17
|
+
if (depth <= 0) return true;
|
|
18
|
+
const inner_depth = depth - 1;
|
|
19
|
+
return values(value).every((value) => isVmConstInner(value, inner_depth));
|
|
20
|
+
}
|
|
21
|
+
/** 检查是否为 Mirascript 值语义值 */
|
|
22
|
+
function isVmConstInner(value: unknown, depth: number): value is VmConst {
|
|
23
|
+
if (value == null) return true; // undefined 在复合类型内部被视为 nil
|
|
24
|
+
if (typeof value == 'string' || typeof value == 'number' || typeof value == 'boolean') return true;
|
|
25
|
+
if (typeof value == 'object') {
|
|
26
|
+
if (isVmWrapper(value)) return false;
|
|
27
|
+
if (isArray(value)) {
|
|
28
|
+
return isVmArrayDeep(value, depth);
|
|
29
|
+
} else {
|
|
30
|
+
return isVmRecordDeep(value, depth);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return false; // Other types are not valid
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 检查是否为 Mirascript 值语义值 */
|
|
37
|
+
export function isVmConst(value: VmAny): value is VmConst;
|
|
38
|
+
/** 检查是否为 Mirascript 值语义值 */
|
|
39
|
+
export function isVmConst(value: unknown, checkDeep: boolean): value is VmConst;
|
|
40
|
+
/** 检查是否为 Mirascript 值语义值 */
|
|
41
|
+
export function isVmConst(value: unknown, checkDeep = false): value is VmConst {
|
|
42
|
+
if (value === undefined) return false;
|
|
43
|
+
return isVmConstInner(value, checkDeep ? MAX_DEPTH : 0);
|
|
44
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { VmValue, VmTypeName, VmAny } from '../../vm/index.js';
|
|
2
|
+
import { isVmWrapper, isVmArray } from './basic.js';
|
|
3
|
+
|
|
4
|
+
/** 获取 MiraScript 类型 */
|
|
5
|
+
export function getVmType(value: VmValue): VmTypeName;
|
|
6
|
+
/** 获取 MiraScript 类型 */
|
|
7
|
+
export function getVmType(value: VmAny): VmTypeName | 'uninitialized';
|
|
8
|
+
/** 获取 MiraScript 类型 */
|
|
9
|
+
export function getVmType(value: VmAny): VmTypeName | 'uninitialized' {
|
|
10
|
+
if (value === undefined) return 'uninitialized';
|
|
11
|
+
if (value === null) return 'nil';
|
|
12
|
+
if (isVmWrapper(value)) return value.type;
|
|
13
|
+
if (isVmArray(value)) return 'array';
|
|
14
|
+
if (typeof value == 'object') return 'record';
|
|
15
|
+
return typeof value as VmTypeName;
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getPrototypeOf, hasOwn, isArray } from '../utils.js';
|
|
2
|
+
|
|
3
|
+
/** 检查是否为普通数组 */
|
|
4
|
+
export function isPlainArray(value: readonly unknown[]): boolean {
|
|
5
|
+
// value 的原型应当为 Array.prototype
|
|
6
|
+
const proto: unknown = getPrototypeOf(value);
|
|
7
|
+
// 使用 isArray 检查原型是否为 Array.prototype,避免直接比较原型对象,防止跨环境问题
|
|
8
|
+
return isArray(proto) && hasOwn(proto, 'push');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** 检查是否为普通对象或空原型对象 */
|
|
12
|
+
export function isPlainObject(value: object): boolean {
|
|
13
|
+
// value 的原型应当为 Object.prototype 或 null
|
|
14
|
+
const proto1: unknown = getPrototypeOf(value);
|
|
15
|
+
if (proto1 == null) return true;
|
|
16
|
+
// Object.prototype 的原型应当为 null
|
|
17
|
+
const proto2: unknown = getPrototypeOf(proto1);
|
|
18
|
+
if (proto2 != null) return false;
|
|
19
|
+
// 检查是否具有 Object.prototype 的方法,避免直接比较原型对象,防止跨环境问题
|
|
20
|
+
return hasOwn(proto1, 'hasOwnProperty');
|
|
21
|
+
}
|
package/src/helpers/utils.ts
CHANGED
|
@@ -29,6 +29,11 @@ export const hasOwnEnumerable = Function.call.bind(
|
|
|
29
29
|
Object.prototype.propertyIsEnumerable,
|
|
30
30
|
) as (o: object, v: PropertyKey) => boolean;
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Snapshot the inherited keys that require data-property semantics when written
|
|
34
|
+
* to a VM record. The host is expected not to mutate `Object.prototype` after
|
|
35
|
+
* MiraScript has been initialized.
|
|
36
|
+
*/
|
|
32
37
|
const SPECIAL_KEYS = new Set(getOwnPropertyNames(Object.prototype));
|
|
33
38
|
/**
|
|
34
39
|
* Set property on an vm record.
|
|
@@ -37,7 +42,8 @@ export const setRecord = (obj: Record<string, VmConst | undefined>, key: string,
|
|
|
37
42
|
if (!SPECIAL_KEYS.has(key)) {
|
|
38
43
|
obj[key] = value ?? null;
|
|
39
44
|
} else {
|
|
40
|
-
|
|
45
|
+
defineProperty(obj, key, {
|
|
46
|
+
__proto__: null,
|
|
41
47
|
value: value ?? null,
|
|
42
48
|
configurable: true,
|
|
43
49
|
writable: true,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { toBoolean } from '../../../../helpers/convert/
|
|
1
|
+
import { toBoolean } from '../../../../helpers/convert/index.js';
|
|
2
2
|
import { entries } from '../../../../helpers/utils.js';
|
|
3
3
|
import { Cp } from '../../../checkpoint.js';
|
|
4
4
|
import { $Call } from '../../../operations/index.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { toBoolean } from '../../../../helpers/convert/
|
|
1
|
+
import { toBoolean } from '../../../../helpers/convert/index.js';
|
|
2
2
|
import { entries } from '../../../../helpers/utils.js';
|
|
3
3
|
import { Cp } from '../../../checkpoint.js';
|
|
4
4
|
import { $Call, $Same } from '../../../operations/index.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { toString } from '../../../../helpers/convert/
|
|
1
|
+
import { toString } from '../../../../helpers/convert/index.js';
|
|
2
2
|
import { fromEntries } from '../../../../helpers/utils.js';
|
|
3
3
|
import { $Call } from '../../../operations/call.js';
|
|
4
4
|
import type { VmConst } from '../../../types/index.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { toBoolean } from '../../../../helpers/convert/
|
|
1
|
+
import { toBoolean } from '../../../../helpers/convert/index.js';
|
|
2
2
|
import { $Call } from '../../../operations/index.js';
|
|
3
3
|
import { isVmConst, type VmAny, type VmValue } from '../../../types/index.js';
|
|
4
4
|
import { VmLib, expectCallable, expectConst, iterate } from '../../helpers.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { VmArray, VmConst, VmRecord } from '../../../types/index.js';
|
|
2
|
-
import { toString } from '../../../../helpers/convert/
|
|
2
|
+
import { toString } from '../../../../helpers/convert/index.js';
|
|
3
3
|
import { VM_ARRAY_MAX_LENGTH } from '../../../../helpers/constants.js';
|
|
4
4
|
import {
|
|
5
5
|
keys as _keys,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { toNumber } from '../../../../helpers/convert/
|
|
1
|
+
import { toNumber } from '../../../../helpers/convert/index.js';
|
|
2
2
|
import { $Call } from '../../../operations/index.js';
|
|
3
3
|
import type { VmAny, VmConst, VmValue } from '../../../types/index.js';
|
|
4
4
|
import { VmLib, expectArray, expectCallable } from '../../helpers.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { toBoolean } from '../../../../helpers/convert/
|
|
1
|
+
import { toBoolean } from '../../../../helpers/convert/index.js';
|
|
2
2
|
import { $Call } from '../../../operations/call.js';
|
|
3
3
|
import { isSame } from '../../../operations/utils.js';
|
|
4
4
|
import type { VmAny, VmConst, VmValue } from '../../../types/index.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { VM_ARRAY_MAX_LENGTH } from '../../../../helpers/constants.js';
|
|
2
2
|
import { toNumber, toString } from '../../../../helpers/convert/index.js';
|
|
3
|
-
import { isVmArray, isVmRecord } from '../../../../helpers/types.js';
|
|
3
|
+
import { isVmArray, isVmRecord } from '../../../../helpers/types/index.js';
|
|
4
4
|
import { isArray, isInteger, isFinite, NotNumber, setRecord, getRecord } from '../../../../helpers/utils.js';
|
|
5
5
|
import { $El } from '../../../operations/helpers.js';
|
|
6
6
|
import type { VmArray, VmConst, VmValue } from '../../../types/index.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describeParam, expectNumberRange, throwError, throwUnexpectedTypeError, VmLib } from '../helpers.js';
|
|
2
2
|
import { isNaN, NotNumber, isFinite } from '../../../helpers/utils.js';
|
|
3
|
-
import { toNumber } from '../../../helpers/convert/
|
|
3
|
+
import { toNumber } from '../../../helpers/convert/index.js';
|
|
4
4
|
import { display } from '../../../helpers/serialize.js';
|
|
5
5
|
import type { VmAny } from '../../types/index.js';
|
|
6
6
|
|
package/src/vm/lib/helpers.ts
CHANGED
|
@@ -2,7 +2,14 @@ import { VM_ARRAY_MAX_LENGTH } from '../../helpers/constants.js';
|
|
|
2
2
|
import { NotNumber, entries, fromEntries, isSafeInteger, isFinite } from '../../helpers/utils.js';
|
|
3
3
|
import { toBoolean, toNumber, toString } from '../../helpers/convert/index.js';
|
|
4
4
|
import { display } from '../../helpers/serialize.js';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
isVmArray,
|
|
7
|
+
isVmFunction,
|
|
8
|
+
isVmPrimitive,
|
|
9
|
+
isVmConst,
|
|
10
|
+
isVmCallable,
|
|
11
|
+
isVmRecord,
|
|
12
|
+
} from '../../helpers/types/index.js';
|
|
6
13
|
import { VmError } from '../../helpers/error.js';
|
|
7
14
|
import type {
|
|
8
15
|
VmExtern,
|
package/src/vm/lib/mod/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * as matrix from './matrix.js';
|
|
1
|
+
export * as matrix from './matrix/index.js';
|