@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.
Files changed (216) hide show
  1. package/dist/{chunk-NT235HY3.js → chunk-LU4ZKFF6.js} +1411 -608
  2. package/dist/chunk-LU4ZKFF6.js.map +6 -0
  3. package/dist/chunk-RIT53WVY.js +1 -0
  4. package/dist/chunk-RLWIIOH5.js +12 -0
  5. package/dist/chunk-RLWIIOH5.js.map +6 -0
  6. package/dist/{chunk-JVFUK7AN.js → chunk-YZGL3D7L.js} +739 -1366
  7. package/dist/chunk-YZGL3D7L.js.map +6 -0
  8. package/dist/cli/index.js +11 -67
  9. package/dist/cli/index.js.map +2 -2
  10. package/dist/compiler/compile-fast.d.ts +1 -1
  11. package/dist/compiler/compile-fast.d.ts.map +1 -1
  12. package/dist/compiler/create-script.d.ts +10 -1
  13. package/dist/compiler/create-script.d.ts.map +1 -1
  14. package/dist/compiler/diagnostic.d.ts +1 -1
  15. package/dist/compiler/diagnostic.d.ts.map +1 -1
  16. package/dist/compiler/emit/constants.d.ts +3 -0
  17. package/dist/compiler/emit/constants.d.ts.map +1 -0
  18. package/dist/compiler/emit/consts.d.ts +6 -0
  19. package/dist/compiler/emit/consts.d.ts.map +1 -0
  20. package/dist/compiler/emit/globals.d.ts +17 -0
  21. package/dist/compiler/emit/globals.d.ts.map +1 -0
  22. package/dist/compiler/emit/index.d.ts +58 -0
  23. package/dist/compiler/emit/index.d.ts.map +1 -0
  24. package/dist/compiler/emit/sourcemap.d.ts +6 -0
  25. package/dist/compiler/emit/sourcemap.d.ts.map +1 -0
  26. package/dist/compiler/index.d.ts +3 -2
  27. package/dist/compiler/index.d.ts.map +1 -1
  28. package/dist/compiler/worker.js +1 -1
  29. package/dist/helpers/constants.d.ts +10 -0
  30. package/dist/helpers/constants.d.ts.map +1 -1
  31. package/dist/helpers/convert.d.ts +12 -0
  32. package/dist/helpers/convert.d.ts.map +1 -0
  33. package/dist/{vm → helpers}/error.d.ts +1 -1
  34. package/dist/helpers/error.d.ts.map +1 -0
  35. package/dist/helpers/serialize.d.ts +13 -4
  36. package/dist/helpers/serialize.d.ts.map +1 -1
  37. package/dist/helpers/types.d.ts +54 -0
  38. package/dist/helpers/types.d.ts.map +1 -0
  39. package/dist/index.js +11 -17
  40. package/dist/subtle.d.ts +3 -2
  41. package/dist/subtle.d.ts.map +1 -1
  42. package/dist/subtle.js +21 -15
  43. package/dist/vm/checkpoint.d.ts +9 -0
  44. package/dist/vm/checkpoint.d.ts.map +1 -0
  45. package/dist/vm/helpers.d.ts +4 -10
  46. package/dist/vm/helpers.d.ts.map +1 -1
  47. package/dist/vm/index.d.ts +3 -3
  48. package/dist/vm/index.d.ts.map +1 -1
  49. package/dist/vm/lib/global/bit.d.ts +7 -7
  50. package/dist/vm/lib/global/bit.d.ts.map +1 -1
  51. package/dist/vm/lib/global/debug.d.ts +2 -2
  52. package/dist/vm/lib/global/debug.d.ts.map +1 -1
  53. package/dist/vm/lib/global/index.d.ts +0 -1
  54. package/dist/vm/lib/global/index.d.ts.map +1 -1
  55. package/dist/vm/lib/global/json.d.ts +2 -2
  56. package/dist/vm/lib/global/json.d.ts.map +1 -1
  57. package/dist/vm/lib/global/math-additional.d.ts +1 -1
  58. package/dist/vm/lib/global/math-additional.d.ts.map +1 -1
  59. package/dist/vm/lib/global/math-arr.d.ts +5 -5
  60. package/dist/vm/lib/global/math-arr.d.ts.map +1 -1
  61. package/dist/vm/lib/global/math-unary.d.ts +26 -26
  62. package/dist/vm/lib/global/math-unary.d.ts.map +1 -1
  63. package/dist/vm/lib/global/math.d.ts +3 -3
  64. package/dist/vm/lib/global/math.d.ts.map +1 -1
  65. package/dist/vm/lib/global/sequence/all-any.d.ts +2 -2
  66. package/dist/vm/lib/global/sequence/all-any.d.ts.map +1 -1
  67. package/dist/vm/lib/global/sequence/entries.d.ts +5 -5
  68. package/dist/vm/lib/global/sequence/entries.d.ts.map +1 -1
  69. package/dist/vm/lib/global/sequence/find.d.ts +3 -3
  70. package/dist/vm/lib/global/sequence/find.d.ts.map +1 -1
  71. package/dist/vm/lib/global/sequence/flatten.d.ts +1 -1
  72. package/dist/vm/lib/global/sequence/flatten.d.ts.map +1 -1
  73. package/dist/vm/lib/global/sequence/len.d.ts +1 -1
  74. package/dist/vm/lib/global/sequence/len.d.ts.map +1 -1
  75. package/dist/vm/lib/global/sequence/map-filter.d.ts +3 -3
  76. package/dist/vm/lib/global/sequence/map-filter.d.ts.map +1 -1
  77. package/dist/vm/lib/global/sequence/repeat.d.ts +1 -1
  78. package/dist/vm/lib/global/sequence/repeat.d.ts.map +1 -1
  79. package/dist/vm/lib/global/sequence/reverse.d.ts +1 -1
  80. package/dist/vm/lib/global/sequence/reverse.d.ts.map +1 -1
  81. package/dist/vm/lib/global/sequence/sort.d.ts +2 -2
  82. package/dist/vm/lib/global/sequence/sort.d.ts.map +1 -1
  83. package/dist/vm/lib/global/sequence/with.d.ts +2 -2
  84. package/dist/vm/lib/global/sequence/with.d.ts.map +1 -1
  85. package/dist/vm/lib/global/sequence/zip.d.ts +1 -1
  86. package/dist/vm/lib/global/sequence/zip.d.ts.map +1 -1
  87. package/dist/vm/lib/global/string.d.ts +10 -10
  88. package/dist/vm/lib/global/string.d.ts.map +1 -1
  89. package/dist/vm/lib/global/time.d.ts +3 -13
  90. package/dist/vm/lib/global/time.d.ts.map +1 -1
  91. package/dist/vm/lib/global/to-primitive.d.ts +4 -4
  92. package/dist/vm/lib/global/to-primitive.d.ts.map +1 -1
  93. package/dist/vm/lib/helpers.d.ts +53 -0
  94. package/dist/vm/lib/helpers.d.ts.map +1 -0
  95. package/dist/vm/lib/index.d.ts +4 -0
  96. package/dist/vm/lib/index.d.ts.map +1 -0
  97. package/dist/vm/lib/{_loader.d.ts → loader.d.ts} +5 -5
  98. package/dist/vm/lib/loader.d.ts.map +1 -0
  99. package/dist/vm/lib/mod/index.d.ts +2 -0
  100. package/dist/vm/lib/mod/index.d.ts.map +1 -0
  101. package/dist/vm/lib/mod/matrix.d.ts +15 -0
  102. package/dist/vm/lib/mod/matrix.d.ts.map +1 -0
  103. package/dist/vm/operations.d.ts +2 -4
  104. package/dist/vm/operations.d.ts.map +1 -1
  105. package/dist/vm/types/boundary.d.ts +1 -1
  106. package/dist/vm/types/boundary.d.ts.map +1 -1
  107. package/dist/vm/types/context.d.ts +10 -9
  108. package/dist/vm/types/context.d.ts.map +1 -1
  109. package/dist/vm/types/extern.d.ts +1 -3
  110. package/dist/vm/types/extern.d.ts.map +1 -1
  111. package/dist/vm/types/function.d.ts +1 -6
  112. package/dist/vm/types/function.d.ts.map +1 -1
  113. package/dist/vm/types/index.d.ts +31 -17
  114. package/dist/vm/types/index.d.ts.map +1 -1
  115. package/dist/vm/types/module.d.ts +2 -4
  116. package/dist/vm/types/module.d.ts.map +1 -1
  117. package/dist/vm/types/wrapper.d.ts +0 -2
  118. package/dist/vm/types/wrapper.d.ts.map +1 -1
  119. package/package.json +7 -3
  120. package/src/cli/index.ts +1 -1
  121. package/src/compiler/compile-fast.ts +1 -2
  122. package/src/compiler/create-script.ts +12 -2
  123. package/src/compiler/diagnostic.ts +17 -8
  124. package/src/compiler/emit/constants.ts +2 -0
  125. package/src/compiler/emit/consts.ts +47 -0
  126. package/src/compiler/emit/globals.ts +39 -0
  127. package/src/compiler/{emit.ts → emit/index.ts} +16 -200
  128. package/src/compiler/emit/sourcemap.ts +163 -0
  129. package/src/compiler/index.ts +9 -9
  130. package/src/compiler/worker.ts +1 -1
  131. package/src/helpers/constants.ts +12 -0
  132. package/src/helpers/convert.ts +128 -0
  133. package/src/{vm → helpers}/error.ts +1 -1
  134. package/src/helpers/serialize.ts +71 -24
  135. package/src/helpers/types.ts +267 -0
  136. package/src/subtle.ts +3 -1
  137. package/src/vm/checkpoint.ts +42 -0
  138. package/src/vm/helpers.ts +9 -53
  139. package/src/vm/index.ts +3 -3
  140. package/src/vm/lib/global/bit.ts +8 -9
  141. package/src/vm/lib/global/debug.ts +5 -4
  142. package/src/vm/lib/global/index.ts +0 -1
  143. package/src/vm/lib/global/json.ts +2 -2
  144. package/src/vm/lib/global/math-additional.ts +2 -4
  145. package/src/vm/lib/global/math-arr.ts +1 -1
  146. package/src/vm/lib/global/math-unary.ts +2 -4
  147. package/src/vm/lib/global/math.ts +3 -4
  148. package/src/vm/lib/global/sequence/all-any.ts +11 -6
  149. package/src/vm/lib/global/sequence/entries.ts +1 -1
  150. package/src/vm/lib/global/sequence/find.ts +4 -3
  151. package/src/vm/lib/global/sequence/flatten.ts +2 -3
  152. package/src/vm/lib/global/sequence/len.ts +1 -1
  153. package/src/vm/lib/global/sequence/map-filter.ts +4 -3
  154. package/src/vm/lib/global/sequence/repeat.ts +2 -4
  155. package/src/vm/lib/global/sequence/reverse.ts +1 -1
  156. package/src/vm/lib/global/sequence/sort.ts +6 -5
  157. package/src/vm/lib/global/sequence/with.ts +21 -20
  158. package/src/vm/lib/global/sequence/zip.ts +3 -3
  159. package/src/vm/lib/global/string.ts +16 -27
  160. package/src/vm/lib/global/time.ts +59 -30
  161. package/src/vm/lib/global/to-primitive.ts +27 -18
  162. package/src/vm/lib/{_helpers.ts → helpers.ts} +129 -41
  163. package/src/vm/lib/index.ts +16 -0
  164. package/src/vm/lib/{_loader.ts → loader.ts} +3 -11
  165. package/src/vm/lib/mod/index.ts +1 -0
  166. package/src/vm/lib/{global/mod → mod}/matrix.ts +9 -7
  167. package/src/vm/operations.ts +31 -126
  168. package/src/vm/types/boundary.ts +10 -13
  169. package/src/vm/types/context.ts +17 -24
  170. package/src/vm/types/extern.ts +8 -15
  171. package/src/vm/types/function.ts +4 -19
  172. package/src/vm/types/index.ts +47 -25
  173. package/src/vm/types/module.ts +3 -7
  174. package/src/vm/types/wrapper.ts +1 -5
  175. package/dist/chunk-35JGBXRE.js +0 -1
  176. package/dist/chunk-JVFUK7AN.js.map +0 -6
  177. package/dist/chunk-NT235HY3.js.map +0 -6
  178. package/dist/compiler/emit.d.ts +0 -5
  179. package/dist/compiler/emit.d.ts.map +0 -1
  180. package/dist/vm/error.d.ts.map +0 -1
  181. package/dist/vm/lib/_helpers.d.ts +0 -35
  182. package/dist/vm/lib/_helpers.d.ts.map +0 -1
  183. package/dist/vm/lib/_loader.d.ts.map +0 -1
  184. package/dist/vm/lib/global/mod/index.d.ts +0 -3
  185. package/dist/vm/lib/global/mod/index.d.ts.map +0 -1
  186. package/dist/vm/lib/global/mod/matrix.d.ts +0 -15
  187. package/dist/vm/lib/global/mod/matrix.d.ts.map +0 -1
  188. package/dist/vm/types/any.d.ts +0 -10
  189. package/dist/vm/types/any.d.ts.map +0 -1
  190. package/dist/vm/types/array.d.ts +0 -12
  191. package/dist/vm/types/array.d.ts.map +0 -1
  192. package/dist/vm/types/callable.d.ts +0 -5
  193. package/dist/vm/types/callable.d.ts.map +0 -1
  194. package/dist/vm/types/const.d.ts +0 -15
  195. package/dist/vm/types/const.d.ts.map +0 -1
  196. package/dist/vm/types/immutable.d.ts +0 -15
  197. package/dist/vm/types/immutable.d.ts.map +0 -1
  198. package/dist/vm/types/primitive.d.ts +0 -7
  199. package/dist/vm/types/primitive.d.ts.map +0 -1
  200. package/dist/vm/types/record.d.ts +0 -20
  201. package/dist/vm/types/record.d.ts.map +0 -1
  202. package/dist/vm/types/script.d.ts +0 -14
  203. package/dist/vm/types/script.d.ts.map +0 -1
  204. package/dist/vm/types/value.d.ts +0 -14
  205. package/dist/vm/types/value.d.ts.map +0 -1
  206. package/src/vm/lib/global/mod/index.ts +0 -4
  207. package/src/vm/types/any.ts +0 -33
  208. package/src/vm/types/array.ts +0 -19
  209. package/src/vm/types/callable.ts +0 -10
  210. package/src/vm/types/const.ts +0 -109
  211. package/src/vm/types/immutable.ts +0 -22
  212. package/src/vm/types/primitive.ts +0 -14
  213. package/src/vm/types/record.ts +0 -53
  214. package/src/vm/types/script.ts +0 -18
  215. package/src/vm/types/value.ts +0 -22
  216. /package/dist/{chunk-35JGBXRE.js.map → chunk-RIT53WVY.js.map} +0 -0
