@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.
Files changed (70) hide show
  1. package/dist/{chunk-5AEWM4W6.js → chunk-4T5YE7LC.js} +241 -177
  2. package/dist/chunk-4T5YE7LC.js.map +6 -0
  3. package/dist/{chunk-RLWIIOH5.js → chunk-BV5YXQYA.js} +1 -1
  4. package/dist/{chunk-RLWIIOH5.js.map → chunk-BV5YXQYA.js.map} +1 -1
  5. package/dist/chunk-OVTSNACH.js +152 -0
  6. package/dist/chunk-OVTSNACH.js.map +6 -0
  7. package/dist/{chunk-BFSB6SQK.js → chunk-ZKL4MRMP.js} +77 -185
  8. package/dist/chunk-ZKL4MRMP.js.map +6 -0
  9. package/dist/cli/index.js +6 -5
  10. package/dist/cli/index.js.map +1 -1
  11. package/dist/compiler/emit/constants.d.ts +1 -2
  12. package/dist/compiler/emit/constants.d.ts.map +1 -1
  13. package/dist/compiler/emit/consts.d.ts +2 -2
  14. package/dist/compiler/emit/consts.d.ts.map +1 -1
  15. package/dist/compiler/emit/index.d.ts +2 -3
  16. package/dist/compiler/emit/index.d.ts.map +1 -1
  17. package/dist/compiler/emit/sourcemap.d.ts +1 -2
  18. package/dist/compiler/emit/sourcemap.d.ts.map +1 -1
  19. package/dist/compiler/emit-script.d.ts +10 -0
  20. package/dist/compiler/emit-script.d.ts.map +1 -0
  21. package/dist/compiler/generate-bytecode.d.ts +4 -2
  22. package/dist/compiler/generate-bytecode.d.ts.map +1 -1
  23. package/dist/compiler/index.d.ts +1 -6
  24. package/dist/compiler/index.d.ts.map +1 -1
  25. package/dist/compiler/load-module.d.ts +2 -0
  26. package/dist/compiler/load-module.d.ts.map +1 -0
  27. package/dist/compiler/worker.js +1 -1
  28. package/dist/helpers/constants.d.ts +2 -0
  29. package/dist/helpers/constants.d.ts.map +1 -1
  30. package/dist/helpers/serialize.d.ts.map +1 -1
  31. package/dist/helpers/utils.d.ts.map +1 -1
  32. package/dist/index.js +6 -11
  33. package/dist/subtle.d.ts +3 -1
  34. package/dist/subtle.d.ts.map +1 -1
  35. package/dist/subtle.js +3 -3
  36. package/dist/vm/checkpoint.d.ts +1 -1
  37. package/dist/vm/checkpoint.d.ts.map +1 -1
  38. package/dist/vm/helpers.d.ts +6 -1
  39. package/dist/vm/helpers.d.ts.map +1 -1
  40. package/dist/vm/lib/global/json.d.ts.map +1 -1
  41. package/dist/vm/lib/helpers.d.ts +1 -1
  42. package/dist/vm/lib/helpers.d.ts.map +1 -1
  43. package/dist/vm/types/context.d.ts +7 -16
  44. package/dist/vm/types/context.d.ts.map +1 -1
  45. package/package.json +4 -4
  46. package/src/compiler/emit/constants.ts +1 -2
  47. package/src/compiler/emit/consts.ts +166 -29
  48. package/src/compiler/emit/index.ts +40 -32
  49. package/src/compiler/emit/sourcemap.ts +21 -76
  50. package/src/compiler/emit-script.ts +30 -0
  51. package/src/compiler/generate-bytecode.ts +5 -8
  52. package/src/compiler/index.ts +2 -30
  53. package/src/compiler/load-module.ts +3 -0
  54. package/src/helpers/constants.ts +2 -0
  55. package/src/helpers/serialize.ts +1 -4
  56. package/src/helpers/utils.ts +2 -7
  57. package/src/subtle.ts +3 -1
  58. package/src/vm/checkpoint.ts +42 -17
  59. package/src/vm/helpers.ts +12 -5
  60. package/src/vm/lib/global/json.ts +2 -0
  61. package/src/vm/lib/helpers.ts +2 -1
  62. package/src/vm/types/context.ts +42 -29
  63. package/src/vm/types/wrapper.ts +3 -3
  64. package/dist/chunk-5AEWM4W6.js.map +0 -6
  65. package/dist/chunk-BFSB6SQK.js.map +0 -6
  66. package/dist/chunk-RIT53WVY.js +0 -1
  67. package/dist/chunk-RIT53WVY.js.map +0 -6
  68. package/dist/compiler/emit/globals.d.ts +0 -17
  69. package/dist/compiler/emit/globals.d.ts.map +0 -1
  70. 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 JSON.stringify(value);
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
- export function readConst(reader: DataView, offset: number): [value: VmPrimitive, consumed: number] {
21
- const type = reader.getUint8(offset);
22
- switch (type) {
23
- /* c8 ignore next 2 */
24
- case 0:
25
- return [null, 1];
26
- case 1:
27
- return [true, 1];
28
- case 2:
29
- return [false, 1];
30
- case 3: {
31
- const ordinal = reader.getInt32(offset + 1, true);
32
- return [ordinal, 5];
33
- }
34
- case 4: {
35
- const num = reader.getFloat64(offset + 1, true);
36
- return [num, 9];
37
- }
38
- case 5: {
39
- const len = reader.getUint32(offset + 1, true);
40
- const str = new TextDecoder().decode(new Uint8Array(reader.buffer, reader.byteOffset + offset + 5, len));
41
- return [str, 5 + len];
42
- }
43
- /* c8 ignore next 2 */
44
- default:
45
- throw new Error(`Unknown constant type: ${type}`);
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 { readGlobal, type GlobalMap } from './globals.js';
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.constReader = new DataView(chunk.buffer, chunk.byteOffset + 12 + this.codeSize, this.constSize);
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
- for (let i = 0, index = 0; i < this.constSize; index++) {
59
- const [constant, size] = readConst(this.constReader, i);
60
- this.constVals.push(constant);
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, eager: boolean): string {
83
- return readGlobal(this, constIdx).e;
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
- const regs = createArray(regn - argn + 1, (i) => (i ? this.wv(i + argn, -1) : this.wv(0, -1))).join(
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
- code = `${this.wv(reg)} = Function((${args.join(', ')}) => { try { CpEnter(); var ${regs};`;
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, false) : this.rv(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, false)};`;
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 (!this.options.sourceMap) return;
720
- const mapLines = createSourceMap(this.source, this.sourcemaps, this.codeLines, this.globals, this.options);
721
- this.codeLines.push(...mapLines);
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 { GLOBAL_HINT, SCRIPT_PREFIX } from './constants.js';
5
- import type { GlobalMap } from './globals.js';
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
- const SOURCE_OFFSET = 3;
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: readonly string[],
106
- globals: GlobalMap,
42
+ codeLines: string[],
43
+ functions: readonly number[],
107
44
  options: TranspileOptions,
108
- ): [string, string] {
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
- const globalLine = codeLines[0];
158
- if (globalLine?.includes(GLOBAL_HINT)) {
159
- addGlobalMappings(globalLine, `${fileName} <globals>`, map, globals);
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
- return [
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
  }
@@ -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
- await loadModule();
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
  */
@@ -0,0 +1,3 @@
1
+ import { loadModule } from '@mirascript/bindings';
2
+
3
+ await loadModule();
@@ -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]/;
@@ -1,5 +1,5 @@
1
1
  import type { VmArray, VmExtern, VmFunction, VmModule, VmAny, VmRecord } from '../vm/index.js';
2
- import { REG_IDENTIFIER, REG_ORDINAL } from './constants.js';
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 */
@@ -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 { generateBytecode, generateBytecodeSync, emitScript } from './compiler/index.js';
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[] = () => {