@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.
Files changed (152) hide show
  1. package/dist/{chunk-VNQQF2W7.js → chunk-BPFOJ4Q6.js} +381 -432
  2. package/dist/chunk-BPFOJ4Q6.js.map +6 -0
  3. package/dist/{chunk-BITOQYYQ.js → chunk-LSPCAN32.js} +204 -149
  4. package/dist/chunk-LSPCAN32.js.map +6 -0
  5. package/dist/compiler/emit/constants.d.ts +1 -1
  6. package/dist/compiler/emit/constants.d.ts.map +1 -1
  7. package/dist/compiler/emit/consts.d.ts.map +1 -1
  8. package/dist/compiler/worker.js +1 -1
  9. package/dist/helpers/convert/{to-boolean.d.ts → boolean.d.ts} +1 -1
  10. package/dist/helpers/convert/boolean.d.ts.map +1 -0
  11. package/dist/helpers/convert/{to-format.d.ts → format.d.ts} +1 -1
  12. package/dist/helpers/convert/format.d.ts.map +1 -0
  13. package/dist/helpers/convert/index.d.ts +4 -4
  14. package/dist/helpers/convert/index.d.ts.map +1 -1
  15. package/dist/helpers/convert/{to-number.d.ts → number.d.ts} +1 -1
  16. package/dist/helpers/convert/number.d.ts.map +1 -0
  17. package/dist/helpers/convert/{to-string.d.ts → string.d.ts} +1 -1
  18. package/dist/helpers/convert/string.d.ts.map +1 -0
  19. package/dist/helpers/serialize.d.ts.map +1 -1
  20. package/dist/helpers/types/array-like.d.ts +8 -0
  21. package/dist/helpers/types/array-like.d.ts.map +1 -0
  22. package/dist/helpers/types/basic.d.ts +26 -0
  23. package/dist/helpers/types/basic.d.ts.map +1 -0
  24. package/dist/helpers/types/composed.d.ts +12 -0
  25. package/dist/helpers/types/composed.d.ts.map +1 -0
  26. package/dist/helpers/types/const.d.ts +6 -0
  27. package/dist/helpers/types/const.d.ts.map +1 -0
  28. package/dist/helpers/types/get-type.d.ts +6 -0
  29. package/dist/helpers/types/get-type.d.ts.map +1 -0
  30. package/dist/helpers/types/index.d.ts +6 -0
  31. package/dist/helpers/types/index.d.ts.map +1 -0
  32. package/dist/helpers/types/proto.d.ts +5 -0
  33. package/dist/helpers/types/proto.d.ts.map +1 -0
  34. package/dist/helpers/utils.d.ts.map +1 -1
  35. package/dist/index.js +2 -2
  36. package/dist/subtle.js +3 -3
  37. package/dist/vm/lib/global/json.d.ts +1 -1
  38. package/dist/vm/lib/global/json.d.ts.map +1 -1
  39. package/dist/vm/lib/helpers.d.ts.map +1 -1
  40. package/dist/vm/lib/mod/index.d.ts +1 -1
  41. package/dist/vm/lib/mod/index.d.ts.map +1 -1
  42. package/dist/vm/lib/mod/matrix/bin-ops.d.ts +8 -0
  43. package/dist/vm/lib/mod/matrix/bin-ops.d.ts.map +1 -0
  44. package/dist/vm/lib/mod/matrix/fill.d.ts +6 -0
  45. package/dist/vm/lib/mod/matrix/fill.d.ts.map +1 -0
  46. package/dist/vm/lib/mod/matrix/helpers.d.ts +6 -0
  47. package/dist/vm/lib/mod/matrix/helpers.d.ts.map +1 -0
  48. package/dist/vm/lib/mod/matrix/index.d.ts +6 -0
  49. package/dist/vm/lib/mod/matrix/index.d.ts.map +1 -0
  50. package/dist/vm/lib/mod/matrix/invert.d.ts +3 -0
  51. package/dist/vm/lib/mod/matrix/invert.d.ts.map +1 -0
  52. package/dist/vm/lib/mod/matrix/size.d.ts +2 -0
  53. package/dist/vm/lib/mod/matrix/size.d.ts.map +1 -0
  54. package/dist/vm/lib/mod/matrix/transpose.d.ts +2 -0
  55. package/dist/vm/lib/mod/matrix/transpose.d.ts.map +1 -0
  56. package/dist/vm/operations/array-range.d.ts +3 -3
  57. package/dist/vm/operations/array-range.d.ts.map +1 -1
  58. package/dist/vm/operations/call.d.ts +1 -1
  59. package/dist/vm/operations/call.d.ts.map +1 -1
  60. package/dist/vm/operations/compound.d.ts +1 -13
  61. package/dist/vm/operations/compound.d.ts.map +1 -1
  62. package/dist/vm/operations/index.d.ts +3 -0
  63. package/dist/vm/operations/index.d.ts.map +1 -1
  64. package/dist/vm/operations/iterable.d.ts +6 -0
  65. package/dist/vm/operations/iterable.d.ts.map +1 -0
  66. package/dist/vm/operations/record.d.ts +6 -0
  67. package/dist/vm/operations/record.d.ts.map +1 -0
  68. package/dist/vm/operations/slice.d.ts.map +1 -1
  69. package/dist/vm/operations/spread.d.ts +6 -0
  70. package/dist/vm/operations/spread.d.ts.map +1 -0
  71. package/dist/vm/operations/utils.d.ts.map +1 -1
  72. package/dist/vm/types/extern/access.d.ts +5 -0
  73. package/dist/vm/types/extern/access.d.ts.map +1 -0
  74. package/dist/vm/types/{extern.d.ts → extern/index.d.ts} +3 -3
  75. package/dist/vm/types/extern/index.d.ts.map +1 -0
  76. package/dist/vm/types/extern/tag.d.ts +3 -0
  77. package/dist/vm/types/extern/tag.d.ts.map +1 -0
  78. package/dist/vm/types/extern/utils.d.ts +13 -0
  79. package/dist/vm/types/extern/utils.d.ts.map +1 -0
  80. package/dist/vm/types/index.d.ts +3 -3
  81. package/dist/vm/types/index.d.ts.map +1 -1
  82. package/package.json +4 -4
  83. package/src/compiler/diagnostic.ts +2 -2
  84. package/src/compiler/emit/constants.ts +1 -1
  85. package/src/compiler/emit/consts.ts +0 -1
  86. package/src/compiler/emit/index.ts +1 -1
  87. package/src/compiler/emit/sourcemap.ts +1 -1
  88. package/src/compiler/load-module.ts +5 -1
  89. package/src/helpers/convert/{to-boolean.ts → boolean.ts} +1 -1
  90. package/src/helpers/convert/{to-format.ts → format.ts} +1 -1
  91. package/src/helpers/convert/index.ts +4 -4
  92. package/src/helpers/convert/{to-number.ts → number.ts} +15 -26
  93. package/src/helpers/convert/{to-string.ts → string.ts} +2 -2
  94. package/src/helpers/serialize.ts +42 -36
  95. package/src/helpers/types/array-like.ts +32 -0
  96. package/src/helpers/types/basic.ts +82 -0
  97. package/src/helpers/types/composed.ts +27 -0
  98. package/src/helpers/types/const.ts +44 -0
  99. package/src/helpers/types/get-type.ts +16 -0
  100. package/src/helpers/types/index.ts +5 -0
  101. package/src/helpers/types/proto.ts +21 -0
  102. package/src/helpers/utils.ts +7 -1
  103. package/src/vm/lib/global/sequence/all-any.ts +1 -1
  104. package/src/vm/lib/global/sequence/find.ts +1 -1
  105. package/src/vm/lib/global/sequence/group.ts +1 -1
  106. package/src/vm/lib/global/sequence/map-filter.ts +1 -1
  107. package/src/vm/lib/global/sequence/new.ts +1 -1
  108. package/src/vm/lib/global/sequence/sort.ts +1 -1
  109. package/src/vm/lib/global/sequence/unique.ts +1 -1
  110. package/src/vm/lib/global/sequence/with.ts +1 -1
  111. package/src/vm/lib/global/time.ts +1 -1
  112. package/src/vm/lib/helpers.ts +8 -1
  113. package/src/vm/lib/mod/index.ts +1 -1
  114. package/src/vm/lib/mod/matrix/bin-ops.ts +291 -0
  115. package/src/vm/lib/mod/matrix/fill.ts +109 -0
  116. package/src/vm/lib/mod/matrix/helpers.ts +26 -0
  117. package/src/vm/lib/mod/matrix/index.ts +5 -0
  118. package/src/vm/lib/mod/matrix/invert.ts +122 -0
  119. package/src/vm/lib/mod/matrix/size.ts +15 -0
  120. package/src/vm/lib/mod/matrix/transpose.ts +32 -0
  121. package/src/vm/operations/array-range.ts +15 -27
  122. package/src/vm/operations/call.ts +2 -2
  123. package/src/vm/operations/compound.ts +4 -131
  124. package/src/vm/operations/helpers.ts +1 -1
  125. package/src/vm/operations/index.ts +3 -0
  126. package/src/vm/operations/iterable.ts +40 -0
  127. package/src/vm/operations/record.ts +33 -0
  128. package/src/vm/operations/slice.ts +23 -22
  129. package/src/vm/operations/spread.ts +57 -0
  130. package/src/vm/operations/type-check.ts +1 -1
  131. package/src/vm/operations/utils.ts +45 -37
  132. package/src/vm/types/boundary.ts +2 -2
  133. package/src/vm/types/extern/access.ts +24 -0
  134. package/src/vm/types/extern/index.ts +124 -0
  135. package/src/vm/types/extern/tag.ts +58 -0
  136. package/src/vm/types/extern/utils.ts +55 -0
  137. package/src/vm/types/function.ts +1 -1
  138. package/src/vm/types/index.ts +3 -3
  139. package/dist/chunk-BITOQYYQ.js.map +0 -6
  140. package/dist/chunk-VNQQF2W7.js.map +0 -6
  141. package/dist/helpers/convert/to-boolean.d.ts.map +0 -1
  142. package/dist/helpers/convert/to-format.d.ts.map +0 -1
  143. package/dist/helpers/convert/to-number.d.ts.map +0 -1
  144. package/dist/helpers/convert/to-string.d.ts.map +0 -1
  145. package/dist/helpers/types.d.ts +0 -58
  146. package/dist/helpers/types.d.ts.map +0 -1
  147. package/dist/vm/lib/mod/matrix.d.ts +0 -15
  148. package/dist/vm/lib/mod/matrix.d.ts.map +0 -1
  149. package/dist/vm/types/extern.d.ts.map +0 -1
  150. package/src/helpers/types.ts +0 -283
  151. package/src/vm/lib/mod/matrix.ts +0 -590
  152. package/src/vm/types/extern.ts +0 -197
