@mirascript/mirascript 0.1.16 → 0.1.18

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 (115) hide show
  1. package/dist/{chunk-LU4ZKFF6.js → chunk-3BAOZ2P2.js} +203 -62
  2. package/dist/chunk-3BAOZ2P2.js.map +6 -0
  3. package/dist/{chunk-YZGL3D7L.js → chunk-5AEWM4W6.js} +41 -95
  4. package/dist/chunk-5AEWM4W6.js.map +6 -0
  5. package/dist/cli/execute.d.ts.map +1 -1
  6. package/dist/cli/index.js +11 -12
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/compiler/diagnostic.d.ts.map +1 -1
  9. package/dist/compiler/emit/sourcemap.d.ts.map +1 -1
  10. package/dist/compiler/worker.js +1 -1
  11. package/dist/helpers/convert/index.d.ts +5 -0
  12. package/dist/helpers/convert/index.d.ts.map +1 -0
  13. package/dist/helpers/convert/to-boolean.d.ts +4 -0
  14. package/dist/helpers/convert/to-boolean.d.ts.map +1 -0
  15. package/dist/helpers/convert/to-format.d.ts +4 -0
  16. package/dist/helpers/convert/to-format.d.ts.map +1 -0
  17. package/dist/helpers/convert/to-number.d.ts +4 -0
  18. package/dist/helpers/convert/to-number.d.ts.map +1 -0
  19. package/dist/helpers/convert/to-string.d.ts +6 -0
  20. package/dist/helpers/convert/to-string.d.ts.map +1 -0
  21. package/dist/helpers/serialize.d.ts.map +1 -1
  22. package/dist/index.js +2 -2
  23. package/dist/subtle.d.ts +2 -2
  24. package/dist/subtle.d.ts.map +1 -1
  25. package/dist/subtle.js +3 -5
  26. package/dist/vm/checkpoint.d.ts.map +1 -1
  27. package/dist/vm/helpers.d.ts.map +1 -1
  28. package/dist/vm/lib/global/bit.d.ts +7 -7
  29. package/dist/vm/lib/global/bit.d.ts.map +1 -1
  30. package/dist/vm/lib/global/debug.d.ts +17 -1
  31. package/dist/vm/lib/global/debug.d.ts.map +1 -1
  32. package/dist/vm/lib/global/json.d.ts +2 -2
  33. package/dist/vm/lib/global/json.d.ts.map +1 -1
  34. package/dist/vm/lib/global/math-additional.d.ts +1 -1
  35. package/dist/vm/lib/global/math-additional.d.ts.map +1 -1
  36. package/dist/vm/lib/global/math-arr.d.ts +5 -5
  37. package/dist/vm/lib/global/math-arr.d.ts.map +1 -1
  38. package/dist/vm/lib/global/math-unary.d.ts +26 -26
  39. package/dist/vm/lib/global/math-unary.d.ts.map +1 -1
  40. package/dist/vm/lib/global/math.d.ts +3 -3
  41. package/dist/vm/lib/global/math.d.ts.map +1 -1
  42. package/dist/vm/lib/global/sequence/all-any.d.ts +2 -2
  43. package/dist/vm/lib/global/sequence/all-any.d.ts.map +1 -1
  44. package/dist/vm/lib/global/sequence/entries.d.ts +3 -3
  45. package/dist/vm/lib/global/sequence/entries.d.ts.map +1 -1
  46. package/dist/vm/lib/global/sequence/find.d.ts +1 -1
  47. package/dist/vm/lib/global/sequence/find.d.ts.map +1 -1
  48. package/dist/vm/lib/global/sequence/flatten.d.ts +1 -1
  49. package/dist/vm/lib/global/sequence/flatten.d.ts.map +1 -1
  50. package/dist/vm/lib/global/sequence/len.d.ts +1 -1
  51. package/dist/vm/lib/global/sequence/len.d.ts.map +1 -1
  52. package/dist/vm/lib/global/sequence/map-filter.d.ts +3 -3
  53. package/dist/vm/lib/global/sequence/map-filter.d.ts.map +1 -1
  54. package/dist/vm/lib/global/sequence/repeat.d.ts +1 -1
  55. package/dist/vm/lib/global/sequence/repeat.d.ts.map +1 -1
  56. package/dist/vm/lib/global/sequence/reverse.d.ts +1 -1
  57. package/dist/vm/lib/global/sequence/reverse.d.ts.map +1 -1
  58. package/dist/vm/lib/global/sequence/sort.d.ts +2 -2
  59. package/dist/vm/lib/global/sequence/sort.d.ts.map +1 -1
  60. package/dist/vm/lib/global/sequence/with.d.ts +1 -1
  61. package/dist/vm/lib/global/sequence/with.d.ts.map +1 -1
  62. package/dist/vm/lib/global/sequence/zip.d.ts +1 -1
  63. package/dist/vm/lib/global/sequence/zip.d.ts.map +1 -1
  64. package/dist/vm/lib/global/string.d.ts +10 -10
  65. package/dist/vm/lib/global/string.d.ts.map +1 -1
  66. package/dist/vm/lib/global/time.d.ts +3 -3
  67. package/dist/vm/lib/global/time.d.ts.map +1 -1
  68. package/dist/vm/lib/global/to-primitive.d.ts +4 -4
  69. package/dist/vm/lib/global/to-primitive.d.ts.map +1 -1
  70. package/dist/vm/lib/helpers.d.ts +4 -2
  71. package/dist/vm/lib/helpers.d.ts.map +1 -1
  72. package/dist/vm/lib/index.d.ts +1 -1
  73. package/dist/vm/lib/index.d.ts.map +1 -1
  74. package/dist/vm/lib/mod/matrix.d.ts +13 -13
  75. package/dist/vm/lib/mod/matrix.d.ts.map +1 -1
  76. package/dist/vm/operations.d.ts.map +1 -1
  77. package/dist/vm/types/context.d.ts +3 -17
  78. package/dist/vm/types/context.d.ts.map +1 -1
  79. package/dist/vm/types/index.d.ts +1 -1
  80. package/dist/vm/types/index.d.ts.map +1 -1
  81. package/package.json +2 -2
  82. package/src/cli/execute.ts +10 -10
  83. package/src/compiler/diagnostic.ts +29 -11
  84. package/src/compiler/emit/globals.ts +1 -1
  85. package/src/compiler/emit/sourcemap.ts +8 -3
  86. package/src/helpers/convert/index.ts +4 -0
  87. package/src/helpers/convert/to-boolean.ts +12 -0
  88. package/src/helpers/convert/to-format.ts +37 -0
  89. package/src/helpers/convert/to-number.ts +35 -0
  90. package/src/helpers/convert/to-string.ts +55 -0
  91. package/src/helpers/serialize.ts +1 -0
  92. package/src/subtle.ts +2 -2
  93. package/src/vm/checkpoint.ts +19 -10
  94. package/src/vm/helpers.ts +1 -1
  95. package/src/vm/lib/global/debug.ts +84 -7
  96. package/src/vm/lib/global/json.ts +3 -4
  97. package/src/vm/lib/global/sequence/all-any.ts +1 -1
  98. package/src/vm/lib/global/sequence/find.ts +1 -1
  99. package/src/vm/lib/global/sequence/map-filter.ts +1 -1
  100. package/src/vm/lib/global/sequence/sort.ts +1 -1
  101. package/src/vm/lib/global/sequence/with.ts +1 -1
  102. package/src/vm/lib/global/time.ts +1 -1
  103. package/src/vm/lib/global/to-primitive.ts +1 -1
  104. package/src/vm/lib/helpers.ts +5 -4
  105. package/src/vm/lib/index.ts +4 -4
  106. package/src/vm/lib/mod/matrix.ts +1 -1
  107. package/src/vm/operations.ts +11 -12
  108. package/src/vm/types/context.ts +26 -38
  109. package/src/vm/types/extern.ts +1 -1
  110. package/src/vm/types/index.ts +1 -1
  111. package/dist/chunk-LU4ZKFF6.js.map +0 -6
  112. package/dist/chunk-YZGL3D7L.js.map +0 -6
  113. package/dist/helpers/convert.d.ts +0 -12
  114. package/dist/helpers/convert.d.ts.map +0 -1
  115. package/src/helpers/convert.ts +0 -128
