@mirascript/mirascript 0.1.33 → 0.1.34
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-BMSHG7ON.js → chunk-DNMS3ZEP.js} +2 -2
- package/dist/{chunk-NRUNNMNC.js → chunk-GUMBLKWM.js} +18 -20
- package/dist/chunk-GUMBLKWM.js.map +6 -0
- package/dist/{chunk-UM7PQV4L.js → chunk-KUOYMOEU.js} +116 -115
- package/dist/chunk-KUOYMOEU.js.map +6 -0
- package/dist/{chunk-VZGKLLRC.js → chunk-VXTRR2CX.js} +2 -2
- package/dist/cli/index.js +4 -4
- package/dist/compiler/compile-fast.d.ts.map +1 -1
- package/dist/compiler/create-script.d.ts +1 -1
- package/dist/compiler/create-script.d.ts.map +1 -1
- package/dist/compiler/emit/constants.d.ts +1 -1
- package/dist/compiler/emit/constants.d.ts.map +1 -1
- package/dist/compiler/worker.js +1 -1
- package/dist/index.js +3 -3
- package/dist/subtle.js +3 -3
- package/dist/vm/lib/global/time.d.ts.map +1 -1
- package/dist/vm/operations/call.d.ts +7 -3
- package/dist/vm/operations/call.d.ts.map +1 -1
- package/dist/vm/operations/common.d.ts +2 -1
- package/dist/vm/operations/common.d.ts.map +1 -1
- package/dist/vm/operations/compound.d.ts +20 -10
- package/dist/vm/operations/compound.d.ts.map +1 -1
- package/dist/vm/operations/convert.d.ts +8 -4
- package/dist/vm/operations/convert.d.ts.map +1 -1
- package/dist/vm/operations/helpers.d.ts +8 -6
- package/dist/vm/operations/helpers.d.ts.map +1 -1
- package/dist/vm/operations/operator.d.ts +44 -22
- package/dist/vm/operations/operator.d.ts.map +1 -1
- package/dist/vm/operations/slice.d.ts +4 -2
- package/dist/vm/operations/slice.d.ts.map +1 -1
- package/dist/vm/operations/type-check.d.ts +14 -7
- package/dist/vm/operations/type-check.d.ts.map +1 -1
- package/dist/vm/types/extern.d.ts +6 -1
- package/dist/vm/types/extern.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/compiler/compile-fast.ts +17 -20
- package/src/compiler/create-script.ts +1 -1
- package/src/compiler/emit/constants.ts +1 -1
- package/src/vm/lib/global/time.ts +6 -5
- package/src/vm/operations/call.ts +30 -7
- package/src/vm/operations/common.ts +3 -2
- package/src/vm/operations/compound.ts +33 -21
- package/src/vm/operations/convert.ts +12 -8
- package/src/vm/operations/helpers.ts +14 -12
- package/src/vm/operations/operator.ts +66 -44
- package/src/vm/operations/slice.ts +6 -4
- package/src/vm/operations/type-check.ts +21 -14
- package/src/vm/types/extern.ts +2 -0
- package/dist/chunk-NRUNNMNC.js.map +0 -6
- package/dist/chunk-UM7PQV4L.js.map +0 -6
- /package/dist/{chunk-BMSHG7ON.js.map → chunk-DNMS3ZEP.js.map} +0 -0
- /package/dist/{chunk-VZGKLLRC.js.map → chunk-VXTRR2CX.js.map} +0 -0
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { TypeName, VmAny, VmArray, VmRecord, VmValue } from '../types/index.js';
|
|
2
|
-
|
|
3
|
-
export declare
|
|
4
|
-
|
|
5
|
-
export declare
|
|
6
|
-
|
|
7
|
-
export declare
|
|
8
|
-
|
|
2
|
+
/** 获取值的类型名称 */
|
|
3
|
+
export declare function $Type(value: VmAny): TypeName;
|
|
4
|
+
/** 判断值是否为布尔值 */
|
|
5
|
+
export declare function $IsBoolean(value: VmAny): value is boolean;
|
|
6
|
+
/** 判断值是否为数字 */
|
|
7
|
+
export declare function $IsNumber(value: VmAny): value is number;
|
|
8
|
+
/** 判断值是否为字符串 */
|
|
9
|
+
export declare function $IsString(value: VmAny): value is string;
|
|
10
|
+
/** 判断值是否为记录 */
|
|
11
|
+
export declare function $IsRecord(value: VmAny): value is VmRecord;
|
|
12
|
+
/** 判断值是否为数组 */
|
|
13
|
+
export declare function $IsArray(value: VmAny): value is VmArray;
|
|
14
|
+
/** 断言值非 nil */
|
|
15
|
+
export declare function $AssertNonNil(value: VmAny): asserts value is NonNullable<VmValue>;
|
|
9
16
|
//# sourceMappingURL=type-check.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type-check.d.ts","sourceRoot":"","sources":["../../../src/vm/operations/type-check.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGrF,
|
|
1
|
+
{"version":3,"file":"type-check.d.ts","sourceRoot":"","sources":["../../../src/vm/operations/type-check.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGrF,eAAe;AACf,wBAAgB,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,QAAQ,CAO5C;AACD,gBAAgB;AAChB,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,OAAO,CAGzD;AACD,eAAe;AACf,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,MAAM,CAGvD;AACD,gBAAgB;AAChB,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,MAAM,CAGvD;AACD,eAAe;AACf,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,QAAQ,CAGzD;AACD,eAAe;AACf,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,OAAO,CAGvD;AACD,eAAe;AACf,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,WAAW,CAAC,OAAO,CAAC,CAIjF"}
|
|
@@ -2,8 +2,13 @@ import type { TypeName, VmAny, VmConst, VmPrimitive, VmValue } from './index.js'
|
|
|
2
2
|
import { VmWrapper } from './wrapper.js';
|
|
3
3
|
/** 包装 Mirascript `extern` 类型的对象 */
|
|
4
4
|
export declare class VmExtern<const T extends object = object> extends VmWrapper<T> {
|
|
5
|
+
/** 当 {@link value} 是函数时,绑定的 this 参数 */
|
|
5
6
|
readonly thisArg: ThisParameterType<T> | null;
|
|
6
|
-
constructor(
|
|
7
|
+
constructor(
|
|
8
|
+
/** 包装值 */
|
|
9
|
+
value: T,
|
|
10
|
+
/** 当 {@link value} 是函数时,绑定的 this 参数 */
|
|
11
|
+
thisArg?: ThisParameterType<T> | null);
|
|
7
12
|
/** Check if the object has a property */
|
|
8
13
|
protected access(key: string, read: boolean): boolean;
|
|
9
14
|
/** 决定是否对属性进行包装 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extern.d.ts","sourceRoot":"","sources":["../../../src/vm/types/extern.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAwBzC,mCAAmC;AACnC,qBAAa,QAAQ,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,SAAS,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"extern.d.ts","sourceRoot":"","sources":["../../../src/vm/types/extern.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAwBzC,mCAAmC;AACnC,qBAAa,QAAQ,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,SAAS,CAAC,CAAC,CAAC;IAInE,uCAAuC;IACvC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAI;;IAH7C,UAAU;IACV,KAAK,EAAE,CAAC;IACR,uCAAuC;IAC9B,OAAO,GAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,IAAW;IAKxD,yCAAyC;IACzC,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO;IAiBrD,kBAAkB;IAClB,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,SAAS,GAAG,KAAK,IAAI,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC;IAIxG,kBAAkB;IACT,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAGlC,kBAAkB;IACT,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK;IAMhC,mCAAmC;IACnC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO;IAMzC,wBAAwB;IACxB,IAAI,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,KAAK;IAerC,kBAAkB;IACT,IAAI,CAAC,oBAAoB,UAAQ,GAAG,MAAM,EAAE;IAqBrD,kBAAkB;IACT,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IAIpC,kBAAkB;IAClB,WAAW,IAAI,IAAI,IAAI,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAGnD,kBAAkB;IACT,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM;IAiB7C,kBAAkB;IAClB,IAAa,IAAI,IAAI,QAAQ,CAE5B;IACD,kBAAkB;IAClB,IAAa,GAAG,IAAI,MAAM,CA6BzB;CACJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mirascript/mirascript",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.34",
|
|
4
4
|
"author": "CloudPSS",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "An expression based scripting language.",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"commander": "^14.0.2",
|
|
37
37
|
"source-map-js": "^1.2.1",
|
|
38
38
|
"supports-color": "^10.2.2",
|
|
39
|
-
"@mirascript/
|
|
40
|
-
"@mirascript/
|
|
39
|
+
"@mirascript/constants": "~0.1.34",
|
|
40
|
+
"@mirascript/bindings": "~0.1.34"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^25.0.3",
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { isKeyword } from '@mirascript/constants';
|
|
2
|
-
import { wrapScript, type VmScript } from './create-script.js';
|
|
2
|
+
import { wrapScript, type VmScript, type VmScriptLike } from './create-script.js';
|
|
3
3
|
import type { TranspileOptions } from './types.js';
|
|
4
4
|
import { $GlobalFallback } from '../vm/operations/index.js';
|
|
5
|
-
import type { VmContext, VmValue } from '../vm/index.js';
|
|
6
5
|
import { defineProperty, isFinite } from '../helpers/utils.js';
|
|
7
6
|
|
|
8
7
|
const REG_NUMBER_FULL = /^(?:[+-])?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
|
|
@@ -82,11 +81,11 @@ function nil(): () => null {
|
|
|
82
81
|
}
|
|
83
82
|
|
|
84
83
|
/** 构造返回全局变量的函数 */
|
|
85
|
-
function globalVariable(id: string):
|
|
86
|
-
const f = (global
|
|
84
|
+
function globalVariable(id: string): VmScriptLike {
|
|
85
|
+
const f: VmScriptLike = (global) => (global ?? $GlobalFallback()).get(id);
|
|
87
86
|
defineProperty(f, 'toString', {
|
|
88
87
|
value: () => {
|
|
89
|
-
return `(global
|
|
88
|
+
return `(global) => (global ?? $GlobalFallback()).get(${JSON.stringify(id)});`;
|
|
90
89
|
},
|
|
91
90
|
writable: false,
|
|
92
91
|
enumerable: false,
|
|
@@ -98,27 +97,26 @@ function globalVariable(id: string): (global: VmContext | undefined) => VmValue
|
|
|
98
97
|
/**
|
|
99
98
|
* 对短代码进行编译
|
|
100
99
|
*/
|
|
101
|
-
function compileScriptFast(code: string
|
|
100
|
+
function compileScriptFast(code: string): VmScript | undefined {
|
|
102
101
|
if (code.length > FAST_SCRIPT_MAX_LEN) return undefined; // 超过长度限制,直接返回 undefined
|
|
103
|
-
const mode = options.input_mode ?? 'Script';
|
|
104
102
|
const trimmedCode = code.trim();
|
|
105
103
|
if (!trimmedCode) {
|
|
106
|
-
return wrapScript(code,
|
|
104
|
+
return wrapScript(code, 'Script', nil());
|
|
107
105
|
}
|
|
108
106
|
switch (trimmedCode) {
|
|
109
107
|
case 'nil':
|
|
110
|
-
return wrapScript(code,
|
|
108
|
+
return wrapScript(code, 'Script', nil());
|
|
111
109
|
case 'true':
|
|
112
|
-
return wrapScript(code,
|
|
110
|
+
return wrapScript(code, 'Script', constantBoolean(true));
|
|
113
111
|
case 'false':
|
|
114
|
-
return wrapScript(code,
|
|
112
|
+
return wrapScript(code, 'Script', constantBoolean(false));
|
|
115
113
|
case 'nan':
|
|
116
|
-
return wrapScript(code,
|
|
114
|
+
return wrapScript(code, 'Script', nan());
|
|
117
115
|
case 'inf':
|
|
118
116
|
case '+inf':
|
|
119
|
-
return wrapScript(code,
|
|
117
|
+
return wrapScript(code, 'Script', posInf());
|
|
120
118
|
case '-inf':
|
|
121
|
-
return wrapScript(code,
|
|
119
|
+
return wrapScript(code, 'Script', negInf());
|
|
122
120
|
}
|
|
123
121
|
if (REG_IDENTIFIER_FAST.test(trimmedCode)) {
|
|
124
122
|
// 直接返回标识符
|
|
@@ -126,13 +124,13 @@ function compileScriptFast(code: string, options: TranspileOptions): VmScript |
|
|
|
126
124
|
if (isKeyword(id)) {
|
|
127
125
|
return undefined; // 关键字不处理
|
|
128
126
|
}
|
|
129
|
-
return wrapScript(code,
|
|
127
|
+
return wrapScript(code, 'Script', globalVariable(id));
|
|
130
128
|
}
|
|
131
129
|
if (REG_NUMBER_FULL.test(trimmedCode)) {
|
|
132
130
|
const num = Number(trimmedCode);
|
|
133
131
|
if (!isFinite(num)) return undefined;
|
|
134
132
|
// 直接返回数字
|
|
135
|
-
return wrapScript(code,
|
|
133
|
+
return wrapScript(code, 'Script', constantFiniteNumber(num));
|
|
136
134
|
}
|
|
137
135
|
return undefined;
|
|
138
136
|
}
|
|
@@ -142,13 +140,12 @@ const FAST_TEMPLATE_MAX_LEN = 1024;
|
|
|
142
140
|
/**
|
|
143
141
|
* 对短代码进行编译
|
|
144
142
|
*/
|
|
145
|
-
function compileTemplateFast(code: string
|
|
143
|
+
function compileTemplateFast(code: string): VmScript | undefined {
|
|
146
144
|
if (code.length > FAST_TEMPLATE_MAX_LEN) return undefined; // 超过长度限制,直接返回 undefined
|
|
147
145
|
|
|
148
146
|
if (!code.includes('$')) {
|
|
149
|
-
const mode = options.input_mode ?? 'Template';
|
|
150
147
|
// 不包含插值的模板
|
|
151
|
-
return wrapScript(code,
|
|
148
|
+
return wrapScript(code, 'Template', constantString(code));
|
|
152
149
|
}
|
|
153
150
|
return undefined;
|
|
154
151
|
}
|
|
@@ -158,5 +155,5 @@ function compileTemplateFast(code: string, options: TranspileOptions): VmScript
|
|
|
158
155
|
*/
|
|
159
156
|
export function compileFast(code: string, options: TranspileOptions): VmScript | undefined {
|
|
160
157
|
if (options.sourceMap) return undefined; // 不支持源映射
|
|
161
|
-
return (options.input_mode === 'Template' ? compileTemplateFast : compileScriptFast)(code
|
|
158
|
+
return (options.input_mode === 'Template' ? compileTemplateFast : compileScriptFast)(code);
|
|
162
159
|
}
|
|
@@ -5,7 +5,7 @@ import type { VmValue, VmContext } from '../vm/types/index.js';
|
|
|
5
5
|
import type { InputMode, ScriptInput } from './types.js';
|
|
6
6
|
|
|
7
7
|
/** Mirascript 脚本 */
|
|
8
|
-
export type VmScriptLike = (global?: VmContext) => VmValue;
|
|
8
|
+
export type VmScriptLike = (global?: VmContext | null) => VmValue;
|
|
9
9
|
|
|
10
10
|
/** Mirascript 脚本 */
|
|
11
11
|
export type VmScript = VmScriptLike & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SCRIPT_PREFIX = `((global
|
|
1
|
+
export const SCRIPT_PREFIX = `((global) => { global ??= $GlobalFallback(); try { $CpEnter();`;
|
|
@@ -69,21 +69,22 @@ export const to_datetime = VmLib(
|
|
|
69
69
|
};
|
|
70
70
|
},
|
|
71
71
|
{
|
|
72
|
-
summary: '将数据转换为
|
|
72
|
+
summary: '将数据转换为 DateTime 记录',
|
|
73
73
|
params: {
|
|
74
74
|
datetime: '要转换的数据,默认为当前时间',
|
|
75
75
|
offset: '时区偏移量(单位:小时),默认为 0',
|
|
76
76
|
fallback: '转换失败时的返回值',
|
|
77
77
|
},
|
|
78
78
|
paramsType: { datetime: 'number | string', offset: 'number', fallback: 'any' },
|
|
79
|
-
returnsType: '
|
|
79
|
+
returnsType: 'DateTime | type(fallback)',
|
|
80
80
|
examples: [
|
|
81
81
|
`
|
|
82
82
|
to_datetime(0)
|
|
83
83
|
// (
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
//
|
|
84
|
+
// year: 1970, month: 1, day: 1,
|
|
85
|
+
// hour: 0, minute: 0, second: 0,
|
|
86
|
+
// millisecond: 0,
|
|
87
|
+
// dayOfWeek: 4, offset: 0
|
|
87
88
|
// )
|
|
88
89
|
`.trim(),
|
|
89
90
|
],
|
|
@@ -1,24 +1,47 @@
|
|
|
1
1
|
import { VmError } from '../../helpers/error.js';
|
|
2
2
|
import { display } from '../../helpers/serialize.js';
|
|
3
3
|
import { isVmFunction, isVmExtern, isVmConst } from '../../helpers/types.js';
|
|
4
|
-
import type { VmAny, VmArray, VmValue } from '../types/index.js';
|
|
4
|
+
import type { VmExtern, VmFunction, VmAny, VmArray, VmValue } from '../types/index.js';
|
|
5
5
|
import { $AssertInit } from './common.js';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
/** 调用返回类型 */
|
|
8
|
+
type CallReturn<T extends VmValue> =
|
|
9
|
+
T extends VmFunction<infer F>
|
|
10
|
+
? F extends (...args: readonly VmAny[]) => infer R
|
|
11
|
+
? // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
|
12
|
+
R extends void | undefined
|
|
13
|
+
? null
|
|
14
|
+
: R
|
|
15
|
+
: VmValue
|
|
16
|
+
: T extends VmExtern<infer E>
|
|
17
|
+
? E extends (...args: readonly VmAny[]) => infer R
|
|
18
|
+
? // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
|
19
|
+
R extends void | undefined
|
|
20
|
+
? null
|
|
21
|
+
: R extends VmValue
|
|
22
|
+
? R
|
|
23
|
+
: R extends object
|
|
24
|
+
? VmExtern<R>
|
|
25
|
+
: VmValue
|
|
26
|
+
: VmValue
|
|
27
|
+
: VmValue;
|
|
28
|
+
|
|
29
|
+
/** 调用函数 */
|
|
30
|
+
export function $Call<T extends VmValue, A extends readonly VmValue[]>(func: T, args: A): CallReturn<T> {
|
|
8
31
|
for (const a of args) {
|
|
9
32
|
$AssertInit(a);
|
|
10
33
|
}
|
|
11
34
|
if (isVmExtern(func)) {
|
|
12
|
-
return func.call(args as readonly VmValue[]) ?? null
|
|
35
|
+
return (func.call(args as readonly VmValue[]) ?? null) as CallReturn<T>;
|
|
13
36
|
}
|
|
14
37
|
if (isVmFunction(func)) {
|
|
15
|
-
return func(...(args as readonly VmValue[])) ?? null
|
|
38
|
+
return (func(...(args as readonly VmValue[])) ?? null) as CallReturn<T>;
|
|
16
39
|
}
|
|
17
40
|
throw new VmError(`Value is not callable: ${display(func)}`, null);
|
|
18
|
-
}
|
|
41
|
+
}
|
|
19
42
|
|
|
20
43
|
/** 过滤剩余参数数组 */
|
|
21
|
-
export
|
|
44
|
+
export function $VArgs(varags: VmAny[]): VmArray {
|
|
22
45
|
for (let i = 0, l = varags.length; i < l; i++) {
|
|
23
46
|
const el = varags[i];
|
|
24
47
|
if (!isVmConst(el)) {
|
|
@@ -26,4 +49,4 @@ export const $VArgs = (varags: VmAny[]): VmArray => {
|
|
|
26
49
|
}
|
|
27
50
|
}
|
|
28
51
|
return varags as VmArray;
|
|
29
|
-
}
|
|
52
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { VmError } from '../../helpers/error.js';
|
|
2
2
|
import type { VmAny, VmValue } from '../types/index.js';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/** 断言值已初始化 */
|
|
5
|
+
export function $AssertInit(value: VmAny): asserts value is VmValue {
|
|
5
6
|
if (value === undefined) throw new VmError(`Uninitialized value`, null);
|
|
6
|
-
}
|
|
7
|
+
}
|
|
@@ -11,7 +11,8 @@ import { $ToString } from './convert.js';
|
|
|
11
11
|
const { trunc } = Math;
|
|
12
12
|
const { at } = Array.prototype;
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
/** 检查值是否在可迭代对象中 */
|
|
15
|
+
export function $In(value: VmAny, iterable: VmAny): boolean {
|
|
15
16
|
$AssertInit(value);
|
|
16
17
|
$AssertInit(iterable);
|
|
17
18
|
if (iterable == null) return false;
|
|
@@ -31,16 +32,20 @@ export const $In = (value: VmAny, iterable: VmAny): boolean => {
|
|
|
31
32
|
const key = toString(value, undefined);
|
|
32
33
|
if (isVmWrapper(iterable)) return iterable.has(key);
|
|
33
34
|
return hasOwnEnumerable(iterable satisfies VmRecord, key);
|
|
34
|
-
}
|
|
35
|
-
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** 获取值的长度 */
|
|
38
|
+
export function $Length(value: VmAny): number {
|
|
36
39
|
$AssertInit(value);
|
|
37
40
|
if (isVmArray(value)) return value.length;
|
|
38
41
|
if (isVmRecord(value)) return keys(value).length;
|
|
39
42
|
if (isVmWrapper(value)) return value.keys().length;
|
|
40
43
|
|
|
41
44
|
throw new VmError(`Value has no length: ${display(value)}`, 0);
|
|
42
|
-
}
|
|
43
|
-
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** 删除记录中的指定字段 */
|
|
48
|
+
export function $Omit(value: VmAny, omitted: ReadonlyArray<number | string>): VmRecord {
|
|
44
49
|
$AssertInit(value);
|
|
45
50
|
if (value == null || !isVmRecord(value)) return {};
|
|
46
51
|
const result: Record<string, VmConst> = {};
|
|
@@ -53,8 +58,10 @@ export const $Omit = (value: VmAny, omitted: ReadonlyArray<number | string>): Vm
|
|
|
53
58
|
}
|
|
54
59
|
}
|
|
55
60
|
return result;
|
|
56
|
-
}
|
|
57
|
-
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** 选择记录中的指定字段 */
|
|
64
|
+
export function $Pick(value: VmAny, picked: ReadonlyArray<number | string>): VmRecord {
|
|
58
65
|
$AssertInit(value);
|
|
59
66
|
if (value == null || !isVmRecord(value)) return {};
|
|
60
67
|
const result: Record<string, VmConst> = {};
|
|
@@ -65,15 +72,17 @@ export const $Pick = (value: VmAny, picked: ReadonlyArray<number | string>): VmR
|
|
|
65
72
|
}
|
|
66
73
|
}
|
|
67
74
|
return result;
|
|
68
|
-
}
|
|
69
|
-
|
|
75
|
+
}
|
|
76
|
+
/** 检查是否拥有字段 */
|
|
77
|
+
export function $Has(obj: VmAny, key: VmAny): boolean {
|
|
70
78
|
$AssertInit(obj);
|
|
71
79
|
const pk = $ToString(key);
|
|
72
80
|
if (obj == null || typeof obj != 'object') return false;
|
|
73
81
|
if (isVmWrapper(obj)) return obj.has(pk);
|
|
74
82
|
return hasOwnEnumerable(obj, pk);
|
|
75
|
-
}
|
|
76
|
-
|
|
83
|
+
}
|
|
84
|
+
/** 获取字段 */
|
|
85
|
+
export function $Get(obj: VmAny, key: VmAny): VmValue {
|
|
77
86
|
$AssertInit(obj);
|
|
78
87
|
if (isVmArray(obj)) {
|
|
79
88
|
$AssertInit(key);
|
|
@@ -86,24 +95,26 @@ export const $Get = (obj: VmAny, key: VmAny): VmValue => {
|
|
|
86
95
|
if (isVmWrapper(obj)) return obj.get(pk) ?? null;
|
|
87
96
|
if (!hasOwnEnumerable(obj, pk)) return null;
|
|
88
97
|
return obj[pk] ?? null;
|
|
89
|
-
}
|
|
90
|
-
|
|
98
|
+
}
|
|
99
|
+
/** 设置字段 */
|
|
100
|
+
export function $Set(obj: VmAny, key: VmAny, value: VmAny): void {
|
|
91
101
|
$AssertInit(obj);
|
|
92
102
|
$AssertInit(value);
|
|
93
103
|
const pk = $ToString(key);
|
|
94
104
|
if (obj == null) return;
|
|
95
105
|
if (!isVmExtern(obj)) throw new VmError(`Expected extern, got ${display(obj)}`, undefined);
|
|
96
106
|
obj.set(pk, value);
|
|
97
|
-
}
|
|
98
|
-
|
|
107
|
+
}
|
|
108
|
+
/** 获取可迭代对象 */
|
|
109
|
+
export function $Iterable(value: VmAny): Iterable<VmValue | undefined> {
|
|
99
110
|
$AssertInit(value);
|
|
100
111
|
if (isVmWrapper(value)) return value.keys();
|
|
101
112
|
if (isVmArray(value)) return value;
|
|
102
113
|
if (value != null && typeof value == 'object') return keys(value);
|
|
103
114
|
throw new VmError(`Value is not iterable: ${display(value)}`, isVmFunction(value) ? [] : [value]);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export
|
|
115
|
+
}
|
|
116
|
+
/** 展开记录 */
|
|
117
|
+
export function $RecordSpread(record: VmAny): VmRecord | null {
|
|
107
118
|
$AssertInit(record);
|
|
108
119
|
if (record == null || isVmRecord(record)) return record;
|
|
109
120
|
if (isVmArray(record)) {
|
|
@@ -127,9 +138,10 @@ export const $RecordSpread = (record: VmAny): VmRecord | null => {
|
|
|
127
138
|
return result;
|
|
128
139
|
}
|
|
129
140
|
throw new VmError(`Expected record, array, extern or nil, got ${display(record)}`, null);
|
|
130
|
-
}
|
|
141
|
+
}
|
|
131
142
|
|
|
132
|
-
|
|
143
|
+
/** 展开数组 */
|
|
144
|
+
export function $ArraySpread(array: VmAny): Iterable<VmConst | undefined> {
|
|
133
145
|
$AssertInit(array);
|
|
134
146
|
if (array == null) return [];
|
|
135
147
|
if (isVmArray(array)) return array;
|
|
@@ -146,4 +158,4 @@ export const $ArraySpread = (array: VmAny): Iterable<VmConst | undefined> => {
|
|
|
146
158
|
return result;
|
|
147
159
|
}
|
|
148
160
|
throw new VmError(`Expected array, iterable extern or nil, got ${display(array)}`, []);
|
|
149
|
-
}
|
|
161
|
+
}
|
|
@@ -2,22 +2,26 @@ import { toNumber, toString, toBoolean, toFormat } from '../../helpers/convert/i
|
|
|
2
2
|
import type { VmAny } from '../types/index.js';
|
|
3
3
|
import { $AssertInit } from './common.js';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/** 转换为布尔值 */
|
|
6
|
+
export function $ToBoolean(value: VmAny): boolean {
|
|
6
7
|
if (typeof value == 'boolean') return value;
|
|
7
8
|
$AssertInit(value);
|
|
8
9
|
return toBoolean(value, undefined);
|
|
9
|
-
}
|
|
10
|
-
|
|
10
|
+
}
|
|
11
|
+
/** 转换为字符串 */
|
|
12
|
+
export function $ToString(value: VmAny): string {
|
|
11
13
|
if (typeof value == 'string') return value;
|
|
12
14
|
$AssertInit(value);
|
|
13
15
|
return toString(value, undefined);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
+
}
|
|
17
|
+
/** 转换为数字 */
|
|
18
|
+
export function $ToNumber(value: VmAny): number {
|
|
16
19
|
if (typeof value == 'number') return value;
|
|
17
20
|
$AssertInit(value);
|
|
18
21
|
return toNumber(value, undefined);
|
|
19
|
-
}
|
|
20
|
-
|
|
22
|
+
}
|
|
23
|
+
/** 格式化值 */
|
|
24
|
+
export function $Format(value: VmAny, format: string | null): string {
|
|
21
25
|
$AssertInit(value);
|
|
22
26
|
return toFormat(value, format);
|
|
23
|
-
}
|
|
27
|
+
}
|
|
@@ -9,31 +9,31 @@ import { $AssertInit } from './common.js';
|
|
|
9
9
|
import { $ToNumber } from './convert.js';
|
|
10
10
|
|
|
11
11
|
/** 构造 record | array 元素 */
|
|
12
|
-
export
|
|
12
|
+
export function $El(value: VmAny): VmConst {
|
|
13
13
|
$AssertInit(value);
|
|
14
14
|
if (!isVmConst(value)) return null;
|
|
15
15
|
return value;
|
|
16
|
-
}
|
|
16
|
+
}
|
|
17
17
|
|
|
18
18
|
const EMPTY = create(null);
|
|
19
19
|
/** 构造 record 可选元素 */
|
|
20
|
-
export
|
|
20
|
+
export function $ElOpt(key: string, value: VmAny): VmConst {
|
|
21
21
|
$AssertInit(value);
|
|
22
22
|
if (value == null || !isVmConst(value)) return EMPTY;
|
|
23
23
|
return { __proto__: null, [key]: value };
|
|
24
|
-
}
|
|
24
|
+
}
|
|
25
25
|
|
|
26
26
|
/** 构造函数和函数表达式 */
|
|
27
|
-
export
|
|
27
|
+
export function $Fn<T extends VmFunctionLike>(name: string | null | undefined, fn: T): VmFunction<T> {
|
|
28
28
|
defineProperty(fn, 'name', { value: name || VM_FUNCTION_ANONYMOUS_NAME });
|
|
29
29
|
return VmFunction(fn, { isLib: false, injectCp: false });
|
|
30
|
-
}
|
|
30
|
+
}
|
|
31
31
|
|
|
32
32
|
/** 读取闭包上值 */
|
|
33
|
-
export
|
|
33
|
+
export function $Upvalue(value: VmAny): VmValue {
|
|
34
34
|
$AssertInit(value);
|
|
35
35
|
return value;
|
|
36
|
-
}
|
|
36
|
+
}
|
|
37
37
|
|
|
38
38
|
const assertArrayLength = (start: number, end: number) => {
|
|
39
39
|
if (end - start > VM_ARRAY_MAX_LENGTH) {
|
|
@@ -43,7 +43,8 @@ const assertArrayLength = (start: number, end: number) => {
|
|
|
43
43
|
const isEmptyRange = (start: number, end: number) => {
|
|
44
44
|
return !isFinite(start) || !isFinite(end) || start > end;
|
|
45
45
|
};
|
|
46
|
-
|
|
46
|
+
/** 构造范围数组 */
|
|
47
|
+
export function $ArrayRange(start: VmAny, end: VmAny): VmArray {
|
|
47
48
|
const s = $ToNumber(start);
|
|
48
49
|
const e = $ToNumber(end);
|
|
49
50
|
if (isEmptyRange(s, e)) return [];
|
|
@@ -53,8 +54,9 @@ export const $ArrayRange = (start: VmAny, end: VmAny): VmArray => {
|
|
|
53
54
|
arr.push(i);
|
|
54
55
|
}
|
|
55
56
|
return arr;
|
|
56
|
-
}
|
|
57
|
-
|
|
57
|
+
}
|
|
58
|
+
/** 构造范围数组(不包含结束值) */
|
|
59
|
+
export function $ArrayRangeExclusive(start: VmAny, end: VmAny): VmArray {
|
|
58
60
|
const s = $ToNumber(start);
|
|
59
61
|
const e = $ToNumber(end);
|
|
60
62
|
if (isEmptyRange(s, e)) return [];
|
|
@@ -64,7 +66,7 @@ export const $ArrayRangeExclusive = (start: VmAny, end: VmAny): VmArray => {
|
|
|
64
66
|
arr.push(i);
|
|
65
67
|
}
|
|
66
68
|
return arr;
|
|
67
|
-
}
|
|
69
|
+
}
|
|
68
70
|
|
|
69
71
|
/** 默认执行上下文 */
|
|
70
72
|
export function $GlobalFallback(): VmContext {
|