@@ -1,28 +1,9 @@
1
1
  import { VmError } from '../../helpers/error.js';
2
- import {
3
- hasOwnEnumerable,
4
- NotNumber,
5
- keys,
6
- create,
7
- isFinite,
8
- keysLength,
9
- getRecord,
10
- setRecord,
11
- } from '../../helpers/utils.js';
12
- import { toNumber, toString } from '../../helpers/convert/index.js';
2
+ import { hasOwnEnumerable, NotNumber, isFinite, getRecord, keysLength } from '../../helpers/utils.js';
3
+ import { toNumber } from '../../helpers/convert/index.js';
13
4
  import { display } from '../../helpers/serialize.js';
14
- import {
15
- isVmPrimitive,
16
- isVmArray,
17
- isVmRecord,
18
- isVmFunction,
19
- isVmExtern,
20
- isVmWrapper,
21
- isVmConst,
22
- } from '../../helpers/types.js';
23
- import { wrapToVmConst } from '../types/boundary.js';
24
- import type { VmAny, VmRecord, VmValue, VmConst } from '../types/index.js';
25
- import { isSame } from './utils.js';
5
+ import { isVmArray, isVmRecord, isVmExtern, isVmWrapper } from '../../helpers/types/index.js';
6
+ import type { VmAny, VmValue } from '../types/index.js';
26
7
  import { $AssertInit } from './common.js';
