@mirascript/mirascript 0.1.0

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 (191) hide show
  1. package/dist/chunk-5FQWUJIY.js +766 -0
  2. package/dist/chunk-5FQWUJIY.js.map +6 -0
  3. package/dist/chunk-BTDGMWFK.js +202 -0
  4. package/dist/chunk-BTDGMWFK.js.map +6 -0
  5. package/dist/chunk-DCXIWIW5.js +3419 -0
  6. package/dist/chunk-DCXIWIW5.js.map +6 -0
  7. package/dist/chunk-RAPJ3XLV.js +10 -0
  8. package/dist/chunk-RAPJ3XLV.js.map +6 -0
  9. package/dist/cli/execute.d.ts +4 -0
  10. package/dist/cli/execute.d.ts.map +1 -0
  11. package/dist/cli/index.d.ts +2 -0
  12. package/dist/cli/index.d.ts.map +1 -0
  13. package/dist/cli/index.js +191 -0
  14. package/dist/cli/index.js.map +6 -0
  15. package/dist/cli/print.d.ts +4 -0
  16. package/dist/cli/print.d.ts.map +1 -0
  17. package/dist/compiler/compile-bytecode.d.ts +12 -0
  18. package/dist/compiler/compile-bytecode.d.ts.map +1 -0
  19. package/dist/compiler/compile-fast.d.ts +7 -0
  20. package/dist/compiler/compile-fast.d.ts.map +1 -0
  21. package/dist/compiler/create-script.d.ts +7 -0
  22. package/dist/compiler/create-script.d.ts.map +1 -0
  23. package/dist/compiler/diagnostic.d.ts +56 -0
  24. package/dist/compiler/diagnostic.d.ts.map +1 -0
  25. package/dist/compiler/emit.d.ts +4 -0
  26. package/dist/compiler/emit.d.ts.map +1 -0
  27. package/dist/compiler/index.d.ts +13 -0
  28. package/dist/compiler/index.d.ts.map +1 -0
  29. package/dist/compiler/types.d.ts +16 -0
  30. package/dist/compiler/types.d.ts.map +1 -0
  31. package/dist/compiler/worker-manager.d.ts +6 -0
  32. package/dist/compiler/worker-manager.d.ts.map +1 -0
  33. package/dist/compiler/worker.d.ts +6 -0
  34. package/dist/compiler/worker.d.ts.map +1 -0
  35. package/dist/compiler/worker.js +34 -0
  36. package/dist/compiler/worker.js.map +6 -0
  37. package/dist/helpers/constants.d.ts +3 -0
  38. package/dist/helpers/constants.d.ts.map +1 -0
  39. package/dist/helpers/serialize.d.ts +45 -0
  40. package/dist/helpers/serialize.d.ts.map +1 -0
  41. package/dist/helpers/utils.d.ts +36 -0
  42. package/dist/helpers/utils.d.ts.map +1 -0
  43. package/dist/index.d.ts +4 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +61 -0
  46. package/dist/index.js.map +6 -0
  47. package/dist/subtle.d.ts +7 -0
  48. package/dist/subtle.d.ts.map +1 -0
  49. package/dist/subtle.js +30 -0
  50. package/dist/subtle.js.map +6 -0
  51. package/dist/vm/env.d.ts +3 -0
  52. package/dist/vm/env.d.ts.map +1 -0
  53. package/dist/vm/error.d.ts +11 -0
  54. package/dist/vm/error.d.ts.map +1 -0
  55. package/dist/vm/helpers.d.ts +21 -0
  56. package/dist/vm/helpers.d.ts.map +1 -0
  57. package/dist/vm/index.d.ts +5 -0
  58. package/dist/vm/index.d.ts.map +1 -0
  59. package/dist/vm/lib/_helpers.d.ts +35 -0
  60. package/dist/vm/lib/_helpers.d.ts.map +1 -0
  61. package/dist/vm/lib/_loader.d.ts +16 -0
  62. package/dist/vm/lib/_loader.d.ts.map +1 -0
  63. package/dist/vm/lib/global/bit.d.ts +9 -0
  64. package/dist/vm/lib/global/bit.d.ts.map +1 -0
  65. package/dist/vm/lib/global/debug.d.ts +5 -0
  66. package/dist/vm/lib/global/debug.d.ts.map +1 -0
  67. package/dist/vm/lib/global/index.d.ts +10 -0
  68. package/dist/vm/lib/global/index.d.ts.map +1 -0
  69. package/dist/vm/lib/global/json.d.ts +4 -0
  70. package/dist/vm/lib/global/json.d.ts.map +1 -0
  71. package/dist/vm/lib/global/math-additional.d.ts +3 -0
  72. package/dist/vm/lib/global/math-additional.d.ts.map +1 -0
  73. package/dist/vm/lib/global/math-arr.d.ts +8 -0
  74. package/dist/vm/lib/global/math-arr.d.ts.map +1 -0
  75. package/dist/vm/lib/global/math-const.d.ts +3 -0
  76. package/dist/vm/lib/global/math-const.d.ts.map +1 -0
  77. package/dist/vm/lib/global/math-unary.d.ts +29 -0
  78. package/dist/vm/lib/global/math-unary.d.ts.map +1 -0
  79. package/dist/vm/lib/global/math.d.ts +9 -0
  80. package/dist/vm/lib/global/math.d.ts.map +1 -0
  81. package/dist/vm/lib/global/mod/index.d.ts +3 -0
  82. package/dist/vm/lib/global/mod/index.d.ts.map +1 -0
  83. package/dist/vm/lib/global/mod/matrix.d.ts +16 -0
  84. package/dist/vm/lib/global/mod/matrix.d.ts.map +1 -0
  85. package/dist/vm/lib/global/sequence/all-any.d.ts +4 -0
  86. package/dist/vm/lib/global/sequence/all-any.d.ts.map +1 -0
  87. package/dist/vm/lib/global/sequence/entries.d.ts +12 -0
  88. package/dist/vm/lib/global/sequence/entries.d.ts.map +1 -0
  89. package/dist/vm/lib/global/sequence/find.d.ts +10 -0
  90. package/dist/vm/lib/global/sequence/find.d.ts.map +1 -0
  91. package/dist/vm/lib/global/sequence/flatten.d.ts +3 -0
  92. package/dist/vm/lib/global/sequence/flatten.d.ts.map +1 -0
  93. package/dist/vm/lib/global/sequence/index.d.ts +12 -0
  94. package/dist/vm/lib/global/sequence/index.d.ts.map +1 -0
  95. package/dist/vm/lib/global/sequence/len.d.ts +3 -0
  96. package/dist/vm/lib/global/sequence/len.d.ts.map +1 -0
  97. package/dist/vm/lib/global/sequence/map-filter.d.ts +9 -0
  98. package/dist/vm/lib/global/sequence/map-filter.d.ts.map +1 -0
  99. package/dist/vm/lib/global/sequence/repeat.d.ts +4 -0
  100. package/dist/vm/lib/global/sequence/repeat.d.ts.map +1 -0
  101. package/dist/vm/lib/global/sequence/reverse.d.ts +3 -0
  102. package/dist/vm/lib/global/sequence/reverse.d.ts.map +1 -0
  103. package/dist/vm/lib/global/sequence/sort.d.ts +5 -0
  104. package/dist/vm/lib/global/sequence/sort.d.ts.map +1 -0
  105. package/dist/vm/lib/global/sequence/with.d.ts +5 -0
  106. package/dist/vm/lib/global/sequence/with.d.ts.map +1 -0
  107. package/dist/vm/lib/global/sequence/zip.d.ts +4 -0
  108. package/dist/vm/lib/global/sequence/zip.d.ts.map +1 -0
  109. package/dist/vm/lib/global/string.d.ts +12 -0
  110. package/dist/vm/lib/global/string.d.ts.map +1 -0
  111. package/dist/vm/lib/global/time.d.ts +15 -0
  112. package/dist/vm/lib/global/time.d.ts.map +1 -0
  113. package/dist/vm/lib/global/to-primitive.d.ts +6 -0
  114. package/dist/vm/lib/global/to-primitive.d.ts.map +1 -0
  115. package/dist/vm/operations.d.ts +49 -0
  116. package/dist/vm/operations.d.ts.map +1 -0
  117. package/dist/vm/types/checker.d.ts +30 -0
  118. package/dist/vm/types/checker.d.ts.map +1 -0
  119. package/dist/vm/types/context.d.ts +43 -0
  120. package/dist/vm/types/context.d.ts.map +1 -0
  121. package/dist/vm/types/extern.d.ts +32 -0
  122. package/dist/vm/types/extern.d.ts.map +1 -0
  123. package/dist/vm/types/function.d.ts +49 -0
  124. package/dist/vm/types/function.d.ts.map +1 -0
  125. package/dist/vm/types/index.d.ts +75 -0
  126. package/dist/vm/types/index.d.ts.map +1 -0
  127. package/dist/vm/types/module.d.ts +25 -0
  128. package/dist/vm/types/module.d.ts.map +1 -0
  129. package/dist/vm/types/script.d.ts +14 -0
  130. package/dist/vm/types/script.d.ts.map +1 -0
  131. package/dist/vm/types/wrapper.d.ts +25 -0
  132. package/dist/vm/types/wrapper.d.ts.map +1 -0
  133. package/package.json +55 -0
  134. package/src/cli/execute.ts +32 -0
  135. package/src/cli/index.ts +73 -0
  136. package/src/cli/print.ts +41 -0
  137. package/src/compiler/compile-bytecode.ts +65 -0
  138. package/src/compiler/compile-fast.ts +81 -0
  139. package/src/compiler/create-script.ts +34 -0
  140. package/src/compiler/diagnostic.ts +175 -0
  141. package/src/compiler/emit.ts +764 -0
  142. package/src/compiler/index.ts +67 -0
  143. package/src/compiler/types.ts +16 -0
  144. package/src/compiler/worker-manager.ts +60 -0
  145. package/src/compiler/worker.ts +37 -0
  146. package/src/helpers/constants.ts +3 -0
  147. package/src/helpers/serialize.ts +280 -0
  148. package/src/helpers/utils.ts +16 -0
  149. package/src/index.ts +3 -0
  150. package/src/subtle.ts +6 -0
  151. package/src/vm/env.ts +16 -0
  152. package/src/vm/error.ts +22 -0
  153. package/src/vm/helpers.ts +121 -0
  154. package/src/vm/index.ts +5 -0
  155. package/src/vm/lib/_helpers.ts +215 -0
  156. package/src/vm/lib/_loader.ts +51 -0
  157. package/src/vm/lib/global/bit.ts +93 -0
  158. package/src/vm/lib/global/debug.ts +36 -0
  159. package/src/vm/lib/global/index.ts +9 -0
  160. package/src/vm/lib/global/json.ts +45 -0
  161. package/src/vm/lib/global/math-additional.ts +71 -0
  162. package/src/vm/lib/global/math-arr.ts +62 -0
  163. package/src/vm/lib/global/math-const.ts +2 -0
  164. package/src/vm/lib/global/math-unary.ts +171 -0
  165. package/src/vm/lib/global/math.ts +27 -0
  166. package/src/vm/lib/global/mod/index.ts +4 -0
  167. package/src/vm/lib/global/mod/matrix.ts +579 -0
  168. package/src/vm/lib/global/sequence/all-any.ts +73 -0
  169. package/src/vm/lib/global/sequence/entries.ts +67 -0
  170. package/src/vm/lib/global/sequence/find.ts +49 -0
  171. package/src/vm/lib/global/sequence/flatten.ts +16 -0
  172. package/src/vm/lib/global/sequence/index.ts +11 -0
  173. package/src/vm/lib/global/sequence/len.ts +15 -0
  174. package/src/vm/lib/global/sequence/map-filter.ts +82 -0
  175. package/src/vm/lib/global/sequence/repeat.ts +28 -0
  176. package/src/vm/lib/global/sequence/reverse.ts +17 -0
  177. package/src/vm/lib/global/sequence/sort.ts +88 -0
  178. package/src/vm/lib/global/sequence/with.ts +43 -0
  179. package/src/vm/lib/global/sequence/zip.ts +40 -0
  180. package/src/vm/lib/global/string.ts +149 -0
  181. package/src/vm/lib/global/time.ts +73 -0
  182. package/src/vm/lib/global/to-primitive.ts +58 -0
  183. package/src/vm/operations.ts +497 -0
  184. package/src/vm/types/checker.ts +164 -0
  185. package/src/vm/types/context.ts +161 -0
  186. package/src/vm/types/extern.ts +166 -0
  187. package/src/vm/types/function.ts +136 -0
  188. package/src/vm/types/index.ts +124 -0
  189. package/src/vm/types/module.ts +40 -0
  190. package/src/vm/types/script.ts +18 -0
  191. package/src/vm/types/wrapper.ts +28 -0
