@mirascript/mirascript 0.1.15 → 0.1.17
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-JG3D67GF.js +1625 -0
- package/dist/chunk-JG3D67GF.js.map +6 -0
- package/dist/chunk-RIT53WVY.js +1 -0
- package/dist/chunk-RLWIIOH5.js +12 -0
- package/dist/chunk-RLWIIOH5.js.map +6 -0
- package/dist/{chunk-NT235HY3.js → chunk-W2I5XPIE.js} +1490 -608
- package/dist/chunk-W2I5XPIE.js.map +6 -0
- package/dist/cli/index.js +11 -67
- package/dist/cli/index.js.map +2 -2
- package/dist/compiler/compile-fast.d.ts +1 -1
- package/dist/compiler/compile-fast.d.ts.map +1 -1
- package/dist/compiler/create-script.d.ts +10 -1
- package/dist/compiler/create-script.d.ts.map +1 -1
- package/dist/compiler/diagnostic.d.ts +1 -1
- package/dist/compiler/diagnostic.d.ts.map +1 -1
- package/dist/compiler/emit/constants.d.ts +3 -0
- package/dist/compiler/emit/constants.d.ts.map +1 -0
- package/dist/compiler/emit/consts.d.ts +6 -0
- package/dist/compiler/emit/consts.d.ts.map +1 -0
- package/dist/compiler/emit/globals.d.ts +17 -0
- package/dist/compiler/emit/globals.d.ts.map +1 -0
- package/dist/compiler/emit/index.d.ts +58 -0
- package/dist/compiler/emit/index.d.ts.map +1 -0
- package/dist/compiler/emit/sourcemap.d.ts +6 -0
- package/dist/compiler/emit/sourcemap.d.ts.map +1 -0
- package/dist/compiler/index.d.ts +3 -2
- package/dist/compiler/index.d.ts.map +1 -1
- package/dist/compiler/worker.js +1 -1
- package/dist/helpers/constants.d.ts +10 -0
- package/dist/helpers/constants.d.ts.map +1 -1
- package/dist/helpers/convert/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/{vm → helpers}/error.d.ts +1 -1
- package/dist/helpers/error.d.ts.map +1 -0
- package/dist/helpers/serialize.d.ts +13 -4
- package/dist/helpers/serialize.d.ts.map +1 -1
- package/dist/helpers/types.d.ts +54 -0
- package/dist/helpers/types.d.ts.map +1 -0
- package/dist/index.js +11 -17
- package/dist/subtle.d.ts +4 -3
- package/dist/subtle.d.ts.map +1 -1
- package/dist/subtle.js +20 -16
- package/dist/vm/checkpoint.d.ts +9 -0
- package/dist/vm/checkpoint.d.ts.map +1 -0
- package/dist/vm/helpers.d.ts +4 -10
- package/dist/vm/helpers.d.ts.map +1 -1
- package/dist/vm/index.d.ts +3 -3
- package/dist/vm/index.d.ts.map +1 -1
- package/dist/vm/lib/global/bit.d.ts +7 -7
- package/dist/vm/lib/global/bit.d.ts.map +1 -1
- package/dist/vm/lib/global/debug.d.ts +2 -2
- package/dist/vm/lib/global/debug.d.ts.map +1 -1
- package/dist/vm/lib/global/index.d.ts +0 -1
- package/dist/vm/lib/global/index.d.ts.map +1 -1
- package/dist/vm/lib/global/json.d.ts +2 -2
- package/dist/vm/lib/global/json.d.ts.map +1 -1
- package/dist/vm/lib/global/math-additional.d.ts +1 -1
- package/dist/vm/lib/global/math-additional.d.ts.map +1 -1
- package/dist/vm/lib/global/math-arr.d.ts +5 -5
- package/dist/vm/lib/global/math-arr.d.ts.map +1 -1
- package/dist/vm/lib/global/math-unary.d.ts +26 -26
- package/dist/vm/lib/global/math-unary.d.ts.map +1 -1
- package/dist/vm/lib/global/math.d.ts +3 -3
- package/dist/vm/lib/global/math.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/all-any.d.ts +2 -2
- package/dist/vm/lib/global/sequence/all-any.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/entries.d.ts +5 -5
- package/dist/vm/lib/global/sequence/entries.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/find.d.ts +3 -3
- package/dist/vm/lib/global/sequence/find.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/flatten.d.ts +1 -1
- package/dist/vm/lib/global/sequence/flatten.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/len.d.ts +1 -1
- package/dist/vm/lib/global/sequence/len.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/map-filter.d.ts +3 -3
- package/dist/vm/lib/global/sequence/map-filter.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/repeat.d.ts +1 -1
- package/dist/vm/lib/global/sequence/repeat.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/reverse.d.ts +1 -1
- package/dist/vm/lib/global/sequence/reverse.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/sort.d.ts +2 -2
- package/dist/vm/lib/global/sequence/sort.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/with.d.ts +2 -2
- package/dist/vm/lib/global/sequence/with.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/zip.d.ts +1 -1
- package/dist/vm/lib/global/sequence/zip.d.ts.map +1 -1
- package/dist/vm/lib/global/string.d.ts +10 -10
- package/dist/vm/lib/global/string.d.ts.map +1 -1
- package/dist/vm/lib/global/time.d.ts +3 -13
- package/dist/vm/lib/global/time.d.ts.map +1 -1
- package/dist/vm/lib/global/to-primitive.d.ts +4 -4
- package/dist/vm/lib/global/to-primitive.d.ts.map +1 -1
- package/dist/vm/lib/helpers.d.ts +53 -0
- package/dist/vm/lib/helpers.d.ts.map +1 -0
- package/dist/vm/lib/index.d.ts +4 -0
- package/dist/vm/lib/index.d.ts.map +1 -0
- package/dist/vm/lib/{_loader.d.ts → loader.d.ts} +5 -5
- package/dist/vm/lib/loader.d.ts.map +1 -0
- package/dist/vm/lib/mod/index.d.ts +2 -0
- package/dist/vm/lib/mod/index.d.ts.map +1 -0
- package/dist/vm/lib/mod/matrix.d.ts +15 -0
- package/dist/vm/lib/mod/matrix.d.ts.map +1 -0
- package/dist/vm/operations.d.ts +2 -4
- package/dist/vm/operations.d.ts.map +1 -1
- package/dist/vm/types/boundary.d.ts +1 -1
- package/dist/vm/types/boundary.d.ts.map +1 -1
- package/dist/vm/types/context.d.ts +4 -17
- package/dist/vm/types/context.d.ts.map +1 -1
- package/dist/vm/types/extern.d.ts +1 -3
- package/dist/vm/types/extern.d.ts.map +1 -1
- package/dist/vm/types/function.d.ts +1 -6
- package/dist/vm/types/function.d.ts.map +1 -1
- package/dist/vm/types/index.d.ts +31 -17
- package/dist/vm/types/index.d.ts.map +1 -1
- package/dist/vm/types/module.d.ts +2 -4
- package/dist/vm/types/module.d.ts.map +1 -1
- package/dist/vm/types/wrapper.d.ts +0 -2
- package/dist/vm/types/wrapper.d.ts.map +1 -1
- package/package.json +7 -3
- package/src/cli/index.ts +1 -1
- package/src/compiler/compile-fast.ts +1 -2
- package/src/compiler/create-script.ts +12 -2
- package/src/compiler/diagnostic.ts +17 -8
- package/src/compiler/emit/constants.ts +2 -0
- package/src/compiler/emit/consts.ts +47 -0
- package/src/compiler/emit/globals.ts +39 -0
- package/src/compiler/{emit.ts → emit/index.ts} +16 -200
- package/src/compiler/emit/sourcemap.ts +168 -0
- package/src/compiler/index.ts +9 -9
- package/src/compiler/worker.ts +1 -1
- package/src/helpers/constants.ts +12 -0
- package/src/helpers/convert/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/{vm → helpers}/error.ts +1 -1
- package/src/helpers/serialize.ts +72 -24
- package/src/helpers/types.ts +267 -0
- package/src/subtle.ts +4 -2
- package/src/vm/checkpoint.ts +42 -0
- package/src/vm/helpers.ts +9 -53
- package/src/vm/index.ts +3 -3
- package/src/vm/lib/global/bit.ts +8 -9
- package/src/vm/lib/global/debug.ts +5 -4
- package/src/vm/lib/global/index.ts +0 -1
- package/src/vm/lib/global/json.ts +2 -2
- package/src/vm/lib/global/math-additional.ts +2 -4
- package/src/vm/lib/global/math-arr.ts +1 -1
- package/src/vm/lib/global/math-unary.ts +2 -4
- package/src/vm/lib/global/math.ts +3 -4
- package/src/vm/lib/global/sequence/all-any.ts +11 -6
- package/src/vm/lib/global/sequence/entries.ts +1 -1
- package/src/vm/lib/global/sequence/find.ts +4 -3
- package/src/vm/lib/global/sequence/flatten.ts +2 -3
- package/src/vm/lib/global/sequence/len.ts +1 -1
- package/src/vm/lib/global/sequence/map-filter.ts +4 -3
- package/src/vm/lib/global/sequence/repeat.ts +2 -4
- package/src/vm/lib/global/sequence/reverse.ts +1 -1
- package/src/vm/lib/global/sequence/sort.ts +6 -5
- package/src/vm/lib/global/sequence/with.ts +21 -20
- package/src/vm/lib/global/sequence/zip.ts +3 -3
- package/src/vm/lib/global/string.ts +16 -27
- package/src/vm/lib/global/time.ts +59 -30
- package/src/vm/lib/global/to-primitive.ts +27 -18
- package/src/vm/lib/{_helpers.ts → helpers.ts} +132 -44
- package/src/vm/lib/index.ts +16 -0
- package/src/vm/lib/{_loader.ts → loader.ts} +3 -11
- package/src/vm/lib/mod/index.ts +1 -0
- package/src/vm/lib/{global/mod → mod}/matrix.ts +9 -7
- package/src/vm/operations.ts +41 -137
- package/src/vm/types/boundary.ts +10 -13
- package/src/vm/types/context.ts +31 -50
- package/src/vm/types/extern.ts +8 -15
- package/src/vm/types/function.ts +4 -19
- package/src/vm/types/index.ts +47 -25
- package/src/vm/types/module.ts +3 -7
- package/src/vm/types/wrapper.ts +1 -5
- package/dist/chunk-35JGBXRE.js +0 -1
- package/dist/chunk-JVFUK7AN.js +0 -2324
- package/dist/chunk-JVFUK7AN.js.map +0 -6
- package/dist/chunk-NT235HY3.js.map +0 -6
- package/dist/compiler/emit.d.ts +0 -5
- package/dist/compiler/emit.d.ts.map +0 -1
- package/dist/vm/error.d.ts.map +0 -1
- package/dist/vm/lib/_helpers.d.ts +0 -35
- package/dist/vm/lib/_helpers.d.ts.map +0 -1
- package/dist/vm/lib/_loader.d.ts.map +0 -1
- package/dist/vm/lib/global/mod/index.d.ts +0 -3
- package/dist/vm/lib/global/mod/index.d.ts.map +0 -1
- package/dist/vm/lib/global/mod/matrix.d.ts +0 -15
- package/dist/vm/lib/global/mod/matrix.d.ts.map +0 -1
- package/dist/vm/types/any.d.ts +0 -10
- package/dist/vm/types/any.d.ts.map +0 -1
- package/dist/vm/types/array.d.ts +0 -12
- package/dist/vm/types/array.d.ts.map +0 -1
- package/dist/vm/types/callable.d.ts +0 -5
- package/dist/vm/types/callable.d.ts.map +0 -1
- package/dist/vm/types/const.d.ts +0 -15
- package/dist/vm/types/const.d.ts.map +0 -1
- package/dist/vm/types/immutable.d.ts +0 -15
- package/dist/vm/types/immutable.d.ts.map +0 -1
- package/dist/vm/types/primitive.d.ts +0 -7
- package/dist/vm/types/primitive.d.ts.map +0 -1
- package/dist/vm/types/record.d.ts +0 -20
- package/dist/vm/types/record.d.ts.map +0 -1
- package/dist/vm/types/script.d.ts +0 -14
- package/dist/vm/types/script.d.ts.map +0 -1
- package/dist/vm/types/value.d.ts +0 -14
- package/dist/vm/types/value.d.ts.map +0 -1
- package/src/vm/lib/global/mod/index.ts +0 -4
- package/src/vm/types/any.ts +0 -33
- package/src/vm/types/array.ts +0 -19
- package/src/vm/types/callable.ts +0 -10
- package/src/vm/types/const.ts +0 -109
- package/src/vm/types/immutable.ts +0 -22
- package/src/vm/types/primitive.ts +0 -14
- package/src/vm/types/record.ts +0 -53
- package/src/vm/types/script.ts +0 -18
- package/src/vm/types/value.ts +0 -22
- /package/dist/{chunk-35JGBXRE.js.map → chunk-RIT53WVY.js.map} +0 -0
package/src/compiler/index.ts
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import { loadModule } from '@mirascript/bindings';
|
|
2
|
-
import type { VmScript } from '../vm/index.js';
|
|
3
2
|
import type { ScriptInput, TranspileOptions } from './types.js';
|
|
4
|
-
import { emit } from './emit.js';
|
|
5
|
-
import { createScript } from './create-script.js';
|
|
3
|
+
import { emit } from './emit/index.js';
|
|
4
|
+
import { createScript, type VmScript } from './create-script.js';
|
|
6
5
|
import { compileFast } from './compile-fast.js';
|
|
7
|
-
import { DiagnosticCode,
|
|
6
|
+
import { DiagnosticCode, formatDiagnostics, parseDiagnostics } from './diagnostic.js';
|
|
8
7
|
import { generateBytecode, generateBytecodeSync } from './generate-bytecode.js';
|
|
9
8
|
import { compileWorker } from './worker-manager.js';
|
|
10
9
|
await loadModule();
|
|
11
10
|
|
|
12
11
|
export { generateBytecode, generateBytecodeSync };
|
|
13
|
-
export
|
|
12
|
+
export * from './types.js';
|
|
13
|
+
export type { VmScript };
|
|
14
14
|
|
|
15
15
|
// 目前编译速度约 2000kB/s
|
|
16
16
|
const WORKER_MIN_LEN = typeof Worker != 'function' ? Number.MAX_VALUE : 1024;
|
|
17
17
|
|
|
18
18
|
/** 报告编译错误 */
|
|
19
|
-
function reportDiagnostic(source: ScriptInput, diagnostics: Uint32Array): never {
|
|
19
|
+
function reportDiagnostic(source: ScriptInput, diagnostics: Uint32Array, fileName: string | undefined): never {
|
|
20
20
|
const parsed = parseDiagnostics(source, diagnostics);
|
|
21
|
-
const messages = parsed.errors
|
|
21
|
+
const messages = formatDiagnostics(parsed.errors, source, fileName);
|
|
22
22
|
throw new Error(`Failed to compile:\n${messages.join('\n')}`);
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -31,7 +31,7 @@ export function emitScript(
|
|
|
31
31
|
options: TranspileOptions,
|
|
32
32
|
): VmScript {
|
|
33
33
|
if (!code) {
|
|
34
|
-
reportDiagnostic(source, diagnostics);
|
|
34
|
+
reportDiagnostic(source, diagnostics, options.fileName);
|
|
35
35
|
}
|
|
36
36
|
const sourcemaps = options.sourceMap
|
|
37
37
|
? parseDiagnostics(source, diagnostics, (c) => c === DiagnosticCode.SourceMap).sourcemaps
|
|
@@ -59,7 +59,7 @@ export async function compile(this: void, source: ScriptInput, options: Transpil
|
|
|
59
59
|
}
|
|
60
60
|
const [target, diagnostics] = await compileWorker(source, options);
|
|
61
61
|
if (target == null) {
|
|
62
|
-
reportDiagnostic(source, diagnostics);
|
|
62
|
+
reportDiagnostic(source, diagnostics, options.fileName);
|
|
63
63
|
}
|
|
64
64
|
return createScript(source, target);
|
|
65
65
|
}
|
package/src/compiler/worker.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ScriptInput, TranspileOptions } from './types.js';
|
|
2
|
-
import { emit } from './emit.js';
|
|
2
|
+
import { emit } from './emit/index.js';
|
|
3
3
|
import { generateBytecode } from './generate-bytecode.js';
|
|
4
4
|
import { DiagnosticCode, parseDiagnostics } from './diagnostic.js';
|
|
5
5
|
|
package/src/helpers/constants.ts
CHANGED
|
@@ -6,3 +6,15 @@ export const REG_HEX = /0[xX][a-fA-F0-9_]*[a-fA-F0-9]/;
|
|
|
6
6
|
export const REG_OCT = /0[oO][0-7_]*[0-7]/;
|
|
7
7
|
export const REG_BIN = /0[bB][01_]*[01]/;
|
|
8
8
|
export const REG_NUMBER = /\d[\d_]*(?:\.[\d_]+)?(?:[eE][+-]?[\d_]*\d)?/u;
|
|
9
|
+
export const VM_ARRAY_MAX_LENGTH = 2 ** 31 - 1;
|
|
10
|
+
|
|
11
|
+
export const kVmScript = Symbol.for('mirascript.vm.script');
|
|
12
|
+
export const kVmFunction = Symbol.for('mirascript.vm.function');
|
|
13
|
+
export const kVmFunctionProxy = Symbol.for('mirascript.vm.function.proxy');
|
|
14
|
+
export const kVmContext = Symbol.for('mirascript.vm.context');
|
|
15
|
+
export const kVmExtern = Symbol.for('mirascript.vm.extern');
|
|
16
|
+
export const kVmModule = Symbol.for('mirascript.vm.module');
|
|
17
|
+
export const kVmWrapper = Symbol.for('mirascript.vm.wrapper');
|
|
18
|
+
|
|
19
|
+
export const VM_SCRIPT_NAME = `<script_root>`;
|
|
20
|
+
export const VM_FUNCTION_ANONYMOUS_NAME = `<anonymous>`;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { VmAny } from '../../vm/index.js';
|
|
2
|
+
import { VmError } from '../error.js';
|
|
3
|
+
import { display } from '../serialize.js';
|
|
4
|
+
|
|
5
|
+
/** 转换为 boolean */
|
|
6
|
+
export function toBoolean<F = undefined>(value: VmAny, fallback?: F): boolean | Exclude<F, undefined> {
|
|
7
|
+
if (typeof value === 'boolean') return value;
|
|
8
|
+
if (fallback === undefined) {
|
|
9
|
+
throw new VmError(`Failed to convert value to boolean: ${display(value)}`, false);
|
|
10
|
+
}
|
|
11
|
+
return fallback as Exclude<F, undefined>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { VmAny } from '../../vm/index.js';
|
|
2
|
+
import { isFinite } from '../utils.js';
|
|
3
|
+
import { toString } from './to-string.js';
|
|
4
|
+
|
|
5
|
+
/** 渲染数字 */
|
|
6
|
+
function formatNumber(value: number): string {
|
|
7
|
+
if (!isFinite(value)) return toString(value, undefined as never);
|
|
8
|
+
if (value === 0) return '0';
|
|
9
|
+
const s = value.toString();
|
|
10
|
+
let ps;
|
|
11
|
+
const abs = Math.abs(value);
|
|
12
|
+
if (abs >= 1000 || abs < 0.001) {
|
|
13
|
+
const ps1 = value.toExponential();
|
|
14
|
+
const ps2 = value.toExponential(5);
|
|
15
|
+
ps = ps1.length < ps2.length ? ps1 : ps2;
|
|
16
|
+
} else {
|
|
17
|
+
ps = value.toPrecision(6);
|
|
18
|
+
}
|
|
19
|
+
return ps.length < s.length ? ps : s;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** 格式化为 string */
|
|
23
|
+
export function toFormat(value: VmAny, format: string | null | undefined): string {
|
|
24
|
+
const f = format == null ? '' : format.trim();
|
|
25
|
+
|
|
26
|
+
if (typeof value == 'number') {
|
|
27
|
+
if (/^\.\d+$/.test(f)) {
|
|
28
|
+
let digits = Math.trunc(Number(f.slice(1)));
|
|
29
|
+
if (!(digits <= 100)) digits = 100;
|
|
30
|
+
return value.toFixed(digits);
|
|
31
|
+
} else {
|
|
32
|
+
return formatNumber(value);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return toString(value, undefined as never);
|
|
37
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { VmAny } from '../../vm/index.js';
|
|
2
|
+
import { VmError } from '../error.js';
|
|
3
|
+
import { display } from '../serialize.js';
|
|
4
|
+
import { isNaN } from '../utils.js';
|
|
5
|
+
const { POSITIVE_INFINITY, NEGATIVE_INFINITY } = Number;
|
|
6
|
+
|
|
7
|
+
/** 转换为 number */
|
|
8
|
+
export function toNumber<F = undefined>(value: VmAny, fallback?: F): number | Exclude<F, undefined> {
|
|
9
|
+
if (typeof value === 'number') {
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
if (typeof value == 'boolean') {
|
|
13
|
+
return value ? 1 : 0;
|
|
14
|
+
}
|
|
15
|
+
if (typeof value == 'string') {
|
|
16
|
+
value = value.trim();
|
|
17
|
+
if (value !== '') {
|
|
18
|
+
if (value === 'inf' || value === '+inf' || value === 'Infinity' || value === '+Infinity') {
|
|
19
|
+
return POSITIVE_INFINITY;
|
|
20
|
+
}
|
|
21
|
+
if (value === '-inf' || value === '-Infinity') {
|
|
22
|
+
return NEGATIVE_INFINITY;
|
|
23
|
+
}
|
|
24
|
+
if (value === 'nan' || value === 'NaN') {
|
|
25
|
+
return Number.NaN;
|
|
26
|
+
}
|
|
27
|
+
const num = Number(value);
|
|
28
|
+
if (!isNaN(num)) return num;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (fallback === undefined) {
|
|
32
|
+
throw new VmError(`Failed to convert value to number: ${display(value)}`, Number.NaN);
|
|
33
|
+
}
|
|
34
|
+
return fallback as Exclude<F, undefined>;
|
|
35
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { VmAny, VmRecord } from '../../vm/index.js';
|
|
2
|
+
import { isVmArray, isVmWrapper } from '../types.js';
|
|
3
|
+
import { VmError } from '../error.js';
|
|
4
|
+
import { display, displayFunction } from '../serialize.js';
|
|
5
|
+
import { keys, isNaN } from '../utils.js';
|
|
6
|
+
|
|
7
|
+
/** 转换为 string */
|
|
8
|
+
function numberToString(value: number): string {
|
|
9
|
+
if (isNaN(value)) return 'nan';
|
|
10
|
+
if (value === Infinity) return 'inf';
|
|
11
|
+
if (value === -Infinity) return '-inf';
|
|
12
|
+
return String(value);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** 转换为 string */
|
|
16
|
+
export function innerToString(value: VmAny, useBraces: boolean): string {
|
|
17
|
+
if (value == null) return 'nil';
|
|
18
|
+
if (typeof value == 'number') return numberToString(value);
|
|
19
|
+
if (typeof value == 'string' || typeof value == 'boolean') return String(value);
|
|
20
|
+
if (typeof value == 'function') return displayFunction(value);
|
|
21
|
+
if (isVmWrapper(value)) return value.toString(useBraces);
|
|
22
|
+
if (isVmArray(value)) {
|
|
23
|
+
const strings: string[] = [];
|
|
24
|
+
for (const item of value) {
|
|
25
|
+
strings.push(innerToString(item, true));
|
|
26
|
+
}
|
|
27
|
+
// 在 join 过程中会自动把 null/undefined 和 empty slot 转为 ''
|
|
28
|
+
// 与 innerToString 行为不一致
|
|
29
|
+
const results = strings.join(', ');
|
|
30
|
+
if (!useBraces) return results;
|
|
31
|
+
return `[${results}]`;
|
|
32
|
+
} else {
|
|
33
|
+
const entries = keys(value satisfies VmRecord)
|
|
34
|
+
.map((key) => `${key}: ${innerToString(value[key], true)}`)
|
|
35
|
+
.join(', ');
|
|
36
|
+
if (!useBraces) return entries;
|
|
37
|
+
return `(${entries})`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** 转换为 string */
|
|
42
|
+
export function toString<F = undefined>(value: VmAny, fallback?: F): string | Exclude<F, undefined> {
|
|
43
|
+
if (typeof value === 'string') return value;
|
|
44
|
+
if (value == null) return '';
|
|
45
|
+
try {
|
|
46
|
+
return innerToString(value, false);
|
|
47
|
+
} catch (ex) {
|
|
48
|
+
if (fallback === undefined) {
|
|
49
|
+
const e = new VmError(`Failed to convert value to string: ${display(value)}`, '');
|
|
50
|
+
e.cause = ex;
|
|
51
|
+
throw e;
|
|
52
|
+
}
|
|
53
|
+
return fallback as Exclude<F, undefined>;
|
|
54
|
+
}
|
|
55
|
+
}
|
package/src/helpers/serialize.ts
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
|
+
import type { VmArray, VmExtern, VmFunction, VmModule, VmAny, VmRecord } from '../vm/index.js';
|
|
2
|
+
import { REG_IDENTIFIER, REG_ORDINAL } from './constants.js';
|
|
3
|
+
import { entries, hasOwn, isFinite, isNaN } from '../helpers/utils.js';
|
|
1
4
|
import {
|
|
5
|
+
getVmFunctionInfo,
|
|
2
6
|
isVmArray,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
type VmExtern,
|
|
6
|
-
type VmFunction,
|
|
7
|
-
type VmModule,
|
|
8
|
-
type VmAny,
|
|
9
|
-
type VmRecord,
|
|
7
|
+
isVmArrayLikeRecordByEntires,
|
|
8
|
+
isVmExtern,
|
|
10
9
|
isVmFunction,
|
|
11
10
|
isVmModule,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
} from '../vm/
|
|
15
|
-
import { REG_IDENTIFIER, REG_ORDINAL } from './constants.js';
|
|
16
|
-
import { entries, hasOwn, isFinite, isNaN } from '../helpers/utils.js';
|
|
11
|
+
isVmRecord,
|
|
12
|
+
} from './types.js';
|
|
13
|
+
import type { VmWrapper } from '../vm/types/wrapper.js';
|
|
17
14
|
|
|
18
15
|
const REG_IDENTIFIER_FULL = new RegExp(`^${REG_IDENTIFIER.source}$`, REG_IDENTIFIER.flags);
|
|
19
16
|
const REG_ORDINAL_FULL = new RegExp(`^${REG_ORDINAL.source}$`, REG_ORDINAL.flags);
|
|
@@ -72,24 +69,33 @@ function isDefaultOptions(options: Partial<SerializeOptions> | undefined): boole
|
|
|
72
69
|
return options == null || options === DEFAULT_OPTIONS;
|
|
73
70
|
}
|
|
74
71
|
|
|
75
|
-
/**
|
|
76
|
-
function
|
|
77
|
-
|
|
72
|
+
/** 合并选项 */
|
|
73
|
+
function mergeOptions(
|
|
74
|
+
base: Readonly<SerializeOptions>,
|
|
75
|
+
options: Partial<SerializeOptions> | null | undefined,
|
|
76
|
+
): Readonly<SerializeOptions> {
|
|
77
|
+
if (options == null) return base;
|
|
78
78
|
let opt: SerializeOptions | null = null;
|
|
79
79
|
for (const key in options) {
|
|
80
|
-
if (!hasOwn(options, key) || !hasOwn(
|
|
80
|
+
if (!hasOwn(options, key) || !hasOwn(base, key)) continue;
|
|
81
81
|
const el = options[key as keyof SerializeOptions];
|
|
82
82
|
if (el == null) continue;
|
|
83
|
-
opt ??= { ...
|
|
83
|
+
opt ??= { ...base };
|
|
84
84
|
opt[key as keyof SerializeOptions] = el as never;
|
|
85
85
|
}
|
|
86
|
-
return opt ? Object.freeze(opt) :
|
|
86
|
+
return opt ? Object.freeze(opt) : base;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** 获取选项 */
|
|
90
|
+
function getSerializeOptions(options: Partial<SerializeOptions> | undefined): Readonly<SerializeOptions> {
|
|
91
|
+
if (isDefaultOptions(options)) return DEFAULT_OPTIONS;
|
|
92
|
+
return mergeOptions(DEFAULT_OPTIONS, options);
|
|
87
93
|
}
|
|
88
94
|
|
|
89
95
|
/**
|
|
90
96
|
* 将 MiraScript 字符串序列化为 MiraScript 字面量。
|
|
91
97
|
*/
|
|
92
|
-
function serializeStringImpl(value: string, options: SerializeOptions): string {
|
|
98
|
+
function serializeStringImpl(value: string, options: Readonly<SerializeOptions>): string {
|
|
93
99
|
if (!/[\p{C}'"`$\\]/u.test(value)) {
|
|
94
100
|
// 不包含特殊字符
|
|
95
101
|
const oq = options.serializeStringQuote(`'`, true, options);
|
|
@@ -153,7 +159,7 @@ function serializeRecordKeyDefault(key: string): string {
|
|
|
153
159
|
}
|
|
154
160
|
|
|
155
161
|
/** 序列化属性名 */
|
|
156
|
-
function serializeRecordKeyOpt(value: string, options: SerializeOptions): string {
|
|
162
|
+
function serializeRecordKeyOpt(value: string, options: Readonly<SerializeOptions>): string {
|
|
157
163
|
if (isDefaultOptions(options)) {
|
|
158
164
|
return serializeRecordKeyDefault(value);
|
|
159
165
|
}
|
|
@@ -199,7 +205,7 @@ export function serializeNumber(value: number): string {
|
|
|
199
205
|
}
|
|
200
206
|
|
|
201
207
|
/** 序列化数组 */
|
|
202
|
-
export function serializeArray(value: VmArray, depth: number, options: SerializeOptions): string {
|
|
208
|
+
export function serializeArray(value: VmArray, depth: number, options: Readonly<SerializeOptions>): string {
|
|
203
209
|
if (depth > options.maxDepth) return `[]`;
|
|
204
210
|
if (value.length === 0) return '[]';
|
|
205
211
|
let str = '[';
|
|
@@ -228,7 +234,7 @@ function customValueOf(value: VmRecord): VmAny | undefined {
|
|
|
228
234
|
}
|
|
229
235
|
|
|
230
236
|
/** 序列化记录 */
|
|
231
|
-
export function serializeRecord(value: VmRecord, depth: number, options: SerializeOptions): string {
|
|
237
|
+
export function serializeRecord(value: VmRecord, depth: number, options: Readonly<SerializeOptions>): string {
|
|
232
238
|
const customValue = customValueOf(value);
|
|
233
239
|
if (customValue !== undefined) {
|
|
234
240
|
return serializeImpl(customValue, depth - 1, options);
|
|
@@ -259,7 +265,7 @@ export function serializeRecord(value: VmRecord, depth: number, options: Seriali
|
|
|
259
265
|
}
|
|
260
266
|
|
|
261
267
|
/** 序列化 */
|
|
262
|
-
function serializeImpl(value: VmAny | undefined, depth: number, options: SerializeOptions): string {
|
|
268
|
+
function serializeImpl(value: VmAny | undefined, depth: number, options: Readonly<SerializeOptions>): string {
|
|
263
269
|
if (value == null) {
|
|
264
270
|
return options.serializeNil(options);
|
|
265
271
|
}
|
|
@@ -293,8 +299,50 @@ function serializeImpl(value: VmAny | undefined, depth: number, options: Seriali
|
|
|
293
299
|
}
|
|
294
300
|
|
|
295
301
|
/**
|
|
296
|
-
* 将 MiraScript 值序列化为 MiraScript
|
|
302
|
+
* 将 MiraScript 值序列化为 MiraScript 字面量字符串,非常量值默认转换为 `nil`。
|
|
297
303
|
*/
|
|
298
304
|
export function serialize(value: VmAny, options?: Partial<SerializeOptions>): string {
|
|
299
305
|
return serializeImpl(value, 0, getSerializeOptions(options));
|
|
300
306
|
}
|
|
307
|
+
|
|
308
|
+
/** 将 MiraScript function 转化为 MiraScript 字符串 */
|
|
309
|
+
export function displayFunction(value: VmFunction): string {
|
|
310
|
+
try {
|
|
311
|
+
const name = getVmFunctionInfo(value)?.fullName;
|
|
312
|
+
return name ? `<function ${name}>` : `<function>`;
|
|
313
|
+
/* c8 ignore next 3 */
|
|
314
|
+
} catch {
|
|
315
|
+
return `<function>`;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/** 将 MiraScript module 转化为 MiraScript 字符串 */
|
|
319
|
+
export function displayWrapper(value: VmWrapper<object>, useBraces: boolean, fallback: string): string {
|
|
320
|
+
try {
|
|
321
|
+
return value.toString(useBraces);
|
|
322
|
+
} catch {
|
|
323
|
+
return fallback;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
const DISPLAY_OPTIONS = Object.freeze({
|
|
327
|
+
maxDepth: 3,
|
|
328
|
+
serializeNil,
|
|
329
|
+
serializeBoolean,
|
|
330
|
+
serializeNumber,
|
|
331
|
+
serializeString: serializeStringImpl,
|
|
332
|
+
serializeStringQuote: (value) => value,
|
|
333
|
+
serializeStringEscape: (value) => value,
|
|
334
|
+
serializeStringContent: (value) => value,
|
|
335
|
+
serializeArray,
|
|
336
|
+
serializeRecord,
|
|
337
|
+
serializePropName: String,
|
|
338
|
+
serializeFunction: displayFunction,
|
|
339
|
+
serializeModule: (value) => displayWrapper(value, true, '<module>'),
|
|
340
|
+
serializeExtern: (value) => displayWrapper(value, true, '<extern>'),
|
|
341
|
+
} satisfies SerializeOptions);
|
|
342
|
+
/**
|
|
343
|
+
* 将 MiraScript 值转化为 MiraScript 字符串。
|
|
344
|
+
*/
|
|
345
|
+
export function display(value: VmAny, options?: Partial<SerializeOptions>): string {
|
|
346
|
+
const opt = mergeOptions(DISPLAY_OPTIONS, options);
|
|
347
|
+
return serializeImpl(value, 0, opt);
|
|
348
|
+
}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import type { VmScript } from '../compiler/index.js';
|
|
2
|
+
import type {
|
|
3
|
+
VmAny,
|
|
4
|
+
VmArray,
|
|
5
|
+
VmConst,
|
|
6
|
+
VmContext,
|
|
7
|
+
VmExtern,
|
|
8
|
+
VmFunction,
|
|
9
|
+
VmFunctionInfo,
|
|
10
|
+
VmFunctionLike,
|
|
11
|
+
VmImmutable,
|
|
12
|
+
VmModule,
|
|
13
|
+
VmPrimitive,
|
|
14
|
+
VmRecord,
|
|
15
|
+
VmValue,
|
|
16
|
+
} from '../vm/types/index.js';
|
|
17
|
+
import type { VmWrapper } from '../vm/types/wrapper.js';
|
|
18
|
+
import {
|
|
19
|
+
kVmContext,
|
|
20
|
+
kVmExtern,
|
|
21
|
+
kVmFunction,
|
|
22
|
+
kVmModule,
|
|
23
|
+
kVmScript,
|
|
24
|
+
kVmWrapper,
|
|
25
|
+
VM_ARRAY_MAX_LENGTH,
|
|
26
|
+
} from './constants.js';
|
|
27
|
+
import { getPrototypeOf, isArray, keys, values } from './utils.js';
|
|
28
|
+
|
|
29
|
+
/** 检查是否为 Mirascript 脚本 */
|
|
30
|
+
export function isVmScript(value: unknown): value is VmScript {
|
|
31
|
+
return typeof value === 'function' && kVmScript in value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** 检查是否为执行上下文 */
|
|
35
|
+
export function isVmContext(context: unknown): context is VmContext {
|
|
36
|
+
return context != null && typeof context == 'object' && kVmContext in context;
|
|
37
|
+
}
|
|
38
|
+
/** 检查是否为 Mirascript 函数 */
|
|
39
|
+
export function isVmFunction<T extends VmFunctionLike>(value: unknown): value is VmFunction<T> {
|
|
40
|
+
return typeof value == 'function' && kVmFunction in value;
|
|
41
|
+
}
|
|
42
|
+
/** 检查是否为 Mirascript 函数,并获取其信息 */
|
|
43
|
+
export function getVmFunctionInfo(value: unknown): VmFunctionInfo | undefined {
|
|
44
|
+
if (typeof value != 'function') return undefined;
|
|
45
|
+
return (value as VmFunction)[kVmFunction];
|
|
46
|
+
}
|
|
47
|
+
/** 检查值是否为 MiraScript 包装器 */
|
|
48
|
+
export function isVmWrapper<T extends object>(value: unknown): value is VmWrapper<T> {
|
|
49
|
+
return value != null && typeof value == 'object' && kVmWrapper in value;
|
|
50
|
+
}
|
|
51
|
+
/** 检查值是否为 Mirascript 模块 */
|
|
52
|
+
export function isVmModule<T extends Record<string, VmImmutable>>(value: unknown): value is VmModule<T> {
|
|
53
|
+
return value != null && typeof value == 'object' && kVmModule in value;
|
|
54
|
+
}
|
|
55
|
+
/** 检查值是否为 Mirascript 外部值 */
|
|
56
|
+
export function isVmExtern<T extends object>(value: unknown): value is VmExtern<T> {
|
|
57
|
+
return value != null && typeof value == 'object' && kVmExtern in value;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** 检查值是否为 Mirascript 可调用值 */
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
62
|
+
export function isVmCallable<E extends Function, F extends VmFunctionLike>(
|
|
63
|
+
value: unknown,
|
|
64
|
+
): value is VmFunction<F> | VmExtern<E> {
|
|
65
|
+
return isVmFunction<F>(value) || (isVmExtern<E>(value) && typeof value.value == 'function');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** 检查值是否为 Mirascript 原始值 */
|
|
69
|
+
export function isVmPrimitive(value: unknown): value is VmPrimitive {
|
|
70
|
+
if (value === null || typeof value == 'number' || typeof value == 'string' || typeof value == 'boolean') {
|
|
71
|
+
value as VmPrimitive satisfies typeof value;
|
|
72
|
+
value satisfies VmPrimitive;
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** 检查值是否为 Mirascript 数组 */
|
|
79
|
+
export function isVmArray(value: VmAny): value is VmArray {
|
|
80
|
+
if (!isArray(value)) return false;
|
|
81
|
+
value as VmArray satisfies VmArray;
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** 检查值是否为 Mirascript 记录 */
|
|
86
|
+
export function isVmRecord(value: VmAny): value is VmRecord {
|
|
87
|
+
if (value == null || typeof value !== 'object') return false;
|
|
88
|
+
if (isVmWrapper(value)) return false;
|
|
89
|
+
if (isVmArray(value)) return false;
|
|
90
|
+
value satisfies VmRecord;
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** 检查是否为仅包含从 0 开始的连续数字键的 MiraScript 记录 */
|
|
95
|
+
export function isVmArrayLikeRecordByEntires(entries: ReadonlyArray<readonly [string, unknown]>): boolean {
|
|
96
|
+
const { length } = entries;
|
|
97
|
+
if (length === 0) return true;
|
|
98
|
+
if (length > VM_ARRAY_MAX_LENGTH) return false;
|
|
99
|
+
const firstKey = entries[0]![0];
|
|
100
|
+
if (firstKey !== '0') return false;
|
|
101
|
+
const lastKey = entries[length - 1]![0];
|
|
102
|
+
if (lastKey !== String(length - 1)) return false;
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** 检查是否为仅包含从 0 开始的连续数字键的 MiraScript 记录 */
|
|
107
|
+
export function isVmArrayLikeRecordByKeys(keys: readonly string[]): boolean {
|
|
108
|
+
const { length } = keys;
|
|
109
|
+
if (length === 0) return true;
|
|
110
|
+
if (length > VM_ARRAY_MAX_LENGTH) return false;
|
|
111
|
+
const firstKey = keys[0]!;
|
|
112
|
+
if (firstKey !== '0') return false;
|
|
113
|
+
const lastKey = keys[length - 1]!;
|
|
114
|
+
if (lastKey !== String(length - 1)) return false;
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** 检查是否为仅包含从 0 开始的连续数字键的 MiraScript 记录 */
|
|
119
|
+
export function isVmArrayLikeRecord(value: VmRecord): boolean {
|
|
120
|
+
return isVmArrayLikeRecordByKeys(keys(value));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const MAX_DEPTH = 16;
|
|
124
|
+
/**
|
|
125
|
+
* 检查是否为 Mirascript 数组
|
|
126
|
+
*/
|
|
127
|
+
function isVmArrayDeep(value: readonly unknown[], depth: number): value is VmArray {
|
|
128
|
+
// VmArray 应为普通数组
|
|
129
|
+
// Array.prototype
|
|
130
|
+
const proto1: unknown = getPrototypeOf(value);
|
|
131
|
+
if (!isArray(proto1)) return false;
|
|
132
|
+
if (!depth) return true;
|
|
133
|
+
return value.every((item) => isVmConstInner(item, depth));
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* 检查是否为 Mirascript 记录
|
|
137
|
+
*/
|
|
138
|
+
function isVmRecordDeep(value: object, depth: number): value is VmRecord {
|
|
139
|
+
// VmRecord 应为普通对象或空原型对象
|
|
140
|
+
let isRecord;
|
|
141
|
+
// Object.prototype
|
|
142
|
+
const proto1: unknown = getPrototypeOf(value);
|
|
143
|
+
if (proto1 == null) {
|
|
144
|
+
isRecord = true;
|
|
145
|
+
} else {
|
|
146
|
+
// null
|
|
147
|
+
const proto2: unknown = getPrototypeOf(proto1);
|
|
148
|
+
if (proto2 != null) {
|
|
149
|
+
isRecord = false;
|
|
150
|
+
} else {
|
|
151
|
+
isRecord = 'hasOwnProperty' in value;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (!isRecord) return false;
|
|
155
|
+
if (!depth) return true;
|
|
156
|
+
return values(value).every((value) => isVmConstInner(value, depth));
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* 检查是否为 Mirascript 值语义值
|
|
160
|
+
*/
|
|
161
|
+
function isVmConstInner(value: unknown, depth: number): value is VmConst {
|
|
162
|
+
if (depth++ >= MAX_DEPTH) return false;
|
|
163
|
+
switch (typeof value) {
|
|
164
|
+
case 'string':
|
|
165
|
+
case 'number':
|
|
166
|
+
case 'boolean':
|
|
167
|
+
case 'undefined': // undefined 在复合类型内部被视为 nil
|
|
168
|
+
return true;
|
|
169
|
+
case 'object':
|
|
170
|
+
if (value == null) return true;
|
|
171
|
+
if (isVmWrapper(value)) return false;
|
|
172
|
+
if (isArray(value)) {
|
|
173
|
+
return isVmArrayDeep(value, depth);
|
|
174
|
+
} else {
|
|
175
|
+
return isVmRecordDeep(value, depth);
|
|
176
|
+
}
|
|
177
|
+
case 'function':
|
|
178
|
+
case 'bigint':
|
|
179
|
+
case 'symbol':
|
|
180
|
+
default:
|
|
181
|
+
return false; // Other types are not valid
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* 检查是否为 Mirascript 值语义值
|
|
187
|
+
*/
|
|
188
|
+
export function isVmConst(value: VmAny): value is VmConst;
|
|
189
|
+
/**
|
|
190
|
+
* 检查是否为 Mirascript 值语义值
|
|
191
|
+
*/
|
|
192
|
+
export function isVmConst(value: unknown, checkDeep: boolean): value is VmConst;
|
|
193
|
+
/**
|
|
194
|
+
* 检查是否为 Mirascript 值语义值
|
|
195
|
+
*/
|
|
196
|
+
export function isVmConst(value: unknown, checkDeep = false): value is VmConst {
|
|
197
|
+
switch (typeof value) {
|
|
198
|
+
case 'string':
|
|
199
|
+
case 'number':
|
|
200
|
+
case 'boolean':
|
|
201
|
+
return true;
|
|
202
|
+
case 'object':
|
|
203
|
+
if (value == null) return true;
|
|
204
|
+
if (isVmWrapper(value)) return false;
|
|
205
|
+
if (!checkDeep) {
|
|
206
|
+
if (isArray(value)) {
|
|
207
|
+
return isVmArrayDeep(value, 0);
|
|
208
|
+
} else {
|
|
209
|
+
return isVmRecordDeep(value, 0);
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
return isVmConstInner(value, 1);
|
|
213
|
+
}
|
|
214
|
+
case 'undefined':
|
|
215
|
+
case 'function':
|
|
216
|
+
case 'bigint':
|
|
217
|
+
case 'symbol':
|
|
218
|
+
default:
|
|
219
|
+
return false; // Other types are not valid
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* 检查是否为 Mirascript 不可变值
|
|
225
|
+
*/
|
|
226
|
+
export function isVmImmutable(value: VmAny): value is VmImmutable;
|
|
227
|
+
/**
|
|
228
|
+
* 检查是否为 Mirascript 不可变值
|
|
229
|
+
*/
|
|
230
|
+
export function isVmImmutable(value: unknown, checkDeep: boolean): value is VmImmutable;
|
|
231
|
+
/**
|
|
232
|
+
* 检查是否为 Mirascript 不可变值
|
|
233
|
+
*/
|
|
234
|
+
export function isVmImmutable(value: unknown, checkDeep = false): value is VmImmutable {
|
|
235
|
+
return isVmModule(value) || isVmFunction(value) || isVmConst(value, checkDeep);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** 检查是否为 Mirascript 值 */
|
|
239
|
+
export function isVmAny(value: unknown, checkDeep: boolean): value is VmAny {
|
|
240
|
+
switch (typeof value) {
|
|
241
|
+
case 'string':
|
|
242
|
+
case 'number':
|
|
243
|
+
case 'boolean':
|
|
244
|
+
case 'undefined':
|
|
245
|
+
return true;
|
|
246
|
+
case 'object':
|
|
247
|
+
if (value == null) return true;
|
|
248
|
+
if (isVmWrapper(value)) return true;
|
|
249
|
+
return isVmConst(value, checkDeep);
|
|
250
|
+
case 'function':
|
|
251
|
+
return isVmFunction(value);
|
|
252
|
+
case 'bigint':
|
|
253
|
+
case 'symbol':
|
|
254
|
+
default:
|
|
255
|
+
return false; // Other types are not valid
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** 检查是否为 Mirascript 合法值 */
|
|
260
|
+
export function isVmValue(value: VmAny): value is VmValue;
|
|
261
|
+
/** 检查是否为 Mirascript 合法值 */
|
|
262
|
+
export function isVmValue(value: unknown, checkDeep: boolean): value is VmValue;
|
|
263
|
+
/** 检查是否为 Mirascript 合法值 */
|
|
264
|
+
export function isVmValue(value: unknown, checkDeep = false): value is VmValue {
|
|
265
|
+
if (value === undefined) return false;
|
|
266
|
+
return isVmAny(value, checkDeep);
|
|
267
|
+
}
|
package/src/subtle.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { getModule } from '@mirascript/bindings';
|
|
2
2
|
|
|
3
3
|
export * as constants from './helpers/constants.js';
|
|
4
|
-
export
|
|
4
|
+
export * as convert from './helpers/convert/index.js';
|
|
5
|
+
export { DefaultVmContext } from './vm/types/context.js';
|
|
5
6
|
export * as operations from './vm/operations.js';
|
|
6
7
|
export {
|
|
8
|
+
display as serializeForDisplay,
|
|
7
9
|
serialize,
|
|
8
10
|
serializeNil,
|
|
9
11
|
serializeBoolean,
|
|
@@ -14,7 +16,7 @@ export {
|
|
|
14
16
|
serializeRecord,
|
|
15
17
|
type SerializeOptions,
|
|
16
18
|
} from './helpers/serialize.js';
|
|
17
|
-
export { lib } from './vm/lib/
|
|
19
|
+
export { lib } from './vm/lib/index.js';
|
|
18
20
|
export * from './compiler/diagnostic.js';
|
|
19
21
|
export { generateBytecode, generateBytecodeSync, emitScript } from './compiler/index.js';
|
|
20
22
|
|