27
8
  import { $ToString } from './convert.js';
28
9
  import { $El } from './helpers.js';
@@ -30,29 +11,6 @@ import { $El } from './helpers.js';
30
11
  const { trunc } = Math;
31
12
  const { at } = Array.prototype;
32
13
 
33
- /** 检查值是否在可迭代对象中 */
34
- export const $In = (value: VmAny, iterable: VmAny): boolean => {
35
- $AssertInit(value);
36
- $AssertInit(iterable);
37
- if (iterable == null) return false;
38
- if (typeof iterable != 'object') return false;
39
- if (isVmArray(iterable)) {
40
- if (value == null) {
41
- // array may have empty slots
42
- for (const item of iterable) if (item == null) return true;
43
- return false;
44
- }
45
- // JS %SameValueZero is same with `isSame` in this context
46
- if (isVmPrimitive(value)) return iterable.includes(value);
47
- // value is not null here, so it's ok to skip empty slots, since `isSame(null, something)` is always false
48
- return iterable.some((item = null) => isSame(item, value satisfies NonNullable<VmValue>));
49
- }
50
- // iterable is a record or an extern here, value should be a string
51
- const key = toString(value, undefined);
52
- if (isVmWrapper(iterable)) return iterable.has(key);
53
- return hasOwnEnumerable(iterable satisfies VmRecord, key);
54
- };
55
-
56
14
  /** 获取值的长度 */
