@mirascript/mirascript 0.1.19 → 0.1.20
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-5AEWM4W6.js → chunk-4T5YE7LC.js} +241 -177
- package/dist/chunk-4T5YE7LC.js.map +6 -0
- package/dist/{chunk-RLWIIOH5.js → chunk-BV5YXQYA.js} +1 -1
- package/dist/{chunk-RLWIIOH5.js.map → chunk-BV5YXQYA.js.map} +1 -1
- package/dist/chunk-OVTSNACH.js +152 -0
- package/dist/chunk-OVTSNACH.js.map +6 -0
- package/dist/{chunk-BFSB6SQK.js → chunk-ZKL4MRMP.js} +77 -185
- package/dist/chunk-ZKL4MRMP.js.map +6 -0
- package/dist/cli/index.js +6 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/compiler/emit/constants.d.ts +1 -2
- package/dist/compiler/emit/constants.d.ts.map +1 -1
- package/dist/compiler/emit/consts.d.ts +2 -2
- package/dist/compiler/emit/consts.d.ts.map +1 -1
- package/dist/compiler/emit/index.d.ts +2 -3
- package/dist/compiler/emit/index.d.ts.map +1 -1
- package/dist/compiler/emit/sourcemap.d.ts +1 -2
- package/dist/compiler/emit/sourcemap.d.ts.map +1 -1
- package/dist/compiler/emit-script.d.ts +10 -0
- package/dist/compiler/emit-script.d.ts.map +1 -0
- package/dist/compiler/generate-bytecode.d.ts +4 -2
- package/dist/compiler/generate-bytecode.d.ts.map +1 -1
- package/dist/compiler/index.d.ts +1 -6
- package/dist/compiler/index.d.ts.map +1 -1
- package/dist/compiler/load-module.d.ts +2 -0
- package/dist/compiler/load-module.d.ts.map +1 -0
- package/dist/compiler/worker.js +1 -1
- package/dist/helpers/constants.d.ts +2 -0
- package/dist/helpers/constants.d.ts.map +1 -1
- package/dist/helpers/serialize.d.ts.map +1 -1
- package/dist/helpers/utils.d.ts.map +1 -1
- package/dist/index.js +6 -11
- package/dist/subtle.d.ts +3 -1
- package/dist/subtle.d.ts.map +1 -1
- package/dist/subtle.js +3 -3
- package/dist/vm/checkpoint.d.ts +1 -1
- package/dist/vm/checkpoint.d.ts.map +1 -1
- package/dist/vm/helpers.d.ts +6 -1
- package/dist/vm/helpers.d.ts.map +1 -1
- package/dist/vm/lib/global/json.d.ts.map +1 -1
- package/dist/vm/lib/helpers.d.ts +1 -1
- package/dist/vm/lib/helpers.d.ts.map +1 -1
- package/dist/vm/types/context.d.ts +7 -16
- package/dist/vm/types/context.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/compiler/emit/constants.ts +1 -2
- package/src/compiler/emit/consts.ts +166 -29
- package/src/compiler/emit/index.ts +40 -32
- package/src/compiler/emit/sourcemap.ts +21 -76
- package/src/compiler/emit-script.ts +30 -0
- package/src/compiler/generate-bytecode.ts +5 -8
- package/src/compiler/index.ts +2 -30
- package/src/compiler/load-module.ts +3 -0
- package/src/helpers/constants.ts +2 -0
- package/src/helpers/serialize.ts +1 -4
- package/src/helpers/utils.ts +2 -7
- package/src/subtle.ts +3 -1
- package/src/vm/checkpoint.ts +42 -17
- package/src/vm/helpers.ts +12 -5
- package/src/vm/lib/global/json.ts +2 -0
- package/src/vm/lib/helpers.ts +2 -1
- package/src/vm/types/context.ts +42 -29
- package/src/vm/types/wrapper.ts +3 -3
- package/dist/chunk-5AEWM4W6.js.map +0 -6
- package/dist/chunk-BFSB6SQK.js.map +0 -6
- package/dist/chunk-RIT53WVY.js +0 -1
- package/dist/chunk-RIT53WVY.js.map +0 -6
- package/dist/compiler/emit/globals.d.ts +0 -17
- package/dist/compiler/emit/globals.d.ts.map +0 -1
- package/src/compiler/emit/globals.ts +0 -39
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { VmPrimitive } from '../../vm/index.js';
|
|
2
|
-
|
|
2
|
+
const { stringify } = JSON;
|
|
3
3
|
/** 将值转为 JS 字面量 */
|
|
4
4
|
export function toJsLiteral(value: VmPrimitive | undefined): string {
|
|
5
5
|
/* c8 ignore next 2 */
|
|
6
6
|
if (value === null) return 'null';
|
|
7
7
|
if (value === undefined) return 'undefined';
|
|
8
8
|
if (typeof value == 'string') {
|
|
9
|
-
return
|
|
9
|
+
return stringify(value);
|
|
10
10
|
}
|
|
11
11
|
// JSON 无法处理 NaN 等特殊数字
|
|
12
12
|
if (value === 0) {
|
|
@@ -16,32 +16,169 @@ export function toJsLiteral(value: VmPrimitive | undefined): string {
|
|
|
16
16
|
return String(value satisfies number | boolean);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
19
|
+
const DECODER = new TextDecoder();
|
|
20
|
+
const { fromCharCode } = String;
|
|
21
|
+
/** 解码 Ascii */
|
|
22
|
+
function shortStringInJS(buf: Uint8Array, begin: number, length: number): string | undefined {
|
|
23
|
+
if (length < 4) {
|
|
24
|
+
if (length < 2) {
|
|
25
|
+
if (length === 0) return '';
|
|
26
|
+
const a = buf[begin]!;
|
|
27
|
+
if ((a & 0x80) > 0) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
return fromCharCode(a);
|
|
31
|
+
}
|
|
32
|
+
const a = buf[begin++]!;
|
|
33
|
+
const b = buf[begin++]!;
|
|
34
|
+
if ((a & 0x80) > 0 || (b & 0x80) > 0) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (length < 3) return fromCharCode(a, b);
|
|
38
|
+
const c = buf[begin++]!;
|
|
39
|
+
if ((c & 0x80) > 0) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
return fromCharCode(a, b, c);
|
|
43
|
+
}
|
|
44
|
+
const a = buf[begin++]!;
|
|
45
|
+
const b = buf[begin++]!;
|
|
46
|
+
const c = buf[begin++]!;
|
|
47
|
+
const d = buf[begin++]!;
|
|
48
|
+
if ((a & 0x80) > 0 || (b & 0x80) > 0 || (c & 0x80) > 0 || (d & 0x80) > 0) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (length < 6) {
|
|
52
|
+
if (length === 4) return fromCharCode(a, b, c, d);
|
|
53
|
+
const e = buf[begin++]!;
|
|
54
|
+
if ((e & 0x80) > 0) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
return fromCharCode(a, b, c, d, e);
|
|
58
|
+
}
|
|
59
|
+
const e = buf[begin++]!;
|
|
60
|
+
const f = buf[begin++]!;
|
|
61
|
+
if ((e & 0x80) > 0 || (f & 0x80) > 0) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (length < 8) {
|
|
65
|
+
if (length < 7) return fromCharCode(a, b, c, d, e, f);
|
|
66
|
+
const g = buf[begin++]!;
|
|
67
|
+
if ((g & 0x80) > 0) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
return fromCharCode(a, b, c, d, e, f, g);
|
|
71
|
+
}
|
|
72
|
+
const g = buf[begin++]!;
|
|
73
|
+
const h = buf[begin++]!;
|
|
74
|
+
if ((g & 0x80) > 0 || (h & 0x80) > 0) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (length < 10) {
|
|
78
|
+
if (length === 8) return fromCharCode(a, b, c, d, e, f, g, h);
|
|
79
|
+
const i = buf[begin++]!;
|
|
80
|
+
if ((i & 0x80) > 0) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
return fromCharCode(a, b, c, d, e, f, g, h, i);
|
|
84
|
+
}
|
|
85
|
+
const i = buf[begin++]!;
|
|
86
|
+
const j = buf[begin++]!;
|
|
87
|
+
if ((i & 0x80) > 0 || (j & 0x80) > 0) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (length < 12) {
|
|
91
|
+
if (length < 11) return fromCharCode(a, b, c, d, e, f, g, h, i, j);
|
|
92
|
+
const k = buf[begin++]!;
|
|
93
|
+
if ((k & 0x80) > 0) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
return fromCharCode(a, b, c, d, e, f, g, h, i, j, k);
|
|
97
|
+
}
|
|
98
|
+
const k = buf[begin++]!;
|
|
99
|
+
const l = buf[begin++]!;
|
|
100
|
+
if ((k & 0x80) > 0 || (l & 0x80) > 0) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (length < 14) {
|
|
104
|
+
if (length === 12) return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l);
|
|
105
|
+
const m = buf[begin++]!;
|
|
106
|
+
if ((m & 0x80) > 0) {
|
|
107
|
+
begin -= 13;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m);
|
|
111
|
+
}
|
|
112
|
+
const m = buf[begin++]!;
|
|
113
|
+
const n = buf[begin++]!;
|
|
114
|
+
if ((m & 0x80) > 0 || (n & 0x80) > 0) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (length < 15) return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n);
|
|
118
|
+
const o = buf[begin++]!;
|
|
119
|
+
if ((o & 0x80) > 0) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
return fromCharCode(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** 解码字符串 */
|
|
126
|
+
function decodeStr(buffer: Uint8Array, offset: number, length: number): string {
|
|
127
|
+
// Fast path for short ascii strings
|
|
128
|
+
if (length < 16) {
|
|
129
|
+
const shortStr = shortStringInJS(buffer, offset, length);
|
|
130
|
+
if (shortStr !== undefined) {
|
|
131
|
+
return shortStr;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return DECODER.decode(buffer.subarray(offset, offset + length));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** 读取常量表 */
|
|
138
|
+
export function readConsts(constChunk: Uint8Array): VmPrimitive[] {
|
|
139
|
+
const reader = new DataView(constChunk.buffer, constChunk.byteOffset, constChunk.byteLength);
|
|
140
|
+
const consts: VmPrimitive[] = [];
|
|
141
|
+
let offset = 0;
|
|
142
|
+
const length = reader.byteLength;
|
|
143
|
+
while (offset < length) {
|
|
144
|
+
const type = reader.getUint8(offset);
|
|
145
|
+
switch (type) {
|
|
146
|
+
/* c8 ignore next 2 */
|
|
147
|
+
case 0:
|
|
148
|
+
consts.push(null);
|
|
149
|
+
offset += 1;
|
|
150
|
+
break;
|
|
151
|
+
case 1:
|
|
152
|
+
consts.push(true);
|
|
153
|
+
offset += 1;
|
|
154
|
+
break;
|
|
155
|
+
case 2:
|
|
156
|
+
consts.push(false);
|
|
157
|
+
offset += 1;
|
|
158
|
+
break;
|
|
159
|
+
case 3: {
|
|
160
|
+
const ordinal = reader.getInt32(offset + 1, true);
|
|
161
|
+
consts.push(ordinal);
|
|
162
|
+
offset += 5;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
case 4: {
|
|
166
|
+
const num = reader.getFloat64(offset + 1, true);
|
|
167
|
+
consts.push(num);
|
|
168
|
+
offset += 9;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
case 5: {
|
|
172
|
+
const len = reader.getUint32(offset + 1, true);
|
|
173
|
+
const str = decodeStr(constChunk, offset + 5, len);
|
|
174
|
+
consts.push(str);
|
|
175
|
+
offset += 5 + len;
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
/* c8 ignore next 2 */
|
|
179
|
+
default:
|
|
180
|
+
throw new Error(`Unknown constant type: ${type}`);
|
|
181
|
+
}
|
|
46
182
|
}
|
|
183
|
+
return consts;
|
|
47
184
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { OpCode } from '@mirascript/bindings';
|
|
2
|
+
import { toString } from '../../helpers/convert/to-string.js';
|
|
2
3
|
import type { VmPrimitive } from '../../vm/index.js';
|
|
3
4
|
import type { ScriptInput, TranspileOptions } from '../types.js';
|
|
4
5
|
import type { IRange } from '../diagnostic.js';
|
|
5
|
-
import {
|
|
6
|
-
import { readConst, toJsLiteral } from './consts.js';
|
|
6
|
+
import { readConsts, toJsLiteral } from './consts.js';
|
|
7
7
|
import { createSourceMap } from './sourcemap.js';
|
|
8
|
+
import { SCRIPT_PREFIX } from './constants.js';
|
|
8
9
|
|
|
9
10
|
/** 生成代码 */
|
|
10
11
|
export function emit(
|
|
@@ -29,8 +30,6 @@ function createArray<T>(length: number, fn: (index: number) => T): T[] {
|
|
|
29
30
|
return result;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
const SCRIPT_PREFIX = `'use strict'; return ((global = GlobalFallback()) => { try { CpEnter();`;
|
|
33
|
-
const GLOBAL_HINT = `/* globals */`;
|
|
34
33
|
/** 代码生成 */
|
|
35
34
|
export class Emitter {
|
|
36
35
|
constructor(
|
|
@@ -47,22 +46,21 @@ export class Emitter {
|
|
|
47
46
|
this.constSize = reader.getUint32(8 + this.codeSize, true);
|
|
48
47
|
|
|
49
48
|
this.codeReader = new DataView(chunk.buffer, chunk.byteOffset + 8, this.codeSize);
|
|
50
|
-
this.
|
|
49
|
+
this.constVals = readConsts(
|
|
50
|
+
new Uint8Array(chunk.buffer, chunk.byteOffset + 12 + this.codeSize, this.constSize),
|
|
51
|
+
);
|
|
51
52
|
}
|
|
52
|
-
readonly pretty;
|
|
53
|
+
readonly pretty: boolean;
|
|
53
54
|
readonly chunkSize: number;
|
|
54
55
|
readonly codeSize: number;
|
|
55
|
-
private readonly constReader: DataView;
|
|
56
56
|
/** 读取常量表 */
|
|
57
57
|
private readConsts(): void {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
this.constLits.push(toJsLiteral(constant));
|
|
62
|
-
i += size;
|
|
58
|
+
const { constVals, constLits } = this;
|
|
59
|
+
for (let i = 0, len = constVals.length; i < len; i++) {
|
|
60
|
+
constLits.push(toJsLiteral(constVals[i]));
|
|
63
61
|
}
|
|
64
62
|
}
|
|
65
|
-
readonly constVals: VmPrimitive[]
|
|
63
|
+
readonly constVals: VmPrimitive[];
|
|
66
64
|
readonly constLits: string[] = [];
|
|
67
65
|
|
|
68
66
|
readonly constSize: number;
|
|
@@ -70,6 +68,8 @@ export class Emitter {
|
|
|
70
68
|
private codeOffset = 0;
|
|
71
69
|
private closureCounter = 0;
|
|
72
70
|
private identCounter = 0;
|
|
71
|
+
/** 记录函数声明所在位置 */
|
|
72
|
+
private readonly functions: number[] = [];
|
|
73
73
|
|
|
74
74
|
/** 制造缩进 */
|
|
75
75
|
private ident(len = 0): string {
|
|
@@ -77,10 +77,16 @@ export class Emitter {
|
|
|
77
77
|
return ' '.repeat(this.identCounter + len);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
readonly globals: GlobalMap = new Map();
|
|
81
80
|
/** 读取全局变量 */
|
|
82
|
-
private rg(constIdx: number
|
|
83
|
-
|
|
81
|
+
private rg(constIdx: number): string {
|
|
82
|
+
const constName = this.constVals[constIdx]!;
|
|
83
|
+
let lit;
|
|
84
|
+
if (typeof constName == 'string') {
|
|
85
|
+
lit = this.constLits[constIdx]!;
|
|
86
|
+
} else {
|
|
87
|
+
lit = toJsLiteral(toString(constName, undefined));
|
|
88
|
+
}
|
|
89
|
+
return `global.get(${lit})`;
|
|
84
90
|
}
|
|
85
91
|
|
|
86
92
|
readonly codeLines: string[] = [];
|
|
@@ -327,14 +333,21 @@ export class Emitter {
|
|
|
327
333
|
}
|
|
328
334
|
return `${wv} = null`;
|
|
329
335
|
});
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
336
|
+
let regs = '_';
|
|
337
|
+
for (let i = 1 + argn; i < regn + 1; i++) {
|
|
338
|
+
regs += ',' + this.wv(i, -1);
|
|
339
|
+
}
|
|
333
340
|
const script = startFunc && !varg && argn === 0;
|
|
334
341
|
if (script) {
|
|
335
342
|
code = `${SCRIPT_PREFIX} var ${regs};`;
|
|
336
343
|
} else {
|
|
337
|
-
|
|
344
|
+
if (!this.options.sourceMap) {
|
|
345
|
+
code = `${this.wv(reg)} = Function(null ,(${args.join(', ')}) => { try { CpEnter(); var ${regs};`;
|
|
346
|
+
} else {
|
|
347
|
+
const index = this.functions.length;
|
|
348
|
+
this.functions.push(this.codeLines.length);
|
|
349
|
+
code = `${this.wv(reg)} = Function(fnName_${index} ,(${args.join(', ')}) => { try { CpEnter(); var ${regs};`;
|
|
350
|
+
}
|
|
338
351
|
}
|
|
339
352
|
if (varg) {
|
|
340
353
|
code += ` var ${this.wv(argn, -1)} = Vargs(vargs);`;
|
|
@@ -415,7 +428,7 @@ export class Emitter {
|
|
|
415
428
|
const args = createArray(n, () => read());
|
|
416
429
|
const ns = read();
|
|
417
430
|
const spreads = createArray(ns, () => read());
|
|
418
|
-
const callTarget = opcode === OpCode.Call ? this.rg(func
|
|
431
|
+
const callTarget = opcode === OpCode.Call ? this.rg(func) : this.rv(func);
|
|
419
432
|
code = `${this.wv(reg)} = $Call(${callTarget}, [${args
|
|
420
433
|
.map((a, i) => {
|
|
421
434
|
if (spreads.includes(i)) return `...$ArraySpread(${this.rv(a)})`;
|
|
@@ -520,7 +533,7 @@ export class Emitter {
|
|
|
520
533
|
case OpCode.GetGlobal: {
|
|
521
534
|
reg = read();
|
|
522
535
|
const i = read();
|
|
523
|
-
code = `${this.wv(reg)} = ${this.rg(i
|
|
536
|
+
code = `${this.wv(reg)} = ${this.rg(i)};`;
|
|
524
537
|
break;
|
|
525
538
|
}
|
|
526
539
|
case OpCode.GetGlobalDyn: {
|
|
@@ -705,19 +718,14 @@ export class Emitter {
|
|
|
705
718
|
read(): void {
|
|
706
719
|
this.readConsts();
|
|
707
720
|
this.readCode();
|
|
708
|
-
if (this.globals.size > 0) {
|
|
709
|
-
let globalsInit = '';
|
|
710
|
-
for (const { v } of this.globals.values()) {
|
|
711
|
-
globalsInit += globalsInit ? `, ${v}` : `var ${GLOBAL_HINT} ${v}`;
|
|
712
|
-
}
|
|
713
|
-
this.codeLines[0] += globalsInit + ';';
|
|
714
|
-
}
|
|
715
721
|
this.addSourceMap();
|
|
716
722
|
}
|
|
717
723
|
/** 添加源映射 */
|
|
718
724
|
addSourceMap(): void {
|
|
719
|
-
if (
|
|
720
|
-
|
|
721
|
-
|
|
725
|
+
if (this.options.sourceMap) {
|
|
726
|
+
createSourceMap(this.source, this.sourcemaps, this.codeLines, this.functions, this.options);
|
|
727
|
+
} else {
|
|
728
|
+
this.codeLines.unshift(`'use strict';`);
|
|
729
|
+
}
|
|
722
730
|
}
|
|
723
731
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { IRange } from '../diagnostic.js';
|
|
2
2
|
import type { ScriptInput, TranspileOptions } from '../types.js';
|
|
3
3
|
import { SourceMapGenerator } from 'source-map-js';
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
4
|
+
import { SCRIPT_PREFIX } from './constants.js';
|
|
5
|
+
import { toJsLiteral } from './consts.js';
|
|
6
6
|
|
|
7
7
|
const ORIGIN = `mira://MiraScript/`;
|
|
8
8
|
const { SOURCE_URL, SOURCE_MAPPING_URL } = ((source, mapping, url) => {
|
|
@@ -13,10 +13,11 @@ const { SOURCE_URL, SOURCE_MAPPING_URL } = ((source, mapping, url) => {
|
|
|
13
13
|
SOURCE_MAPPING_URL: prefix.concat(source, mapping, url),
|
|
14
14
|
};
|
|
15
15
|
})(`source`, `Mapping`, `URL`);
|
|
16
|
-
//
|
|
16
|
+
// 前 3 行固定为:
|
|
17
17
|
// (function anonymous($Add,$Aeq, ...
|
|
18
18
|
// ) {
|
|
19
|
-
|
|
19
|
+
// 'use strict';
|
|
20
|
+
const SOURCE_OFFSET = 4;
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Node.js Buffer 类型的简易声明,@mirascript/playground 调试环境下会直接加载此文件
|
|
@@ -33,79 +34,15 @@ const toDataUrl: (json: string) => string =
|
|
|
33
34
|
? (s) => `data:application/json;base64,${Buffer.from(s, 'utf8').toString('base64')}`
|
|
34
35
|
: (s) => `data:application/json;charset=utf-8,${encodeURIComponent(s)}`;
|
|
35
36
|
|
|
36
|
-
/** 添加全局变量的源映射 */
|
|
37
|
-
function addGlobalMappings(globalLine: string, fileName: string, map: SourceMapGenerator, globals: GlobalMap) {
|
|
38
|
-
let globalFile = `global;\n`;
|
|
39
|
-
map.addMapping({
|
|
40
|
-
generated: {
|
|
41
|
-
line: 3,
|
|
42
|
-
column: globalLine.indexOf(`global = `),
|
|
43
|
-
},
|
|
44
|
-
original: {
|
|
45
|
-
line: 1,
|
|
46
|
-
column: 0,
|
|
47
|
-
},
|
|
48
|
-
source: fileName,
|
|
49
|
-
name: 'global',
|
|
50
|
-
});
|
|
51
|
-
map.addMapping({
|
|
52
|
-
generated: {
|
|
53
|
-
line: 3,
|
|
54
|
-
column: SCRIPT_PREFIX.length,
|
|
55
|
-
},
|
|
56
|
-
original: {
|
|
57
|
-
line: 1,
|
|
58
|
-
column: 7,
|
|
59
|
-
},
|
|
60
|
-
source: fileName,
|
|
61
|
-
name: '',
|
|
62
|
-
});
|
|
63
|
-
let i = 1;
|
|
64
|
-
let pos = globalLine.indexOf(GLOBAL_HINT, SCRIPT_PREFIX.length) + GLOBAL_HINT.length;
|
|
65
|
-
for (const p of globals.values()) {
|
|
66
|
-
i++;
|
|
67
|
-
if (pos < 0) break;
|
|
68
|
-
const { v, n } = p;
|
|
69
|
-
pos = globalLine.indexOf(v, pos);
|
|
70
|
-
if (pos < 0) break;
|
|
71
|
-
map.addMapping({
|
|
72
|
-
generated: {
|
|
73
|
-
line: 3,
|
|
74
|
-
column: pos,
|
|
75
|
-
},
|
|
76
|
-
original: {
|
|
77
|
-
line: i,
|
|
78
|
-
column: 0,
|
|
79
|
-
},
|
|
80
|
-
source: fileName,
|
|
81
|
-
name: n,
|
|
82
|
-
});
|
|
83
|
-
globalFile += `${n};\n`;
|
|
84
|
-
}
|
|
85
|
-
map.addMapping({
|
|
86
|
-
generated: {
|
|
87
|
-
line: 3,
|
|
88
|
-
column: pos,
|
|
89
|
-
},
|
|
90
|
-
original: {
|
|
91
|
-
line: i,
|
|
92
|
-
column: 0,
|
|
93
|
-
},
|
|
94
|
-
source: fileName,
|
|
95
|
-
name: '',
|
|
96
|
-
});
|
|
97
|
-
map.setSourceContent(fileName, globalFile);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
37
|
let sourceId = 1;
|
|
101
38
|
/** 创建源映射 */
|
|
102
39
|
export function createSourceMap(
|
|
103
40
|
source: ScriptInput | undefined,
|
|
104
41
|
sourcemaps: readonly IRange[],
|
|
105
|
-
codeLines:
|
|
106
|
-
|
|
42
|
+
codeLines: string[],
|
|
43
|
+
functions: readonly number[],
|
|
107
44
|
options: TranspileOptions,
|
|
108
|
-
):
|
|
45
|
+
): void {
|
|
109
46
|
let fileName = (options.fileName ?? '').trim();
|
|
110
47
|
const hasSchema = /^\w+:/.test(fileName);
|
|
111
48
|
if (!hasSchema) {
|
|
@@ -154,15 +91,23 @@ export function createSourceMap(
|
|
|
154
91
|
source: fileName,
|
|
155
92
|
});
|
|
156
93
|
}
|
|
157
|
-
|
|
158
|
-
if (
|
|
159
|
-
|
|
94
|
+
let fnNames = `'use strict';`;
|
|
95
|
+
if (typeof source === 'string') {
|
|
96
|
+
const lines = source.split(/\r?\n/);
|
|
97
|
+
for (let i = 0; i < functions.length; i++) {
|
|
98
|
+
const index = functions[i]!;
|
|
99
|
+
const mapping = sourcemaps[index];
|
|
100
|
+
const line = mapping ? lines[mapping.startLineNumber - 1] : undefined;
|
|
101
|
+
const fnName = mapping && line ? line.slice(mapping.startColumn - 1, mapping.endColumn - 1) : '';
|
|
102
|
+
fnNames += `var fnName_${i} = ${fnName ? toJsLiteral(fnName) : 'null'};`;
|
|
103
|
+
}
|
|
160
104
|
}
|
|
161
105
|
const sourceURL = hasSchema ? fileName : `${ORIGIN}${fileName}`;
|
|
162
106
|
const dataUrl = toDataUrl(map.toString());
|
|
163
|
-
|
|
107
|
+
codeLines.unshift(fnNames);
|
|
108
|
+
codeLines.push(
|
|
164
109
|
// Prevent source map from being recognized as of this file
|
|
165
110
|
`${SOURCE_URL}=${sourceURL}.js`,
|
|
166
111
|
`${SOURCE_MAPPING_URL}=${dataUrl}`,
|
|
167
|
-
|
|
112
|
+
);
|
|
168
113
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ScriptInput, TranspileOptions } from './types.js';
|
|
2
|
+
import type { VmBytecodeResult } from './generate-bytecode.js';
|
|
3
|
+
import { emit } from './emit/index.js';
|
|
4
|
+
import { createScript, type VmScript } from './create-script.js';
|
|
5
|
+
import { DiagnosticCode, formatDiagnostics, parseDiagnostics } from './diagnostic.js';
|
|
6
|
+
|
|
7
|
+
/** 报告编译错误 */
|
|
8
|
+
export function reportDiagnostic(source: ScriptInput, diagnostics: Uint32Array, fileName: string | undefined): never {
|
|
9
|
+
const parsed = parseDiagnostics(source, diagnostics);
|
|
10
|
+
const messages = formatDiagnostics(parsed.errors, source, fileName);
|
|
11
|
+
throw new Error(`Failed to compile:\n${messages.join('\n')}`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 生成 MiraScript 对应的 JavaScript 代码
|
|
16
|
+
*/
|
|
17
|
+
export function emitScript(
|
|
18
|
+
source: ScriptInput,
|
|
19
|
+
[code, diagnostics]: VmBytecodeResult,
|
|
20
|
+
options: TranspileOptions,
|
|
21
|
+
): VmScript {
|
|
22
|
+
if (!code) {
|
|
23
|
+
reportDiagnostic(source, diagnostics, options.fileName);
|
|
24
|
+
}
|
|
25
|
+
const sourcemaps = options.sourceMap
|
|
26
|
+
? parseDiagnostics(source, diagnostics, (c) => c === DiagnosticCode.SourceMap).sourcemaps
|
|
27
|
+
: [];
|
|
28
|
+
const target = emit(source, code, sourcemaps, options);
|
|
29
|
+
return createScript(source, target);
|
|
30
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { getModule, loadModule } from '@mirascript/bindings';
|
|
2
2
|
import type { CompileOptions, ScriptInput } from './types.js';
|
|
3
3
|
|
|
4
|
+
/** MiraScript 字节码 */
|
|
5
|
+
export type VmBytecodeResult = [code: Uint8Array | undefined, diagnostics: Uint32Array];
|
|
6
|
+
|
|
4
7
|
/**
|
|
5
8
|
* 生成 MiraScript 字节码
|
|
6
9
|
*/
|
|
7
|
-
export function generateBytecodeSync(
|
|
8
|
-
script: ScriptInput,
|
|
9
|
-
options: CompileOptions,
|
|
10
|
-
): [Uint8Array | undefined, Uint32Array] {
|
|
10
|
+
export function generateBytecodeSync(script: ScriptInput, options: CompileOptions): VmBytecodeResult {
|
|
11
11
|
const module = getModule();
|
|
12
12
|
const result = module.compileSync(script, options);
|
|
13
13
|
return [result.chunk, result.diagnostics];
|
|
@@ -16,10 +16,7 @@ export function generateBytecodeSync(
|
|
|
16
16
|
/**
|
|
17
17
|
* 生成 MiraScript 字节码
|
|
18
18
|
*/
|
|
19
|
-
export async function generateBytecode(
|
|
20
|
-
script: ScriptInput,
|
|
21
|
-
options: CompileOptions,
|
|
22
|
-
): Promise<[Uint8Array | undefined, Uint32Array]> {
|
|
19
|
+
export async function generateBytecode(script: ScriptInput, options: CompileOptions): Promise<VmBytecodeResult> {
|
|
23
20
|
if (options == null) {
|
|
24
21
|
throw new TypeError('options must be provided');
|
|
25
22
|
}
|
package/src/compiler/index.ts
CHANGED
|
@@ -1,45 +1,17 @@
|
|
|
1
|
-
import { loadModule } from '@mirascript/bindings';
|
|
2
1
|
import type { ScriptInput, TranspileOptions } from './types.js';
|
|
3
|
-
import { emit } from './emit/index.js';
|
|
4
2
|
import { createScript, type VmScript } from './create-script.js';
|
|
5
3
|
import { compileFast } from './compile-fast.js';
|
|
6
|
-
import { DiagnosticCode, formatDiagnostics, parseDiagnostics } from './diagnostic.js';
|
|
7
4
|
import { generateBytecode, generateBytecodeSync } from './generate-bytecode.js';
|
|
8
5
|
import { compileWorker } from './worker-manager.js';
|
|
9
|
-
|
|
6
|
+
import { emitScript, reportDiagnostic } from './emit-script.js';
|
|
7
|
+
import './load-module.js';
|
|
10
8
|
|
|
11
|
-
export { generateBytecode, generateBytecodeSync };
|
|
12
9
|
export * from './types.js';
|
|
13
10
|
export type { VmScript };
|
|
14
11
|
|
|
15
12
|
// 目前编译速度约 2000kB/s
|
|
16
13
|
const WORKER_MIN_LEN = typeof Worker != 'function' ? Number.MAX_VALUE : 1024;
|
|
17
14
|
|
|
18
|
-
/** 报告编译错误 */
|
|
19
|
-
function reportDiagnostic(source: ScriptInput, diagnostics: Uint32Array, fileName: string | undefined): never {
|
|
20
|
-
const parsed = parseDiagnostics(source, diagnostics);
|
|
21
|
-
const messages = formatDiagnostics(parsed.errors, source, fileName);
|
|
22
|
-
throw new Error(`Failed to compile:\n${messages.join('\n')}`);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* 生成 MiraScript 对应的 JavaScript 代码
|
|
27
|
-
*/
|
|
28
|
-
export function emitScript(
|
|
29
|
-
source: ScriptInput,
|
|
30
|
-
[code, diagnostics]: [Uint8Array | undefined, Uint32Array],
|
|
31
|
-
options: TranspileOptions,
|
|
32
|
-
): VmScript {
|
|
33
|
-
if (!code) {
|
|
34
|
-
reportDiagnostic(source, diagnostics, options.fileName);
|
|
35
|
-
}
|
|
36
|
-
const sourcemaps = options.sourceMap
|
|
37
|
-
? parseDiagnostics(source, diagnostics, (c) => c === DiagnosticCode.SourceMap).sourcemaps
|
|
38
|
-
: [];
|
|
39
|
-
const target = emit(source, code, sourcemaps, options);
|
|
40
|
-
return createScript(source, target);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
15
|
/**
|
|
44
16
|
* 生成 MiraScript 对应的 JavaScript 代码
|
|
45
17
|
*/
|
package/src/helpers/constants.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export const REG_IDENTIFIER = /(?:_+|@+|\$+|\p{XID_Start})\p{XID_Continue}*/u;
|
|
2
2
|
export const REG_ORDINAL =
|
|
3
3
|
/(?:214748364[0-7]|21474836[0-3]\d|2147483[0-5]\d{2}|214748[0-2]\d{3}|21474[0-7]\d{4}|2147[0-3]\d{5}|214[0-6]\d{6}|21[0-3]\d{7}|20\d{8}|1\d{9}|[1-9]\d{0,8}|0)/;
|
|
4
|
+
export const REG_IDENTIFIER_FULL = new RegExp(`^${REG_IDENTIFIER.source}$`, REG_IDENTIFIER.flags);
|
|
5
|
+
export const REG_ORDINAL_FULL = new RegExp(`^${REG_ORDINAL.source}$`, REG_ORDINAL.flags);
|
|
4
6
|
export const REG_WHITESPACE = /[ \t\v\f\r\n]/u;
|
|
5
7
|
export const REG_HEX = /0[xX][a-fA-F0-9_]*[a-fA-F0-9]/;
|
|
6
8
|
export const REG_OCT = /0[oO][0-7_]*[0-7]/;
|
package/src/helpers/serialize.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { VmArray, VmExtern, VmFunction, VmModule, VmAny, VmRecord } from '../vm/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { REG_IDENTIFIER_FULL, REG_ORDINAL_FULL } from './constants.js';
|
|
3
3
|
import { entries, hasOwn, isFinite, isNaN } from '../helpers/utils.js';
|
|
4
4
|
import {
|
|
5
5
|
getVmFunctionInfo,
|
|
@@ -12,9 +12,6 @@ import {
|
|
|
12
12
|
} from './types.js';
|
|
13
13
|
import type { VmWrapper } from '../vm/types/wrapper.js';
|
|
14
14
|
|
|
15
|
-
const REG_IDENTIFIER_FULL = new RegExp(`^${REG_IDENTIFIER.source}$`, REG_IDENTIFIER.flags);
|
|
16
|
-
const REG_ORDINAL_FULL = new RegExp(`^${REG_ORDINAL.source}$`, REG_ORDINAL.flags);
|
|
17
|
-
|
|
18
15
|
/** 序列化设置 */
|
|
19
16
|
export interface SerializeOptions {
|
|
20
17
|
/** 最大递归深度,超过该深度的值将被序列化为 `nil`,默认值为 128 */
|
package/src/helpers/utils.ts
CHANGED
|
@@ -6,12 +6,7 @@ export const { apply } = Reflect;
|
|
|
6
6
|
/**
|
|
7
7
|
* Determines whether an object has an enumerable property with the specified name.
|
|
8
8
|
*/
|
|
9
|
-
export const hasOwnEnumerable = Function.call.bind
|
|
10
|
-
object['propertyIsEnumerable'],
|
|
11
|
-
[],
|
|
12
|
-
[o: object, v: PropertyKey],
|
|
13
|
-
boolean
|
|
14
|
-
>(
|
|
9
|
+
export const hasOwnEnumerable = Function.call.bind(
|
|
15
10
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
16
11
|
Object.prototype.propertyIsEnumerable,
|
|
17
|
-
);
|
|
12
|
+
) as (o: object, v: PropertyKey) => boolean;
|
package/src/subtle.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getModule } from '@mirascript/bindings';
|
|
2
|
+
import './compiler/load-module.js';
|
|
2
3
|
|
|
3
4
|
export * as constants from './helpers/constants.js';
|
|
4
5
|
export * as convert from './helpers/convert/index.js';
|
|
@@ -18,7 +19,8 @@ export {
|
|
|
18
19
|
} from './helpers/serialize.js';
|
|
19
20
|
export { lib } from './vm/lib/index.js';
|
|
20
21
|
export * from './compiler/diagnostic.js';
|
|
21
|
-
export {
|
|
22
|
+
export { emitScript } from './compiler/emit-script.js';
|
|
23
|
+
export { generateBytecode, generateBytecodeSync, type VmBytecodeResult } from './compiler/generate-bytecode.js';
|
|
22
24
|
|
|
23
25
|
/** 所有 MiraScript 关键字 */
|
|
24
26
|
export let keywords: () => readonly string[] = () => {
|