@@ -0,0 +1,164 @@
1
+ import { getPrototypeOf, isArray, values } from '../../helpers/utils.js';
2
+ import {
3
+ isVmFunction,
4
+ VmModule,
5
+ type VmAny,
6
+ type VmArray,
7
+ type VmConst,
8
+ type VmImmutable,
9
+ type VmRecord,
10
+ type VmValue,
11
+ } from './index.js';
12
+ import { VmWrapper } from './wrapper.js';
13
+
14
+ const MAX_DEPTH = 32;
15
+ /**
16
+ * 检查是否为 Mirascript 数组
17
+ */
18
+ function isVmArrayDeep(value: readonly unknown[], depth: number): value is VmArray {
19
+ // VmArray 应为普通数组
20
+ // Array.prototype
21
+ const proto1: unknown = getPrototypeOf(value);
22
+ if (!isArray(proto1)) return false;
23
+ if (!depth) return true;
24
+ return value.every((item) => isVmConstInner(item, depth));
25
+ }
26
+ /**
27
+ * 检查是否为 Mirascript 记录
28
+ */
29
+ function isVmRecordDeep(value: object, depth: number): value is VmRecord {
30
+ // VmRecord 应为普通对象或空原型对象
31
+ let isRecord;
32
+ // Object.prototype
33
+ const proto1: unknown = getPrototypeOf(value);
34
+ if (proto1 == null) {
35
+ isRecord = true;
36
+ } else {
37
+ // null
38
+ const proto2: unknown = getPrototypeOf(proto1);
39
+ if (proto2 != null) {
40
+ isRecord = false;
41
+ } else {
42
+ isRecord = 'hasOwnProperty' in value;
43
+ }
44
+ }
45
+ if (!isRecord) return false;
46
+ if (!depth) return true;
47
+ return values(value).every((value) => isVmConstInner(value, depth));
48
+ }
49
+ /**
50
+ * 检查是否为 Mirascript 值语义值
51
+ */
52
+ function isVmConstInner(value: unknown, depth: number): value is VmConst {
53
+ if (depth++ >= MAX_DEPTH) return false;
54
+ switch (typeof value) {
55
+ case 'string':
56
+ case 'number':
57
+ case 'boolean':
58
+ case 'undefined': // undefined 在复合类型内部被视为 nil
59
+ return true;
60
+ case 'object':
61
+ if (value == null) return true;
62
+ if (value instanceof VmWrapper) return false;
63
+ if (isArray(value)) {
64
+ return isVmArrayDeep(value, depth);
65
+ } else {
66
+ return isVmRecordDeep(value, depth);
67
+ }
68
+ case 'function':
69
+ case 'bigint':
70
+ case 'symbol':
71
+ default:
72
+ return false; // Other types are not valid
73
+ }
74
+ }
75
+
76
+ /**
77
+ * 检查是否为 Mirascript 值语义值
78
+ */
79
+ export function isVmConst(value: VmAny): value is VmConst;
80
+ /**
81
+ * 检查是否为 Mirascript 值语义值
82
+ */
83
+ export function isVmConst(value: unknown, checkDeep: boolean): value is VmConst;
84
+ /**
85
+ * 检查是否为 Mirascript 值语义值
86
+ */
87
+ export function isVmConst(value: unknown, checkDeep = false): value is VmConst {
88
+ switch (typeof value) {
89
+ case 'string':
90
+ case 'number':
91
+ case 'boolean':
92
+ return true;
93
+ case 'object':
94
+ if (value == null) return true;
95
+ if (value instanceof VmWrapper) return false;
96
+ if (!checkDeep) {
97
+ if (isArray(value)) {
98
+ return isVmArrayDeep(value, 0);
99
+ } else {
100
+ return isVmRecordDeep(value, 0);
101
+ }
102
+ } else {
103
+ return isVmConstInner(value, 1);
104
+ }
105
+ case 'undefined':
106
+ case 'function':
107
+ case 'bigint':
108
+ case 'symbol':
109
+ default:
110
+ return false; // Other types are not valid
111
+ }
112
+ }
113
+ /**
114
+ * 检查是否为 Mirascript 不可变值
115
+ */
116
+ export function isVmImmutable(value: VmAny): value is VmImmutable;
117
+ /**
118
+ * 检查是否为 Mirascript 不可变值
119
+ */
120
+ export function isVmImmutable(value: unknown, checkDeep: boolean): value is VmImmutable;
121
+ /**
122
+ * 检查是否为 Mirascript 不可变值
123
+ */
124
+ export function isVmImmutable(value: unknown, checkDeep = false): value is VmImmutable {
125
+ return value instanceof VmModule || isVmFunction(value) || isVmConst(value, checkDeep);
126
+ }
127
+ /**
128
+ * 检查是否为 Mirascript 合法值
129
+ */
130
+ export function isVmValue(value: VmAny): value is VmValue;
131
+ /**
132
+ * 检查是否为 Mirascript 合法值
133
+ */
134
+ export function isVmValue(value: unknown, checkDeep: boolean): value is VmValue;
135
+ /**
136
+ * 检查是否为 Mirascript 合法值
137
+ */
138
+ export function isVmValue(value: unknown, checkDeep = false): value is VmValue {
139
+ if (value === undefined) return false;
140
+ return isVmAny(value, checkDeep);
141
+ }
142
+
143
+ /**
144
+ * 检查是否为 Mirascript 值
145
+ */
146
+ export function isVmAny(value: unknown, checkDeep: boolean): value is VmAny {
147
+ switch (typeof value) {
148
+ case 'string':
149
+ case 'number':
150
+ case 'boolean':
151
+ case 'undefined':
152
+ return true;
153
+ case 'object':
154
+ if (value == null) return true;
155
+ if (value instanceof VmWrapper) return true;
156
+ return isVmConst(value, checkDeep);
157
+ case 'function':
158
+ return isVmFunction(value);
159
+ case 'bigint':
160
+ case 'symbol':
161
+ default:
162
+ return false; // Other types are not valid
163
+ }
164
+ }
@@ -0,0 +1,161 @@
1
+ import {
2
+ VmFunction,
3
+ type VmAny,
4
+ type VmImmutable,
5
+ type VmValue,
6
+ wrapToVmValue,
7
+ isVmAny,
8
+ type VmFunctionLike,
9
+ } from './index.js';
10
+ import { entries, keys } from '../../helpers/utils.js';
11
+ import type * as global from '../lib/global/index.js';
12
+
13
+ /** 全局导入的标准库 */
14
+ type GlobalKeys = keyof typeof global;
15
+ /** 全局导入的标准库值 */
16
+ type ToGlobalValue<T extends GlobalKeys> = (typeof global)[T] extends VmFunctionLike
17
+ ? VmFunction<(typeof global)[T]>
18
+ : (typeof global)[T];
19
+ /** 全局导入的标准库 */
20
+ type VmContextBase = {
21
+ [key in GlobalKeys]: ToGlobalValue<key>;
22
+ };
23
+ const kVmContext = Symbol.for('mira:vm-context');
24
+ /** MiraScript 执行上下文的基础,仅包含标准库 */
25
+ export type VmSharedContext = VmContextBase & Record<string, VmImmutable>;
26
+ /** MiraScript 执行上下文 */
27
+ export interface VmContext {
28
+ /** 内部标识符 */
29
+ readonly [kVmContext]: true;
30
+ /** 枚举所有 key,仅在 LSP 中使用 */
31
+ keys(): Iterable<string>;
32
+ /** 获取指定 key 的值 `global[key]` */
33
+ get(key: string): VmValue;
34
+ /** 查找指定 key 是否存在 `key in global` */
35
+ has(key: string): boolean;
36
+ }
37
+ /** MiraScript 执行上下文 */
38
+ export type VmContextRecord = Record<string, VmValue | undefined>;
39
+ export const VmSharedContext = { __proto__: null } as object as VmSharedContext;
40
+
41
+ /** 定义在所有 MiraScript 执行上下文中共享的全局变量 */
42
+ export function defineVmContextValue(
43
+ name: string,
44
+ value: VmImmutable | ((...args: VmAny[]) => VmAny),
45
+ override = false,
46
+ ): void {
47
+ if (!override && name in VmSharedContext) throw new Error(`Global variable '${name}' is already defined.`);
48
+ let v: VmImmutable;
49
+ if (typeof value == 'function') {
50
+ v = VmFunction(value, {
51
+ isLib: true,
52
+ fullName: `global.${name}`,
53
+ });
54
+ } else {
55
+ v = value;
56
+ }
57
+ VmSharedContext[name] = v ?? null;
58
+ }
59
+
60
+ /** 无后备的实现 */
61
+ export const DefaultVmContext: VmContext = Object.freeze({
62
+ [kVmContext]: true as const,
63
+ /** @inheritdoc */
64
+ keys(): Iterable<string> {
65
+ return keys(VmSharedContext);
66
+ },
67
+ /** @inheritdoc */
68
+ get(key: string): VmValue {
69
+ return VmSharedContext[key] ?? null;
70
+ },
71
+ /** @inheritdoc */
72
+ has(key: string): boolean {
73
+ return key in VmSharedContext;
74
+ },
75
+ });
76
+
77
+ /** 以值为后备的实现 */
78
+ class ValueVmContext implements VmContext {
79
+ readonly [kVmContext] = true;
80
+ private cachedKeys: readonly string[] | null = null;
81
+ /** @inheritdoc */
82
+ keys(): Iterable<string> {
83
+ this.cachedKeys ??= keys(this.env);
84
+ return [...this.cachedKeys, ...DefaultVmContext.keys()];
85
+ }
86
+ /** @inheritdoc */
87
+ get(key: string): VmValue {
88
+ return this.env[key] ?? null;
89
+ }
90
+ /** @inheritdoc */
91
+ has(key: string): boolean {
92
+ return key in this.env;
93
+ }
94
+ constructor(private readonly env: VmContextRecord & { __proto__: VmSharedContext }) {}
95
+ }
96
+
97
+ /** 以工厂函数为后备的实现 */
98
+ class FactoryVmContext implements VmContext {
99
+ readonly [kVmContext] = true;
100
+ /** @inheritdoc */
101
+ keys(): Iterable<string> {
102
+ if (!this.enumerator) return DefaultVmContext.keys();
103
+ return [...this.enumerator(), ...DefaultVmContext.keys()];
104
+ }
105
+ /** @inheritdoc */
106
+ get(key: string): VmValue {
107
+ const value = this.getter(key);
108
+ if (value !== undefined) return value;
109
+ return DefaultVmContext.get(key);
110
+ }
111
+ /** @inheritdoc */
112
+ has(key: string): boolean {
113
+ return this.getter(key) !== undefined || DefaultVmContext.has(key);
114
+ }
115
+ constructor(
116
+ private readonly getter: (key: string) => VmValue | undefined,
117
+ private readonly enumerator?: () => Iterable<string>,
118
+ ) {}
119
+ }
120
+
121
+ /** 创建用于执行脚本的执行上下文 */
122
+ export function createVmContext(
123
+ ...args:
124
+ | readonly [
125
+ vmValues?: VmContextRecord | null | undefined,
126
+ externValues?: Record<string, unknown> | null | undefined,
127
+ ]
128
+ | readonly [
129
+ getter: (key: string) => VmValue | undefined,
130
+ enumerator?: (() => Iterable<string>) | null | undefined,
131
+ ]
132
+ ): VmContext {
133
+ if (args[0] == null && args[1] == null) {
134
+ return { ...DefaultVmContext };
135
+ }
136
+
137
+ if (typeof args[0] == 'function') {
138
+ return new FactoryVmContext(args[0], args[1] as (() => Iterable<string>) | undefined);
139
+ }
140
+
141
+ const [vmValues, externValues] = args;
142
+ const env = { __proto__: VmSharedContext } as { __proto__: VmSharedContext } & VmContextRecord;
143
+ if (vmValues) {
144
+ for (const [key, value] of entries(vmValues)) {
145
+ if (!isVmAny(value, false)) continue;
146
+ env[key] = value ?? null;
147
+ }
148
+ }
149
+ if (externValues) {
150
+ for (const [key, value] of entries(externValues as Record<string, unknown>)) {
151
+ env[key] = value == null ? null : wrapToVmValue(value, null);
152
+ }
153
+ }
154
+ return new ValueVmContext(env);
155
+ }
156
+
157
+ /** 检查是否为执行上下文 */
158
+ export function isVmContext(context: unknown): context is VmContext {
159
+ if (context == null || typeof context != 'object') return false;
160
+ return (context as VmContext)[kVmContext] === true;
161
+ }
@@ -0,0 +1,166 @@
1
+ import { VmError } from '../error.js';
2
+ import { fromVmFunctionProxy, toVmFunctionProxy, type VmFunctionLike } from './function.js';
3
+ import { VmWrapper } from './wrapper.js';
4
+ import type { TypeName, VmAny, VmModule, VmValue } from './index.js';
5
+ import { getPrototypeOf, hasOwn } from '../../helpers/utils.js';
6
+ const { apply } = Reflect;
7
+
8
+ /** 包装为 Mirascript 类型 */
9
+ export function wrapToVmValue(value: unknown, caller: VmExtern | null): VmValue {
10
+ if (value == null) return null;
11
+ switch (typeof value) {
12
+ case 'function': {
13
+ const unwrapped = fromVmFunctionProxy(value as VmFunctionLike);
14
+ if (unwrapped) return unwrapped;
15
+ return new VmExtern(value, caller);
16
+ }
17
+ case 'object':
18
+ if (value instanceof VmWrapper) return value as VmModule | VmExtern;
19
+ return new VmExtern(value, null);
20
+ case 'string':
21
+ case 'number':
22
+ case 'boolean':
23
+ return value;
24
+ case 'bigint':
25
+ return Number(value);
26
+ case 'symbol':
27
+ case 'undefined':
28
+ default:
29
+ return null;
30
+ }
31
+ }
32
+
33
+ /** 取消 Mirascript 类型包装 */
34
+ export function unwrapFromVmValue(value: VmAny): unknown {
35
+ if (typeof value == 'function') {
36
+ return toVmFunctionProxy(value);
37
+ }
38
+ if (value == null || typeof value != 'object') return value;
39
+ if (!(value instanceof VmExtern)) return value;
40
+ if (value.caller == null || typeof value.value != 'function') {
41
+ return value.value;
42
+ }
43
+ const caller = value.caller.value;
44
+ const func = value.value as (...args: unknown[]) => unknown;
45
+ return new Proxy(func, {
46
+ apply(target, thisArg, args): unknown {
47
+ return apply(target, caller, args);
48
+ },
49
+ });
50
+ }
51
+
52
+ const ObjectPrototype = Object.prototype;
53
+ // eslint-disable-next-line @typescript-eslint/unbound-method
54
+ const ObjectToString = ObjectPrototype.toString;
55
+ /** 包装 Mirascript `extern` 类型的对象 */
56
+ export class VmExtern<const T extends object = object> extends VmWrapper<T> {
57
+ constructor(
58
+ value: T,
59
+ readonly caller: VmExtern | null = null,
60
+ ) {
61
+ super(value);
62
+ }
63
+
64
+ /** Check if the object has a property */
65
+ protected access(key: string, read: boolean): boolean {
66
+ // __proto__ and other private properties are not accessible
67
+ if (key.startsWith('_')) return false;
68
+ // Function-specific properties are not accessible
69
+ if (typeof this.value == 'function' && (key === 'prototype' || key === 'arguments' || key === 'caller'))
70
+ return false;
71
+ if (hasOwn(this.value, key)) return true;
72
+ if (!read) return true;
73
+ if (!(key in this.value)) return false;
74
+ if (key === 'constructor') return false; // constructor is not accessible
75
+ const prop = (this.value as Record<string, unknown>)[key];
76
+ if (key in Function.prototype && prop === Function.prototype[key as keyof (() => void)]) return false;
77
+ if (key in Array.prototype && prop === Array.prototype[key as keyof unknown[]]) return false;
78
+ if (key in Object.prototype && prop === Object.prototype[key as keyof object]) return false;
79
+ return true;
80
+ }
81
+
82
+ /** @inheritdoc */
83
+ override has(key: string): boolean {
84
+ return this.access(key, true);
85
+ }
86
+ /** @inheritdoc */
87
+ override get(key: string): VmAny {
88
+ if (!this.has(key)) return undefined;
89
+ const prop = (this.value as Record<string, unknown>)[key];
90
+ return wrapToVmValue(prop, this);
91
+ }
92
+ /** Set a property on the object */
93
+ set(key: string, value: VmValue): boolean {
94
+ if (!this.access(key, false)) return false;
95
+ const prop = unwrapFromVmValue(value);
96
+ (this.value as Record<string, unknown>)[key] = prop;
97
+ return true;
98
+ }
99
+ /** Call extern value */
100
+ call(args: readonly VmValue[]): VmAny {
101
+ const { value } = this;
102
+ const caller = this.caller?.value ?? null;
103
+ const unwrappedArgs = args.map(unwrapFromVmValue);
104
+ try {
105
+ const ret: unknown = apply(value as (...args: unknown[]) => unknown, caller, unwrappedArgs);
106
+ return wrapToVmValue(ret, null);
107
+ } catch (ex) {
108
+ throw VmError.from(`Not a callable extern`, ex, null);
109
+ }
110
+ }
111
+ /** @inheritdoc */
112
+ override keys(): string[] {
113
+ const keys: string[] = [];
114
+ for (const key in this.value) {
115
+ if (this.has(key)) keys.push(key);
116
+ }
117
+ return keys;
118
+ }
119
+ /** @inheritdoc */
120
+ override same(other: VmAny): boolean {
121
+ if (!(other instanceof VmExtern)) return false;
122
+ return this.value === other.value && this.caller === other.caller;
123
+ }
124
+ /** @inheritdoc */
125
+ override toString(): string {
126
+ // eslint-disable-next-line @typescript-eslint/unbound-method
127
+ const { toString } = this.value;
128
+ if (typeof toString != 'function' || toString === ObjectToString) {
129
+ return super.toString();
130
+ }
131
+ try {
132
+ return String(this.value);
133
+ } catch {
134
+ return super.toString();
135
+ }
136
+ }
137
+ /** @inheritdoc */
138
+ override get type(): TypeName {
139
+ return 'extern';
140
+ }
141
+ /** @inheritdoc */
142
+ override get describe(): string {
143
+ const tag = ObjectToString.call(this.value).slice(8, -1);
144
+ if (tag === 'Object') {
145
+ const proto = getPrototypeOf(this.value);
146
+ if (proto === ObjectPrototype) {
147
+ return 'Object';
148
+ }
149
+ if (proto == null) {
150
+ return 'Object: null prototype';
151
+ }
152
+ if (typeof proto.constructor === 'function' && proto.constructor.name) {
153
+ return proto.constructor.name;
154
+ }
155
+ } else if (tag === 'Function' && 'prototype' in this.value && typeof this.value.prototype == 'object') {
156
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
157
+ const { name } = this.value as unknown as Function;
158
+ if (name) {
159
+ return `Class ${name}`;
160
+ } else {
161
+ return 'Class';
162
+ }
163
+ }
164
+ return tag;
165
+ }
166
+ }
@@ -0,0 +1,136 @@
1
+ import { defineProperty } from '../../helpers/utils.js';
2
+ import { CpEnter, CpExit } from '../helpers.js';
3
+ import { $Call } from '../operations.js';
4
+ import type { VmAny, VmValue } from './index.js';
5
+ import { wrapToVmValue, unwrapFromVmValue } from './extern.js';
6
+
7
+ const kVmFunction = Symbol.for('mirascript.vm.function');
8
+ const kProxy = Symbol.for('mirascript.vm.function.proxy');
9
+
10
+ /**
11
+ * Mirascript 函数签名
12
+ *
13
+ * 虽然所有输入参数的类型均为 {@linkcode VmValue},但当参数不足时,对应的参数会被填充为 `undefined`。
14
+ */
15
+ // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
16
+ export type VmFunctionLike = (...args: ReadonlyArray<VmValue | undefined>) => VmAny | void;
17
+
18
+ /** Mirascript 函数 */
19
+ export type VmFunction<T extends VmFunctionLike = VmFunctionLike> = T & { readonly [kVmFunction]: VmFunctionInfo };
20
+
21
+ /** Mirascript 函数信息 */
22
+ export interface VmFunctionInfo {
23
+ /** 完整名称 */
24
+ readonly fullName: string;
25
+ /** 是否为库函数 */
26
+ readonly isLib: boolean;
27
+ /** 文档字符串 */
28
+ readonly summary?: string;
29
+ /** 文档字符串 */
30
+ readonly params?: Record<string, string>;
31
+ /** 文档字符串 */
32
+ readonly paramsType?: Record<string, string>;
33
+ /** 文档字符串 */
34
+ readonly returns?: string;
35
+ /** 文档字符串 */
36
+ readonly returnsType?: string;
37
+ /** 文档字符串 */
38
+ readonly examples?: string[];
39
+ /** 如果添加了包装,返回原函数 */
40
+ readonly original?: VmFunctionLike;
41
+ }
42
+
43
+ /** Mirascript 函数创建选项 */
44
+ export type VmFunctionOption = Partial<
45
+ Omit<VmFunctionInfo, 'original'> & {
46
+ readonly injectCp: boolean;
47
+ }
48
+ >;
49
+
50
+ /** 检查是否为 Mirascript 函数 */
51
+ export function isVmFunction<T extends VmFunctionLike>(value: unknown): value is VmFunction<T> {
52
+ return getVmFunctionInfo(value) != null;
53
+ }
54
+
55
+ /** 检查是否为 Mirascript 函数,并获取其信息 */
56
+ export function getVmFunctionInfo(value: unknown): VmFunctionInfo | undefined {
57
+ if (typeof value != 'function') return undefined;
58
+ return (value as VmFunction)[kVmFunction];
59
+ }
60
+
61
+ /** 创建 Mirascript 函数 */
62
+ export function VmFunction<T extends VmFunctionLike>(fn: T, option: VmFunctionOption = {}): VmFunction<T> {
63
+ if (typeof fn != 'function') {
64
+ throw new TypeError('Invalid function');
65
+ }
66
+
67
+ const exists = fromVmFunctionProxy(fn);
68
+ // 如果已经是 VmFunction,则直接返回
69
+ if (exists) return exists;
70
+
71
+ const info: Writable<VmFunctionInfo> = {
72
+ fullName: option.fullName ?? fn.name,
73
+ isLib: option.isLib ?? false,
74
+ summary: option.summary || undefined,
75
+ params: option.params,
76
+ paramsType: option.paramsType,
77
+ returns: option.returns || undefined,
78
+ returnsType: option.returnsType || undefined,
79
+ examples: option.examples?.length ? option.examples : undefined,
80
+ };
81
+ if (option.injectCp) {
82
+ const original = fn;
83
+ info.original = original;
84
+ fn = ((...args) => {
85
+ try {
86
+ CpEnter();
87
+ const ret = original(...args);
88
+ return ret;
89
+ } finally {
90
+ CpExit();
91
+ }
92
+ }) as typeof fn;
93
+ defineProperty(fn, 'name', {
94
+ value: original.name,
95
+ configurable: true,
96
+ });
97
+ }
98
+ defineProperty(fn, kVmFunction, {
99
+ value: Object.freeze(info),
100
+ });
101
+ return fn as VmFunction<T>;
102
+ }
103
+
104
+ /** 创建 Mirascript 函数在宿主语言运行的代理 */
105
+ export function toVmFunctionProxy<T extends VmFunctionLike>(fn: VmFunction<T>): T {
106
+ if (!isVmFunction(fn)) return fn;
107
+
108
+ const cached = (fn as unknown as { [kProxy]?: T })[kProxy];
109
+ if (cached) return cached;
110
+
111
+ const proxy = (...args: unknown[]) => {
112
+ const ret = $Call(
113
+ fn,
114
+ // 作为函数参数传入的值一定丢失了它的 this
115
+ args.map((v) => wrapToVmValue(v, null)),
116
+ );
117
+ return unwrapFromVmValue(ret);
118
+ };
119
+ defineProperty(fn, kProxy, { value: proxy });
120
+ defineProperty(proxy, kProxy, { value: fn });
121
+ defineProperty(proxy, 'name', {
122
+ value: fn.name,
123
+ configurable: true,
124
+ });
125
+ return proxy as T;
126
+ }
127
+
128
+ /** 解开 Mirascript 函数在宿主语言运行的代理 */
129
+ export function fromVmFunctionProxy<T extends VmFunctionLike>(fn: T): VmFunction<T> | undefined {
130
+ if (isVmFunction(fn)) return fn;
131
+
132
+ const original = (fn as unknown as { [kProxy]?: VmFunction<T> })[kProxy];
133
+ if (original && isVmFunction(original)) return original;
134
+
135
+ return undefined;
136
+ }