@@ -1,35 +1,60 @@
1
- import { $ToString, $ToNumber } from '../../operations.js';
2
- import { VmLib } from '../_helpers.js';
3
- import { isFinite } from '../../../helpers/utils.js';
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
- if (datetime == null) {
8
- return Date.now();
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: { datetime: '要转换的数据,默认为当前时间' },
22
- paramsType: { datetime: 'number | string' },
23
- returnsType: 'number',
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 = to_timestamp(datetime);
31
- if (!isFinite(timestamp)) return null;
32
- const o = $ToNumber(offset ?? 0) || 0;
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 = to_timestamp(datetime);
70
- if (!isFinite(timestamp)) return null;
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: { datetime: '要转换的数据,默认为当前时间' },
76
- paramsType: { datetime: 'number | string' },
77
- returnsType: 'string',
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 { $ToString, $ToNumber, $ToBoolean, $Format } from '../../operations.js';
2
- import { required, VmLib } from '../_helpers.js';
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 $ToString(data);
7
+ return toString(data, fallback);
8
8
  },
9
9
  {
10
10
  summary: '将数据转换为字符串',
11
- params: { data: '要转换的数据' },
12
- paramsType: { data: 'any' },
13
- returnsType: 'string',
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 $ToNumber(data);
24
+ return toNumber(data, fallback);
22
25
  },
