@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.
- package/dist/{chunk-LU4ZKFF6.js → chunk-3BAOZ2P2.js} +203 -62
- package/dist/chunk-3BAOZ2P2.js.map +6 -0
- package/dist/{chunk-YZGL3D7L.js → chunk-5AEWM4W6.js} +41 -95
- package/dist/chunk-5AEWM4W6.js.map +6 -0
- package/dist/cli/execute.d.ts.map +1 -1
- package/dist/cli/index.js +11 -12
- package/dist/cli/index.js.map +1 -1
- package/dist/compiler/diagnostic.d.ts.map +1 -1
- package/dist/compiler/emit/sourcemap.d.ts.map +1 -1
- package/dist/compiler/worker.js +1 -1
- package/dist/helpers/convert/index.d.ts +5 -0
- package/dist/helpers/convert/index.d.ts.map +1 -0
- package/dist/helpers/convert/to-boolean.d.ts +4 -0
- package/dist/helpers/convert/to-boolean.d.ts.map +1 -0
- package/dist/helpers/convert/to-format.d.ts +4 -0
- package/dist/helpers/convert/to-format.d.ts.map +1 -0
- package/dist/helpers/convert/to-number.d.ts +4 -0
- package/dist/helpers/convert/to-number.d.ts.map +1 -0
- package/dist/helpers/convert/to-string.d.ts +6 -0
- package/dist/helpers/convert/to-string.d.ts.map +1 -0
- package/dist/helpers/serialize.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/subtle.d.ts +2 -2
- package/dist/subtle.d.ts.map +1 -1
- package/dist/subtle.js +3 -5
- package/dist/vm/checkpoint.d.ts.map +1 -1
- package/dist/vm/helpers.d.ts.map +1 -1
- package/dist/vm/lib/global/bit.d.ts +7 -7
- package/dist/vm/lib/global/bit.d.ts.map +1 -1
- package/dist/vm/lib/global/debug.d.ts +17 -1
- package/dist/vm/lib/global/debug.d.ts.map +1 -1
- package/dist/vm/lib/global/json.d.ts +2 -2
- package/dist/vm/lib/global/json.d.ts.map +1 -1
- package/dist/vm/lib/global/math-additional.d.ts +1 -1
- package/dist/vm/lib/global/math-additional.d.ts.map +1 -1
- package/dist/vm/lib/global/math-arr.d.ts +5 -5
- package/dist/vm/lib/global/math-arr.d.ts.map +1 -1
- package/dist/vm/lib/global/math-unary.d.ts +26 -26
- package/dist/vm/lib/global/math-unary.d.ts.map +1 -1
- package/dist/vm/lib/global/math.d.ts +3 -3
- package/dist/vm/lib/global/math.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/all-any.d.ts +2 -2
- package/dist/vm/lib/global/sequence/all-any.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/entries.d.ts +3 -3
- package/dist/vm/lib/global/sequence/entries.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/find.d.ts +1 -1
- package/dist/vm/lib/global/sequence/find.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/flatten.d.ts +1 -1
- package/dist/vm/lib/global/sequence/flatten.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/len.d.ts +1 -1
- package/dist/vm/lib/global/sequence/len.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/map-filter.d.ts +3 -3
- package/dist/vm/lib/global/sequence/map-filter.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/repeat.d.ts +1 -1
- package/dist/vm/lib/global/sequence/repeat.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/reverse.d.ts +1 -1
- package/dist/vm/lib/global/sequence/reverse.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/sort.d.ts +2 -2
- package/dist/vm/lib/global/sequence/sort.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/with.d.ts +1 -1
- package/dist/vm/lib/global/sequence/with.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/zip.d.ts +1 -1
- package/dist/vm/lib/global/sequence/zip.d.ts.map +1 -1
- package/dist/vm/lib/global/string.d.ts +10 -10
- package/dist/vm/lib/global/string.d.ts.map +1 -1
- package/dist/vm/lib/global/time.d.ts +3 -3
- package/dist/vm/lib/global/time.d.ts.map +1 -1
- package/dist/vm/lib/global/to-primitive.d.ts +4 -4
- package/dist/vm/lib/global/to-primitive.d.ts.map +1 -1
- package/dist/vm/lib/helpers.d.ts +4 -2
- package/dist/vm/lib/helpers.d.ts.map +1 -1
- package/dist/vm/lib/index.d.ts +1 -1
- package/dist/vm/lib/index.d.ts.map +1 -1
- package/dist/vm/lib/mod/matrix.d.ts +13 -13
- package/dist/vm/lib/mod/matrix.d.ts.map +1 -1
- package/dist/vm/operations.d.ts.map +1 -1
- package/dist/vm/types/context.d.ts +3 -17
- package/dist/vm/types/context.d.ts.map +1 -1
- package/dist/vm/types/index.d.ts +1 -1
- package/dist/vm/types/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/cli/execute.ts +10 -10
- package/src/compiler/diagnostic.ts +29 -11
- package/src/compiler/emit/globals.ts +1 -1
- package/src/compiler/emit/sourcemap.ts +8 -3
- package/src/helpers/convert/index.ts +4 -0
- package/src/helpers/convert/to-boolean.ts +12 -0
- package/src/helpers/convert/to-format.ts +37 -0
- package/src/helpers/convert/to-number.ts +35 -0
- package/src/helpers/convert/to-string.ts +55 -0
- package/src/helpers/serialize.ts +1 -0
- package/src/subtle.ts +2 -2
- package/src/vm/checkpoint.ts +19 -10
- package/src/vm/helpers.ts +1 -1
- package/src/vm/lib/global/debug.ts +84 -7
- package/src/vm/lib/global/json.ts +3 -4
- package/src/vm/lib/global/sequence/all-any.ts +1 -1
- package/src/vm/lib/global/sequence/find.ts +1 -1
- package/src/vm/lib/global/sequence/map-filter.ts +1 -1
- package/src/vm/lib/global/sequence/sort.ts +1 -1
- package/src/vm/lib/global/sequence/with.ts +1 -1
- package/src/vm/lib/global/time.ts +1 -1
- package/src/vm/lib/global/to-primitive.ts +1 -1
- package/src/vm/lib/helpers.ts +5 -4
- package/src/vm/lib/index.ts +4 -4
- package/src/vm/lib/mod/matrix.ts +1 -1
- package/src/vm/operations.ts +11 -12
- package/src/vm/types/context.ts +26 -38
- package/src/vm/types/extern.ts +1 -1
- package/src/vm/types/index.ts +1 -1
- package/dist/chunk-LU4ZKFF6.js.map +0 -6
- package/dist/chunk-YZGL3D7L.js.map +0 -6
- package/dist/helpers/convert.d.ts +0 -12
- package/dist/helpers/convert.d.ts.map +0 -1
- 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(
|
|
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
|
-
|
|
50
|
-
|
|
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
|
-
|
|
30
|
-
if (typeof json != 'string') return json;
|
|
29
|
+
const j = expectString('json', json);
|
|
31
30
|
try {
|
|
32
|
-
return parse(
|
|
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(
|
package/src/vm/lib/helpers.ts
CHANGED
|
@@ -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
|
|
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 &
|
|
300
|
+
return ret as VmLib<T> & P;
|
|
300
301
|
}
|
package/src/vm/lib/index.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import * as global from './global/index.js';
|
|
2
2
|
import * as mods from './mod/index.js';
|
|
3
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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));
|
package/src/vm/lib/mod/matrix.ts
CHANGED
|
@@ -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';
|
package/src/vm/operations.ts
CHANGED
|
@@ -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
|
-
|
|
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 ${
|
|
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 ${
|
|
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(
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 => {
|
package/src/vm/types/context.ts
CHANGED
|
@@ -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 {
|
|
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():
|
|
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
|
|
47
|
-
|
|
48
|
-
let
|
|
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
|
|
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
|
-
|
|
72
|
-
|
|
55
|
+
VM_SHARED_CONTEXT[name] = v ?? null;
|
|
56
|
+
VM_SHARED_CONTEXT_KEYS = null;
|
|
73
57
|
}
|
|
74
58
|
|
|
75
59
|
/** 无后备的实现 */
|
|
76
|
-
export const DefaultVmContext: VmContext =
|
|
60
|
+
export const DefaultVmContext: VmContext = freeze({
|
|
77
61
|
[kVmContext]: true as const,
|
|
78
62
|
/** @inheritdoc */
|
|
79
|
-
keys():
|
|
80
|
-
|
|
81
|
-
return
|
|
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 =
|
|
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
|
|
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():
|
|
101
|
-
|
|
102
|
-
|
|
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():
|
|
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(
|
|
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;
|
package/src/vm/types/extern.ts
CHANGED
|
@@ -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';
|
package/src/vm/types/index.ts
CHANGED
|
@@ -76,7 +76,7 @@ export {
|
|
|
76
76
|
|
|
77
77
|
export { wrapToVmValue, unwrapFromVmValue } from './boundary.js';
|
|
78
78
|
|
|
79
|
-
export { type VmContext,
|
|
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';
|