@mirascript/mirascript 0.1.15 → 0.1.16
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-NT235HY3.js → chunk-LU4ZKFF6.js} +1411 -608
- package/dist/chunk-LU4ZKFF6.js.map +6 -0
- package/dist/chunk-RIT53WVY.js +1 -0
- package/dist/chunk-RLWIIOH5.js +12 -0
- package/dist/chunk-RLWIIOH5.js.map +6 -0
- package/dist/{chunk-JVFUK7AN.js → chunk-YZGL3D7L.js} +739 -1366
- package/dist/chunk-YZGL3D7L.js.map +6 -0
- package/dist/cli/index.js +11 -67
- package/dist/cli/index.js.map +2 -2
- package/dist/compiler/compile-fast.d.ts +1 -1
- package/dist/compiler/compile-fast.d.ts.map +1 -1
- package/dist/compiler/create-script.d.ts +10 -1
- package/dist/compiler/create-script.d.ts.map +1 -1
- package/dist/compiler/diagnostic.d.ts +1 -1
- package/dist/compiler/diagnostic.d.ts.map +1 -1
- package/dist/compiler/emit/constants.d.ts +3 -0
- package/dist/compiler/emit/constants.d.ts.map +1 -0
- package/dist/compiler/emit/consts.d.ts +6 -0
- package/dist/compiler/emit/consts.d.ts.map +1 -0
- package/dist/compiler/emit/globals.d.ts +17 -0
- package/dist/compiler/emit/globals.d.ts.map +1 -0
- package/dist/compiler/emit/index.d.ts +58 -0
- package/dist/compiler/emit/index.d.ts.map +1 -0
- package/dist/compiler/emit/sourcemap.d.ts +6 -0
- package/dist/compiler/emit/sourcemap.d.ts.map +1 -0
- package/dist/compiler/index.d.ts +3 -2
- package/dist/compiler/index.d.ts.map +1 -1
- package/dist/compiler/worker.js +1 -1
- package/dist/helpers/constants.d.ts +10 -0
- package/dist/helpers/constants.d.ts.map +1 -1
- package/dist/helpers/convert.d.ts +12 -0
- package/dist/helpers/convert.d.ts.map +1 -0
- package/dist/{vm → helpers}/error.d.ts +1 -1
- package/dist/helpers/error.d.ts.map +1 -0
- package/dist/helpers/serialize.d.ts +13 -4
- package/dist/helpers/serialize.d.ts.map +1 -1
- package/dist/helpers/types.d.ts +54 -0
- package/dist/helpers/types.d.ts.map +1 -0
- package/dist/index.js +11 -17
- package/dist/subtle.d.ts +3 -2
- package/dist/subtle.d.ts.map +1 -1
- package/dist/subtle.js +21 -15
- package/dist/vm/checkpoint.d.ts +9 -0
- package/dist/vm/checkpoint.d.ts.map +1 -0
- package/dist/vm/helpers.d.ts +4 -10
- package/dist/vm/helpers.d.ts.map +1 -1
- package/dist/vm/index.d.ts +3 -3
- package/dist/vm/index.d.ts.map +1 -1
- package/dist/vm/lib/global/bit.d.ts +7 -7
- package/dist/vm/lib/global/bit.d.ts.map +1 -1
- package/dist/vm/lib/global/debug.d.ts +2 -2
- package/dist/vm/lib/global/debug.d.ts.map +1 -1
- package/dist/vm/lib/global/index.d.ts +0 -1
- package/dist/vm/lib/global/index.d.ts.map +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/math-additional.d.ts +1 -1
- package/dist/vm/lib/global/math-additional.d.ts.map +1 -1
- package/dist/vm/lib/global/math-arr.d.ts +5 -5
- package/dist/vm/lib/global/math-arr.d.ts.map +1 -1
- package/dist/vm/lib/global/math-unary.d.ts +26 -26
- package/dist/vm/lib/global/math-unary.d.ts.map +1 -1
- package/dist/vm/lib/global/math.d.ts +3 -3
- package/dist/vm/lib/global/math.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/all-any.d.ts +2 -2
- package/dist/vm/lib/global/sequence/all-any.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/entries.d.ts +5 -5
- package/dist/vm/lib/global/sequence/entries.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/find.d.ts +3 -3
- package/dist/vm/lib/global/sequence/find.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/flatten.d.ts +1 -1
- package/dist/vm/lib/global/sequence/flatten.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/len.d.ts +1 -1
- package/dist/vm/lib/global/sequence/len.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/map-filter.d.ts +3 -3
- package/dist/vm/lib/global/sequence/map-filter.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/repeat.d.ts +1 -1
- package/dist/vm/lib/global/sequence/repeat.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/reverse.d.ts +1 -1
- package/dist/vm/lib/global/sequence/reverse.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/sort.d.ts +2 -2
- package/dist/vm/lib/global/sequence/sort.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/with.d.ts +2 -2
- 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/lib/global/sequence/zip.d.ts.map +1 -1
- package/dist/vm/lib/global/string.d.ts +10 -10
- package/dist/vm/lib/global/string.d.ts.map +1 -1
- package/dist/vm/lib/global/time.d.ts +3 -13
- package/dist/vm/lib/global/time.d.ts.map +1 -1
- package/dist/vm/lib/global/to-primitive.d.ts +4 -4
- package/dist/vm/lib/global/to-primitive.d.ts.map +1 -1
- package/dist/vm/lib/helpers.d.ts +53 -0
- package/dist/vm/lib/helpers.d.ts.map +1 -0
- package/dist/vm/lib/index.d.ts +4 -0
- package/dist/vm/lib/index.d.ts.map +1 -0
- package/dist/vm/lib/{_loader.d.ts → loader.d.ts} +5 -5
- package/dist/vm/lib/loader.d.ts.map +1 -0
- package/dist/vm/lib/mod/index.d.ts +2 -0
- package/dist/vm/lib/mod/index.d.ts.map +1 -0
- package/dist/vm/lib/mod/matrix.d.ts +15 -0
- package/dist/vm/lib/mod/matrix.d.ts.map +1 -0
- package/dist/vm/operations.d.ts +2 -4
- package/dist/vm/operations.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 +10 -9
- package/dist/vm/types/context.d.ts.map +1 -1
- package/dist/vm/types/extern.d.ts +1 -3
- package/dist/vm/types/extern.d.ts.map +1 -1
- package/dist/vm/types/function.d.ts +1 -6
- package/dist/vm/types/function.d.ts.map +1 -1
- package/dist/vm/types/index.d.ts +31 -17
- package/dist/vm/types/index.d.ts.map +1 -1
- package/dist/vm/types/module.d.ts +2 -4
- package/dist/vm/types/module.d.ts.map +1 -1
- package/dist/vm/types/wrapper.d.ts +0 -2
- package/dist/vm/types/wrapper.d.ts.map +1 -1
- package/package.json +7 -3
- package/src/cli/index.ts +1 -1
- package/src/compiler/compile-fast.ts +1 -2
- package/src/compiler/create-script.ts +12 -2
- package/src/compiler/diagnostic.ts +17 -8
- package/src/compiler/emit/constants.ts +2 -0
- package/src/compiler/emit/consts.ts +47 -0
- package/src/compiler/emit/globals.ts +39 -0
- package/src/compiler/{emit.ts → emit/index.ts} +16 -200
- package/src/compiler/emit/sourcemap.ts +163 -0
- package/src/compiler/index.ts +9 -9
- package/src/compiler/worker.ts +1 -1
- package/src/helpers/constants.ts +12 -0
- package/src/helpers/convert.ts +128 -0
- package/src/{vm → helpers}/error.ts +1 -1
- package/src/helpers/serialize.ts +71 -24
- package/src/helpers/types.ts +267 -0
- package/src/subtle.ts +3 -1
- package/src/vm/checkpoint.ts +42 -0
- package/src/vm/helpers.ts +9 -53
- package/src/vm/index.ts +3 -3
- package/src/vm/lib/global/bit.ts +8 -9
- package/src/vm/lib/global/debug.ts +5 -4
- package/src/vm/lib/global/index.ts +0 -1
- package/src/vm/lib/global/json.ts +2 -2
- package/src/vm/lib/global/math-additional.ts +2 -4
- package/src/vm/lib/global/math-arr.ts +1 -1
- package/src/vm/lib/global/math-unary.ts +2 -4
- package/src/vm/lib/global/math.ts +3 -4
- package/src/vm/lib/global/sequence/all-any.ts +11 -6
- package/src/vm/lib/global/sequence/entries.ts +1 -1
- package/src/vm/lib/global/sequence/find.ts +4 -3
- package/src/vm/lib/global/sequence/flatten.ts +2 -3
- package/src/vm/lib/global/sequence/len.ts +1 -1
- package/src/vm/lib/global/sequence/map-filter.ts +4 -3
- package/src/vm/lib/global/sequence/repeat.ts +2 -4
- package/src/vm/lib/global/sequence/reverse.ts +1 -1
- package/src/vm/lib/global/sequence/sort.ts +6 -5
- package/src/vm/lib/global/sequence/with.ts +21 -20
- package/src/vm/lib/global/sequence/zip.ts +3 -3
- package/src/vm/lib/global/string.ts +16 -27
- package/src/vm/lib/global/time.ts +59 -30
- package/src/vm/lib/global/to-primitive.ts +27 -18
- package/src/vm/lib/{_helpers.ts → helpers.ts} +129 -41
- package/src/vm/lib/index.ts +16 -0
- package/src/vm/lib/{_loader.ts → loader.ts} +3 -11
- package/src/vm/lib/mod/index.ts +1 -0
- package/src/vm/lib/{global/mod → mod}/matrix.ts +9 -7
- package/src/vm/operations.ts +31 -126
- package/src/vm/types/boundary.ts +10 -13
- package/src/vm/types/context.ts +17 -24
- package/src/vm/types/extern.ts +8 -15
- package/src/vm/types/function.ts +4 -19
- package/src/vm/types/index.ts +47 -25
- package/src/vm/types/module.ts +3 -7
- package/src/vm/types/wrapper.ts +1 -5
- package/dist/chunk-35JGBXRE.js +0 -1
- package/dist/chunk-JVFUK7AN.js.map +0 -6
- package/dist/chunk-NT235HY3.js.map +0 -6
- package/dist/compiler/emit.d.ts +0 -5
- package/dist/compiler/emit.d.ts.map +0 -1
- package/dist/vm/error.d.ts.map +0 -1
- package/dist/vm/lib/_helpers.d.ts +0 -35
- package/dist/vm/lib/_helpers.d.ts.map +0 -1
- package/dist/vm/lib/_loader.d.ts.map +0 -1
- package/dist/vm/lib/global/mod/index.d.ts +0 -3
- package/dist/vm/lib/global/mod/index.d.ts.map +0 -1
- package/dist/vm/lib/global/mod/matrix.d.ts +0 -15
- package/dist/vm/lib/global/mod/matrix.d.ts.map +0 -1
- package/dist/vm/types/any.d.ts +0 -10
- package/dist/vm/types/any.d.ts.map +0 -1
- package/dist/vm/types/array.d.ts +0 -12
- package/dist/vm/types/array.d.ts.map +0 -1
- package/dist/vm/types/callable.d.ts +0 -5
- package/dist/vm/types/callable.d.ts.map +0 -1
- package/dist/vm/types/const.d.ts +0 -15
- package/dist/vm/types/const.d.ts.map +0 -1
- package/dist/vm/types/immutable.d.ts +0 -15
- package/dist/vm/types/immutable.d.ts.map +0 -1
- package/dist/vm/types/primitive.d.ts +0 -7
- package/dist/vm/types/primitive.d.ts.map +0 -1
- package/dist/vm/types/record.d.ts +0 -20
- package/dist/vm/types/record.d.ts.map +0 -1
- package/dist/vm/types/script.d.ts +0 -14
- package/dist/vm/types/script.d.ts.map +0 -1
- package/dist/vm/types/value.d.ts +0 -14
- package/dist/vm/types/value.d.ts.map +0 -1
- package/src/vm/lib/global/mod/index.ts +0 -4
- package/src/vm/types/any.ts +0 -33
- package/src/vm/types/array.ts +0 -19
- package/src/vm/types/callable.ts +0 -10
- package/src/vm/types/const.ts +0 -109
- package/src/vm/types/immutable.ts +0 -22
- package/src/vm/types/primitive.ts +0 -14
- package/src/vm/types/record.ts +0 -53
- package/src/vm/types/script.ts +0 -18
- package/src/vm/types/value.ts +0 -22
- /package/dist/{chunk-35JGBXRE.js.map → chunk-RIT53WVY.js.map} +0 -0
|
@@ -1,35 +1,60 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { describeParam, expectNumberRange, throwError, throwUnexpectedTypeError, VmLib } from '../helpers.js';
|
|
2
|
+
import { isNaN, isFinite } from '../../../helpers/utils.js';
|
|
3
|
+
import { toNumber } from '../../../helpers/convert.js';
|
|
4
|
+
import { display } from '../../../helpers/serialize.js';
|
|
5
|
+
import type { VmAny } from '../../types/index.js';
|
|
6
|
+
|
|
7
|
+
const fromNumber = (datetime: number, fallback: boolean): number | null => {
|
|
8
|
+
const n = new Date(datetime).getTime();
|
|
9
|
+
if (isFinite(n)) return n;
|
|
10
|
+
if (fallback) return null;
|
|
11
|
+
throwError(`${describeParam('datetime')} is an invalid timestamp: ${display(datetime)}`, Number.NaN);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const getTimestamp = (datetime: VmAny, fallback: boolean): number | null => {
|
|
15
|
+
if (datetime == null) {
|
|
16
|
+
return Date.now();
|
|
17
|
+
}
|
|
18
|
+
if (typeof datetime == 'number') {
|
|
19
|
+
return fromNumber(datetime, fallback);
|
|
20
|
+
}
|
|
21
|
+
if (typeof datetime != 'string') {
|
|
22
|
+
if (fallback) return null;
|
|
23
|
+
throwUnexpectedTypeError('datetime', 'number | string', datetime, Number.NaN);
|
|
24
|
+
}
|
|
25
|
+
const num = toNumber(datetime, Number.NaN);
|
|
26
|
+
if (!isNaN(num)) {
|
|
27
|
+
return fromNumber(num, fallback);
|
|
28
|
+
}
|
|
29
|
+
const parsed = Date.parse(datetime);
|
|
30
|
+
if (isFinite(parsed)) return parsed;
|
|
31
|
+
if (fallback) return null;
|
|
32
|
+
throwError(`${describeParam('datetime')} cannot be parsed as datetime: ${display(datetime)}`, Number.NaN);
|
|
33
|
+
};
|
|
4
34
|
|
|
5
35
|
export const to_timestamp = VmLib(
|
|
6
|
-
(datetime) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (typeof datetime == 'number') {
|
|
11
|
-
return new Date(datetime).getTime();
|
|
12
|
-
}
|
|
13
|
-
const str = $ToString(datetime);
|
|
14
|
-
if (!str) return Number.NaN;
|
|
15
|
-
const num = $ToNumber(str);
|
|
16
|
-
if (isFinite(num)) return num;
|
|
17
|
-
return Date.parse(str);
|
|
36
|
+
(datetime, fallback) => {
|
|
37
|
+
const timestamp = getTimestamp(datetime, fallback !== undefined);
|
|
38
|
+
if (timestamp == null) return fallback;
|
|
39
|
+
return timestamp;
|
|
18
40
|
},
|
|
19
41
|
{
|
|
20
42
|
summary: '将数据转换为 Unix 毫秒时间戳',
|
|
21
|
-
params: {
|
|
22
|
-
|
|
23
|
-
|
|
43
|
+
params: {
|
|
44
|
+
datetime: '要转换的数据,默认为当前时间',
|
|
45
|
+
fallback: '转换失败时的返回值',
|
|
46
|
+
},
|
|
47
|
+
paramsType: { datetime: 'number | string', fallback: 'any' },
|
|
48
|
+
returnsType: 'number | type(fallback)',
|
|
24
49
|
examples: ['to_timestamp("1970-01-01T00:00:00Z") // 0'],
|
|
25
50
|
},
|
|
26
51
|
);
|
|
27
52
|
|
|
28
53
|
export const to_datetime = VmLib(
|
|
29
|
-
(datetime, offset) => {
|
|
30
|
-
const timestamp =
|
|
31
|
-
if (
|
|
32
|
-
const o =
|
|
54
|
+
(datetime, offset, fallback) => {
|
|
55
|
+
const timestamp = getTimestamp(datetime, fallback !== undefined);
|
|
56
|
+
if (timestamp == null) return fallback;
|
|
57
|
+
const o = expectNumberRange('offset', offset ?? 0, -24, 24);
|
|
33
58
|
const dateOffset = new Date(timestamp + o * 1000 * 60 * 60);
|
|
34
59
|
return {
|
|
35
60
|
year: dateOffset.getUTCFullYear(),
|
|
@@ -48,9 +73,10 @@ export const to_datetime = VmLib(
|
|
|
48
73
|
params: {
|
|
49
74
|
datetime: '要转换的数据,默认为当前时间',
|
|
50
75
|
offset: '时区偏移量(单位:小时),默认为 0',
|
|
76
|
+
fallback: '转换失败时的返回值',
|
|
51
77
|
},
|
|
52
|
-
paramsType: { datetime: 'number | string', offset: 'number' },
|
|
53
|
-
returnsType: 'Date',
|
|
78
|
+
paramsType: { datetime: 'number | string', offset: 'number', fallback: 'any' },
|
|
79
|
+
returnsType: 'Date | type(fallback)',
|
|
54
80
|
examples: [
|
|
55
81
|
`
|
|
56
82
|
to_datetime(0)
|
|
@@ -65,16 +91,19 @@ to_datetime(0)
|
|
|
65
91
|
);
|
|
66
92
|
|
|
67
93
|
export const to_iso8601 = VmLib(
|
|
68
|
-
(datetime) => {
|
|
69
|
-
const timestamp =
|
|
70
|
-
if (
|
|
94
|
+
(datetime, fallback) => {
|
|
95
|
+
const timestamp = getTimestamp(datetime, fallback !== undefined);
|
|
96
|
+
if (timestamp == null) return fallback;
|
|
71
97
|
return new Date(timestamp).toISOString();
|
|
72
98
|
},
|
|
73
99
|
{
|
|
74
100
|
summary: '将数据转换为 ISO 8601 格式的字符串',
|
|
75
|
-
params: {
|
|
76
|
-
|
|
77
|
-
|
|
101
|
+
params: {
|
|
102
|
+
datetime: '要转换的数据,默认为当前时间',
|
|
103
|
+
fallback: '转换失败时的返回值',
|
|
104
|
+
},
|
|
105
|
+
paramsType: { datetime: 'number | string', fallback: 'any' },
|
|
106
|
+
returnsType: 'string | type(fallback)',
|
|
78
107
|
examples: ['to_iso8601(0) // "1970-01-01T00:00:00.000Z"'],
|
|
79
108
|
},
|
|
80
109
|
);
|
|
@@ -1,44 +1,53 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { required, VmLib } from '../
|
|
1
|
+
import { toBoolean, toFormat, toNumber, toString } from '../../../helpers/convert.js';
|
|
2
|
+
import { expectString, required, VmLib } from '../helpers.js';
|
|
3
3
|
|
|
4
4
|
export const to_string = VmLib(
|
|
5
|
-
(data) => {
|
|
5
|
+
(data, fallback) => {
|
|
6
6
|
required('data', data, '');
|
|
7
|
-
return
|
|
7
|
+
return toString(data, fallback);
|
|
8
8
|
},
|
|
9
9
|
{
|
|
10
10
|
summary: '将数据转换为字符串',
|
|
11
|
-
params: {
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
params: {
|
|
12
|
+
data: '要转换的数据',
|
|
13
|
+
fallback: '转换失败时的返回值',
|
|
14
|
+
},
|
|
15
|
+
paramsType: { data: 'any', fallback: 'any' },
|
|
16
|
+
returnsType: 'string | type(fallback)',
|
|
14
17
|
examples: ['to_string([1, 2]) // "1, 2"'],
|
|
15
18
|
},
|
|
16
19
|
);
|
|
17
20
|
|
|
18
21
|
export const to_number = VmLib(
|
|
19
|
-
(data) => {
|
|
22
|
+
(data, fallback) => {
|
|
20
23
|
required('data', data, Number.NaN);
|
|
21
|
-
return
|
|
24
|
+
return toNumber(data, fallback);
|
|
22
25
|
},
|
|
23
26
|
{
|
|
24
27
|
summary: '将数据转换为数字',
|
|
25
|
-
params: {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
params: {
|
|
29
|
+
data: '要转换的数据',
|
|
30
|
+
fallback: '转换失败时的返回值',
|
|
31
|
+
},
|
|
32
|
+
paramsType: { data: 'any', fallback: 'any' },
|
|
33
|
+
returnsType: 'number | type(fallback)',
|
|
28
34
|
examples: ['to_number("1.5") // 1.5'],
|
|
29
35
|
},
|
|
30
36
|
);
|
|
31
37
|
|
|
32
38
|
export const to_boolean = VmLib(
|
|
33
|
-
(data) => {
|
|
39
|
+
(data, fallback) => {
|
|
34
40
|
required('data', data, false);
|
|
35
|
-
return
|
|
41
|
+
return toBoolean(data, fallback);
|
|
36
42
|
},
|
|
37
43
|
{
|
|
38
44
|
summary: '将数据转换为布尔值',
|
|
39
|
-
params: {
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
params: {
|
|
46
|
+
data: '要转换的数据',
|
|
47
|
+
fallback: '转换失败时的返回值',
|
|
48
|
+
},
|
|
49
|
+
paramsType: { data: 'any', fallback: 'any' },
|
|
50
|
+
returnsType: 'boolean | type(fallback)',
|
|
42
51
|
examples: ['to_boolean(nil) // false'],
|
|
43
52
|
},
|
|
44
53
|
);
|
|
@@ -46,7 +55,7 @@ export const to_boolean = VmLib(
|
|
|
46
55
|
export const format = VmLib(
|
|
47
56
|
(data, format) => {
|
|
48
57
|
required('data', data, '');
|
|
49
|
-
return
|
|
58
|
+
return toFormat(data, expectString('format', format));
|
|
50
59
|
},
|
|
51
60
|
{
|
|
52
61
|
summary: '将数据格式化为指定格式的字符串',
|
|
@@ -1,44 +1,59 @@
|
|
|
1
1
|
import type { Writable } from 'type-fest';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
isVmCallable,
|
|
2
|
+
import { VM_ARRAY_MAX_LENGTH } from '../../helpers/constants.js';
|
|
3
|
+
import { isNaN, entries, fromEntries, isSafeInteger, isFinite } from '../../helpers/utils.js';
|
|
4
|
+
import { toBoolean, toNumber, toString } from '../../helpers/convert.js';
|
|
5
|
+
import { display } from '../../helpers/serialize.js';
|
|
6
|
+
import { isVmArray, isVmFunction, isVmPrimitive, isVmConst, isVmCallable, isVmRecord } from '../../helpers/types.js';
|
|
7
|
+
import { VmError } from '../../helpers/error.js';
|
|
8
|
+
import type {
|
|
9
|
+
VmExtern,
|
|
10
|
+
VmFunction,
|
|
11
|
+
VmAny,
|
|
12
|
+
VmArray,
|
|
13
|
+
VmValue,
|
|
14
|
+
VmRecord,
|
|
15
|
+
VmModule,
|
|
16
|
+
VmConst,
|
|
17
|
+
VmFunctionLike,
|
|
18
|
+
VmFunctionOption,
|
|
20
19
|
} from '../types/index.js';
|
|
21
|
-
import type { VmFunctionLike, VmFunctionOption } from '../types/function.js';
|
|
22
20
|
import { Cp } from '../helpers.js';
|
|
23
|
-
import { isNaN, entries, fromEntries } from '../../helpers/utils.js';
|
|
24
21
|
|
|
25
22
|
/** 抛出异常 */
|
|
26
23
|
export function throwError(message: string, recovered: VmAny | (() => VmAny)): never {
|
|
27
24
|
const recoveredValue = typeof recovered === 'function' && !isVmFunction(recovered) ? recovered() : recovered;
|
|
28
25
|
throw new VmError(message, recoveredValue);
|
|
29
26
|
}
|
|
27
|
+
/** 描述参数 */
|
|
28
|
+
type ParamIndex = number | string | null;
|
|
29
|
+
/** 描述参数 */
|
|
30
|
+
export function describeParam(name: ParamIndex): string {
|
|
31
|
+
if (name == null) return 'Value';
|
|
32
|
+
if (typeof name == 'string') {
|
|
33
|
+
if (!name) return 'Argument';
|
|
34
|
+
return `Argument '${name}'`;
|
|
35
|
+
}
|
|
36
|
+
const pos = name <= 0 ? 'first' : name <= 1 ? 'second' : `${name + 1}th`;
|
|
37
|
+
return `Argument at the ${pos} position`;
|
|
38
|
+
}
|
|
30
39
|
|
|
31
40
|
/** 抛出预期外类型异常 */
|
|
32
41
|
export function throwUnexpectedTypeError(
|
|
33
|
-
name:
|
|
42
|
+
name: ParamIndex,
|
|
43
|
+
expected: string,
|
|
44
|
+
value: VmAny,
|
|
45
|
+
recovered: VmAny | (() => VmAny),
|
|
46
|
+
): never {
|
|
47
|
+
throwError(`${describeParam(name)} is not ${expected}: ${display(value)}`, recovered);
|
|
48
|
+
}
|
|
49
|
+
/** 抛出预期外类型异常 */
|
|
50
|
+
export function throwUnconvertedTypeError(
|
|
51
|
+
name: ParamIndex,
|
|
34
52
|
expected: string,
|
|
35
53
|
value: VmAny,
|
|
36
54
|
recovered: VmAny | (() => VmAny),
|
|
37
55
|
): never {
|
|
38
|
-
|
|
39
|
-
if (typeof name == 'string') throwError(`Expected ${expected} for parameter '${name}', got ${actual}`, recovered);
|
|
40
|
-
const pos = name <= 0 ? 'first' : name <= 1 ? 'second' : name + 1 + 'th';
|
|
41
|
-
throwError(`Expected ${expected} at the ${pos} position, got ${actual}`, recovered);
|
|
56
|
+
throwError(`${describeParam(name)} cannot be converted to ${expected}: ${display(value)}`, recovered);
|
|
42
57
|
}
|
|
43
58
|
|
|
44
59
|
/** 重新抛出异常 */
|
|
@@ -49,20 +64,86 @@ export function rethrowError(prefix: string, error: unknown, recovered: VmAny |
|
|
|
49
64
|
|
|
50
65
|
/** 标记参数为必须项 */
|
|
51
66
|
export function required<const T = VmValue>(
|
|
52
|
-
name:
|
|
67
|
+
name: ParamIndex,
|
|
53
68
|
value: T | undefined,
|
|
54
69
|
recovered: VmAny | (() => VmAny),
|
|
55
70
|
): asserts value is T {
|
|
56
71
|
if (value === undefined) {
|
|
57
|
-
|
|
58
|
-
const pos = name <= 0 ? 'first' : name <= 1 ? 'second' : name + 1 + 'th';
|
|
59
|
-
throwError(`Missing required parameter at the ${pos} position`, recovered);
|
|
72
|
+
throwError(`${describeParam(name)} is required`, recovered);
|
|
60
73
|
}
|
|
61
74
|
}
|
|
62
75
|
|
|
76
|
+
/** 标记并转换参数为数字 */
|
|
77
|
+
export function expectNumber(name: ParamIndex, value: VmAny): number {
|
|
78
|
+
required(name, value, Number.NaN);
|
|
79
|
+
const v = toNumber(value, null);
|
|
80
|
+
if (v == null) {
|
|
81
|
+
throwUnconvertedTypeError(name, 'number', value, Number.NaN);
|
|
82
|
+
}
|
|
83
|
+
return v;
|
|
84
|
+
}
|
|
85
|
+
/** 标记并转换参数为数字 */
|
|
86
|
+
export function expectNumberRange(name: ParamIndex, value: VmAny, min: number, max: number): number {
|
|
87
|
+
const v = expectNumber(name, value);
|
|
88
|
+
if (!isFinite(v)) {
|
|
89
|
+
throwError(`${describeParam(name)} is not a finite number: ${display(value)}`, Number.NaN);
|
|
90
|
+
}
|
|
91
|
+
if (v < min) {
|
|
92
|
+
throwError(`${describeParam(name)} is less than minimum value ${min}: ${display(value)}`, min);
|
|
93
|
+
}
|
|
94
|
+
if (v > max) {
|
|
95
|
+
throwError(`${describeParam(name)} is greater than maximum value ${max}: ${display(value)}`, max);
|
|
96
|
+
}
|
|
97
|
+
return v;
|
|
98
|
+
}
|
|
99
|
+
/** 标记并转换参数为整数 */
|
|
100
|
+
export function expectIntegerRange(name: ParamIndex, value: VmAny, min: number, max: number): number {
|
|
101
|
+
const i = expectInteger(name, value);
|
|
102
|
+
if (i < min) {
|
|
103
|
+
throwError(`${describeParam(name)} is less than minimum value ${min}: ${display(value)}`, min);
|
|
104
|
+
}
|
|
105
|
+
if (i > max) {
|
|
106
|
+
throwError(`${describeParam(name)} is greater than maximum value ${max}: ${display(value)}`, max);
|
|
107
|
+
}
|
|
108
|
+
return i;
|
|
109
|
+
}
|
|
110
|
+
/** 标记并转换参数为整数 */
|
|
111
|
+
export function expectInteger(name: ParamIndex, value: VmAny): number {
|
|
112
|
+
required(name, value, 0);
|
|
113
|
+
const v = toNumber(value, null);
|
|
114
|
+
if (v == null) {
|
|
115
|
+
throwUnconvertedTypeError(name, 'integer', value, 0);
|
|
116
|
+
}
|
|
117
|
+
const i = Math.trunc(v);
|
|
118
|
+
if (!isSafeInteger(i)) {
|
|
119
|
+
throwUnconvertedTypeError(name, 'integer', value, 0);
|
|
120
|
+
}
|
|
121
|
+
return i;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** 标记并转换参数为布尔值 */
|
|
125
|
+
export function expectBoolean(name: ParamIndex, value: VmAny): boolean {
|
|
126
|
+
required(name, value, false);
|
|
127
|
+
const v = toBoolean(value, null);
|
|
128
|
+
if (v == null) {
|
|
129
|
+
throwUnconvertedTypeError(name, 'boolean', value, false);
|
|
130
|
+
}
|
|
131
|
+
return v;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** 标记并转换参数为字符串 */
|
|
135
|
+
export function expectString(name: ParamIndex, value: VmAny): string {
|
|
136
|
+
required(name, value, '');
|
|
137
|
+
const v = toString(value, null);
|
|
138
|
+
if (v == null) {
|
|
139
|
+
throwUnconvertedTypeError(name, 'string', value, '');
|
|
140
|
+
}
|
|
141
|
+
return v;
|
|
142
|
+
}
|
|
143
|
+
|
|
63
144
|
/** 标记参数为数组 */
|
|
64
145
|
export function expectArray(
|
|
65
|
-
name:
|
|
146
|
+
name: ParamIndex,
|
|
66
147
|
value: VmAny,
|
|
67
148
|
recovered: VmAny | (() => VmAny),
|
|
68
149
|
): asserts value is VmArray {
|
|
@@ -74,7 +155,7 @@ export function expectArray(
|
|
|
74
155
|
|
|
75
156
|
/** 标记参数为记录 */
|
|
76
157
|
export function expectRecord(
|
|
77
|
-
name:
|
|
158
|
+
name: ParamIndex,
|
|
78
159
|
value: VmAny,
|
|
79
160
|
recovered: VmAny | (() => VmAny),
|
|
80
161
|
): asserts value is VmRecord {
|
|
@@ -86,7 +167,7 @@ export function expectRecord(
|
|
|
86
167
|
|
|
87
168
|
/** 标记参数为数组或记录 */
|
|
88
169
|
export function expectArrayOrRecord(
|
|
89
|
-
name:
|
|
170
|
+
name: ParamIndex,
|
|
90
171
|
value: VmAny,
|
|
91
172
|
recovered: VmAny | (() => VmAny),
|
|
92
173
|
): asserts value is VmArray | VmRecord {
|
|
@@ -98,7 +179,7 @@ export function expectArrayOrRecord(
|
|
|
98
179
|
|
|
99
180
|
/** 标记参数为复合类型 */
|
|
100
181
|
export function expectCompound(
|
|
101
|
-
name:
|
|
182
|
+
name: ParamIndex,
|
|
102
183
|
value: VmAny,
|
|
103
184
|
recovered: VmAny | (() => VmAny),
|
|
104
185
|
): asserts value is VmArray | VmRecord | VmModule | VmExtern {
|
|
@@ -110,7 +191,7 @@ export function expectCompound(
|
|
|
110
191
|
|
|
111
192
|
/** 标记参数为常量 */
|
|
112
193
|
export function expectConst(
|
|
113
|
-
name:
|
|
194
|
+
name: ParamIndex,
|
|
114
195
|
value: VmAny,
|
|
115
196
|
recovered: VmAny | (() => VmAny),
|
|
116
197
|
): asserts value is VmConst {
|
|
@@ -122,7 +203,7 @@ export function expectConst(
|
|
|
122
203
|
|
|
123
204
|
/** 标记为可调用 */
|
|
124
205
|
export function expectCallable(
|
|
125
|
-
name:
|
|
206
|
+
name: ParamIndex,
|
|
126
207
|
value: VmAny,
|
|
127
208
|
recovered: VmAny | (() => VmAny),
|
|
128
209
|
): asserts value is VmFunction | VmExtern {
|
|
@@ -135,20 +216,27 @@ export function expectCallable(
|
|
|
135
216
|
/** Get numbers from the arguments. */
|
|
136
217
|
export function getNumbers(args: readonly VmAny[]): number[] {
|
|
137
218
|
if (args.length === 0) return [];
|
|
138
|
-
|
|
219
|
+
let useFirst = false;
|
|
220
|
+
if (args.length === 1 && isVmArray(args[0])) {
|
|
221
|
+
args = args[0];
|
|
222
|
+
useFirst = true;
|
|
223
|
+
}
|
|
139
224
|
const numbers: number[] = [];
|
|
140
|
-
for (
|
|
141
|
-
|
|
142
|
-
numbers.push($ToNumber(arg));
|
|
225
|
+
for (let len = args.length, i = 0; i < len; i++) {
|
|
226
|
+
numbers.push(expectNumber(useFirst ? null : i, args[i]));
|
|
143
227
|
}
|
|
144
228
|
return numbers;
|
|
145
229
|
}
|
|
146
230
|
|
|
147
231
|
/** 将值转为数组长度 */
|
|
148
232
|
export function arrayLen(len: number | null | undefined): number {
|
|
149
|
-
if (len == null || isNaN(len) || len <=
|
|
233
|
+
if (len == null || isNaN(len) || len <= -1) {
|
|
234
|
+
throwError('Array length must be a non-negative integer', null);
|
|
235
|
+
}
|
|
150
236
|
len = Math.trunc(len);
|
|
151
|
-
if (len > VM_ARRAY_MAX_LENGTH)
|
|
237
|
+
if (len > VM_ARRAY_MAX_LENGTH) {
|
|
238
|
+
throwError(`Array length exceeds maximum limit of ${VM_ARRAY_MAX_LENGTH}`, null);
|
|
239
|
+
}
|
|
152
240
|
return len;
|
|
153
241
|
}
|
|
154
242
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as global from './global/index.js';
|
|
2
|
+
import * as mods from './mod/index.js';
|
|
3
|
+
import { VmSharedContext } from '../types/context.js';
|
|
4
|
+
import { create, entries } from '../../helpers/utils.js';
|
|
5
|
+
import { createModule, wrapEntry, type RawValue } from './loader.js';
|
|
6
|
+
|
|
7
|
+
for (const [name, value] of entries(global)) {
|
|
8
|
+
VmSharedContext[name] = wrapEntry(name, value as RawValue, 'global');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
for (const [name, value] of entries(mods)) {
|
|
12
|
+
const mod = createModule(name, value as Record<string, RawValue>);
|
|
13
|
+
VmSharedContext[name] = wrapEntry(name, mod, 'global');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const lib = Object.freeze(Object.assign(create(null), global, mods));
|
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
import { VmFunction, VmModule, type VmConst, type VmFunctionLike, type VmImmutable } from '../types/index.js';
|
|
2
2
|
import { create, defineProperty, entries } from '../../helpers/utils.js';
|
|
3
|
-
import { VmSharedContext } from '../types/context.js';
|
|
4
3
|
|
|
5
|
-
import type { VmLib, VmLibOption } from './
|
|
6
|
-
import * as global from './global/index.js';
|
|
7
|
-
|
|
8
|
-
for (const [name, value] of entries(global)) {
|
|
9
|
-
VmSharedContext[name] = wrapEntry(name, value as RawValue, 'global');
|
|
10
|
-
}
|
|
4
|
+
import type { VmLib, VmLibOption } from './helpers.js';
|
|
11
5
|
|
|
12
6
|
/** 原始值 */
|
|
13
|
-
type RawValue = VmLib | VmConst | VmModule;
|
|
7
|
+
export type RawValue = VmLib | VmConst | VmModule;
|
|
14
8
|
/** 包装值 */
|
|
15
9
|
type ToWrappedValue<V extends RawValue> = V extends VmFunctionLike ? VmFunction<V> : V;
|
|
16
10
|
/** 包装值 */
|
|
17
|
-
function wrapEntry<const T extends RawValue>(name: string, value: T, module: string): ToWrappedValue<T> {
|
|
11
|
+
export function wrapEntry<const T extends RawValue>(name: string, value: T, module: string): ToWrappedValue<T> {
|
|
18
12
|
if (typeof value == 'function') {
|
|
19
13
|
if (value.name !== name) {
|
|
20
14
|
// 如果函数名和导出名不一致,则重命名
|
|
@@ -47,5 +41,3 @@ export function createModule<const T extends Record<string, RawValue>>(name: str
|
|
|
47
41
|
}
|
|
48
42
|
return new VmModule(name, mod) as ToWrappedModule<T>;
|
|
49
43
|
}
|
|
50
|
-
|
|
51
|
-
export const lib = global;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * as matrix from './matrix.js';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { toNumber } from '../../../helpers/convert.js';
|
|
2
|
+
import { isArray } from '../../../helpers/utils.js';
|
|
3
|
+
import { Cp } from '../../helpers.js';
|
|
4
|
+
import { $Add, $Call, $Div, $Mul, $Sub } from '../../operations.js';
|
|
5
|
+
import { isVmArray, isVmConst, type VmAny, type VmArray, type VmConst, type VmValue } from '../../types/index.js';
|
|
5
6
|
import {
|
|
6
7
|
VmLib,
|
|
7
8
|
expectArray,
|
|
@@ -12,7 +13,8 @@ import {
|
|
|
12
13
|
getNumbers,
|
|
13
14
|
arrayLen,
|
|
14
15
|
map,
|
|
15
|
-
|
|
16
|
+
expectInteger,
|
|
17
|
+
} from '../helpers.js';
|
|
16
18
|
|
|
17
19
|
/** 计算尺寸 */
|
|
18
20
|
function sizeImpl(matrix: VmValue): [] | [number] | [number, number] {
|
|
@@ -35,7 +37,7 @@ function sizeImpl(matrix: VmValue): [] | [number] | [number, number] {
|
|
|
35
37
|
|
|
36
38
|
/** 数组元素转为 number */
|
|
37
39
|
function num(v: VmConst | undefined): number {
|
|
38
|
-
return
|
|
40
|
+
return toNumber(v, undefined);
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
export const size = VmLib(
|
|
@@ -535,7 +537,7 @@ export const identity = VmLib(
|
|
|
535
537
|
export const diagonal = VmLib(
|
|
536
538
|
(x, k = 0) => {
|
|
537
539
|
expectArray('x', x, []);
|
|
538
|
-
const fk =
|
|
540
|
+
const fk = expectInteger('k', k);
|
|
539
541
|
if (x.every((e) => isArray(e))) {
|
|
540
542
|
// 获取对角线元素
|
|
541
543
|
const diag: VmConst[] = [];
|