23
26
  {
24
27
  summary: '将数据转换为数字',
25
- params: { data: '要转换的数据' },
26
- paramsType: { data: 'any' },
27
- returnsType: 'number',
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 $ToBoolean(data);
41
+ return toBoolean(data, fallback);
36
42
  },
37
43
  {
38
44
  summary: '将数据转换为布尔值',
39
- params: { data: '要转换的数据' },
40
- paramsType: { data: 'any' },
41
- returnsType: 'boolean',
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 $Format(data, format);
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 { VmError } from '../error.js';
3
- import { $ToNumber, $Type } from '../operations.js';
4
- import {
5
- isVmArray,
6
- isVmFunction,
7
- type VmExtern,
8
- type VmFunction,
9
- type VmAny,
10
- type VmArray,
11
- type VmValue,
12
- isVmRecord,
13
- type VmRecord,
14
- type VmModule,
15
- isVmPrimitive,
16
- type VmConst,
17
- isVmConst,
18
- VM_ARRAY_MAX_LENGTH,
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: number | string,
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
- const actual = $Type(value);
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: number | string,
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
- if (typeof name == 'string') throwError(`Missing required parameter '${name}'`, recovered);
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: number | string,
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: number | string,
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: number | string,
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: number | string,
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: number | string,
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: number | string,
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
- if (args.length === 1 && isVmArray(args[0])) args = args[0];
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 (const arg of args) {
141
- if (arg == null) continue;
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 <= 0) return 0;
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) throwError(`Array length exceeds maximum limit of ${VM_ARRAY_MAX_LENGTH}`, null);
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 './_helpers.js';
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 { isArray } from '../../../../helpers/utils.js';
2
- import { Cp } from '../../../helpers.js';
3
- import { $Add, $Call, $Div, $Mul, $Sub, $ToNumber } from '../../../operations.js';
4
- import { isVmArray, isVmConst, type VmAny, type VmArray, type VmConst, type VmValue } from '../../../types/index.js';
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
- } from '../../_helpers.js';
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 $ToNumber(v ?? null);
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 = Math.round($ToNumber(k) || 0);
540
+ const fk = expectInteger('k', k);
539
541
  if (x.every((e) => isArray(e))) {
540
542
  // 获取对角线元素
541
543
  const diag: VmConst[] = [];