@mirascript/mirascript 0.1.86 → 0.1.88
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-LSPCAN32.js → chunk-HHKY7Y7L.js} +125 -756
- package/dist/chunk-HHKY7Y7L.js.map +6 -0
- package/dist/{chunk-A425FGG3.js → chunk-Y7S6AHE7.js} +689 -32
- package/dist/chunk-Y7S6AHE7.js.map +6 -0
- package/dist/compiler/{emit → bytecode}/consts.d.ts +0 -2
- package/dist/compiler/bytecode/consts.d.ts.map +1 -0
- package/dist/compiler/bytecode/index.d.ts +28 -0
- package/dist/compiler/bytecode/index.d.ts.map +1 -0
- package/dist/compiler/emit/index.d.ts +2 -13
- package/dist/compiler/emit/index.d.ts.map +1 -1
- package/dist/compiler/emit/utils.d.ts +6 -0
- package/dist/compiler/emit/utils.d.ts.map +1 -0
- package/dist/compiler/generate-bytecode.d.ts +1 -1
- package/dist/compiler/generate-bytecode.d.ts.map +1 -1
- package/dist/compiler/index.d.ts +1 -1
- package/dist/compiler/index.d.ts.map +1 -1
- package/dist/compiler/options.d.ts +5 -0
- package/dist/compiler/options.d.ts.map +1 -0
- package/dist/compiler/verbose.d.ts +11 -0
- package/dist/compiler/verbose.d.ts.map +1 -0
- package/dist/compiler/worker.d.ts +1 -1
- package/dist/compiler/worker.js +3 -3
- package/dist/compiler/worker.js.map +1 -1
- package/dist/index.js +17 -51
- package/dist/index.js.map +2 -2
- package/dist/subtle.d.ts +3 -1
- package/dist/subtle.d.ts.map +1 -1
- package/dist/subtle.js +18 -14
- package/dist/subtle.js.map +1 -1
- package/dist/vm/lib/index.d.ts +9 -1
- package/dist/vm/lib/index.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/compiler/{emit → bytecode}/consts.ts +0 -16
- package/src/compiler/bytecode/index.ts +58 -0
- package/src/compiler/emit/index.ts +19 -72
- package/src/compiler/emit/sourcemap.ts +1 -1
- package/src/compiler/emit/utils.ts +28 -0
- package/src/compiler/generate-bytecode.ts +3 -3
- package/src/compiler/index.ts +9 -29
- package/src/compiler/options.ts +16 -0
- package/src/compiler/verbose.ts +32 -0
- package/src/compiler/worker.ts +2 -2
- package/src/subtle.ts +3 -1
- package/src/vm/lib/index.ts +10 -1
- package/dist/chunk-A425FGG3.js.map +0 -6
- package/dist/chunk-LSPCAN32.js.map +0 -6
- package/dist/compiler/emit/consts.d.ts.map +0 -1
package/dist/subtle.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subtle.d.ts","sourceRoot":"","sources":["../src/subtle.ts"],"names":[],"mappings":"AAAA,OAAO,2BAA2B,CAAC;AAEnC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,OAAO,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,UAAU,MAAM,0BAA0B,CAAC;AACvD,OAAO,EACH,OAAO,IAAI,mBAAmB,EAC9B,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,KAAK,gBAAgB,GACxB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"subtle.d.ts","sourceRoot":"","sources":["../src/subtle.ts"],"names":[],"mappings":"AAAA,OAAO,2BAA2B,CAAC;AAEnC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,OAAO,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,UAAU,MAAM,0BAA0B,CAAC;AACvD,OAAO,EACH,OAAO,IAAI,mBAAmB,EAC9B,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,KAAK,gBAAgB,GACxB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACpE,cAAc,0BAA0B,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,KAAK,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAChH,OAAO,EAAE,KAAK,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/subtle.js
CHANGED
|
@@ -1,32 +1,34 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DefaultVmContext,
|
|
3
|
+
compileVerbose,
|
|
4
|
+
constants_exports,
|
|
5
|
+
convert_exports,
|
|
3
6
|
createScript,
|
|
7
|
+
display,
|
|
4
8
|
emitScript,
|
|
5
9
|
lib,
|
|
6
10
|
operations_exports,
|
|
11
|
+
serialize,
|
|
12
|
+
serializeArray,
|
|
13
|
+
serializeBoolean,
|
|
14
|
+
serializeNil,
|
|
15
|
+
serializeNumber,
|
|
16
|
+
serializeRecord,
|
|
17
|
+
serializeRecordKey,
|
|
18
|
+
serializeString,
|
|
7
19
|
wrapScript
|
|
8
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-Y7S6AHE7.js";
|
|
9
21
|
import {
|
|
22
|
+
BytecodeReader,
|
|
10
23
|
DiagnosticCode,
|
|
11
|
-
constants_exports,
|
|
12
|
-
convert_exports,
|
|
13
|
-
display,
|
|
14
24
|
formatDiagnosticMessage,
|
|
15
25
|
formatDiagnostics,
|
|
16
26
|
generateBytecode,
|
|
17
27
|
generateBytecodeSync,
|
|
18
28
|
getDiagnosticMessage,
|
|
19
29
|
getDiagnosticSeverity,
|
|
20
|
-
parseDiagnostics
|
|
21
|
-
|
|
22
|
-
serializeArray,
|
|
23
|
-
serializeBoolean,
|
|
24
|
-
serializeNil,
|
|
25
|
-
serializeNumber,
|
|
26
|
-
serializeRecord,
|
|
27
|
-
serializeRecordKey,
|
|
28
|
-
serializeString
|
|
29
|
-
} from "./chunk-LSPCAN32.js";
|
|
30
|
+
parseDiagnostics
|
|
31
|
+
} from "./chunk-HHKY7Y7L.js";
|
|
30
32
|
|
|
31
33
|
// src/subtle.ts
|
|
32
34
|
import { OpCode, isKeyword } from "@mirascript/constants";
|
|
@@ -92,10 +94,12 @@ function analyzeGlobalReferences(expression, mode) {
|
|
|
92
94
|
return accessChains;
|
|
93
95
|
}
|
|
94
96
|
export {
|
|
97
|
+
BytecodeReader,
|
|
95
98
|
DefaultVmContext,
|
|
96
99
|
DiagnosticCode,
|
|
97
100
|
OpCode,
|
|
98
101
|
analyzeGlobalReferences,
|
|
102
|
+
compileVerbose,
|
|
99
103
|
constants_exports as constants,
|
|
100
104
|
convert_exports as convert,
|
|
101
105
|
createScript,
|
package/dist/subtle.js.map
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/subtle.ts", "../src/helpers/analyze.ts"],
|
|
4
|
-
"mappings": "
|
|
4
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,SAAS,QAAQ,iBAAiB;;;ACFlC,SAAS,sBAAsB;AAQ/B,IAAM,YAAY;AAClB,IAAM,YAAY,IAAI;AAAA,EAClB,OAAO,QAAQ,eAAe,MAAM,OAAO,UAAU,MAAM,UAAU,eAAe,MAAM;AAAA,EAC1F;AACJ;AACA,IAAM,kBAAkB;AAExB,IAAM,EAAE,SAAS,IAAI;AAId,SAAS,wBAAwB,YAAoB,MAA0C;AAClG,MAAI,WAAW,KAAK,MAAM,IAAI;AAC1B,WAAO,CAAC;AAAA,EACZ;AACA,QAAM,CAAC,MAAM,WAAW,IAAI,qBAAqB,YAAY;AAAA,IACzD,YAAY,QAAQ;AAAA,IACpB,8BAA8B;AAAA;AAAA,IAE9B,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,sBAAsB;AAAA,IACtB,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,IACtB,QAAQ;AAAA,EACZ,CAAC;AACD,MAAI,QAAQ,QAAQ,YAAY,WAAW,GAAG;AAC1C,WAAO,CAAC;AAAA,EACZ;AACA,QAAM,oBAAoB,iBAAiB,YAAY,WAAW;AAClE,QAAM,UAAU,kBAAkB,KAAK,OAAO,CAAC,MAAM,EAAE,SAAS,eAAe,cAAc;AAC7F,MAAI,QAAQ,WAAW,GAAG;AACtB,WAAO,CAAC;AAAA,EACZ;AACA,QAAM,QAAQ,WAAW,MAAM,OAAO;AACtC,QAAM,SAAS,oBAAI,IAAY;AAC/B,aAAW,UAAU,SAAS;AAE1B,UAAM,OAAO,MAAM,OAAO,MAAM,kBAAkB,CAAC;AACnD,QAAI,CAAC,KAAM;AACX,QAAI,KAAK,SAAS,gBAAiB;AACnC,UAAM,SAAS,KAAK,MAAM,OAAO,MAAM,cAAc,CAAC;AACtD,UAAM,QAAQ,UAAU,KAAK,MAAM;AACnC,QAAI,SAAS,KAAM;AACnB,UAAM,aAAa,MAAM,CAAC;AAC1B,QAAI,YAAY,WAAW,OAAO,MAAM,YAAY,OAAO,MAAM,YAAa;AAC9E,UAAM,WAAW,MAAM,CAAC,EAAE,MAAM,SAAS,EAAE,KAAK,GAAG;AACnD,WAAO,IAAI,QAAQ;AAAA,EACvB;AACA,QAAM,eAAuC,CAAC;AAC9C,aAAW,YAAY,QAAQ;AAC3B,UAAM,QAAQ,SAAS,MAAM,GAAG,EAAE,IAAI,CAAC,SAAS;AAC5C,UAAI,MAAM,KAAK,IAAI,GAAG;AAElB,eAAO,SAAS,MAAM,EAAE;AAAA,MAC5B;AACA,aAAO;AAAA,IACX,CAAC;AACD,iBAAa,KAAK,KAAwC;AAAA,EAC9D;AACA,SAAO;AACX;",
|
|
5
5
|
"names": []
|
|
6
6
|
}
|
package/dist/vm/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import * as global from './global/index.js';
|
|
2
2
|
import * as mods from './mod/index.js';
|
|
3
|
-
|
|
3
|
+
/** 标准库 */
|
|
4
|
+
type LibData = typeof global & typeof mods;
|
|
5
|
+
/** 标准库 */
|
|
6
|
+
export type Lib = {
|
|
7
|
+
readonly [key in keyof LibData]: LibData[key];
|
|
8
|
+
};
|
|
9
|
+
/** 标准库 */
|
|
10
|
+
export declare const lib: Lib;
|
|
11
|
+
export type { VmLibOption } from './helpers.js';
|
|
4
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/vm/lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAC;AAkBvC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/vm/lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAC;AAkBvC,UAAU;AACV,KAAK,OAAO,GAAG,OAAO,MAAM,GAAG,OAAO,IAAI,CAAC;AAC3C,UAAU;AACV,MAAM,MAAM,GAAG,GAAG;IACd,QAAQ,EAAE,GAAG,IAAI,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC;CAChD,CAAC;AAEF,UAAU;AACV,eAAO,MAAM,GAAG,EAAE,GAA8D,CAAC;AACjF,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mirascript/mirascript",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.88",
|
|
4
4
|
"author": "CloudPSS",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "An expression based scripting language.",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"@cloudpss/worker": "^0.1.11",
|
|
43
43
|
"source-map-js": "^1.2.1",
|
|
44
44
|
"supports-color": "^11.0.0",
|
|
45
|
-
"@mirascript/
|
|
46
|
-
"@mirascript/
|
|
45
|
+
"@mirascript/constants": "~0.1.88",
|
|
46
|
+
"@mirascript/bindings": "~0.1.88"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"ava": "^8.0.1",
|
|
@@ -1,21 +1,5 @@
|
|
|
1
1
|
/* eslint-disable no-useless-assignment */
|
|
2
2
|
import type { VmPrimitive } from '../../vm/index.js';
|
|
3
|
-
const { stringify } = JSON;
|
|
4
|
-
/** 将值转为 JS 字面量 */
|
|
5
|
-
export function toJsLiteral(value: VmPrimitive | undefined): string {
|
|
6
|
-
/* c8 ignore next 2 */
|
|
7
|
-
if (value === null) return 'null';
|
|
8
|
-
if (value === undefined) return 'undefined';
|
|
9
|
-
if (typeof value == 'string') {
|
|
10
|
-
return stringify(value);
|
|
11
|
-
}
|
|
12
|
-
// JSON 无法处理 NaN 等特殊数字
|
|
13
|
-
if (value === 0) {
|
|
14
|
-
if (1 / value === -Infinity) return '-0';
|
|
15
|
-
return '0';
|
|
16
|
-
}
|
|
17
|
-
return String(value satisfies number | boolean);
|
|
18
|
-
}
|
|
19
3
|
|
|
20
4
|
const DECODER = new TextDecoder();
|
|
21
5
|
const { fromCharCode } = String;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { OpCode } from '@mirascript/constants';
|
|
2
|
+
import type { VmPrimitive } from '../../vm/index.js';
|
|
3
|
+
import { readConsts } from './consts.js';
|
|
4
|
+
|
|
5
|
+
/** MiraScript 字节码读取器。 */
|
|
6
|
+
export class BytecodeReader {
|
|
7
|
+
constructor(readonly chunk: Uint8Array) {
|
|
8
|
+
const reader = new DataView(chunk.buffer, chunk.byteOffset, chunk.byteLength);
|
|
9
|
+
this.chunkSize = reader.getUint32(0, true);
|
|
10
|
+
this.codeSize = reader.getUint32(4, true);
|
|
11
|
+
this.constSize = reader.getUint32(8 + this.codeSize, true);
|
|
12
|
+
this.codeReader = new DataView(chunk.buffer, chunk.byteOffset + 8, this.codeSize);
|
|
13
|
+
this.constVals = readConsts(
|
|
14
|
+
new Uint8Array(chunk.buffer, chunk.byteOffset + 12 + this.codeSize, this.constSize),
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
readonly chunkSize: number;
|
|
19
|
+
readonly codeSize: number;
|
|
20
|
+
readonly constSize: number;
|
|
21
|
+
readonly constVals: VmPrimitive[];
|
|
22
|
+
protected readonly codeReader: DataView;
|
|
23
|
+
protected codeOffset = 0;
|
|
24
|
+
|
|
25
|
+
/** 是否仍有指令可读。 */
|
|
26
|
+
protected get hasCode(): boolean {
|
|
27
|
+
return this.codeOffset < this.codeSize;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** 读取操作码。 */
|
|
31
|
+
protected readOpcode(): { opcode: OpCode; wide: boolean; offset: number } {
|
|
32
|
+
const offset = this.codeOffset;
|
|
33
|
+
const raw = this.codeReader.getUint8(this.codeOffset++);
|
|
34
|
+
return { opcode: raw & 0x7f, wide: raw >= 0x80, offset };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** 读取操作码。 */
|
|
38
|
+
protected peekOpcode(): OpCode {
|
|
39
|
+
const raw = this.codeReader.getUint8(this.codeOffset);
|
|
40
|
+
return raw & 0x7f;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** 读取无符号参数。 */
|
|
44
|
+
protected readParam(wide: boolean): number {
|
|
45
|
+
const value = wide
|
|
46
|
+
? this.codeReader.getUint32(this.codeOffset, true)
|
|
47
|
+
: this.codeReader.getUint8(this.codeOffset);
|
|
48
|
+
this.codeOffset += wide ? 4 : 1;
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** 读取有符号索引。 */
|
|
53
|
+
protected readIndex(wide: boolean): number {
|
|
54
|
+
const value = wide ? this.codeReader.getInt32(this.codeOffset, true) : this.codeReader.getInt8(this.codeOffset);
|
|
55
|
+
this.codeOffset += wide ? 4 : 1;
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { OpCode } from '@mirascript/constants';
|
|
2
|
-
import { toString } from '../../helpers/convert/index.js';
|
|
3
|
-
import type { VmPrimitive } from '../../vm/index.js';
|
|
4
2
|
import type { ScriptInput, TranspileOptions } from '../types.js';
|
|
5
3
|
import type { IRange } from '../diagnostic.js';
|
|
6
|
-
import { readConsts, toJsLiteral } from './consts.js';
|
|
7
4
|
import { createSourceMap } from './sourcemap.js';
|
|
8
5
|
import { SCRIPT_PREFIX, SCRIPT_PREFIX_NO_GLOBAL, type ScriptPrefix } from './constants.js';
|
|
6
|
+
import { BytecodeReader } from '../bytecode/index.js';
|
|
7
|
+
import { createArray, toJsLiteral } from './utils.js';
|
|
9
8
|
|
|
10
9
|
/** 生成代码 */
|
|
11
10
|
export function emit(
|
|
@@ -20,39 +19,18 @@ export function emit(
|
|
|
20
19
|
return code;
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
/** 创建数组 */
|
|
24
|
-
function createArray<T>(length: number, fn: (index: number) => T): T[] {
|
|
25
|
-
// micro bench shows that this is faster than Array.from
|
|
26
|
-
const result: T[] = [];
|
|
27
|
-
for (let i = 0; i < length; i++) {
|
|
28
|
-
result.push(fn(i));
|
|
29
|
-
}
|
|
30
|
-
return result;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
22
|
/** 代码生成 */
|
|
34
|
-
export class Emitter {
|
|
23
|
+
export class Emitter extends BytecodeReader {
|
|
35
24
|
constructor(
|
|
36
25
|
readonly source: ScriptInput,
|
|
37
|
-
|
|
26
|
+
chunk: Uint8Array,
|
|
38
27
|
readonly sourcemaps: readonly IRange[],
|
|
39
28
|
readonly options: TranspileOptions,
|
|
40
29
|
) {
|
|
30
|
+
super(chunk);
|
|
41
31
|
this.pretty = options.pretty ?? false;
|
|
42
|
-
|
|
43
|
-
const reader = new DataView(chunk.buffer, chunk.byteOffset, chunk.byteLength);
|
|
44
|
-
this.chunkSize = reader.getUint32(0, true);
|
|
45
|
-
this.codeSize = reader.getUint32(4, true);
|
|
46
|
-
this.constSize = reader.getUint32(8 + this.codeSize, true);
|
|
47
|
-
|
|
48
|
-
this.codeReader = new DataView(chunk.buffer, chunk.byteOffset + 8, this.codeSize);
|
|
49
|
-
this.constVals = readConsts(
|
|
50
|
-
new Uint8Array(chunk.buffer, chunk.byteOffset + 12 + this.codeSize, this.constSize),
|
|
51
|
-
);
|
|
52
32
|
}
|
|
53
33
|
readonly pretty: boolean;
|
|
54
|
-
readonly chunkSize: number;
|
|
55
|
-
readonly codeSize: number;
|
|
56
34
|
/** 读取常量表 */
|
|
57
35
|
private readConsts(): void {
|
|
58
36
|
const { constVals, constLits } = this;
|
|
@@ -60,12 +38,7 @@ export class Emitter {
|
|
|
60
38
|
constLits.push(toJsLiteral(constVals[i]));
|
|
61
39
|
}
|
|
62
40
|
}
|
|
63
|
-
readonly constVals: VmPrimitive[];
|
|
64
41
|
readonly constLits: string[] = [];
|
|
65
|
-
|
|
66
|
-
readonly constSize: number;
|
|
67
|
-
private readonly codeReader: DataView;
|
|
68
|
-
private codeOffset = 0;
|
|
69
42
|
private closureCounter = 0;
|
|
70
43
|
private identCounter = 0;
|
|
71
44
|
/** 记录函数声明所在位置 */
|
|
@@ -81,13 +54,7 @@ export class Emitter {
|
|
|
81
54
|
private useGlobal = false;
|
|
82
55
|
/** 读取全局变量 */
|
|
83
56
|
private rg(constIdx: number): string {
|
|
84
|
-
const
|
|
85
|
-
let lit;
|
|
86
|
-
if (typeof constName == 'string') {
|
|
87
|
-
lit = this.constLits[constIdx]!;
|
|
88
|
-
} else {
|
|
89
|
-
lit = toJsLiteral(toString(constName, undefined));
|
|
90
|
-
}
|
|
57
|
+
const lit = this.constLits[constIdx]!;
|
|
91
58
|
this.useGlobal = true;
|
|
92
59
|
return `global.get(${lit})`;
|
|
93
60
|
}
|
|
@@ -105,27 +72,12 @@ export class Emitter {
|
|
|
105
72
|
if (!i) return '_';
|
|
106
73
|
return this.rv(i, level);
|
|
107
74
|
}
|
|
108
|
-
/** 读取 code param */
|
|
109
|
-
private readParam(wide: boolean): number {
|
|
110
|
-
const value = wide
|
|
111
|
-
? this.codeReader.getUint32(this.codeOffset, true)
|
|
112
|
-
: this.codeReader.getUint8(this.codeOffset);
|
|
113
|
-
this.codeOffset += wide ? 4 : 1;
|
|
114
|
-
return value;
|
|
115
|
-
}
|
|
116
|
-
/** 读取 code param */
|
|
117
|
-
private readIndex(wide: boolean): number {
|
|
118
|
-
const value = wide ? this.codeReader.getInt32(this.codeOffset, true) : this.codeReader.getInt8(this.codeOffset);
|
|
119
|
-
this.codeOffset += wide ? 4 : 1;
|
|
120
|
-
return value;
|
|
121
|
-
}
|
|
122
75
|
/** 读取闭包 */
|
|
123
76
|
private readClosure(): void {
|
|
124
77
|
this.closureCounter++;
|
|
125
78
|
this.identCounter++;
|
|
126
79
|
while (this.codeOffset < this.codeSize) {
|
|
127
|
-
const
|
|
128
|
-
const opcode = opcode_raw & 0x7f;
|
|
80
|
+
const opcode = this.peekOpcode();
|
|
129
81
|
if (opcode !== OpCode.FuncEnd) {
|
|
130
82
|
this.readCode();
|
|
131
83
|
continue;
|
|
@@ -142,8 +94,7 @@ export class Emitter {
|
|
|
142
94
|
/** 读取块结束 */
|
|
143
95
|
private readBlockEnd(end: OpCode): void {
|
|
144
96
|
while (this.codeOffset < this.codeSize) {
|
|
145
|
-
const
|
|
146
|
-
const opcode = opcode_raw & 0x7f;
|
|
97
|
+
const opcode = this.peekOpcode();
|
|
147
98
|
if (opcode !== end) {
|
|
148
99
|
this.readCode();
|
|
149
100
|
continue;
|
|
@@ -163,8 +114,7 @@ export class Emitter {
|
|
|
163
114
|
private readIfElse(): void {
|
|
164
115
|
this.identCounter++;
|
|
165
116
|
while (this.codeOffset < this.codeSize) {
|
|
166
|
-
const
|
|
167
|
-
const opcode = opcode_raw & 0x7f;
|
|
117
|
+
const opcode = this.peekOpcode();
|
|
168
118
|
if (opcode === OpCode.IfEnd) {
|
|
169
119
|
return this.readBlockEnd(OpCode.IfEnd);
|
|
170
120
|
}
|
|
@@ -183,11 +133,10 @@ export class Emitter {
|
|
|
183
133
|
private readModule(obj: number): void {
|
|
184
134
|
this.identCounter++;
|
|
185
135
|
while (this.codeOffset < this.codeSize) {
|
|
186
|
-
const
|
|
187
|
-
const opcode = opcode_raw & 0x7f;
|
|
188
|
-
const wide = opcode_raw >= 0x80;
|
|
136
|
+
const { opcode, wide } = this.readOpcode();
|
|
189
137
|
const read = () => this.readParam(wide);
|
|
190
138
|
let code: string;
|
|
139
|
+
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
|
|
191
140
|
switch (opcode) {
|
|
192
141
|
case OpCode.Field: {
|
|
193
142
|
const field = read();
|
|
@@ -222,11 +171,10 @@ export class Emitter {
|
|
|
222
171
|
private readRecord(obj: number): void {
|
|
223
172
|
this.identCounter++;
|
|
224
173
|
while (this.codeOffset < this.codeSize) {
|
|
225
|
-
const
|
|
226
|
-
const opcode = opcode_raw & 0x7f;
|
|
227
|
-
const wide = opcode_raw >= 0x80;
|
|
174
|
+
const { opcode, wide } = this.readOpcode();
|
|
228
175
|
const read = () => this.readParam(wide);
|
|
229
176
|
let code: string;
|
|
177
|
+
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
|
|
230
178
|
switch (opcode) {
|
|
231
179
|
case OpCode.FieldOpt:
|
|
232
180
|
case OpCode.Field: {
|
|
@@ -289,11 +237,10 @@ export class Emitter {
|
|
|
289
237
|
private readArray(arr: number): void {
|
|
290
238
|
this.identCounter++;
|
|
291
239
|
while (this.codeOffset < this.codeSize) {
|
|
292
|
-
const
|
|
293
|
-
const opcode = opcode_raw & 0x7f;
|
|
294
|
-
const wide = opcode_raw >= 0x80;
|
|
240
|
+
const { opcode, wide } = this.readOpcode();
|
|
295
241
|
const read = () => this.readParam(wide);
|
|
296
242
|
let code: string;
|
|
243
|
+
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
|
|
297
244
|
switch (opcode) {
|
|
298
245
|
case OpCode.Item: {
|
|
299
246
|
const value = read();
|
|
@@ -343,14 +290,13 @@ export class Emitter {
|
|
|
343
290
|
|
|
344
291
|
/** 读取代码 */
|
|
345
292
|
private readCode(): void {
|
|
346
|
-
const
|
|
347
|
-
const opcode = opcode_raw & 0x7f;
|
|
348
|
-
const wide = opcode_raw >= 0x80;
|
|
293
|
+
const { opcode, wide } = this.readOpcode();
|
|
349
294
|
const read = () => this.readParam(wide);
|
|
350
295
|
const readIndex = () => this.readIndex(wide);
|
|
351
296
|
const ident = this.ident();
|
|
352
297
|
let code: string;
|
|
353
298
|
let reg = 0;
|
|
299
|
+
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
|
|
354
300
|
switch (opcode) {
|
|
355
301
|
case OpCode.FuncVarg:
|
|
356
302
|
case OpCode.Func: {
|
|
@@ -635,7 +581,7 @@ export class Emitter {
|
|
|
635
581
|
}
|
|
636
582
|
case OpCode.Module: {
|
|
637
583
|
reg = read();
|
|
638
|
-
const nameIdx =
|
|
584
|
+
const nameIdx = read();
|
|
639
585
|
const name = this.constLits[nameIdx];
|
|
640
586
|
code = `${this.wv(reg)} = $Module(${name}, {`;
|
|
641
587
|
break;
|
|
@@ -725,6 +671,7 @@ export class Emitter {
|
|
|
725
671
|
}
|
|
726
672
|
}
|
|
727
673
|
this.codeLines.push(ident + code);
|
|
674
|
+
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
|
|
728
675
|
switch (opcode) {
|
|
729
676
|
case OpCode.FuncVarg:
|
|
730
677
|
case OpCode.Func: {
|
|
@@ -2,7 +2,7 @@ import { SourceMapGenerator } from 'source-map-js';
|
|
|
2
2
|
import type { IRange } from '../diagnostic.js';
|
|
3
3
|
import type { ScriptInput, TranspileOptions } from '../types.js';
|
|
4
4
|
import type { ScriptPrefix } from './constants.js';
|
|
5
|
-
import { toJsLiteral } from './
|
|
5
|
+
import { toJsLiteral } from './utils.js';
|
|
6
6
|
|
|
7
7
|
const ORIGIN = `mira://MiraScript/`;
|
|
8
8
|
const { SOURCE_URL, SOURCE_MAPPING_URL } = ((source, mapping, url) => {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { VmPrimitive } from '../../index.js';
|
|
2
|
+
|
|
3
|
+
const { stringify } = JSON;
|
|
4
|
+
/** 将值转为 JS 字面量 */
|
|
5
|
+
export function toJsLiteral(value: VmPrimitive | undefined): string {
|
|
6
|
+
/* c8 ignore next 2 */
|
|
7
|
+
if (value === null) return 'null';
|
|
8
|
+
if (value === undefined) return 'undefined';
|
|
9
|
+
if (typeof value == 'string') {
|
|
10
|
+
return stringify(value);
|
|
11
|
+
}
|
|
12
|
+
// JSON 无法处理 NaN 等特殊数字
|
|
13
|
+
if (value === 0) {
|
|
14
|
+
if (1 / value === -Infinity) return '-0';
|
|
15
|
+
return '0';
|
|
16
|
+
}
|
|
17
|
+
return String(value satisfies number | boolean);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** 创建数组 */
|
|
21
|
+
export function createArray<T>(length: number, fn: (index: number) => T): T[] {
|
|
22
|
+
// micro bench shows that this is faster than Array.from
|
|
23
|
+
const result: T[] = [];
|
|
24
|
+
for (let i = 0; i < length; i++) {
|
|
25
|
+
result.push(fn(i));
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
@@ -2,7 +2,7 @@ import { getModule, loadModule } from '@mirascript/bindings';
|
|
|
2
2
|
import type { CompileOptions, ScriptInput } from './types.js';
|
|
3
3
|
|
|
4
4
|
/** MiraScript 字节码 */
|
|
5
|
-
export type VmBytecodeResult = [code: Uint8Array | undefined, diagnostics: Uint32Array];
|
|
5
|
+
export type VmBytecodeResult = [code: Uint8Array<ArrayBuffer> | undefined, diagnostics: Uint32Array<ArrayBuffer>];
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* 生成 MiraScript 字节码
|
|
@@ -10,7 +10,7 @@ export type VmBytecodeResult = [code: Uint8Array | undefined, diagnostics: Uint3
|
|
|
10
10
|
export function generateBytecodeSync(script: ScriptInput, options: CompileOptions): VmBytecodeResult {
|
|
11
11
|
const module = getModule();
|
|
12
12
|
const result = module.compileSync(script, options);
|
|
13
|
-
return [result.chunk, result.diagnostics];
|
|
13
|
+
return [result.chunk as Uint8Array<ArrayBuffer> | undefined, result.diagnostics as Uint32Array<ArrayBuffer>];
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -22,5 +22,5 @@ export async function generateBytecode(script: ScriptInput, options: CompileOpti
|
|
|
22
22
|
}
|
|
23
23
|
const module = await loadModule();
|
|
24
24
|
const result = 'compile' in module ? await module.compile(script, options) : module.compileSync(script, options);
|
|
25
|
-
return [result.chunk, result.diagnostics];
|
|
25
|
+
return [result.chunk as Uint8Array<ArrayBuffer> | undefined, result.diagnostics as Uint32Array<ArrayBuffer>];
|
|
26
26
|
}
|
package/src/compiler/index.ts
CHANGED
|
@@ -1,54 +1,34 @@
|
|
|
1
1
|
import './load-module.js';
|
|
2
2
|
import type { ScriptInput, TranspileOptions } from './types.js';
|
|
3
|
-
import {
|
|
3
|
+
import type { VmScript } from './create-script.js';
|
|
4
4
|
import { compileFast } from './compile-fast.js';
|
|
5
|
-
import {
|
|
6
|
-
import { compileWorker } from './worker-manager.js';
|
|
5
|
+
import { generateBytecodeSync } from './generate-bytecode.js';
|
|
7
6
|
import { emitScript, CompileError } from './emit-script.js';
|
|
7
|
+
import { normalizeTranspileOptions } from './options.js';
|
|
8
|
+
import { compileVerbose } from './verbose.js';
|
|
8
9
|
|
|
9
10
|
export * from './types.js';
|
|
10
11
|
export type { VmScript };
|
|
11
12
|
export { CompileError };
|
|
12
13
|
|
|
13
|
-
// 目前编译速度约 2000kB/s
|
|
14
|
-
const WORKER_MIN_LEN = typeof Worker != 'function' ? Number.MAX_VALUE : 1024;
|
|
15
|
-
|
|
16
|
-
/** 设置 options */
|
|
17
|
-
function getOptions(options: TranspileOptions | undefined): TranspileOptions {
|
|
18
|
-
options ??= {};
|
|
19
|
-
if (options.sourceMap) {
|
|
20
|
-
options.diagnostic_sourcemap = true;
|
|
21
|
-
// https://tc39.es/ecma426/#sec-terms-and-definitions-colun
|
|
22
|
-
options.diagnostic_position_encoding ??= 'Utf16';
|
|
23
|
-
}
|
|
24
|
-
options.input_mode ??= 'Script';
|
|
25
|
-
return options;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
14
|
/**
|
|
29
15
|
* 生成 MiraScript 对应的 JavaScript 代码
|
|
30
16
|
*/
|
|
31
17
|
export async function compile(this: void, source: ScriptInput, options?: TranspileOptions): Promise<VmScript> {
|
|
32
|
-
options = getOptions(options);
|
|
33
18
|
if (typeof source == 'string') {
|
|
19
|
+
options = normalizeTranspileOptions(options);
|
|
34
20
|
const result = compileFast(source, options);
|
|
35
21
|
if (result) return result;
|
|
36
22
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return emitScript(source, bc, options);
|
|
40
|
-
}
|
|
41
|
-
const [target, diagnostics] = await compileWorker(source, options);
|
|
42
|
-
if (target == null) {
|
|
43
|
-
throw new CompileError(source, diagnostics, options.fileName);
|
|
44
|
-
}
|
|
45
|
-
return createScript(source, options.input_mode ?? 'Script', target);
|
|
23
|
+
const { script } = await compileVerbose(source, options);
|
|
24
|
+
return script;
|
|
46
25
|
}
|
|
26
|
+
|
|
47
27
|
/**
|
|
48
28
|
* 生成 MiraScript 对应的 JavaScript 代码
|
|
49
29
|
*/
|
|
50
30
|
export function compileSync(this: void, source: ScriptInput, options?: TranspileOptions): VmScript {
|
|
51
|
-
options =
|
|
31
|
+
options = normalizeTranspileOptions(options);
|
|
52
32
|
if (typeof source == 'string') {
|
|
53
33
|
const result = compileFast(source, options);
|
|
54
34
|
if (result) return result;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TranspileOptions } from './types.js';
|
|
2
|
+
|
|
3
|
+
// 目前编译速度约 2000kB/s
|
|
4
|
+
export const WORKER_MIN_LEN = typeof Worker != 'function' ? Number.MAX_VALUE : 1024;
|
|
5
|
+
|
|
6
|
+
/** 补全代码生成选项。 */
|
|
7
|
+
export function normalizeTranspileOptions(options: TranspileOptions | undefined): TranspileOptions {
|
|
8
|
+
options ??= {};
|
|
9
|
+
if (options.sourceMap) {
|
|
10
|
+
options.diagnostic_sourcemap = true;
|
|
11
|
+
// https://tc39.es/ecma426/#sec-terms-and-definitions-colun
|
|
12
|
+
options.diagnostic_position_encoding ??= 'Utf16';
|
|
13
|
+
}
|
|
14
|
+
options.input_mode ??= 'Script';
|
|
15
|
+
return options;
|
|
16
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ScriptInput, TranspileOptions } from './types.js';
|
|
2
|
+
import { createScript, type VmScript } from './create-script.js';
|
|
3
|
+
import { generateBytecode } from './generate-bytecode.js';
|
|
4
|
+
import { compileWorker } from './worker-manager.js';
|
|
5
|
+
import { emitScript, CompileError } from './emit-script.js';
|
|
6
|
+
import { normalizeTranspileOptions, WORKER_MIN_LEN } from './options.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 生成 MiraScript 对应的 JavaScript 代码
|
|
10
|
+
*/
|
|
11
|
+
export async function compileVerbose(
|
|
12
|
+
this: void,
|
|
13
|
+
source: ScriptInput,
|
|
14
|
+
options?: TranspileOptions,
|
|
15
|
+
): Promise<{ script: VmScript; bytecode: Uint8Array<ArrayBuffer>; diagnostics: Uint32Array<ArrayBuffer> }> {
|
|
16
|
+
options = normalizeTranspileOptions(options);
|
|
17
|
+
if (source.length < WORKER_MIN_LEN) {
|
|
18
|
+
const bc = await generateBytecode(source, options);
|
|
19
|
+
const script = emitScript(source, bc, options);
|
|
20
|
+
return {
|
|
21
|
+
script,
|
|
22
|
+
bytecode: bc[0]!, // Will throw if bytecode is undefined, but that should be handled by emitScript
|
|
23
|
+
diagnostics: bc[1],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const [bytecode, target, diagnostics] = await compileWorker(source, options);
|
|
27
|
+
if (target == null) {
|
|
28
|
+
throw new CompileError(source, diagnostics, options.fileName);
|
|
29
|
+
}
|
|
30
|
+
const script = createScript(source, options.input_mode ?? 'Script', target);
|
|
31
|
+
return { script, bytecode, diagnostics };
|
|
32
|
+
}
|
package/src/compiler/worker.ts
CHANGED
|
@@ -12,13 +12,13 @@ export default expose(async () => {
|
|
|
12
12
|
async compile(script: ScriptInput, options: TranspileOptions) {
|
|
13
13
|
const [bytecode, errors] = await generateBytecode(script, options);
|
|
14
14
|
if (bytecode == null) {
|
|
15
|
-
return WorkerResult([undefined, errors], [errors.buffer]);
|
|
15
|
+
return WorkerResult([undefined, undefined, errors], [errors.buffer]);
|
|
16
16
|
}
|
|
17
17
|
const sourcemaps = options.sourceMap
|
|
18
18
|
? parseDiagnostics(script, errors, (c) => c === DiagnosticCode.SourceMap).sourcemaps
|
|
19
19
|
: [];
|
|
20
20
|
const generatedCode = emit(script, bytecode, sourcemaps, options);
|
|
21
|
-
return WorkerResult([generatedCode, errors], [errors.buffer]);
|
|
21
|
+
return WorkerResult([bytecode, generatedCode, errors], [bytecode.buffer, errors.buffer]);
|
|
22
22
|
},
|
|
23
23
|
};
|
|
24
24
|
// 预热编译器
|
package/src/subtle.ts
CHANGED
|
@@ -17,9 +17,11 @@ export {
|
|
|
17
17
|
serializeRecord,
|
|
18
18
|
type SerializeOptions,
|
|
19
19
|
} from './helpers/serialize.js';
|
|
20
|
-
export { lib } from './vm/lib/index.js';
|
|
20
|
+
export { lib, type Lib, type VmLibOption } from './vm/lib/index.js';
|
|
21
21
|
export * from './compiler/diagnostic.js';
|
|
22
|
+
export { compileVerbose } from './compiler/verbose.js';
|
|
22
23
|
export { emitScript } from './compiler/emit-script.js';
|
|
23
24
|
export { createScript, wrapScript } from './compiler/create-script.js';
|
|
25
|
+
export { BytecodeReader } from './compiler/bytecode/index.js';
|
|
24
26
|
export { generateBytecode, generateBytecodeSync, type VmBytecodeResult } from './compiler/generate-bytecode.js';
|
|
25
27
|
export { type GlobalReferenceChain, analyzeGlobalReferences } from './helpers/analyze.js';
|
package/src/vm/lib/index.ts
CHANGED
|
@@ -17,4 +17,13 @@ for (const [name, value] of entries(mods)) {
|
|
|
17
17
|
VM_SHARED_CONTEXT_DESCRIPTIONS[name] = description;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
/** 标准库 */
|
|
21
|
+
type LibData = typeof global & typeof mods;
|
|
22
|
+
/** 标准库 */
|
|
23
|
+
export type Lib = {
|
|
24
|
+
readonly [key in keyof LibData]: LibData[key];
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** 标准库 */
|
|
28
|
+
export const lib: Lib = Object.freeze(Object.assign(create(null), global, mods));
|
|
29
|
+
export type { VmLibOption } from './helpers.js';
|