@@ -1,13 +1,87 @@
1
1
  import supportsColor from 'supports-color';
2
2
  import { VmError } from '../../../helpers/error.js';
3
- import { toString } from '../../../helpers/convert.js';
3
+ import { toString } from '../../../helpers/convert/index.js';
4
4
  import type { VmAny } from '../../types/index.js';
5
5
  import { VmLib } from '../helpers.js';
6
6
 
7
+ /** 序列化格式 */
8
+ type SerializeFormat =
9
+ /** 表示未指定格式 */
10
+ | ''
11
+ /** 以 `%` 开头的格式占位符 */
12
+ | `%${string}`;
13
+ /**
14
+ * 默认的序列化函数
15
+ * @param arg 要序列化的值
16
+ * @param format 序列化格式
17
+ * @returns 序列化后的字符串,或 null 表示直接将原值传递给控制台
18
+ */
19
+ function defaultSerializer(arg: VmAny, format: SerializeFormat): string | null {
20
+ return null;
21
+ }
22
+
23
+ /** 序列化值 */
24
+ function serializeValue(arg: VmAny, format: SerializeFormat, serializer: typeof defaultSerializer): string | null {
25
+ if (serializer == null || serializer === defaultSerializer) {
26
+ return defaultSerializer(arg, format);
27
+ }
28
+ try {
29
+ return serializer(arg, format);
30
+ } catch {
31
+ return defaultSerializer(arg, format);
32
+ }
33
+ }
34
+
7
35
  export const debug_print = VmLib(
8
36
  (...args) => {
37
+ const { serializer } = debug_print;
38
+ if (args.length <= 1 || typeof args[0] != 'string' || !args[0].includes('%')) {
39
+ // eslint-disable-next-line no-console
40
+ console.log(...debug_print.prefix, ...args.map((v) => serializeValue(v, '', serializer) ?? v));
41
+ return;
42
+ }
43
+ const [prefix, ...additional] = debug_print.prefix;
44
+ const [arg0, ...argsRest] = args;
45
+ const format = `${prefix || ''} ${arg0}`;
46
+ const values = [...additional, ...argsRest];
47
+ const parts = format.split(/(%[%\w])/g);
48
+ const messageToConsole: string[] = [];
49
+ const valuesToConsole: unknown[] = [];
50
+ let valIndex = 0;
51
+ for (let i = 0; i < parts.length; i++) {
52
+ if (i % 2 === 0) {
53
+ // Regular string part
54
+ messageToConsole.push(parts[i]!);
55
+ continue;
56
+ }
57
+ // Specifier part
58
+ const specifier = parts[i]!;
59
+ if (specifier === '%%') {
60
+ messageToConsole.push('%');
61
+ } else {
62
+ if (valIndex >= values.length) {
63
+ messageToConsole.push(specifier);
64
+ continue;
65
+ }
66
+ const arg = values[valIndex++]!;
67
+ const f = serializeValue(arg, specifier as SerializeFormat, serializer);
68
+ if (f != null) {
69
+ messageToConsole.push('%s');
70
+ valuesToConsole.push(f);
71
+ } else {
72
+ messageToConsole.push(specifier);
73
+ valuesToConsole.push(arg);
74
+ }
75
+ }
76
+ }
77
+
78
+ // Append any remaining arguments separated by spaces
79
+ if (valIndex < values.length) {
80
+ const remaining = values.slice(valIndex);
81
+ valuesToConsole.push(...remaining.map((v) => serializeValue(v, '', serializer) ?? v));
82
+ }
9
83
  // eslint-disable-next-line no-console
10
- console.log(...debug_print.prefix, ...args);
84
+ console.log(messageToConsole.join(''), ...valuesToConsole);
11
85
  },
12
86
  {
13
87
  summary: '打印调试信息到控制台',
@@ -17,7 +91,8 @@ export const debug_print = VmLib(
17
91
  examples: ['debug_print("value:", 42);'],
18
92
  },
19
93
  {
20
- prefix: ['MiraScript'] as readonly string[],
94
+ prefix: ['MiraScript'] as readonly [prefix: string, ...additional: readonly string[]],
95
+ serializer: defaultSerializer,
21
96
  },
22
97
  );
23
98
 
@@ -26,7 +101,7 @@ export const panic = VmLib(
26
101
  // eslint-disable-next-line no-console
27
102
  if (message === undefined) console.error(...panic.prefix);
28
103
  // eslint-disable-next-line no-console
29
- else console.error(...panic.prefix, message);
104
+ else console.error(...panic.prefix, serializeValue(message, '', panic.serializer));
30
105
  const mgsStr = toString(message, null);
31
106
  const error = !mgsStr ? 'panic' : 'panic: ' + mgsStr;
32
107
  throw new VmError(error, undefined);
@@ -40,14 +115,16 @@ export const panic = VmLib(
40
115
  },
41
116
  {
42
117
  prefix: ['MiraScript'] as readonly string[],
118
+ serializer: defaultSerializer,
43
119
  },
44
120
  );
45
121
 
46
122
  if (typeof location != 'undefined') {
47
- const badge = '%cMiraScript';
123
+ const badge = '%cMiraScript%c';
48
124
  const common = 'display: inline-block; padding: 1px 4px; border-radius: 3px;';
49
- debug_print.prefix = [badge, `${common} background: #007acc; color: #fff;`];
50
- panic.prefix = [badge, `${common} background: #d23d3d; color: #fff;`];
125
+ const reset = '';
126
+ debug_print.prefix = [badge, `${common} background: #007acc; color: #fff;`, reset];
127
+ panic.prefix = [badge, `${common} background: #d23d3d; color: #fff;`, reset];
51
128
  } else {
52
129
  if (supportsColor.stdout) {
53
130
  debug_print.prefix = ['\u001B[44;37m MiraScript \u001B[0m'];
@@ -1,5 +1,5 @@
1
1
  import { isVmExtern, isVmModule } from '../../types/index.js';
2
- import { required, rethrowError, VmLib } from '../helpers.js';
2
+ import { expectString, required, rethrowError, VmLib } from '../helpers.js';
3
3
  const { parse, stringify } = JSON;
4
4
 
5
5
  export const to_json = VmLib(
@@ -26,10 +26,9 @@ export const to_json = VmLib(
26
26
 
27
27
  export const from_json = VmLib(
28
28
  (json, fallback) => {
29
- required('json', json, null);
30
- if (typeof json != 'string') return json;
29
+ const j = expectString('json', json);
31
30
  try {
32
- return parse(json);
31
+ return parse(j);
33
32
  } catch (ex) {
34
33
  if (fallback !== undefined) return fallback;
35
34
  rethrowError('Invalid JSON', ex, null);
@@ -1,4 +1,4 @@
1
- import { toBoolean } from '../../../../helpers/convert.js';
1
+ import { toBoolean } from '../../../../helpers/convert/to-boolean.js';
2
2
  import { entries } from '../../../../helpers/utils.js';
3
3
  import { Cp } from '../../../helpers.js';
4
4
  import { $Call } from '../../../operations.js';
@@ -1,4 +1,4 @@
1
- import { toBoolean } from '../../../../helpers/convert.js';
1
+ import { toBoolean } from '../../../../helpers/convert/to-boolean.js';
2
2
  import { entries } from '../../../../helpers/utils.js';
3
3
  import { Cp } from '../../../helpers.js';
4
4
  import { $Call, $Same } from '../../../operations.js';
@@ -1,4 +1,4 @@
1
- import { toBoolean } from '../../../../helpers/convert.js';
1
+ import { toBoolean } from '../../../../helpers/convert/to-boolean.js';
2
2
  import { $Call } from '../../../operations.js';
3
3
  import { isVmConst, type VmAny, type VmValue } from '../../../types/index.js';
4
4
  import { VmLib, expectCallable, expectConst, map as mapImpl } from '../../helpers.js';
@@ -1,4 +1,4 @@
1
- import { toNumber } from '../../../../helpers/convert.js';
1
+ import { toNumber } from '../../../../helpers/convert/to-number.js';
2
2
  import { $Call } from '../../../operations.js';
3
3
  import type { VmAny, VmConst, VmValue } from '../../../types/index.js';
4
4
  import { VmLib, expectArray, expectCallable } from '../../helpers.js';
@@ -1,5 +1,5 @@
1
1
  import { VM_ARRAY_MAX_LENGTH } from '../../../../helpers/constants.js';
2
- import { toNumber, toString } from '../../../../helpers/convert.js';
2
+ import { toNumber, toString } from '../../../../helpers/convert/index.js';
3
3
  import { isVmArray, isVmRecord } from '../../../../helpers/types.js';
4
4
  import { isArray, isInteger, isNaN } from '../../../../helpers/utils.js';
5
5
  import { Element } from '../../../helpers.js';
@@ -1,6 +1,6 @@
1
1
  import { describeParam, expectNumberRange, throwError, throwUnexpectedTypeError, VmLib } from '../helpers.js';
2
2
  import { isNaN, isFinite } from '../../../helpers/utils.js';
3
- import { toNumber } from '../../../helpers/convert.js';
3
+ import { toNumber } from '../../../helpers/convert/to-number.js';
4
4
  import { display } from '../../../helpers/serialize.js';
5
5
  import type { VmAny } from '../../types/index.js';
6
6
 
@@ -1,4 +1,4 @@
1
- import { toBoolean, toFormat, toNumber, toString } from '../../../helpers/convert.js';
1
+ import { toBoolean, toFormat, toNumber, toString } from '../../../helpers/convert/index.js';
2
2
  import { expectString, required, VmLib } from '../helpers.js';
3
3
 
4
4
  export const to_string = VmLib(
@@ -1,7 +1,7 @@
1
1
  import type { Writable } from 'type-fest';
2
2
  import { VM_ARRAY_MAX_LENGTH } from '../../helpers/constants.js';
3
3
  import { isNaN, entries, fromEntries, isSafeInteger, isFinite } from '../../helpers/utils.js';
4
- import { toBoolean, toNumber, toString } from '../../helpers/convert.js';
4
+ import { toBoolean, toNumber, toString } from '../../helpers/convert/index.js';
5
5
  import { display } from '../../helpers/serialize.js';
6
6
  import { isVmArray, isVmFunction, isVmPrimitive, isVmConst, isVmCallable, isVmRecord } from '../../helpers/types.js';
7
7
  import { VmError } from '../../helpers/error.js';
@@ -243,6 +243,7 @@ export function arrayLen(len: number | null | undefined): number {
243
243
  /** 应用映射函数 */
244
244
  export function map(
245
245
  data: VmConst,
246
+ /** 返回 `undefined` 表示跳过该元素 */
246
247
  mapper: (value: VmConst, index: number | string | null, data: VmConst) => VmConst | undefined,
247
248
  ): VmConst {
248
249
  if (isVmPrimitive(data)) {
@@ -279,7 +280,7 @@ export type VmLibOption = Pick<
279
280
  export type VmLib<T extends VmFunctionLike = VmFunctionLike> = T & VmLibOption;
280
281
 
281
282
  /** 创建库函数 */
282
- export function VmLib<T extends VmFunctionLike, P extends Record<string, unknown>>(
283
+ export function VmLib<const T extends VmFunctionLike, P extends Record<string, unknown> = Record<never, never>>(
283
284
  fn: T,
284
285
  option: VmLibOption,
285
286
  properties?: P,
@@ -288,7 +289,7 @@ export function VmLib<T extends VmFunctionLike, P extends Record<string, unknown
288
289
  if (typeof fn != 'function') throw new TypeError('Invalid function');
289
290
  if (isVmFunction(fn)) throw new TypeError('Cannot create VmLib from a VmFunction');
290
291
 
291
- const ret = fn as T & VmLibOption & P as Writable<T & VmLibOption & P>;
292
+ const ret = fn as Writable<VmLib<T>> & P;
292
293
  Object.assign(ret, properties);
293
294
  ret.params = option.params;
294
295
  ret.paramsType = option.paramsType;
@@ -296,5 +297,5 @@ export function VmLib<T extends VmFunctionLike, P extends Record<string, unknown
296
297
  ret.returnsType = option.returnsType;
297
298
  ret.summary = option.summary;
298
299
  ret.examples = option.examples;
299
- return ret as T & VmLibOption & P;
300
+ return ret as VmLib<T> & P;
300
301
  }
@@ -1,16 +1,16 @@
1
1
  import * as global from './global/index.js';
2
2
  import * as mods from './mod/index.js';
3
- import { VmSharedContext } from '../types/context.js';
3
+ import { VM_SHARED_CONTEXT } from '../types/context.js';
4
4
  import { create, entries } from '../../helpers/utils.js';
5
5
  import { createModule, wrapEntry, type RawValue } from './loader.js';
6
6
 
7
7
  for (const [name, value] of entries(global)) {
8
- VmSharedContext[name] = wrapEntry(name, value as RawValue, 'global');
8
+ VM_SHARED_CONTEXT[name] = wrapEntry(name, value as RawValue, 'global');
9
9
  }
10
10
 
11
11
  for (const [name, value] of entries(mods)) {
12
12
  const mod = createModule(name, value as Record<string, RawValue>);
13
- VmSharedContext[name] = wrapEntry(name, mod, 'global');
13
+ VM_SHARED_CONTEXT[name] = wrapEntry(name, mod, 'global');
14
14
  }
15
15
 
16
- export const lib = Object.freeze(Object.assign(create(null), global, mods));
16
+ export const lib: Readonly<typeof global & typeof mods> = Object.freeze(Object.assign(create(null), global, mods));
@@ -1,4 +1,4 @@
1
- import { toNumber } from '../../../helpers/convert.js';
1
+ import { toNumber } from '../../../helpers/convert/to-number.js';
2
2
  import { isArray } from '../../../helpers/utils.js';
3
3
  import { Cp } from '../../helpers.js';
4
4
  import { $Add, $Call, $Div, $Mul, $Sub } from '../../operations.js';
@@ -1,6 +1,6 @@
1
1
  import { VmError } from '../helpers/error.js';
2
2
  import { hasOwnEnumerable, isNaN, isSafeInteger, keys, create } from '../helpers/utils.js';
3
- import { toNumber, toString, toBoolean, toFormat } from '../helpers/convert.js';
3
+ import { toNumber, toString, toBoolean, toFormat } from '../helpers/convert/index.js';
4
4
  import { display } from '../helpers/serialize.js';
5
5
  import { isVmPrimitive, isVmArray, isVmRecord, isVmFunction, isVmExtern, isVmWrapper } from '../helpers/types.js';
6
6
  import type { TypeName, VmAny, VmImmutable, VmRecord, VmValue, VmArray, VmConst } from './types/index.js';
@@ -200,10 +200,9 @@ export const $Length = (value: VmAny): number => {
200
200
  $AssertInit(value);
201
201
  if (isVmArray(value)) return value.length;
202
202
  if (isVmRecord(value)) return keys(value).length;
203
- if (isVmWrapper(value)) {
204
- return value.keys().length;
205
- }
206
- return Number.NaN;
203
+ if (isVmWrapper(value)) return value.keys().length;
204
+
205
+ throw new VmError(`Value has no length: ${display(value)}`, 0);
207
206
  };
208
207
  export const $Omit = (value: VmAny, omitted: ReadonlyArray<number | string>): VmRecord => {
209
208
  $AssertInit(value);
@@ -250,14 +249,14 @@ const sliceCore = (value: VmArray, start: number, end: number, exclusive: boolea
250
249
  };
251
250
  export const $Slice = (value: VmAny, start: VmAny, end: VmAny): VmArray => {
252
251
  $AssertInit(value);
253
- if (!isVmArray(value)) throw new VmError(`Expected array, got ${$Type(value)}`, []);
252
+ if (!isVmArray(value)) throw new VmError(`Expected array, got ${display(value)}`, []);
254
253
  const s = start != null ? $ToNumber(start) : 0;
255
254
  const e = end != null ? $ToNumber(end) : value.length - 1;
256
255
  return sliceCore(value, s, e, false);
257
256
  };
258
257
  export const $SliceExclusive = (value: VmAny, start: VmAny, end: VmAny): VmArray => {
259
258
  $AssertInit(value);
260
- if (!isVmArray(value)) throw new VmError(`Expected array, got ${$Type(value)}`, []);
259
+ if (!isVmArray(value)) throw new VmError(`Expected array, got ${display(value)}`, []);
261
260
  const s = start != null ? $ToNumber(start) : 0;
262
261
  const e = end != null ? $ToNumber(end) : value.length;
263
262
  return sliceCore(value, s, e, true);
@@ -323,7 +322,7 @@ export const $IsArray = (value: VmAny): value is VmArray => {
323
322
  export const $AssertNonNil = (value: VmAny): asserts value is NonNullable<VmValue> => {
324
323
  $AssertInit(value);
325
324
  if (value !== null) return;
326
- throw new VmError('Expected non-nil value', null);
325
+ throw new VmError(`Expected non-nil value`, null);
327
326
  };
328
327
  export const $Has = (obj: VmAny, key: VmAny): boolean => {
329
328
  $AssertInit(obj);
@@ -350,7 +349,7 @@ export const $Set = (obj: VmAny, key: VmAny, value: VmAny): void => {
350
349
  $AssertInit(value);
351
350
  const pk = $ToString(key);
352
351
  if (obj == null) return;
353
- if (!isVmExtern(obj)) throw new VmError(`Expected extern, got ${$Type(obj)}`, undefined);
352
+ if (!isVmExtern(obj)) throw new VmError(`Expected extern, got ${display(obj)}`, undefined);
354
353
  obj.set(pk, value);
355
354
  };
356
355
  export const $Iterable = (value: VmAny): Iterable<VmValue | undefined> => {
@@ -358,7 +357,7 @@ export const $Iterable = (value: VmAny): Iterable<VmValue | undefined> => {
358
357
  if (isVmWrapper(value)) return value.keys();
359
358
  if (isVmArray(value)) return value;
360
359
  if (value != null && typeof value == 'object') return keys(value);
361
- throw new VmError(`Value is not iterable`, isVmFunction(value) ? [] : [value]);
360
+ throw new VmError(`Value is not iterable: ${display(value)}`, isVmFunction(value) ? [] : [value]);
362
361
  };
363
362
 
364
363
  export const $RecordSpread = (record: VmAny): VmRecord | null => {
@@ -384,7 +383,7 @@ export const $RecordSpread = (record: VmAny): VmRecord | null => {
384
383
  }
385
384
  return result;
386
385
  }
387
- throw new VmError(`Expected record, array, extern or nil, got ${$Type(record)}`, null);
386
+ throw new VmError(`Expected record, array, extern or nil, got ${display(record)}`, null);
388
387
  };
389
388
 
390
389
  export const $ArraySpread = (array: VmAny): Iterable<VmConst | undefined> => {
@@ -403,7 +402,7 @@ export const $ArraySpread = (array: VmAny): Iterable<VmConst | undefined> => {
403
402
  }
404
403
  return result;
405
404
  }
406
- throw new VmError(`Expected array, iterable extern or nil, got ${$Type(array)}`, []);
405
+ throw new VmError(`Expected array, iterable extern or nil, got ${display(array)}`, []);
407
406
  };
408
407
 
409
408
  export const $Format = (value: VmAny, format: VmAny): string => {
@@ -2,33 +2,17 @@ import { create, entries, keys } from '../../helpers/utils.js';
2
2
  import { isVmAny } from '../../helpers/types.js';
3
3
  import { VmError } from '../../helpers/error.js';
4
4
  import { kVmContext } from '../../helpers/constants.js';
5
- import type { lib } from '../lib/index.js';
6
- import type { VmAny, VmImmutable, VmValue, VmFunctionLike, VmModule } from './index.js';
5
+ import type { VmAny, VmImmutable, VmValue } from './index.js';
7
6
  import { wrapToVmValue } from './boundary.js';
8
7
  import { VmFunction } from './function.js';
8
+ const { freeze } = Object;
9
9
 
10
- /** 全局导入的标准库值 */
11
- type ToLibValue<V> = V extends VmFunctionLike
12
- ? VmFunction<V>
13
- : V extends Record<string, VmImmutable | VmFunctionLike>
14
- ? ToLibModule<V>
15
- : V;
16
- /** 全局导入的标准库值 */
17
- type ToLibModule<V extends Record<string, VmImmutable | VmFunctionLike>> = VmModule<{
18
- [key in keyof V]: ToLibValue<V[key]>;
19
- }>;
20
- /** 全局导入的标准库 */
21
- type VmContextBase = {
22
- [key in keyof typeof lib]: ToLibValue<(typeof lib)[key]>;
23
- };
24
- /** MiraScript 执行上下文的基础,仅包含标准库 */
25
- export type VmSharedContext = VmContextBase & Record<string, VmImmutable>;
26
10
  /** MiraScript 执行上下文 */
27
11
  export interface VmContext {
28
12
  /** 内部标识符 */
29
13
  readonly [kVmContext]: true;
30
14
  /** 枚举所有 key,仅在 LSP 中使用 */
31
- keys(): Iterable<string>;
15
+ keys(): readonly string[];
32
16
  /** 描述值,返回 MarkDown 文本,仅在 LSP 中使用 */
33
17
  describe?(key: string): string | undefined;
34
18
  /**
@@ -43,9 +27,9 @@ export interface VmContext {
43
27
  export type VmContextRecord = Record<string, VmValue>;
44
28
  /** MiraScript 执行上下文 */
45
29
  export type VmContextRecordLoose = Record<string, VmValue | undefined>;
46
- export const VmSharedContext = create(null) as VmSharedContext;
47
-
48
- let VmSharedContextKeys: readonly string[] | null = null;
30
+ export const VM_SHARED_CONTEXT: Record<string, VmImmutable> = create(null);
31
+ /** 缓存 {@link VM_SHARED_CONTEXT} 的 keys */
32
+ let VM_SHARED_CONTEXT_KEYS: readonly string[] | null = null;
49
33
 
50
34
  /** 全局变量未找到 */
51
35
  function globalVarNotFound(name: string): never {
@@ -58,7 +42,7 @@ export function defineVmContextValue(
58
42
  value: VmImmutable | ((...args: VmAny[]) => VmAny),
59
43
  override = false,
60
44
  ): void {
61
- if (!override && name in VmSharedContext) throw new Error(`Global variable '${name}' is already defined.`);
45
+ if (!override && name in VM_SHARED_CONTEXT) throw new Error(`Global variable '${name}' is already defined.`);
62
46
  let v: VmImmutable;
63
47
  if (typeof value == 'function') {
64
48
  v = VmFunction(value, {
@@ -68,38 +52,42 @@ export function defineVmContextValue(
68
52
  } else {
69
53
  v = value;
70
54
  }
71
- VmSharedContext[name] = v ?? null;
72
- VmSharedContextKeys = null;
55
+ VM_SHARED_CONTEXT[name] = v ?? null;
56
+ VM_SHARED_CONTEXT_KEYS = null;
73
57
  }
74
58
 
75
59
  /** 无后备的实现 */
76
- export const DefaultVmContext: VmContext = Object.freeze({
60
+ export const DefaultVmContext: VmContext = freeze({
77
61
  [kVmContext]: true as const,
78
62
  /** @inheritdoc */
79
- keys(): Iterable<string> {
80
- VmSharedContextKeys ??= Object.freeze(keys(VmSharedContext));
81
- return VmSharedContextKeys;
63
+ keys(): readonly string[] {
64
+ VM_SHARED_CONTEXT_KEYS ??= freeze(keys(VM_SHARED_CONTEXT));
65
+ return VM_SHARED_CONTEXT_KEYS;
82
66
  },
83
67
  /** @inheritdoc */
84
68
  get(key: string): VmValue {
85
- const val = VmSharedContext[key];
69
+ const val = VM_SHARED_CONTEXT[key];
86
70
  if (val === undefined) globalVarNotFound(key);
87
71
  return val;
88
72
  },
89
73
  /** @inheritdoc */
90
74
  has(key: string): boolean {
91
- return key in VmSharedContext;
75
+ return key in VM_SHARED_CONTEXT;
92
76
  },
93
77
  });
94
78
 
95
79
  /** 以值为后备的实现 */
96
80
  class ValueVmContext implements VmContext {
97
81
  readonly [kVmContext] = true;
98
- private cachedKeys: readonly string[] | null = null;
82
+ private cachedKeys: readonly [def: readonly string[], all: readonly string[]] | null = null;
99
83
  /** @inheritdoc */
100
- keys(): Iterable<string> {
101
- this.cachedKeys ??= keys(this.env);
102
- return [...this.cachedKeys, ...DefaultVmContext.keys()];
84
+ keys(): readonly string[] {
85
+ const defaultKeys = DefaultVmContext.keys();
86
+ if (this.cachedKeys?.[0] !== defaultKeys) {
87
+ const allKeys = freeze([...keys(this.env), ...defaultKeys]);
88
+ this.cachedKeys = freeze([defaultKeys, allKeys]);
89
+ }
90
+ return this.cachedKeys[1];
103
91
  }
104
92
  /** @inheritdoc */
105
93
  get(key: string): VmValue {
@@ -122,9 +110,9 @@ class ValueVmContext implements VmContext {
122
110
  class FactoryVmContext implements VmContext {
123
111
  readonly [kVmContext] = true;
124
112
  /** @inheritdoc */
125
- keys(): Iterable<string> {
113
+ keys(): readonly string[] {
126
114
  if (!this.enumerator) return DefaultVmContext.keys();
127
- return [...this.enumerator(), ...DefaultVmContext.keys()];
115
+ return freeze([...this.enumerator(), ...DefaultVmContext.keys()]);
128
116
  }
129
117
  /** @inheritdoc */
130
118
  get(key: string): VmValue {
@@ -169,7 +157,7 @@ export function createVmContext(...args: CreateVmContextWithValues | CreateVmCon
169
157
  }
170
158
 
171
159
  const [vmValues, externValues, describer] = args as CreateVmContextWithValues;
172
- const env = create(VmSharedContext) as VmContextRecord;
160
+ const env: VmContextRecord = create(VM_SHARED_CONTEXT);
173
161
  if (vmValues) {
174
162
  for (const [key, value] of entries(vmValues)) {
175
163
  if (!isVmAny(value, false)) continue;
@@ -1,6 +1,6 @@
1
1
  import { VmError } from '../../helpers/error.js';
2
2
  import { getPrototypeOf, hasOwn, apply, isArray } from '../../helpers/utils.js';
3
- import { innerToString } from '../../helpers/convert.js';
3
+ import { innerToString } from '../../helpers/convert/to-string.js';
4
4
  import { isVmExtern } from '../../helpers/types.js';
5
5
  import { kVmExtern } from '../../helpers/constants.js';
6
6
  import type { TypeName, VmAny, VmConst, VmPrimitive, VmValue } from './index.js';
@@ -76,7 +76,7 @@ export {
76
76
 
77
77
  export { wrapToVmValue, unwrapFromVmValue } from './boundary.js';
78
78
 
79
- export { type VmContext, type VmSharedContext, defineVmContextValue, createVmContext } from './context.js';
79
+ export { type VmContext, defineVmContextValue, createVmContext } from './context.js';
80
80
  export { VmExtern } from './extern.js';
81
81
  export { VmFunction, type VmFunctionInfo, type VmFunctionLike, type VmFunctionOption } from './function.js';
82
82
  export { VmModule } from './module.js';