57
15
  export const $Length = (value: VmAny): number => {
58
16
  $AssertInit(value);
@@ -63,34 +21,6 @@ export const $Length = (value: VmAny): number => {
63
21
  throw new VmError(`Value has no length: ${display(value)}`, 0);
64
22
  };
65
23
 
66
- /** 删除记录中的指定字段 */
67
- export const $Omit = (value: VmAny, omitted: ReadonlyArray<number | string>): VmRecord => {
68
- $AssertInit(value);
69
- if (!isVmRecord(value)) return {};
70
- const result: Record<string, VmConst> = {};
71
- const valueKeys = keys(value);
72
- const omittedSet = new Set(omitted.map($ToString));
73
- for (const key of valueKeys) {
74
- if (!omittedSet.has(key)) {
75
- setRecord(result, key, value[key]);
76
- }
77
- }
78
- return result;
79
- };
80
-
81
- /** 选择记录中的指定字段 */
82
- export const $Pick = (value: VmAny, picked: ReadonlyArray<number | string>): VmRecord => {
83
- $AssertInit(value);
84
- if (!isVmRecord(value)) return {};
85
- const result: Record<string, VmConst> = {};
86
- for (const key of picked) {
87
- const k = $ToString(key);
88
- if (hasOwnEnumerable(value, k)) {
89
- setRecord(result, k, value[k]);
90
- }
91
- }
92
- return result;
93
- };
94
24
  /** 检查是否拥有字段 */
95
25
  export const $Has = (obj: VmAny, key: VmAny): boolean => {
96
26
  $AssertInit(obj);
@@ -132,60 +62,3 @@ export const $Set = (obj: VmAny, key: VmAny, value: VmAny): void => {
132
62
  if (!isVmExtern(obj)) throw new VmError(`Expected extern, got ${display(obj)}`, undefined);
133
63
  obj.set(pk, value);
134
64
  };
135
- /** 获取可迭代对象 */
136
- export const $Iterable = (value: VmAny): Iterable<VmValue | undefined> => {
137
- $AssertInit(value);
138
- if (isVmWrapper(value)) return value.keys();
139
- if (isVmArray(value)) return value;
140
- if (value != null && typeof value == 'object') return keys(value);
141
- throw new VmError(`Value is not iterable: ${display(value)}`, isVmFunction(value) ? [] : [value]);
142
- };
143
- /** 展开记录 */
144
- export const $RecordSpread = (record: VmAny): VmRecord | null => {
145
- $AssertInit(record);
146
- if (record == null || isVmRecord(record)) return record;
147
- if (isVmArray(record)) {
148
- const result: Record<string, VmConst> = {};
149
- const len = record.length;
150
- for (let i = 0; i < len; i++) {
151
- const item = record[i];
152
- result[i] = item ?? null;
153
- }
154
- return result;
155
- }
156
- if (isVmExtern(record)) {
157
- const result: Record<string, VmConst> = create(null);
158
- for (const key of record.keys()) {
159
- const value = record.get(key) ?? null;
160
- if (isVmConst(value)) {
161
- result[key] = value;
162
- }
163
- }
164
- return result;
165
- }
166
- throw new VmError(`Expected record, array, extern or nil, got ${display(record)}`, null);
167
- };
168
-
169
- /** 展开数组 */
170
- export const $ArraySpread = (array: VmAny): Iterable<VmConst | undefined> => {
171
- $AssertInit(array);
172
- if (array == null) return [];
173
- if (isVmArray(array)) return array;
174
- if (isVmExtern(array)) {
175
- if (array.isArrayLike()) {
176
- const result: VmConst[] = [];
177
- for (let i = 0, len = array.value.length; i < len; i++) {
178
- const item = array.value[i];
179
- result.push(wrapToVmConst(item, (v) => array.assumeVmValue(v, i)));
180
- }
181
- return result;
182
- } else if (typeof (array.value as Iterable<unknown>)[Symbol.iterator] == 'function') {
183
- const result: VmConst[] = [];
184
- for (const item of array.value as Iterable<unknown>) {
185
- result.push(wrapToVmConst(item, (v) => array.assumeVmValue(v, Symbol.iterator as never)));
186
- }
187
- return result;
188
- }
189
- }
190
- throw new VmError(`Expected array, iterable extern or nil, got ${display(array)}`, []);
191
- };
@@ -1,6 +1,6 @@
1
1
  import { create, defineProperty, entries } from '../../helpers/utils.js';
2
2
  import { VM_FUNCTION_ANONYMOUS_NAME } from '../../helpers/constants.js';
3
- import { isVmConst } from '../../helpers/types.js';
3
+ import { isVmConst } from '../../helpers/types/index.js';
4
4
  import type { VmFunctionLike } from '../types/function.js';
5
5
  import { DefaultVmContext, type VmContext } from '../types/context.js';
6
6
  import type { VmConst, VmAny, VmValue, VmImmutable } from '../types/index.js';
@@ -5,6 +5,9 @@ export * from './operator.js';
5
5
  export * from './slice.js';
6
6
  export * from './helpers.js';
7
7
  export * from './compound.js';
8
+ export * from './spread.js';
9
+ export * from './record.js';
10
+ export * from './iterable.js';
8
11
  export * from './cp.js';
9
12
  export * from './call.js';
10
13
  export * from './array-range.js';
@@ -0,0 +1,40 @@
1
+ import { VmError } from '../../helpers/error.js';
2
+ import { hasOwnEnumerable, keys } from '../../helpers/utils.js';
3
+ import { toString } from '../../helpers/convert/index.js';
4
+ import { display } from '../../helpers/serialize.js';
5
+ import { isVmPrimitive, isVmArray, isVmFunction, isVmWrapper } from '../../helpers/types/index.js';
6
+ import type { VmAny, VmRecord, VmValue } from '../types/index.js';
7
+ import { isSame } from './utils.js';
8
+ import { $AssertInit } from './common.js';
9
+
10
+ /** 检查值是否在可迭代对象中 */
11
+ export const $In = (value: VmAny, iterable: VmAny): boolean => {
12
+ $AssertInit(value);
13
+ $AssertInit(iterable);
14
+ if (iterable == null) return false;
15
+ if (typeof iterable != 'object') return false;
16
+ if (isVmArray(iterable)) {
17
+ if (value == null) {
18
+ // array may have empty slots
19
+ for (const item of iterable) if (item == null) return true;
20
+ return false;
21
+ }
22
+ // JS %SameValueZero is same with `isSame` in this context
23
+ if (isVmPrimitive(value)) return iterable.includes(value);
24
+ // value is not null here, so it's ok to skip empty slots, since `isSame(null, something)` is always false
25
+ return iterable.some((item = null) => isSame(item, value satisfies NonNullable<VmValue>));
26
+ }
27
+ // iterable is a record or an extern here, value should be a string
28
+ const key = toString(value, undefined);
29
+ if (isVmWrapper(iterable)) return iterable.has(key);
30
+ return hasOwnEnumerable(iterable satisfies VmRecord, key);
31
+ };
32
+
33
+ /** 获取可迭代对象 */
34
+ export const $Iterable = (value: VmAny): Iterable<VmValue | undefined> => {
35
+ $AssertInit(value);
36
+ if (isVmWrapper(value)) return value.keys();
37
+ if (isVmArray(value)) return value;
38
+ if (value != null && typeof value == 'object') return keys(value);
39
+ throw new VmError(`Value is not iterable: ${display(value)}`, isVmFunction(value) ? [] : [value]);
40
+ };
@@ -0,0 +1,33 @@
1
+ import { hasOwnEnumerable, keys, setRecord } from '../../helpers/utils.js';
2
+ import { isVmRecord } from '../../helpers/types/index.js';
3
+ import type { VmAny, VmRecord, VmConst } from '../types/index.js';
4
+ import { $AssertInit } from './common.js';
5
+
6
+ /** 删除记录中的指定字段 */
7
+ export const $Omit = (value: VmAny, omitted: ReadonlyArray<number | string>): VmRecord => {
8
+ $AssertInit(value);
9
+ if (!isVmRecord(value)) return {};
10
+ const result: Record<string, VmConst> = {};
11
+ const valueKeys = keys(value);
12
+ const omittedSet = new Set(omitted.map(String));
13
+ for (const key of valueKeys) {
14
+ if (!omittedSet.has(key)) {
15
+ setRecord(result, key, value[key]);
16
+ }
17
+ }
18
+ return result;
19
+ };
20
+
21
+ /** 选择记录中的指定字段 */
22
+ export const $Pick = (value: VmAny, picked: ReadonlyArray<number | string>): VmRecord => {
23
+ $AssertInit(value);
24
+ if (!isVmRecord(value)) return {};
25
+ const result: Record<string, VmConst> = {};
26
+ for (const key of picked) {
27
+ const k = String(key);
28
+ if (hasOwnEnumerable(value, k)) {
29
+ setRecord(result, k, value[k]);
30
+ }
31
+ }
32
+ return result;
33
+ };
@@ -1,44 +1,45 @@
1
1
  import { VmError } from '../../helpers/error.js';
2
2
  import { display } from '../../helpers/serialize.js';
3
+ import { toNumber } from '../../helpers/convert/number.js';
3
4
  import { isNaN, isSafeInteger } from '../../helpers/utils.js';
4
- import { isVmArray } from '../../helpers/types.js';
5
+ import { isVmArray } from '../../helpers/types/index.js';
5
6
  import type { VmAny, VmArray } from '../types/index.js';
6
7
  import { $AssertInit } from './common.js';
7
- import { $ToNumber } from './convert.js';
8
8
  const { ceil } = Math;
9
9
  const { slice } = Array.prototype;
10
10
 
11
- const sliceCore = (value: VmArray, start: number, end: number, exclusive: boolean): VmArray => {
11
+ const sliceCore = (value: VmAny, start: VmAny, end: VmAny, exclusive: boolean): VmArray => {
12
+ $AssertInit(value);
13
+ $AssertInit(start);
14
+ $AssertInit(end);
15
+
16
+ if (!isVmArray(value)) {
17
+ throw new VmError(`Expected array, got ${display(value)}`, []);
18
+ }
12
19
  const { length } = value;
20
+ let s = start != null ? toNumber(start) : 0;
21
+ let e = end != null ? toNumber(end) : length - (exclusive ? 0 : 1);
13
22
 
14
- if (isNaN(start)) start = 0;
15
- else if (start < 0) start = length + start;
23
+ if (isNaN(s)) s = 0;
24
+ else if (s < 0) s = length + s;
16
25
 
17
- if (isNaN(end)) end = exclusive ? length : length - 1;
18
- else if (end < 0) end = length + end;
26
+ if (isNaN(e)) e = exclusive ? length : length - 1;
27
+ else if (e < 0) e = length + e;
19
28
 
20
- start = ceil(start);
21
- if (exclusive || !isSafeInteger(end)) {
22
- end = ceil(end);
29
+ s = ceil(s);
30
+ if (exclusive || !isSafeInteger(e)) {
31
+ e = ceil(e);
23
32
  } else {
24
- end = end + 1;
33
+ e = e + 1;
25
34
  }
26
- return slice.call(value, start, end) satisfies unknown[] as VmArray;
35
+ return slice.call(value, s, e) satisfies unknown[] as VmArray;
27
36
  };
28
37
 
29
38
  /** 获取数组切片 */
30
39
  export const $Slice = (value: VmAny, start: VmAny, end: VmAny): VmArray => {
31
- $AssertInit(value);
32
- if (!isVmArray(value)) throw new VmError(`Expected array, got ${display(value)}`, []);
33
- const s = start != null ? $ToNumber(start) : 0;
34
- const e = end != null ? $ToNumber(end) : value.length - 1;
35
- return sliceCore(value, s, e, false);
40
+ return sliceCore(value, start, end, false);
36
41
  };
37
42
  /** 获取数组切片(不包含结束位置) */
38
43
  export const $SliceExclusive = (value: VmAny, start: VmAny, end: VmAny): VmArray => {
39
- $AssertInit(value);
40
- if (!isVmArray(value)) throw new VmError(`Expected array, got ${display(value)}`, []);
41
- const s = start != null ? $ToNumber(start) : 0;
42
- const e = end != null ? $ToNumber(end) : value.length;
43
- return sliceCore(value, s, e, true);
44
+ return sliceCore(value, start, end, true);
44
45
  };
@@ -0,0 +1,57 @@
1
+ import { VmError } from '../../helpers/error.js';
2
+ import { create } from '../../helpers/utils.js';
3
+ import { display } from '../../helpers/serialize.js';
4
+ import { isVmArray, isVmRecord, isVmExtern, isVmConst } from '../../helpers/types/index.js';
5
+ import { wrapToVmConst } from '../types/boundary.js';
6
+ import type { VmAny, VmRecord, VmConst } from '../types/index.js';
7
+ import { $AssertInit } from './common.js';
8
+
9
+ /** 展开记录 */
10
+ export const $RecordSpread = (record: VmAny): VmRecord | null => {
11
+ $AssertInit(record);
12
+ if (record == null || isVmRecord(record)) return record;
13
+ if (isVmArray(record)) {
14
+ const result: Record<string, VmConst> = {};
15
+ const len = record.length;
16
+ for (let i = 0; i < len; i++) {
17
+ const item = record[i];
18
+ result[i] = item ?? null;
19
+ }
20
+ return result;
21
+ }
22
+ if (isVmExtern(record)) {
23
+ const result: Record<string, VmConst> = create(null);
24
+ for (const key of record.keys()) {
25
+ const value = record.get(key) ?? null;
26
+ if (isVmConst(value)) {
27
+ result[key] = value;
28
+ }
29
+ }
30
+ return result;
31
+ }
32
+ throw new VmError(`Expected record, array, extern or nil, got ${display(record)}`, null);
33
+ };
34
+
35
+ /** 展开数组 */
36
+ export const $ArraySpread = (array: VmAny): Iterable<VmConst | undefined> => {
37
+ $AssertInit(array);
38
+ if (array == null) return [];
39
+ if (isVmArray(array)) return array;
40
+ if (isVmExtern(array)) {
41
+ if (array.isArrayLike()) {
42
+ const result: VmConst[] = [];
43
+ for (let i = 0, len = array.value.length; i < len; i++) {
44
+ const item = array.value[i];
45
+ result.push(wrapToVmConst(item, (v) => array.assumeVmValue(v, i)));
46
+ }
47
+ return result;
48
+ } else if (typeof (array.value as Iterable<unknown>)[Symbol.iterator] == 'function') {
49
+ const result: VmConst[] = [];
50
+ for (const item of array.value as Iterable<unknown>) {
51
+ result.push(wrapToVmConst(item, (v) => array.assumeVmValue(v, Symbol.iterator as never)));
52
+ }
53
+ return result;
54
+ }
55
+ }
56
+ throw new VmError(`Expected array, iterable extern or nil, got ${display(array)}`, []);
57
+ };
@@ -1,5 +1,5 @@
1
1
  import { VmError } from '../../helpers/error.js';
2
- import { getVmType, isVmArray, isVmRecord } from '../../helpers/types.js';
2
+ import { getVmType, isVmArray, isVmRecord } from '../../helpers/types/index.js';
3
3
  import type { VmTypeName, VmAny, VmArray, VmRecord, VmValue } from '../types/index.js';
4
4
  import { $AssertInit } from './common.js';
5
5
 
@@ -1,6 +1,6 @@
1
- import { hasOwnEnumerable, isNaN, keys } from '../../helpers/utils.js';
2
- import { isVmArray, isVmWrapper } from '../../helpers/types.js';
3
- import type { VmAny, VmValue } from '../types/index.js';
1
+ import { isNaN, keys, getRecord } from '../../helpers/utils.js';
2
+ import { getVmType, isVmWrapper } from '../../helpers/types/index.js';
3
+ import type { VmAny, VmArray, VmRecord, VmValue } from '../types/index.js';
4
4
 
5
5
  /**
6
6
  * 确定操作的重载
@@ -12,6 +12,38 @@ export const overloadNumberString = (a: VmAny, b: VmAny): boolean => {
12
12
  return true;
13
13
  };
14
14
 
15
+ const isArraySame = (a: VmArray, b: VmArray): boolean => {
16
+ const len = a.length;
17
+ if (len !== b.length) return false;
18
+
19
+ for (let i = 0; i < len; i++) {
20
+ if (!isSame(a[i] ?? null, b[i] ?? null)) {
21
+ return false;
22
+ }
23
+ }
24
+ return true;
25
+ };
26
+
27
+ const isRecordSame = (a: VmRecord, b: VmRecord): boolean => {
28
+ const aKeys = keys(a);
29
+ const bKeys = keys(b);
30
+
31
+ const len = aKeys.length;
32
+ if (len !== bKeys.length) return false;
33
+ if (len === 0) return true;
34
+
35
+ for (let i = 0; i < len; i++) {
36
+ const key = aKeys[i]!;
37
+ const av = a[key] ?? null;
38
+ const bv = getRecord(b, key);
39
+ // Key not found in b
40
+ if (bv === undefined) return false;
41
+ // Key found in b, but values are not the same
42
+ if (!isSame(av, bv)) return false;
43
+ }
44
+ return true;
45
+ };
46
+
15
47
  /**
16
48
  * 检查两个 VmValue 是否相同
17
49
  */
@@ -24,43 +56,19 @@ export const isSame = (a: VmValue, b: VmValue): boolean => {
24
56
  if (a === b) return true;
25
57
  // Any primitives and functions arrive here are not equal
26
58
  if (a == null || typeof a != 'object' || b == null || typeof b != 'object') return false;
27
- // Handle wrapper values
28
- if (isVmWrapper(a)) return a.same(b);
29
- if (isVmWrapper(b)) return b.same(a);
59
+ const aType = getVmType(a);
60
+ const bType = getVmType(b);
61
+ if (aType !== bType) return false;
30
62
  // Handle array values
31
- if (isVmArray(a) && isVmArray(b)) {
32
- const len = a.length;
33
- if (len !== b.length) {
34
- return false;
35
- }
36
- // Compare array items
37
- for (let i = 0; i < len; i++) {
38
- if (!isSame(a[i] ?? null, b[i] ?? null)) {
39
- return false;
40
- }
41
- }
42
- return true;
63
+ if (aType === 'array') {
64
+ return isArraySame(a as VmArray, b as VmArray);
43
65
  }
44
66
  // Handle record values
45
- if (!isVmArray(a) && !isVmArray(b)) {
46
- // Compare record fields
47
- const aKeys = keys(a);
48
- const bKeys = keys(b);
49
-
50
- const len = aKeys.length;
51
- if (len !== bKeys.length) return false;
52
-
53
- if (len === 0) return true;
54
-
55
- let i = len;
56
- while (i--) {
57
- const key = aKeys[i]!;
58
- if (!hasOwnEnumerable(b, key)) return false;
59
- const av = a[key] ?? null;
60
- const bv = b[key] ?? null;
61
- if (!isSame(av, bv)) return false;
62
- }
63
- return true;
67
+ if (aType === 'record') {
68
+ return isRecordSame(a as VmRecord, b as VmRecord);
64
69
  }
70
+ // Handle wrapper values
71
+ if (isVmWrapper(a)) return a.same(b);
72
+ if (isVmWrapper(b)) return b.same(a);
65
73
  return false;
66
74
  };
@@ -1,10 +1,10 @@
1
1
  import { defineProperty, apply } from '../../helpers/utils.js';
2
- import { isVmExtern, isVmFunction, isVmWrapper } from '../../helpers/types.js';
2
+ import { isVmExtern, isVmFunction, isVmWrapper } from '../../helpers/types/index.js';
3
3
  import { kVmFunctionProxy } from '../../helpers/constants.js';
4
4
  import { $Call } from '../operations/call.js';
5
5
  import type { VmAny, VmConst, VmModule, VmPrimitive, VmValue } from './index.js';
6
6
  import type { VmFunctionLike, VmFunction } from './function.js';
7
- import { VmExtern } from './extern.js';
7
+ import { VmExtern } from './extern/index.js';
8
8
 
9
9
  /** 创建 Mirascript 函数在宿主语言运行的代理 */
10
10
  export function toVmFunctionProxy<T extends VmFunctionLike>(fn: VmFunction<T>): T {
@@ -0,0 +1,24 @@
1
+ import { hasOwn } from '../../../helpers/utils.js';
2
+
3
+ const pFunction = Function.prototype;
4
+ const pArray = Array.prototype;
5
+ const pObject = Object.prototype;
6
+ /**
7
+ * Can property be accessed on the extern object?
8
+ */
9
+ export function canAccessProperty(value: object, key: string, read: boolean): boolean {
10
+ // __proto__ and other “private” properties are not accessible
11
+ if (key.startsWith('_')) return false;
12
+ // Function-specific properties are not accessible
13
+ if (typeof value == 'function' && (key === 'prototype' || key === 'arguments' || key === 'caller')) return false;
14
+ if (hasOwn(value, key)) return true;
15
+ if (!read) return true;
16
+ if (!(key in value)) return false;
17
+ if (key === 'constructor') return false; // constructor is not accessible
18
+ // property is not readable if it is the same as the prototype's property
19
+ const prop = (value as Record<string, unknown>)[key];
20
+ if (key in pFunction && prop === pFunction[key as keyof (() => void)]) return false;
21
+ if (key in pArray && prop === pArray[key as keyof unknown[]]) return false;
22
+ if (key in pObject && prop === pObject[key as keyof object]) return false;
23
+ return true;
24
+ }
@@ -0,0 +1,124 @@
1
+ import { VmError } from '../../../helpers/error.js';
2
+ import { apply } from '../../../helpers/utils.js';
3
+ import { innerToString } from '../../../helpers/convert/string.js';
4
+ import { isVmExtern } from '../../../helpers/types/index.js';
5
+ import { kVmExtern } from '../../../helpers/constants.js';
6
+ import type { VmTypeName, VmAny, VmConst, VmPrimitive, VmValue } from '../index.js';
7
+ import { VmWrapper } from '../wrapper.js';
8
+ import { unwrapFromVmValue, wrapToVmValue } from '../boundary.js';
9
+ import { getTag } from './tag.js';
10
+ import { getKeys, isArrayLike, hasCustomToString } from './utils.js';
11
+ import { canAccessProperty } from './access.js';
12
+
13
+ const ArrayMap = Array.prototype.map;
14
+
15
+ /** 包装 Mirascript `extern` 类型的对象 */
16
+ export class VmExtern<const T extends object = object> extends VmWrapper<T> {
17
+ constructor(
18
+ /** 包装值 */
19
+ value: T,
20
+ /** 当 {@link value} 是函数时,绑定的 this 参数 */
21
+ readonly thisArg: ThisParameterType<T> | null = null,
22
+ ) {
23
+ super(value);
24
+ }
25
+
26
+ /**
27
+ * Check if the object has a property
28
+ * This method will be used in {@link get}, {@link set}, {@link has}, and {@link keys} methods
29
+ */
30
+ protected access(key: string, read: boolean): boolean {
31
+ return canAccessProperty(this.value, key, read);
32
+ }
33
+
34
+ /** 决定是否对属性进行包装 */
35
+ assumeVmValue(value: object, key: keyof T | undefined): value is Exclude<VmConst, VmPrimitive> {
36
+ return false;
37
+ }
38
+
39
+ /** @inheritdoc */
40
+ override has(key: string): boolean {
41
+ return this.access(key, true);
42
+ }
43
+ /** @inheritdoc */
44
+ override get(key: string): VmAny {
45
+ if (!(key in this.value)) return undefined;
46
+ if (!this.access(key, true)) return undefined;
47
+ const prop = (this.value as Record<string, unknown>)[key];
48
+ return wrapToVmValue(prop, this.value, (v) => this.assumeVmValue(v, key as keyof T));
49
+ }
50
+ /** Set a property on the object */
51
+ set(key: string, value: VmValue): boolean {
52
+ if (!this.access(key, false)) return false;
53
+ const prop = unwrapFromVmValue(value, true);
54
+ (this.value as Record<string, unknown>)[key] = prop;
55
+ return true;
56
+ }
57
+ /** Call extern value */
58
+ call(args: readonly VmValue[]): VmAny {
59
+ const { value } = this;
60
+ if (typeof value != 'function') {
61
+ throw VmError.from(`Not a callable extern`, null, null);
62
+ }
63
+ const caller = this.thisArg;
64
+ const unwrappedArgs = args.map((arg) => unwrapFromVmValue(arg, true));
65
+ let ret: unknown;
66
+ try {
67
+ ret = apply(value, caller, unwrappedArgs);
68
+ } catch (ex) {
69
+ throw VmError.from(`Callable extern`, ex, null);
70
+ }
71
+ return wrapToVmValue(ret, null, (obj) => this.assumeVmValue(obj, undefined));
72
+ }
73
+ /** @inheritdoc */
74
+ override keys(includeNonEnumerable = false): string[] {
75
+ const keys = getKeys(this.value, includeNonEnumerable);
76
+ return keys.filter((key) => this.access(key, true));
77
+ }
78
+ /** @inheritdoc */
79
+ override same(other: VmAny): boolean {
80
+ if (!isVmExtern(other)) return false;
81
+ return this.value === other.value && this.thisArg === other.thisArg;
82
+ }
83
+ /**
84
+ * Should this extern be treated as array-like?
85
+ *
86
+ * By default, this method returns true if the wrapped value is an Array or a TypedArray.
87
+ */
88
+ isArrayLike(): this is VmExtern<ArrayLike<unknown>> {
89
+ return isArrayLike(this.value);
90
+ }
91
+ /** @inheritdoc */
92
+ override toString(useBraces: boolean): string {
93
+ if (hasCustomToString(this.value)) {
94
+ // Use the wrapped object's toString method
95
+ return String(this.value);
96
+ }
97
+ if (this.isArrayLike()) {
98
+ // Handle array-like externs specially when using default toString
99
+ const mapped = ArrayMap.call(this.value, (item: unknown) => {
100
+ if (item === undefined) return '';
101
+ return innerToString(wrapToVmValue(item ?? null, null, null), true);
102
+ });
103
+ const str = mapped.join(', ');
104
+ if (useBraces) return `[${str}]`;
105
+ return str;
106
+ }
107
+ // When the toString method is not overridden or invalid, provide a better default representation
108
+ return super.toString(useBraces);
109
+ }
110
+ /** @inheritdoc */
111
+ override get type(): VmTypeName {
112
+ return 'extern';
113
+ }
114
+ /** @inheritdoc */
115
+ override get tag(): string {
116
+ const tag = getTag(this.value);
117
+ if (this.isArrayLike()) {
118
+ return `${tag}(${this.value.length})`;
119
+ }
120
+ return tag;
121
+ }
122
+ }
123
+
124
+ Object.defineProperty(VmExtern.prototype, kVmExtern, { value: true });