@mirascript/mirascript 0.1.3 → 0.1.5
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-3RUWGMBP.js → chunk-JB6LPPFJ.js} +190 -24
- package/dist/chunk-JB6LPPFJ.js.map +6 -0
- package/dist/{chunk-MVHCSH3E.js → chunk-OU3K5EYB.js} +61 -131
- package/dist/chunk-OU3K5EYB.js.map +6 -0
- package/dist/cli/execute.d.ts +1 -1
- package/dist/cli/execute.d.ts.map +1 -1
- package/dist/cli/index.js +58 -28
- package/dist/cli/index.js.map +2 -2
- package/dist/cli/print.d.ts.map +1 -1
- package/dist/compiler/diagnostic.d.ts +3 -1
- package/dist/compiler/diagnostic.d.ts.map +1 -1
- package/dist/compiler/emit.d.ts +2 -1
- package/dist/compiler/emit.d.ts.map +1 -1
- package/dist/compiler/index.d.ts.map +1 -1
- package/dist/compiler/worker.d.ts.map +1 -1
- package/dist/compiler/worker.js +6 -3
- package/dist/compiler/worker.js.map +1 -1
- package/dist/helpers/serialize.d.ts +10 -2
- package/dist/helpers/serialize.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/subtle.d.ts +1 -1
- package/dist/subtle.d.ts.map +1 -1
- package/dist/subtle.js +17 -7
- package/dist/vm/lib/_helpers.d.ts +1 -1
- package/dist/vm/lib/_helpers.d.ts.map +1 -1
- package/dist/vm/lib/global/bit.d.ts +7 -8
- package/dist/vm/lib/global/bit.d.ts.map +1 -1
- package/dist/vm/lib/global/debug.d.ts +6 -3
- package/dist/vm/lib/global/debug.d.ts.map +1 -1
- package/dist/vm/lib/global/json.d.ts +2 -3
- package/dist/vm/lib/global/json.d.ts.map +1 -1
- package/dist/vm/lib/global/math-additional.d.ts +1 -2
- package/dist/vm/lib/global/math-additional.d.ts.map +1 -1
- package/dist/vm/lib/global/math-arr.d.ts +5 -6
- package/dist/vm/lib/global/math-arr.d.ts.map +1 -1
- package/dist/vm/lib/global/math-unary.d.ts +26 -27
- package/dist/vm/lib/global/math-unary.d.ts.map +1 -1
- package/dist/vm/lib/global/math.d.ts +3 -4
- package/dist/vm/lib/global/math.d.ts.map +1 -1
- package/dist/vm/lib/global/mod/matrix.d.ts +13 -14
- package/dist/vm/lib/global/mod/matrix.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/all-any.d.ts +2 -3
- package/dist/vm/lib/global/sequence/all-any.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/entries.d.ts +4 -5
- package/dist/vm/lib/global/sequence/entries.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/find.d.ts +2 -3
- package/dist/vm/lib/global/sequence/find.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/flatten.d.ts +1 -2
- package/dist/vm/lib/global/sequence/flatten.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/len.d.ts +1 -2
- package/dist/vm/lib/global/sequence/len.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/map-filter.d.ts +3 -4
- package/dist/vm/lib/global/sequence/map-filter.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/repeat.d.ts +1 -2
- package/dist/vm/lib/global/sequence/repeat.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/reverse.d.ts +1 -2
- package/dist/vm/lib/global/sequence/reverse.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/sort.d.ts +2 -3
- package/dist/vm/lib/global/sequence/sort.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/with.d.ts +1 -2
- package/dist/vm/lib/global/sequence/with.d.ts.map +1 -1
- package/dist/vm/lib/global/sequence/zip.d.ts +1 -2
- package/dist/vm/lib/global/sequence/zip.d.ts.map +1 -1
- package/dist/vm/lib/global/string.d.ts +10 -11
- package/dist/vm/lib/global/string.d.ts.map +1 -1
- package/dist/vm/lib/global/time.d.ts +4 -5
- package/dist/vm/lib/global/time.d.ts.map +1 -1
- package/dist/vm/lib/global/to-primitive.d.ts +4 -5
- package/dist/vm/lib/global/to-primitive.d.ts.map +1 -1
- package/dist/vm/types/wrapper.d.ts.map +1 -1
- package/package.json +7 -5
- package/src/cli/execute.ts +15 -7
- package/src/cli/index.ts +22 -5
- package/src/cli/print.ts +43 -27
- package/src/compiler/diagnostic.ts +19 -3
- package/src/compiler/emit.ts +45 -19
- package/src/compiler/index.ts +10 -2
- package/src/compiler/worker.ts +5 -1
- package/src/helpers/serialize.ts +6 -6
- package/src/subtle.ts +11 -1
- package/src/vm/lib/_helpers.ts +8 -3
- package/src/vm/lib/global/debug.ts +24 -3
- package/src/vm/lib/global/math-arr.ts +1 -1
- package/src/vm/types/wrapper.ts +3 -1
- package/dist/chunk-3RUWGMBP.js.map +0 -6
- package/dist/chunk-MVHCSH3E.js.map +0 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"to-primitive.d.ts","sourceRoot":"","sources":["../../../../src/vm/lib/global/to-primitive.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"to-primitive.d.ts","sourceRoot":"","sources":["../../../../src/vm/lib/global/to-primitive.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,SAAS,mIAYrB,CAAC;AAEF,eAAO,MAAM,SAAS,mIAYrB,CAAC;AAEF,eAAO,MAAM,UAAU,oIAYtB,CAAC;AAEF,eAAO,MAAM,MAAM,yLAYlB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../../../src/vm/types/wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAElD;;GAEG;AACH,8BAAsB,SAAS,CAAC,CAAC,SAAS,MAAM;IAChC,QAAQ,CAAC,KAAK,EAAE,CAAC;gBAAR,KAAK,EAAE,CAAC;IAC7B,cAAc;IACd,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAClC,cAAc;IACd,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK;IAChC,WAAW;IACX,QAAQ,CAAC,IAAI,IAAI,MAAM,EAAE;IACzB,aAAa;IACb,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IACpC,WAAW;IACX,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC;IAC9B,WAAW;IACX,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC;IAChC,iCAAiC;IACjC,MAAM,IAAI,SAAS;IAGnB,YAAY;IACZ,QAAQ,IAAI,MAAM;
|
|
1
|
+
{"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../../../src/vm/types/wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAElD;;GAEG;AACH,8BAAsB,SAAS,CAAC,CAAC,SAAS,MAAM;IAChC,QAAQ,CAAC,KAAK,EAAE,CAAC;gBAAR,KAAK,EAAE,CAAC;IAC7B,cAAc;IACd,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAClC,cAAc;IACd,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK;IAChC,WAAW;IACX,QAAQ,CAAC,IAAI,IAAI,MAAM,EAAE;IACzB,aAAa;IACb,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IACpC,WAAW;IACX,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC;IAC9B,WAAW;IACX,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC;IAChC,iCAAiC;IACjC,MAAM,IAAI,SAAS;IAGnB,YAAY;IACZ,QAAQ,IAAI,MAAM;CAKrB;AAID,4BAA4B;AAC5B,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAAC,CAAC,CAAC,CAEnF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mirascript/mirascript",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "An expression based scripting language.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -35,8 +35,10 @@
|
|
|
35
35
|
"ansi-styles": "^6.2.3",
|
|
36
36
|
"commander": "^14.0.2",
|
|
37
37
|
"js-base64": "^3.7.8",
|
|
38
|
-
"
|
|
39
|
-
"
|
|
38
|
+
"source-map-js": "^1.2.1",
|
|
39
|
+
"supports-color": "^10.2.2",
|
|
40
|
+
"@mirascript/napi": "~0.1.5",
|
|
41
|
+
"@mirascript/wasm": "~0.1.5"
|
|
40
42
|
},
|
|
41
43
|
"devDependencies": {
|
|
42
44
|
"@types/node": "^24.10.0",
|
|
@@ -44,13 +46,13 @@
|
|
|
44
46
|
"ava": "^6.4.1",
|
|
45
47
|
"c8": "^10.1.3",
|
|
46
48
|
"sinon": "^21.0.0",
|
|
47
|
-
"type-fest": "^5.
|
|
49
|
+
"type-fest": "^5.2.0"
|
|
48
50
|
},
|
|
49
51
|
"scripts": {
|
|
50
52
|
"watch": "pnpm build:ts --watch",
|
|
51
53
|
"build:ts": "pnpm clean && tsc",
|
|
52
54
|
"build": "pnpm build:ts --emitDeclarationOnly && node ./esbuild.config.js",
|
|
53
|
-
"mirascript": "node ./dist/cli/index.js",
|
|
55
|
+
"mirascript": "node --enable-source-maps ./dist/cli/index.js",
|
|
54
56
|
"clean": "rimraf dist",
|
|
55
57
|
"test": "c8 ava"
|
|
56
58
|
}
|
package/src/cli/execute.ts
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import styles from 'ansi-styles';
|
|
3
|
+
import supportsColor from 'supports-color';
|
|
3
4
|
import { compile } from '../index.js';
|
|
4
5
|
import { createVmContext, VmFunction, type VmValue } from '../vm/index.js';
|
|
5
6
|
import { debug_print } from '../vm/lib/global/debug.js';
|
|
6
7
|
import { print } from './print.js';
|
|
7
8
|
|
|
8
9
|
/** 执行脚本 */
|
|
9
|
-
export async function execute(
|
|
10
|
+
export async function execute(
|
|
11
|
+
script: string,
|
|
12
|
+
template: boolean,
|
|
13
|
+
variables: Record<string, VmValue>,
|
|
14
|
+
fileName: string,
|
|
15
|
+
): Promise<void> {
|
|
10
16
|
try {
|
|
11
|
-
const f = await compile(script, { input_mode: template ? 'Template' : 'Script' });
|
|
17
|
+
const f = await compile(script, { input_mode: template ? 'Template' : 'Script', sourceMap: true, fileName });
|
|
12
18
|
const r = f(
|
|
13
19
|
createVmContext({
|
|
14
20
|
debug_print: VmFunction((...values) => {
|
|
15
|
-
console.log(
|
|
16
|
-
'\u001B[46;30m MiraScript \u001B[0m',
|
|
17
|
-
...values.map((v) => (typeof v == 'string' ? v : print(v))),
|
|
18
|
-
);
|
|
21
|
+
console.log(...debug_print.prefix, ...values.map((v) => (typeof v == 'string' ? v : print(v))));
|
|
19
22
|
}, debug_print),
|
|
20
23
|
...variables,
|
|
21
24
|
}),
|
|
@@ -26,7 +29,12 @@ export async function execute(script: string, template: boolean, variables: Reco
|
|
|
26
29
|
console.log(print(r));
|
|
27
30
|
}
|
|
28
31
|
} catch (ex) {
|
|
29
|
-
|
|
32
|
+
const { stack } = ex as Error;
|
|
33
|
+
if (supportsColor.stderr) {
|
|
34
|
+
console.error(styles.red.open + stack + styles.red.close);
|
|
35
|
+
} else {
|
|
36
|
+
console.error(stack);
|
|
37
|
+
}
|
|
30
38
|
process.exitCode = 2;
|
|
31
39
|
}
|
|
32
40
|
}
|
package/src/cli/index.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/* c8 ignore start */
|
|
2
2
|
/* eslint-disable no-console */
|
|
3
3
|
import { readFile, stat } from 'node:fs/promises';
|
|
4
|
-
import {
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import { InvalidArgumentError, program } from '@commander-js/extra-typings';
|
|
5
6
|
import { execute } from './execute.js';
|
|
6
7
|
import pkg from '../../package.json' with { type: 'json' };
|
|
7
8
|
import { compileSync } from '../compiler/index.js';
|
|
8
|
-
import type
|
|
9
|
+
import { configCheckpoint, type VmValue } from '../vm/index.js';
|
|
10
|
+
|
|
11
|
+
const DEFAULT_TIMEOUT = 3000;
|
|
9
12
|
|
|
10
13
|
program.name(pkg.name.split('/').pop()!).version(pkg.version).description(pkg.description);
|
|
11
14
|
|
|
@@ -33,12 +36,26 @@ program
|
|
|
33
36
|
{} as Record<string, VmValue>,
|
|
34
37
|
)
|
|
35
38
|
.option('-t, --template', '使用模板模式')
|
|
39
|
+
.option(
|
|
40
|
+
'--timeout <ms>',
|
|
41
|
+
'脚本执行超时时间(毫秒,0 表示不超时)',
|
|
42
|
+
(v) => {
|
|
43
|
+
const ms = Number.parseFloat(v);
|
|
44
|
+
if (Number.isNaN(ms) || ms < 0) {
|
|
45
|
+
throw new InvalidArgumentError('超时时间必须是非负整数');
|
|
46
|
+
}
|
|
47
|
+
return ms;
|
|
48
|
+
},
|
|
49
|
+
DEFAULT_TIMEOUT,
|
|
50
|
+
)
|
|
36
51
|
.option('--no-template', '使用脚本模式')
|
|
37
52
|
.option('-e, --eval <script>', '要执行的脚本')
|
|
38
53
|
.argument('[script]', '要执行的脚本文件路径(如果提供了 -e 则忽略此参数)')
|
|
39
54
|
.action(async (script, opt) => {
|
|
55
|
+
configCheckpoint(opt.timeout || Number.POSITIVE_INFINITY);
|
|
40
56
|
if (opt.eval != null) {
|
|
41
|
-
|
|
57
|
+
const template = !!opt.template;
|
|
58
|
+
await execute(opt.eval, template, opt.variable, template ? 'eval.miratpl' : 'eval.mira');
|
|
42
59
|
return;
|
|
43
60
|
}
|
|
44
61
|
if (script) {
|
|
@@ -62,9 +79,9 @@ program
|
|
|
62
79
|
}
|
|
63
80
|
return;
|
|
64
81
|
}
|
|
65
|
-
const context = await readFile(script, '
|
|
82
|
+
const context = await readFile(script, 'utf-8');
|
|
66
83
|
const template = opt.template ?? script.endsWith('.miratpl');
|
|
67
|
-
await execute(context, template, opt.variable);
|
|
84
|
+
await execute(context, template, opt.variable, pathToFileURL(script).href);
|
|
68
85
|
return;
|
|
69
86
|
}
|
|
70
87
|
program.help({ error: true });
|
package/src/cli/print.ts
CHANGED
|
@@ -1,40 +1,56 @@
|
|
|
1
1
|
import styles from 'ansi-styles';
|
|
2
|
-
import
|
|
2
|
+
import supportsColor from 'supports-color';
|
|
3
|
+
import {
|
|
4
|
+
serialize,
|
|
5
|
+
serializeNumber,
|
|
6
|
+
serializeBoolean,
|
|
7
|
+
serializeNil,
|
|
8
|
+
type SerializeOptions,
|
|
9
|
+
operations,
|
|
10
|
+
} from '../subtle.js';
|
|
3
11
|
import type { VmAny, VmRecord } from '../vm/index.js';
|
|
4
12
|
|
|
13
|
+
const noColor = !supportsColor.stdout;
|
|
14
|
+
|
|
5
15
|
const options: Partial<SerializeOptions> = {
|
|
6
16
|
maxDepth: 3,
|
|
7
|
-
serializeNil: () => styles.gray.open +
|
|
8
|
-
serializeBoolean: (v) => styles.blue.open + (v
|
|
9
|
-
serializeNumber: (v) =>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
serializeFunction:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
17
|
+
serializeNil: noColor ? undefined : () => styles.gray.open + serializeNil() + styles.gray.close,
|
|
18
|
+
serializeBoolean: noColor ? undefined : (v) => styles.blue.open + serializeBoolean(v) + styles.blue.close,
|
|
19
|
+
serializeNumber: noColor ? undefined : (v) => styles.yellow.open + serializeNumber(v) + styles.yellow.close,
|
|
20
|
+
serializeStringQuote: noColor
|
|
21
|
+
? undefined
|
|
22
|
+
: (v, open) => {
|
|
23
|
+
const q = styles.dim.open + v + styles.dim.close;
|
|
24
|
+
if (open) {
|
|
25
|
+
return styles.green.open + q;
|
|
26
|
+
} else {
|
|
27
|
+
return q + styles.green.close;
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
serializeStringEscape: noColor ? undefined : (v) => styles.bold.open + v + styles.bold.close,
|
|
31
|
+
serializePropName: noColor ? undefined : (v) => styles.whiteBright.open + String(v) + styles.whiteBright.close,
|
|
32
|
+
serializeFunction: noColor
|
|
33
|
+
? operations.$ToString
|
|
34
|
+
: (v) => styles.cyan.open + operations.$ToString(v) + styles.cyan.close,
|
|
35
|
+
serializeModule: noColor
|
|
36
|
+
? (v, depth, options) => {
|
|
37
|
+
return operations.$ToString(v) + ' ' + options.serializeRecord(v.value as VmRecord, depth, options);
|
|
38
|
+
}
|
|
39
|
+
: (v, depth, options) => {
|
|
40
|
+
return (
|
|
41
|
+
styles.magenta.open +
|
|
42
|
+
operations.$ToString(v) +
|
|
43
|
+
styles.magenta.close +
|
|
44
|
+
' ' +
|
|
45
|
+
options.serializeRecord(v.value as VmRecord, depth, options)
|
|
46
|
+
);
|
|
47
|
+
},
|
|
33
48
|
};
|
|
34
49
|
|
|
35
50
|
/** 序列化值 */
|
|
36
51
|
export function print(value: VmAny, depth = 3): string {
|
|
37
52
|
if (value === undefined) {
|
|
53
|
+
if (noColor) return '<uninitialized>';
|
|
38
54
|
return styles.gray.open + '<uninitialized>' + styles.gray.close;
|
|
39
55
|
}
|
|
40
56
|
return serialize(value, { ...options, maxDepth: depth });
|
|
@@ -77,20 +77,30 @@ interface ParsedDiagnostics {
|
|
|
77
77
|
references: SourceReference[];
|
|
78
78
|
/** 标签引用诊断信息 */
|
|
79
79
|
tagsReferences: SourceReference[];
|
|
80
|
+
|
|
81
|
+
/** 代码映射信息 */
|
|
82
|
+
sourcemaps: IRange[];
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
/** 分析诊断信息,{@link diagnostic_position_encoding} 不能设为 `None` */
|
|
83
|
-
export function parseDiagnostics(
|
|
86
|
+
export function parseDiagnostics(
|
|
87
|
+
source: ScriptInput,
|
|
88
|
+
diagnostics: Uint32Array,
|
|
89
|
+
filter?: (code: DiagnosticCode) => boolean,
|
|
90
|
+
): ParsedDiagnostics {
|
|
84
91
|
const parsed = [];
|
|
85
92
|
const bufLen = diagnostics.length;
|
|
86
93
|
for (let i = 0; i < bufLen; i += 5) {
|
|
94
|
+
const code = diagnostics[i + 4]! as DiagnosticCode;
|
|
95
|
+
if (filter && !filter(code)) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
87
98
|
const startLineNumber = diagnostics[i]!;
|
|
88
99
|
const startColumn = diagnostics[i + 1]!;
|
|
89
100
|
const endLineNumber = diagnostics[i + 2]!;
|
|
90
101
|
const endColumn = diagnostics[i + 3]!;
|
|
91
|
-
const error = diagnostics[i + 4]! as DiagnosticCode;
|
|
92
102
|
parsed.push({
|
|
93
|
-
code
|
|
103
|
+
code,
|
|
94
104
|
range: {
|
|
95
105
|
startLineNumber,
|
|
96
106
|
startColumn,
|
|
@@ -107,6 +117,7 @@ export function parseDiagnostics(source: ScriptInput, diagnostics: Uint32Array):
|
|
|
107
117
|
const _tags: SourceDiagnostic[] = [];
|
|
108
118
|
const _references: SourceReference[] = [];
|
|
109
119
|
const _tagsReferences: SourceReference[] = [];
|
|
120
|
+
const _sourcemaps: IRange[] = [];
|
|
110
121
|
for (let i = 0; i < parsed.length; i++) {
|
|
111
122
|
const diagnostic = parsed[i]!;
|
|
112
123
|
const { code } = diagnostic;
|
|
@@ -120,7 +131,11 @@ export function parseDiagnostics(source: ScriptInput, diagnostics: Uint32Array):
|
|
|
120
131
|
_hints.push(diagnostic);
|
|
121
132
|
} else if (code > DiagnosticCode.TagStart && code < DiagnosticCode.TagEnd) {
|
|
122
133
|
_tags.push(diagnostic);
|
|
134
|
+
} else if (code === DiagnosticCode.SourceMap) {
|
|
135
|
+
_sourcemaps.push(diagnostic.range);
|
|
136
|
+
continue;
|
|
123
137
|
} else {
|
|
138
|
+
// 非法诊断代码,跳过
|
|
124
139
|
continue;
|
|
125
140
|
}
|
|
126
141
|
diagnostic.references = [];
|
|
@@ -151,6 +166,7 @@ export function parseDiagnostics(source: ScriptInput, diagnostics: Uint32Array):
|
|
|
151
166
|
tags: _tags,
|
|
152
167
|
references: _references,
|
|
153
168
|
tagsReferences: _tagsReferences,
|
|
169
|
+
sourcemaps: _sourcemaps,
|
|
154
170
|
};
|
|
155
171
|
}
|
|
156
172
|
|
package/src/compiler/emit.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { OpCode } from '@mirascript/wasm/types';
|
|
2
|
-
import {
|
|
2
|
+
import { toBase64 } from 'js-base64';
|
|
3
3
|
import type { VmConst, VmPrimitive } from '../vm/index.js';
|
|
4
4
|
import type { ScriptInput, TranspileOptions } from './types.js';
|
|
5
|
+
import type { IRange } from './diagnostic.js';
|
|
6
|
+
import { SourceMapGenerator } from 'source-map-js';
|
|
5
7
|
|
|
6
8
|
/** 生成代码 */
|
|
7
|
-
export function emit(
|
|
8
|
-
|
|
9
|
+
export function emit(
|
|
10
|
+
source: ScriptInput,
|
|
11
|
+
chunk: Uint8Array,
|
|
12
|
+
sourcemaps: readonly IRange[],
|
|
13
|
+
options: TranspileOptions,
|
|
14
|
+
): string {
|
|
15
|
+
const gen = new Emitter(source, chunk, sourcemaps, options);
|
|
9
16
|
gen.read();
|
|
10
17
|
const code = gen.codeLines.join('\n');
|
|
11
18
|
return code;
|
|
@@ -57,7 +64,7 @@ function toJavascript(value: VmConst | undefined): string {
|
|
|
57
64
|
return String(value);
|
|
58
65
|
}
|
|
59
66
|
|
|
60
|
-
const ORIGIN = `mira://MiraScript
|
|
67
|
+
const ORIGIN = `mira://MiraScript/`;
|
|
61
68
|
let sourceId = 1;
|
|
62
69
|
|
|
63
70
|
/** 创建数组 */
|
|
@@ -75,6 +82,7 @@ class Emitter {
|
|
|
75
82
|
constructor(
|
|
76
83
|
readonly source: ScriptInput,
|
|
77
84
|
readonly chunk: Uint8Array,
|
|
85
|
+
readonly sourcemaps: readonly IRange[],
|
|
78
86
|
readonly options: TranspileOptions,
|
|
79
87
|
) {
|
|
80
88
|
this.pretty = options.pretty ?? false;
|
|
@@ -362,9 +370,9 @@ class Emitter {
|
|
|
362
370
|
);
|
|
363
371
|
if (script) {
|
|
364
372
|
args.unshift(`global = GlobalFallback()`);
|
|
365
|
-
code = `'use strict'; return (
|
|
373
|
+
code = `'use strict'; return ((${args.join(', ')}) => { try { CpEnter(); var ${regs};`;
|
|
366
374
|
} else {
|
|
367
|
-
code = `${this.wv(reg)} = Function(
|
|
375
|
+
code = `${this.wv(reg)} = Function((${args.join(', ')}) => { try { CpEnter(); var ${regs};`;
|
|
368
376
|
}
|
|
369
377
|
if (varg) {
|
|
370
378
|
code += ` var ${this.wv(argn, -1)} = Vargs(vargs);`;
|
|
@@ -688,6 +696,9 @@ class Emitter {
|
|
|
688
696
|
code = `continue;`;
|
|
689
697
|
break;
|
|
690
698
|
}
|
|
699
|
+
case OpCode.Noop: {
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
691
702
|
default: {
|
|
692
703
|
code = `; // ${OpCode[opcode] ?? opcode}`;
|
|
693
704
|
break;
|
|
@@ -742,27 +753,42 @@ class Emitter {
|
|
|
742
753
|
const hasSchema = /^\w+:/.test(fileName);
|
|
743
754
|
if (!hasSchema) {
|
|
744
755
|
if (fileName.startsWith('/')) {
|
|
745
|
-
fileName = fileName.replace(
|
|
756
|
+
fileName = fileName.replace(/^\/+\s*/, '');
|
|
746
757
|
}
|
|
747
758
|
if (!fileName) {
|
|
748
759
|
fileName = `${sourceId++}.${this.options.input_mode === 'Template' ? 'miratpl' : 'mira'}`;
|
|
749
760
|
}
|
|
750
761
|
}
|
|
751
|
-
const
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
762
|
+
const map = new SourceMapGenerator({
|
|
763
|
+
file: fileName + '.js',
|
|
764
|
+
});
|
|
765
|
+
if (typeof this.source === 'string') {
|
|
766
|
+
map.setSourceContent(fileName, this.source);
|
|
767
|
+
}
|
|
768
|
+
for (let i = 0; i < this.sourcemaps.length; i++) {
|
|
769
|
+
const range = this.sourcemaps[i];
|
|
770
|
+
if (!range) break;
|
|
771
|
+
map.addMapping({
|
|
772
|
+
generated: {
|
|
773
|
+
// 前两行固定为:
|
|
774
|
+
// (function anonymous($Add,$Aeq, ...
|
|
775
|
+
// ) {
|
|
776
|
+
line: i + 3,
|
|
777
|
+
column: 0,
|
|
778
|
+
},
|
|
779
|
+
original: {
|
|
780
|
+
line: range.startLineNumber,
|
|
781
|
+
column: range.startColumn - 1,
|
|
782
|
+
},
|
|
783
|
+
source: fileName,
|
|
784
|
+
});
|
|
785
|
+
}
|
|
760
786
|
const prefix = '//# ';
|
|
761
|
-
const sourceURL = hasSchema ? fileName : `${ORIGIN}
|
|
787
|
+
const sourceURL = hasSchema ? fileName : `${ORIGIN}${fileName}`;
|
|
762
788
|
this.codeLines.push(
|
|
763
789
|
// Prevent source map from being recognized as of this file
|
|
764
|
-
`${prefix}sourceURL=${sourceURL}`,
|
|
765
|
-
`${prefix}sourceMappingURL=data:application/json;base64,${
|
|
790
|
+
`${prefix}sourceURL=${sourceURL}.js`,
|
|
791
|
+
`${prefix}sourceMappingURL=data:application/json;base64,${toBase64(map.toString())}`,
|
|
766
792
|
);
|
|
767
793
|
}
|
|
768
794
|
}
|
package/src/compiler/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ import './types.js';
|
|
|
4
4
|
import { emit } from './emit.js';
|
|
5
5
|
import { createScript } from './create-script.js';
|
|
6
6
|
import { compileFast } from './compile-fast.js';
|
|
7
|
-
import { formatDiagnostic, parseDiagnostics } from './diagnostic.js';
|
|
7
|
+
import { DiagnosticCode, formatDiagnostic, parseDiagnostics } from './diagnostic.js';
|
|
8
8
|
import { generateBytecode, generateBytecodeSync, loadModule } from './generate-bytecode.js';
|
|
9
9
|
import { compileWorker } from './worker-manager.js';
|
|
10
10
|
await loadModule();
|
|
@@ -33,7 +33,10 @@ export function emitScript(
|
|
|
33
33
|
if (!code) {
|
|
34
34
|
reportDiagnostic(source, diagnostics);
|
|
35
35
|
}
|
|
36
|
-
const
|
|
36
|
+
const sourcemaps = options.sourceMap
|
|
37
|
+
? parseDiagnostics(source, diagnostics, (c) => c === DiagnosticCode.SourceMap).sourcemaps
|
|
38
|
+
: [];
|
|
39
|
+
const target = emit(source, code, sourcemaps, options);
|
|
37
40
|
return createScript(source, target);
|
|
38
41
|
}
|
|
39
42
|
|
|
@@ -41,6 +44,11 @@ export function emitScript(
|
|
|
41
44
|
* 生成 MiraScript 对应的 JavaScript 代码
|
|
42
45
|
*/
|
|
43
46
|
export async function compile(this: void, source: ScriptInput, options: TranspileOptions = {}): Promise<VmScript> {
|
|
47
|
+
if (options.sourceMap) {
|
|
48
|
+
options.diagnostic_sourcemap = true;
|
|
49
|
+
// https://tc39.es/ecma426/#sec-terms-and-definitions-colun
|
|
50
|
+
options.diagnostic_position_encoding ??= 'Utf16';
|
|
51
|
+
}
|
|
44
52
|
if (typeof source == 'string') {
|
|
45
53
|
const result = compileFast(source, options);
|
|
46
54
|
if (result) return result;
|
package/src/compiler/worker.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ScriptInput, TranspileOptions } from './types.js';
|
|
2
2
|
import { emit } from './emit.js';
|
|
3
3
|
import { generateBytecode } from './generate-bytecode.js';
|
|
4
|
+
import { DiagnosticCode, parseDiagnostics } from './diagnostic.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* 生成 MiraScript 对应的 JavaScript 代码
|
|
@@ -13,7 +14,10 @@ export async function compile(
|
|
|
13
14
|
if (bytecode == null) {
|
|
14
15
|
return [undefined, errors];
|
|
15
16
|
}
|
|
16
|
-
const
|
|
17
|
+
const sourcemaps = options.sourceMap
|
|
18
|
+
? parseDiagnostics(script, errors, (c) => c === DiagnosticCode.SourceMap).sourcemaps
|
|
19
|
+
: [];
|
|
20
|
+
const generatedCode = emit(script, bytecode, sourcemaps, options);
|
|
17
21
|
return [generatedCode, errors];
|
|
18
22
|
}
|
|
19
23
|
|
package/src/helpers/serialize.ts
CHANGED
|
@@ -67,7 +67,7 @@ const DEFAULT_OPTIONS = Object.freeze({
|
|
|
67
67
|
} satisfies SerializeOptions);
|
|
68
68
|
|
|
69
69
|
/** 获取选项 */
|
|
70
|
-
|
|
70
|
+
function getSerializeOptions(options: Partial<SerializeOptions> | undefined): SerializeOptions {
|
|
71
71
|
if (options == null) return DEFAULT_OPTIONS;
|
|
72
72
|
const opt = { ...DEFAULT_OPTIONS };
|
|
73
73
|
for (const key in options) {
|
|
@@ -157,17 +157,17 @@ export function serializePropName(value: string, options?: Partial<SerializeOpti
|
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
/** 序列化 nil 值 */
|
|
160
|
-
function serializeNil(): string {
|
|
160
|
+
export function serializeNil(): string {
|
|
161
161
|
return 'nil';
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
/** 序列化布尔值 */
|
|
165
|
-
function serializeBoolean(value: boolean): string {
|
|
165
|
+
export function serializeBoolean(value: boolean): string {
|
|
166
166
|
return value ? 'true' : 'false';
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
/** 序列化数字 */
|
|
170
|
-
function serializeNumber(value: number): string {
|
|
170
|
+
export function serializeNumber(value: number): string {
|
|
171
171
|
if (isNaN(value)) return 'nan';
|
|
172
172
|
if (!isFinite(value)) return value < 0 ? '-inf' : 'inf';
|
|
173
173
|
if (value === 0) {
|
|
@@ -178,7 +178,7 @@ function serializeNumber(value: number): string {
|
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
/** 序列化数组 */
|
|
181
|
-
function serializeArray(value: VmArray, depth: number, options: SerializeOptions): string {
|
|
181
|
+
export function serializeArray(value: VmArray, depth: number, options: SerializeOptions): string {
|
|
182
182
|
if (depth > options.maxDepth) return `[]`;
|
|
183
183
|
if (value.length === 0) return '[]';
|
|
184
184
|
let str = '[';
|
|
@@ -207,7 +207,7 @@ function customValueOf(value: VmRecord): VmAny | undefined {
|
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
/** 序列化记录 */
|
|
210
|
-
function serializeRecord(value: VmRecord, depth: number, options: SerializeOptions): string {
|
|
210
|
+
export function serializeRecord(value: VmRecord, depth: number, options: SerializeOptions): string {
|
|
211
211
|
const customValue = customValueOf(value);
|
|
212
212
|
if (customValue !== undefined) {
|
|
213
213
|
return serializeImpl(customValue, depth - 1, options);
|
package/src/subtle.ts
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
export * as constants from './helpers/constants.js';
|
|
2
2
|
export { VmSharedContext, DefaultVmContext } from './vm/types/context.js';
|
|
3
3
|
export * as operations from './vm/operations.js';
|
|
4
|
-
export {
|
|
4
|
+
export {
|
|
5
|
+
serialize,
|
|
6
|
+
serializeNil,
|
|
7
|
+
serializeBoolean,
|
|
8
|
+
serializeNumber,
|
|
9
|
+
serializeString,
|
|
10
|
+
serializePropName,
|
|
11
|
+
serializeArray,
|
|
12
|
+
serializeRecord,
|
|
13
|
+
type SerializeOptions,
|
|
14
|
+
} from './helpers/serialize.js';
|
|
5
15
|
export { lib } from './vm/lib/_loader.js';
|
|
6
16
|
export * from './compiler/diagnostic.js';
|
|
7
17
|
export { generateBytecode, generateBytecodeSync, emitScript } from './compiler/index.js';
|
package/src/vm/lib/_helpers.ts
CHANGED
|
@@ -191,17 +191,22 @@ export type VmLibOption = Pick<
|
|
|
191
191
|
export type VmLib<T extends VmFunctionLike = VmFunctionLike> = T & VmLibOption;
|
|
192
192
|
|
|
193
193
|
/** 创建库函数 */
|
|
194
|
-
export function VmLib<T extends VmFunctionLike
|
|
194
|
+
export function VmLib<T extends VmFunctionLike, P extends Record<string, unknown>>(
|
|
195
|
+
fn: T,
|
|
196
|
+
option: VmLibOption,
|
|
197
|
+
properties?: P,
|
|
198
|
+
): VmLib<T> & P {
|
|
195
199
|
/* c8 ignore next 2 */
|
|
196
200
|
if (typeof fn != 'function') throw new TypeError('Invalid function');
|
|
197
201
|
if (isVmFunction(fn)) throw new TypeError('Cannot create VmLib from a VmFunction');
|
|
198
202
|
|
|
199
|
-
const ret = fn as T & VmLibOption as Writable<VmLibOption>;
|
|
203
|
+
const ret = fn as T & VmLibOption & P as Writable<T & VmLibOption & P>;
|
|
204
|
+
Object.assign(ret, properties);
|
|
200
205
|
ret.params = option.params;
|
|
201
206
|
ret.paramsType = option.paramsType;
|
|
202
207
|
ret.returns = option.returns;
|
|
203
208
|
ret.returnsType = option.returnsType;
|
|
204
209
|
ret.summary = option.summary;
|
|
205
210
|
ret.examples = option.examples;
|
|
206
|
-
return ret as T & VmLibOption;
|
|
211
|
+
return ret as T & VmLibOption & P;
|
|
207
212
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import supportsColor from 'supports-color';
|
|
1
2
|
import { VmError } from '../../error.js';
|
|
2
3
|
import { $ToString } from '../../operations.js';
|
|
3
4
|
import type { VmAny } from '../../types/index.js';
|
|
@@ -6,7 +7,7 @@ import { VmLib } from '../_helpers.js';
|
|
|
6
7
|
export const debug_print = VmLib(
|
|
7
8
|
(...args) => {
|
|
8
9
|
// eslint-disable-next-line no-console
|
|
9
|
-
console.log(
|
|
10
|
+
console.log(...debug_print.prefix, ...args);
|
|
10
11
|
},
|
|
11
12
|
{
|
|
12
13
|
summary: '打印调试信息到控制台',
|
|
@@ -15,14 +16,17 @@ export const debug_print = VmLib(
|
|
|
15
16
|
returnsType: 'nil',
|
|
16
17
|
examples: ['debug_print("value:", 42);'],
|
|
17
18
|
},
|
|
19
|
+
{
|
|
20
|
+
prefix: ['MiraScript'] as readonly string[],
|
|
21
|
+
},
|
|
18
22
|
);
|
|
19
23
|
|
|
20
24
|
export const panic = VmLib(
|
|
21
25
|
(message: VmAny) => {
|
|
22
26
|
// eslint-disable-next-line no-console
|
|
23
|
-
if (message === undefined) console.error(
|
|
27
|
+
if (message === undefined) console.error(...panic.prefix);
|
|
24
28
|
// eslint-disable-next-line no-console
|
|
25
|
-
else console.error(
|
|
29
|
+
else console.error(...panic.prefix, message);
|
|
26
30
|
const error = message == null ? 'panic' : 'panic: ' + $ToString(message);
|
|
27
31
|
throw new VmError(error, undefined);
|
|
28
32
|
},
|
|
@@ -33,4 +37,21 @@ export const panic = VmLib(
|
|
|
33
37
|
returnsType: 'never',
|
|
34
38
|
examples: ['panic("boom");'],
|
|
35
39
|
},
|
|
40
|
+
{
|
|
41
|
+
prefix: ['MiraScript'] as readonly string[],
|
|
42
|
+
},
|
|
36
43
|
);
|
|
44
|
+
|
|
45
|
+
if (typeof location != 'undefined') {
|
|
46
|
+
const badge = '%cMiraScript';
|
|
47
|
+
const common = 'display: inline-block; padding: 1px 4px; border-radius: 3px;';
|
|
48
|
+
debug_print.prefix = [badge, `${common} background: #007acc; color: #fff;`];
|
|
49
|
+
panic.prefix = [badge, `${common} background: #d23d3d; color: #fff;`];
|
|
50
|
+
} else {
|
|
51
|
+
if (supportsColor.stdout) {
|
|
52
|
+
debug_print.prefix = ['\u001B[44;37m MiraScript \u001B[0m'];
|
|
53
|
+
}
|
|
54
|
+
if (supportsColor.stderr) {
|
|
55
|
+
panic.prefix = ['\u001B[41;37m MiraScript \u001B[0m'];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -36,7 +36,7 @@ export const hypot = VmLib(build(Math.hypot), {
|
|
|
36
36
|
export const sum = VmLib(
|
|
37
37
|
(...values: readonly VmAny[]) => {
|
|
38
38
|
const numbers = getNumbers(values);
|
|
39
|
-
return numbers.reduce((a, b) => a + b, 0);
|
|
39
|
+
return numbers.reduce((a, b) => a + b, -0);
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
42
|
summary: '返回一组数的总和',
|
package/src/vm/types/wrapper.ts
CHANGED
|
@@ -23,7 +23,9 @@ export abstract class VmWrapper<T extends object> {
|
|
|
23
23
|
}
|
|
24
24
|
/** 转为字符串 */
|
|
25
25
|
toString(): string {
|
|
26
|
-
|
|
26
|
+
const { type, describe } = this;
|
|
27
|
+
if (!describe) return `<${type}>`;
|
|
28
|
+
return `<${type} ${describe}>`;
|
|
27
29
|
}
|
|
28
30
|
}
|
|
29
31
|
|