@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.
- package/dist/chunk-5FQWUJIY.js +766 -0
- package/dist/chunk-5FQWUJIY.js.map +6 -0
- package/dist/chunk-BTDGMWFK.js +202 -0
- package/dist/chunk-BTDGMWFK.js.map +6 -0
- package/dist/chunk-DCXIWIW5.js +3419 -0
- package/dist/chunk-DCXIWIW5.js.map +6 -0
- package/dist/chunk-RAPJ3XLV.js +10 -0
- package/dist/chunk-RAPJ3XLV.js.map +6 -0
- package/dist/cli/execute.d.ts +4 -0
- package/dist/cli/execute.d.ts.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +191 -0
- package/dist/cli/index.js.map +6 -0
- package/dist/cli/print.d.ts +4 -0
- package/dist/cli/print.d.ts.map +1 -0
- package/dist/compiler/compile-bytecode.d.ts +12 -0
- package/dist/compiler/compile-bytecode.d.ts.map +1 -0
- package/dist/compiler/compile-fast.d.ts +7 -0
- package/dist/compiler/compile-fast.d.ts.map +1 -0
- package/dist/compiler/create-script.d.ts +7 -0
- package/dist/compiler/create-script.d.ts.map +1 -0
- package/dist/compiler/diagnostic.d.ts +56 -0
- package/dist/compiler/diagnostic.d.ts.map +1 -0
- package/dist/compiler/emit.d.ts +4 -0
- package/dist/compiler/emit.d.ts.map +1 -0
- package/dist/compiler/index.d.ts +13 -0
- package/dist/compiler/index.d.ts.map +1 -0
- package/dist/compiler/types.d.ts +16 -0
- package/dist/compiler/types.d.ts.map +1 -0
- package/dist/compiler/worker-manager.d.ts +6 -0
- package/dist/compiler/worker-manager.d.ts.map +1 -0
- package/dist/compiler/worker.d.ts +6 -0
- package/dist/compiler/worker.d.ts.map +1 -0
- package/dist/compiler/worker.js +34 -0
- package/dist/compiler/worker.js.map +6 -0
- package/dist/helpers/constants.d.ts +3 -0
- package/dist/helpers/constants.d.ts.map +1 -0
- package/dist/helpers/serialize.d.ts +45 -0
- package/dist/helpers/serialize.d.ts.map +1 -0
- package/dist/helpers/utils.d.ts +36 -0
- package/dist/helpers/utils.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +6 -0
- package/dist/subtle.d.ts +7 -0
- package/dist/subtle.d.ts.map +1 -0
- package/dist/subtle.js +30 -0
- package/dist/subtle.js.map +6 -0
- package/dist/vm/env.d.ts +3 -0
- package/dist/vm/env.d.ts.map +1 -0
- package/dist/vm/error.d.ts +11 -0
- package/dist/vm/error.d.ts.map +1 -0
- package/dist/vm/helpers.d.ts +21 -0
- package/dist/vm/helpers.d.ts.map +1 -0
- package/dist/vm/index.d.ts +5 -0
- package/dist/vm/index.d.ts.map +1 -0
- package/dist/vm/lib/_helpers.d.ts +35 -0
- package/dist/vm/lib/_helpers.d.ts.map +1 -0
- package/dist/vm/lib/_loader.d.ts +16 -0
- package/dist/vm/lib/_loader.d.ts.map +1 -0
- package/dist/vm/lib/global/bit.d.ts +9 -0
- package/dist/vm/lib/global/bit.d.ts.map +1 -0
- package/dist/vm/lib/global/debug.d.ts +5 -0
- package/dist/vm/lib/global/debug.d.ts.map +1 -0
- package/dist/vm/lib/global/index.d.ts +10 -0
- package/dist/vm/lib/global/index.d.ts.map +1 -0
- package/dist/vm/lib/global/json.d.ts +4 -0
- package/dist/vm/lib/global/json.d.ts.map +1 -0
- package/dist/vm/lib/global/math-additional.d.ts +3 -0
- package/dist/vm/lib/global/math-additional.d.ts.map +1 -0
- package/dist/vm/lib/global/math-arr.d.ts +8 -0
- package/dist/vm/lib/global/math-arr.d.ts.map +1 -0
- package/dist/vm/lib/global/math-const.d.ts +3 -0
- package/dist/vm/lib/global/math-const.d.ts.map +1 -0
- package/dist/vm/lib/global/math-unary.d.ts +29 -0
- package/dist/vm/lib/global/math-unary.d.ts.map +1 -0
- package/dist/vm/lib/global/math.d.ts +9 -0
- package/dist/vm/lib/global/math.d.ts.map +1 -0
- package/dist/vm/lib/global/mod/index.d.ts +3 -0
- package/dist/vm/lib/global/mod/index.d.ts.map +1 -0
- package/dist/vm/lib/global/mod/matrix.d.ts +16 -0
- package/dist/vm/lib/global/mod/matrix.d.ts.map +1 -0
- package/dist/vm/lib/global/sequence/all-any.d.ts +4 -0
- package/dist/vm/lib/global/sequence/all-any.d.ts.map +1 -0
- package/dist/vm/lib/global/sequence/entries.d.ts +12 -0
- package/dist/vm/lib/global/sequence/entries.d.ts.map +1 -0
- package/dist/vm/lib/global/sequence/find.d.ts +10 -0
- package/dist/vm/lib/global/sequence/find.d.ts.map +1 -0
- package/dist/vm/lib/global/sequence/flatten.d.ts +3 -0
- package/dist/vm/lib/global/sequence/flatten.d.ts.map +1 -0
- package/dist/vm/lib/global/sequence/index.d.ts +12 -0
- package/dist/vm/lib/global/sequence/index.d.ts.map +1 -0
- package/dist/vm/lib/global/sequence/len.d.ts +3 -0
- package/dist/vm/lib/global/sequence/len.d.ts.map +1 -0
- package/dist/vm/lib/global/sequence/map-filter.d.ts +9 -0
- package/dist/vm/lib/global/sequence/map-filter.d.ts.map +1 -0
- package/dist/vm/lib/global/sequence/repeat.d.ts +4 -0
- package/dist/vm/lib/global/sequence/repeat.d.ts.map +1 -0
- package/dist/vm/lib/global/sequence/reverse.d.ts +3 -0
- package/dist/vm/lib/global/sequence/reverse.d.ts.map +1 -0
- package/dist/vm/lib/global/sequence/sort.d.ts +5 -0
- package/dist/vm/lib/global/sequence/sort.d.ts.map +1 -0
- package/dist/vm/lib/global/sequence/with.d.ts +5 -0
- package/dist/vm/lib/global/sequence/with.d.ts.map +1 -0
- package/dist/vm/lib/global/sequence/zip.d.ts +4 -0
- package/dist/vm/lib/global/sequence/zip.d.ts.map +1 -0
- package/dist/vm/lib/global/string.d.ts +12 -0
- package/dist/vm/lib/global/string.d.ts.map +1 -0
- package/dist/vm/lib/global/time.d.ts +15 -0
- package/dist/vm/lib/global/time.d.ts.map +1 -0
- package/dist/vm/lib/global/to-primitive.d.ts +6 -0
- package/dist/vm/lib/global/to-primitive.d.ts.map +1 -0
- package/dist/vm/operations.d.ts +49 -0
- package/dist/vm/operations.d.ts.map +1 -0
- package/dist/vm/types/checker.d.ts +30 -0
- package/dist/vm/types/checker.d.ts.map +1 -0
- package/dist/vm/types/context.d.ts +43 -0
- package/dist/vm/types/context.d.ts.map +1 -0
- package/dist/vm/types/extern.d.ts +32 -0
- package/dist/vm/types/extern.d.ts.map +1 -0
- package/dist/vm/types/function.d.ts +49 -0
- package/dist/vm/types/function.d.ts.map +1 -0
- package/dist/vm/types/index.d.ts +75 -0
- package/dist/vm/types/index.d.ts.map +1 -0
- package/dist/vm/types/module.d.ts +25 -0
- package/dist/vm/types/module.d.ts.map +1 -0
- package/dist/vm/types/script.d.ts +14 -0
- package/dist/vm/types/script.d.ts.map +1 -0
- package/dist/vm/types/wrapper.d.ts +25 -0
- package/dist/vm/types/wrapper.d.ts.map +1 -0
- package/package.json +55 -0
- package/src/cli/execute.ts +32 -0
- package/src/cli/index.ts +73 -0
- package/src/cli/print.ts +41 -0
- package/src/compiler/compile-bytecode.ts +65 -0
- package/src/compiler/compile-fast.ts +81 -0
- package/src/compiler/create-script.ts +34 -0
- package/src/compiler/diagnostic.ts +175 -0
- package/src/compiler/emit.ts +764 -0
- package/src/compiler/index.ts +67 -0
- package/src/compiler/types.ts +16 -0
- package/src/compiler/worker-manager.ts +60 -0
- package/src/compiler/worker.ts +37 -0
- package/src/helpers/constants.ts +3 -0
- package/src/helpers/serialize.ts +280 -0
- package/src/helpers/utils.ts +16 -0
- package/src/index.ts +3 -0
- package/src/subtle.ts +6 -0
- package/src/vm/env.ts +16 -0
- package/src/vm/error.ts +22 -0
- package/src/vm/helpers.ts +121 -0
- package/src/vm/index.ts +5 -0
- package/src/vm/lib/_helpers.ts +215 -0
- package/src/vm/lib/_loader.ts +51 -0
- package/src/vm/lib/global/bit.ts +93 -0
- package/src/vm/lib/global/debug.ts +36 -0
- package/src/vm/lib/global/index.ts +9 -0
- package/src/vm/lib/global/json.ts +45 -0
- package/src/vm/lib/global/math-additional.ts +71 -0
- package/src/vm/lib/global/math-arr.ts +62 -0
- package/src/vm/lib/global/math-const.ts +2 -0
- package/src/vm/lib/global/math-unary.ts +171 -0
- package/src/vm/lib/global/math.ts +27 -0
- package/src/vm/lib/global/mod/index.ts +4 -0
- package/src/vm/lib/global/mod/matrix.ts +579 -0
- package/src/vm/lib/global/sequence/all-any.ts +73 -0
- package/src/vm/lib/global/sequence/entries.ts +67 -0
- package/src/vm/lib/global/sequence/find.ts +49 -0
- package/src/vm/lib/global/sequence/flatten.ts +16 -0
- package/src/vm/lib/global/sequence/index.ts +11 -0
- package/src/vm/lib/global/sequence/len.ts +15 -0
- package/src/vm/lib/global/sequence/map-filter.ts +82 -0
- package/src/vm/lib/global/sequence/repeat.ts +28 -0
- package/src/vm/lib/global/sequence/reverse.ts +17 -0
- package/src/vm/lib/global/sequence/sort.ts +88 -0
- package/src/vm/lib/global/sequence/with.ts +43 -0
- package/src/vm/lib/global/sequence/zip.ts +40 -0
- package/src/vm/lib/global/string.ts +149 -0
- package/src/vm/lib/global/time.ts +73 -0
- package/src/vm/lib/global/to-primitive.ts +58 -0
- package/src/vm/operations.ts +497 -0
- package/src/vm/types/checker.ts +164 -0
- package/src/vm/types/context.ts +161 -0
- package/src/vm/types/extern.ts +166 -0
- package/src/vm/types/function.ts +136 -0
- package/src/vm/types/index.ts +124 -0
- package/src/vm/types/module.ts +40 -0
- package/src/vm/types/script.ts +18 -0
- package/src/vm/types/wrapper.ts +28 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { isVmArray, isVmRecord, type VmConst } from '../../../types/index.js';
|
|
2
|
+
import { VmLib, expectArrayOrRecord, expectCompound } from '../../_helpers.js';
|
|
3
|
+
import { keys as _keys, values as _values, entries as _entries } from '../../../../helpers/utils.js';
|
|
4
|
+
|
|
5
|
+
export const keys = VmLib(
|
|
6
|
+
(data) => {
|
|
7
|
+
expectCompound('data', data, []);
|
|
8
|
+
if (isVmArray(data)) {
|
|
9
|
+
const arr: number[] = [];
|
|
10
|
+
const len = data.length;
|
|
11
|
+
for (let i = 0; i < len; i++) {
|
|
12
|
+
arr.push(i);
|
|
13
|
+
}
|
|
14
|
+
return arr;
|
|
15
|
+
}
|
|
16
|
+
if (isVmRecord(data)) {
|
|
17
|
+
return _keys(data);
|
|
18
|
+
}
|
|
19
|
+
return data.keys();
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
summary: '返回数组、记录、外部对象或模块的键列表',
|
|
23
|
+
params: { data: '要获取键的数组、记录、外部对象或模块' },
|
|
24
|
+
paramsType: { data: 'array | record | extern | module' },
|
|
25
|
+
returnsType: '(string | number)[]',
|
|
26
|
+
examples: ['keys([10, 20]) // [0, 1]', 'keys((10, 20)) // ["0", "1"]'],
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export const values = VmLib(
|
|
31
|
+
(data) => {
|
|
32
|
+
expectArrayOrRecord('data', data, []);
|
|
33
|
+
if (isVmArray(data)) {
|
|
34
|
+
return data;
|
|
35
|
+
}
|
|
36
|
+
return _values(data);
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
summary: '返回数组或记录的值列表',
|
|
40
|
+
params: { data: '要获取值的数组或记录' },
|
|
41
|
+
paramsType: { data: 'array | record' },
|
|
42
|
+
returnsType: 'array',
|
|
43
|
+
examples: ['values((a: 1, b: 2)) // [1, 2]'],
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
export const entries = VmLib(
|
|
48
|
+
(data) => {
|
|
49
|
+
expectArrayOrRecord('data', data, []);
|
|
50
|
+
if (isVmArray(data)) {
|
|
51
|
+
const arr: Array<{ 0: number; 1: VmConst }> = [];
|
|
52
|
+
const len = data.length;
|
|
53
|
+
for (let i = 0; i < len; i++) {
|
|
54
|
+
arr.push({ 0: i, 1: data[i] ?? null });
|
|
55
|
+
}
|
|
56
|
+
return arr;
|
|
57
|
+
}
|
|
58
|
+
return _entries(data).map(([key, value]) => ({ 0: key, 1: value ?? null }));
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
summary: '返回数组或记录的键值对列表',
|
|
62
|
+
params: { data: '要获取键值对的数组或记录' },
|
|
63
|
+
paramsType: { data: 'array | record' },
|
|
64
|
+
returnsType: '(string | number, any)[]',
|
|
65
|
+
examples: ['entries([1]) // [(0, 1)]', 'entries((a: 1)) // [("a", 1)]'],
|
|
66
|
+
},
|
|
67
|
+
);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { entries } from '../../../../helpers/utils.js';
|
|
2
|
+
import { Cp } from '../../../helpers.js';
|
|
3
|
+
import { $Call, $ToBoolean } from '../../../operations.js';
|
|
4
|
+
import { type VmValue, isVmArray } from '../../../types/index.js';
|
|
5
|
+
import { VmLib, expectArrayOrRecord, expectCallable } from '../../_helpers.js';
|
|
6
|
+
|
|
7
|
+
export const find = VmLib(
|
|
8
|
+
(data, predicate) => {
|
|
9
|
+
expectArrayOrRecord('data', data, null);
|
|
10
|
+
expectCallable('predicate', predicate, data);
|
|
11
|
+
const p = (value: VmValue, key: string | number, data: VmValue) => {
|
|
12
|
+
const ret = $Call(predicate, [value, key, data]);
|
|
13
|
+
return $ToBoolean(ret);
|
|
14
|
+
};
|
|
15
|
+
if (isVmArray(data)) {
|
|
16
|
+
const { length } = data;
|
|
17
|
+
for (let i = 0; i < length; i++) {
|
|
18
|
+
Cp();
|
|
19
|
+
const value = data[i] ?? null;
|
|
20
|
+
const ret = p(value, i, data);
|
|
21
|
+
if (!ret) continue;
|
|
22
|
+
return { 0: i, 1: value };
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
} else {
|
|
26
|
+
for (const [key, v] of entries(data)) {
|
|
27
|
+
Cp();
|
|
28
|
+
const value = v ?? null;
|
|
29
|
+
const ret = p(value, key, data);
|
|
30
|
+
if (!ret) continue;
|
|
31
|
+
return { 0: key, 1: value };
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
summary: '查找数组或记录中的键值对,返回第一个满足条件的键值对',
|
|
38
|
+
params: {
|
|
39
|
+
data: '查的数组或记录',
|
|
40
|
+
predicate: '用于测试每个键值对的函数,返回 true 或 false',
|
|
41
|
+
},
|
|
42
|
+
paramsType: {
|
|
43
|
+
data: 'array | record',
|
|
44
|
+
predicate: 'fn(value: any, key: number | string | nil, input: type(data)) -> boolean',
|
|
45
|
+
},
|
|
46
|
+
returnsType: '(string | number, any) | nil',
|
|
47
|
+
examples: ['find([3, 5, 8], fn (v) { v % 2 == 0 }) // (2, 8)'],
|
|
48
|
+
},
|
|
49
|
+
);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { $ToNumber } from '../../../operations.js';
|
|
2
|
+
import { VmLib, expectArray } from '../../_helpers.js';
|
|
3
|
+
|
|
4
|
+
export const flatten = VmLib(
|
|
5
|
+
(data, depth = 1) => {
|
|
6
|
+
expectArray('data', data, data);
|
|
7
|
+
return data.flat($ToNumber(depth) as 1);
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
summary: '将数组扁平化',
|
|
11
|
+
params: { data: '要扁平化的数组', depth: '扁平化的深度,默认为 1' },
|
|
12
|
+
paramsType: { data: 'array', depth: 'number' },
|
|
13
|
+
returnsType: 'array',
|
|
14
|
+
examples: ['flatten([[1, 2], [3, [4]]], 2) // [1, 2, 3, 4]'],
|
|
15
|
+
},
|
|
16
|
+
);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './with.js';
|
|
2
|
+
export * from './entries.js';
|
|
3
|
+
export * from './len.js';
|
|
4
|
+
export * from './map-filter.js';
|
|
5
|
+
export * from './find.js';
|
|
6
|
+
export * from './flatten.js';
|
|
7
|
+
export * from './reverse.js';
|
|
8
|
+
export * from './zip.js';
|
|
9
|
+
export * from './all-any.js';
|
|
10
|
+
export * from './sort.js';
|
|
11
|
+
export * from './repeat.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { VmLib, expectArray } from '../../_helpers.js';
|
|
2
|
+
|
|
3
|
+
export const len = VmLib(
|
|
4
|
+
(arr) => {
|
|
5
|
+
expectArray('arr', arr, Number.NaN);
|
|
6
|
+
return arr.length;
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
summary: '返回数组的长度',
|
|
10
|
+
params: { arr: '要求长度的数组' },
|
|
11
|
+
paramsType: { arr: 'array' },
|
|
12
|
+
returnsType: 'number',
|
|
13
|
+
examples: ['len([1, 2, 3]) // 3'],
|
|
14
|
+
},
|
|
15
|
+
);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { $Call, $ToBoolean } from '../../../operations.js';
|
|
2
|
+
import { isVmConst, type VmAny, type VmValue } from '../../../types/index.js';
|
|
3
|
+
import { VmLib, expectCallable, expectConst, map as mapImpl } from '../../_helpers.js';
|
|
4
|
+
|
|
5
|
+
export * from './with.js';
|
|
6
|
+
export * from './entries.js';
|
|
7
|
+
export * from './len.js';
|
|
8
|
+
|
|
9
|
+
/** map 和 filter 的实现 */
|
|
10
|
+
function mapImplWrapped(
|
|
11
|
+
data: VmAny,
|
|
12
|
+
fnName: string,
|
|
13
|
+
fn: VmAny,
|
|
14
|
+
mapper: (fn: VmValue, value: VmValue, index: number | string | null, data: VmValue) => VmValue | undefined,
|
|
15
|
+
): VmValue {
|
|
16
|
+
expectConst('data', data, null);
|
|
17
|
+
expectCallable(fnName, fn, data);
|
|
18
|
+
return mapImpl(data, (value, index, data) => {
|
|
19
|
+
const ret = mapper(fn, value, index, data);
|
|
20
|
+
if (ret === undefined || isVmConst(ret)) return ret;
|
|
21
|
+
return null;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const map = VmLib(
|
|
26
|
+
(data, f) => mapImplWrapped(data, 'f', f, (fn, value, key, data) => $Call(fn, [value, key, data])),
|
|
27
|
+
{
|
|
28
|
+
summary: '对数组或记录中的每个元素应用函数,并返回结果',
|
|
29
|
+
params: {
|
|
30
|
+
data: '要映射的数组或记录',
|
|
31
|
+
f: '应用于每个元素的函数',
|
|
32
|
+
},
|
|
33
|
+
paramsType: {
|
|
34
|
+
data: 'array | record',
|
|
35
|
+
f: 'fn(value: any, key: number | string | nil, input: type(data)) -> any',
|
|
36
|
+
},
|
|
37
|
+
returnsType: 'type(data)',
|
|
38
|
+
examples: ['map([1, 2, 3], fn (v) { v * v }) // [1, 4, 9]'],
|
|
39
|
+
},
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
export const filter = VmLib(
|
|
43
|
+
(data, predicate) =>
|
|
44
|
+
mapImplWrapped(data, 'predicate', predicate, (fn, value, key, data) => {
|
|
45
|
+
const ret = $Call(fn, [value, key, data]);
|
|
46
|
+
return $ToBoolean(ret) ? value : undefined;
|
|
47
|
+
}),
|
|
48
|
+
{
|
|
49
|
+
summary: '过滤数组或记录中的元素,返回满足条件的元素',
|
|
50
|
+
params: {
|
|
51
|
+
data: '要过滤的数组或记录',
|
|
52
|
+
predicate: '用于测试每个元素的函数,返回 true 或 false',
|
|
53
|
+
},
|
|
54
|
+
paramsType: {
|
|
55
|
+
data: 'array | record',
|
|
56
|
+
predicate: 'fn(value: any, key: number | string | nil, input: type(data)) -> boolean',
|
|
57
|
+
},
|
|
58
|
+
returnsType: 'type(data)',
|
|
59
|
+
examples: ['filter([1, 2, 3, 4], fn (v) { v % 2 == 0 }) // [2, 4]'],
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
export const filter_map = VmLib(
|
|
64
|
+
(data, f) =>
|
|
65
|
+
mapImplWrapped(data, 'f', f, (fn, value, key, data) => {
|
|
66
|
+
const ret = $Call(fn, [value, key, data]);
|
|
67
|
+
return ret ?? undefined;
|
|
68
|
+
}),
|
|
69
|
+
{
|
|
70
|
+
summary: '对数组或记录中的每个元素应用函数,并返回非 nil 的结果',
|
|
71
|
+
params: {
|
|
72
|
+
data: '要映射的数组或记录',
|
|
73
|
+
f: '应用于每个元素的函数,返回 nil 或非 nil 的值',
|
|
74
|
+
},
|
|
75
|
+
paramsType: {
|
|
76
|
+
data: 'array | record',
|
|
77
|
+
f: 'fn(value: any, key: number | string | nil, input: type(data)) -> any | nil',
|
|
78
|
+
},
|
|
79
|
+
returnsType: 'type(data)',
|
|
80
|
+
examples: ['filter_map([1, 2, 3], fn (v) { if v % 2 == 0 { v * v } else { nil } }) // [4]'],
|
|
81
|
+
},
|
|
82
|
+
);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { $ToNumber } from '../../../operations.js';
|
|
2
|
+
import type { VmConst } from '../../../types/index.js';
|
|
3
|
+
import { arrayLen, expectConst, required, VmLib } from '../../_helpers.js';
|
|
4
|
+
|
|
5
|
+
export const repeat = VmLib(
|
|
6
|
+
(data, times) => {
|
|
7
|
+
expectConst('data', data, []);
|
|
8
|
+
required('times', times, []);
|
|
9
|
+
const n = arrayLen($ToNumber(times));
|
|
10
|
+
const result: VmConst[] = [];
|
|
11
|
+
result.length = n;
|
|
12
|
+
result.fill(data);
|
|
13
|
+
return result;
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
summary: '创建一个包含重复元素的数组',
|
|
17
|
+
params: {
|
|
18
|
+
data: '要重复的元素',
|
|
19
|
+
times: '重复的次数,必须是非负整数',
|
|
20
|
+
},
|
|
21
|
+
paramsType: {
|
|
22
|
+
data: 'any',
|
|
23
|
+
times: 'number',
|
|
24
|
+
},
|
|
25
|
+
returnsType: 'type(data)[]',
|
|
26
|
+
examples: ['repeat(0, 5) // [0, 0, 0, 0, 0]', 'repeat("a", 3) // ["a", "a", "a"]'],
|
|
27
|
+
},
|
|
28
|
+
);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { VmLib, expectArray } from '../../_helpers.js';
|
|
2
|
+
|
|
3
|
+
export const reverse = VmLib(
|
|
4
|
+
(arr) => {
|
|
5
|
+
expectArray('arr', arr, null);
|
|
6
|
+
const dup = [...arr];
|
|
7
|
+
dup.reverse();
|
|
8
|
+
return dup;
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
summary: '返回数组的反转副本',
|
|
12
|
+
params: { arr: '要反转的数组' },
|
|
13
|
+
paramsType: { arr: 'array' },
|
|
14
|
+
returnsType: 'array',
|
|
15
|
+
examples: ['reverse([1, 2, 3]) // [3, 2, 1]'],
|
|
16
|
+
},
|
|
17
|
+
);
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { $Call, $ToNumber } from '../../../operations.js';
|
|
2
|
+
import type { VmAny, VmConst, VmValue } from '../../../types/index.js';
|
|
3
|
+
import { VmLib, expectArray, expectCallable } from '../../_helpers.js';
|
|
4
|
+
|
|
5
|
+
/** 默认比较 */
|
|
6
|
+
function defaultCompare(a: VmValue, b: VmValue): number {
|
|
7
|
+
a ??= '';
|
|
8
|
+
b ??= '';
|
|
9
|
+
if (typeof a == 'string' && typeof b == 'string') {
|
|
10
|
+
if (a < b) return -1;
|
|
11
|
+
if (a > b) return 1;
|
|
12
|
+
return 0;
|
|
13
|
+
}
|
|
14
|
+
if (Object.is(a, b)) return 0;
|
|
15
|
+
const an = $ToNumber(a) || 0;
|
|
16
|
+
const bn = $ToNumber(b) || 0;
|
|
17
|
+
return an - bn;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** 获取比较函数 */
|
|
21
|
+
function cmp(comparator: VmAny, recovered: VmValue): typeof defaultCompare {
|
|
22
|
+
if (comparator == null) return defaultCompare;
|
|
23
|
+
expectCallable('comparator', comparator, recovered);
|
|
24
|
+
return (a: VmValue, b: VmValue) => {
|
|
25
|
+
const ret = $Call(comparator, [a, b]);
|
|
26
|
+
return $ToNumber(ret);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const sort = VmLib(
|
|
31
|
+
(data, comparator) => {
|
|
32
|
+
expectArray('data', data, null);
|
|
33
|
+
const compare = cmp(comparator, data);
|
|
34
|
+
const arr: VmConst[] = [];
|
|
35
|
+
for (const v of data) {
|
|
36
|
+
arr.push(v ?? null);
|
|
37
|
+
}
|
|
38
|
+
arr.sort(compare);
|
|
39
|
+
return arr;
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
summary: '对数组中的元素进行排序,并返回排序后的结果',
|
|
43
|
+
params: {
|
|
44
|
+
data: '要排序的数组',
|
|
45
|
+
comparator: '用于比较两个元素的函数,返回一个数字,表示它们的相对顺序,默认按升序排列',
|
|
46
|
+
},
|
|
47
|
+
paramsType: {
|
|
48
|
+
data: 'array',
|
|
49
|
+
comparator: 'fn(a: any, b: any) -> number',
|
|
50
|
+
},
|
|
51
|
+
returnsType: 'array',
|
|
52
|
+
examples: ['sort(["c", "a", "b"]) // ["a", "b", "c"]'],
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
export const sort_by = VmLib(
|
|
57
|
+
(data, key_fn, comparator) => {
|
|
58
|
+
expectArray('data', data, null);
|
|
59
|
+
expectCallable('key_fn', key_fn, data);
|
|
60
|
+
const compare = cmp(comparator, data);
|
|
61
|
+
const arr: Array<{ o: VmConst; k: VmValue }> = [];
|
|
62
|
+
const len = data.length;
|
|
63
|
+
for (let i = 0; i < len; i++) {
|
|
64
|
+
const v = data[i] ?? null;
|
|
65
|
+
arr.push({
|
|
66
|
+
o: v,
|
|
67
|
+
k: $Call(key_fn, [v, i, data]),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
arr.sort((a, b) => compare(a.k, b.k));
|
|
71
|
+
return arr.map((e) => e.o);
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
summary: '根据键函数对数组中的元素进行排序,并返回排序后的结果',
|
|
75
|
+
params: {
|
|
76
|
+
data: '要排序的数组',
|
|
77
|
+
key_fn: '用于提取排序键的函数,接受一个元素并返回其排序键',
|
|
78
|
+
comparator: '用于比较两个排序键的函数,返回一个数字,表示它们的相对顺序,默认按升序排列',
|
|
79
|
+
},
|
|
80
|
+
paramsType: {
|
|
81
|
+
data: 'array',
|
|
82
|
+
key_fn: 'fn(value: any, index: number, arr: type(data)) -> any',
|
|
83
|
+
comparator: 'fn(a: any, b: any) -> number',
|
|
84
|
+
},
|
|
85
|
+
returnsType: 'array',
|
|
86
|
+
examples: ['sort_by([(0, "x"), (2, "y"), (1, "z")], fn (item) { item[0] }) // [(0, "x"), (1, "z"), (2, "y")]'],
|
|
87
|
+
},
|
|
88
|
+
);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Element } from '../../../helpers.js';
|
|
2
|
+
import { $ToNumber, $ToString } from '../../../operations.js';
|
|
3
|
+
import { isVmArray, type VmConst } from '../../../types/index.js';
|
|
4
|
+
import { VmLib, expectArrayOrRecord, throwError } from '../../_helpers.js';
|
|
5
|
+
import { isSafeInteger } from '../../../../helpers/utils.js';
|
|
6
|
+
|
|
7
|
+
const _with = VmLib(
|
|
8
|
+
(data, ...entries) => {
|
|
9
|
+
expectArrayOrRecord('data', data, data);
|
|
10
|
+
if (entries.length % 2 !== 0) {
|
|
11
|
+
throwError('Expected even number of entries', data);
|
|
12
|
+
}
|
|
13
|
+
if (isVmArray(data)) {
|
|
14
|
+
const result: Array<VmConst | undefined> = [...data];
|
|
15
|
+
for (let i = 0; i < entries.length; i += 2) {
|
|
16
|
+
const index = Math.trunc($ToNumber(entries[i]));
|
|
17
|
+
if (!isSafeInteger(index) || index < 0) continue;
|
|
18
|
+
const value = entries[i + 1];
|
|
19
|
+
while (index > result.length) {
|
|
20
|
+
result.push(null);
|
|
21
|
+
}
|
|
22
|
+
result[index] = Element(value);
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
} else {
|
|
26
|
+
const result: Record<string, VmConst | undefined> = { ...data };
|
|
27
|
+
for (let i = 0; i < entries.length; i += 2) {
|
|
28
|
+
const key = $ToString(entries[i]);
|
|
29
|
+
const value = entries[i + 1];
|
|
30
|
+
result[key] = Element(value);
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
summary: '在数组或记录中设置多个键值对',
|
|
37
|
+
params: { data: '要设置的数组或记录', '..entries': '要设置的键值对,成对出现' },
|
|
38
|
+
paramsType: { data: 'array | record', '..entries': '[..[string | number, any][]]' },
|
|
39
|
+
returnsType: 'type(data)',
|
|
40
|
+
examples: ['with([10, 20], 2, 99) // [10, 20, 99]', 'with((a: 1), "b", 2) // (a: 1, b: 2)'],
|
|
41
|
+
},
|
|
42
|
+
);
|
|
43
|
+
export { _with as 'with' };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { serialize } from '../../../../subtle.js';
|
|
2
|
+
import { Cp } from '../../../helpers.js';
|
|
3
|
+
import { isVmArray, type VmConst, type VmArray } from '../../../types/index.js';
|
|
4
|
+
import { VmLib, throwError } from '../../_helpers.js';
|
|
5
|
+
import { entries } from './entries.js';
|
|
6
|
+
|
|
7
|
+
export const zip = VmLib(
|
|
8
|
+
(data) => {
|
|
9
|
+
const ets = entries(data);
|
|
10
|
+
let len = 0;
|
|
11
|
+
for (const { 0: key, 1: arr } of ets) {
|
|
12
|
+
if (!isVmArray(arr)) {
|
|
13
|
+
throwError(`data[${serialize(key)}] is not an array`, null);
|
|
14
|
+
}
|
|
15
|
+
len = Math.max(len, arr.length);
|
|
16
|
+
}
|
|
17
|
+
if (len === 0) return [];
|
|
18
|
+
const result: Array<Record<string | number, VmConst>> = [];
|
|
19
|
+
const isArr = isVmArray(data);
|
|
20
|
+
for (let i = 0; i < len; i++) {
|
|
21
|
+
Cp();
|
|
22
|
+
const obj: Record<number | string, VmConst> = isArr ? ([] as Record<number, VmConst>) : {};
|
|
23
|
+
for (const { 0: key, 1: arr } of ets) {
|
|
24
|
+
obj[key] = (arr as VmArray)[i] ?? null;
|
|
25
|
+
}
|
|
26
|
+
result.push(obj);
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
summary: '将数组的数组/记录转换为数组/记录的数组',
|
|
32
|
+
params: { data: '要转换的数组/记录' },
|
|
33
|
+
paramsType: { data: 'array | record' },
|
|
34
|
+
returnsType: '(array | record)[]',
|
|
35
|
+
examples: [
|
|
36
|
+
'zip((x: [1, 2], y: ["a", "b"])) // [(x: 1, y: "a"), (x: 2, y: "b")]',
|
|
37
|
+
`zip([[1, 2], ["a", "b"]]) // [[1, "a"], [2, "b"]]`,
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
);
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { $ToString } from '../../operations.js';
|
|
2
|
+
import { expectArray, required, VmLib } from '../_helpers.js';
|
|
3
|
+
|
|
4
|
+
export const chars = VmLib(
|
|
5
|
+
(str) => {
|
|
6
|
+
required('str', str, null);
|
|
7
|
+
return [...$ToString(str)];
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
summary: '将字符串转换为字符数组',
|
|
11
|
+
params: { str: '要转换的字符串' },
|
|
12
|
+
paramsType: { str: 'string' },
|
|
13
|
+
returnsType: 'string[]',
|
|
14
|
+
examples: ['chars("Mira") // ["M", "i", "r", "a"]'],
|
|
15
|
+
},
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
export const starts_with = VmLib(
|
|
19
|
+
(str, search) => {
|
|
20
|
+
required('str', str, null);
|
|
21
|
+
required('search', search, null);
|
|
22
|
+
return $ToString(str).startsWith($ToString(search));
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
summary: '检查字符串是否以指定子串开头',
|
|
26
|
+
params: { str: '要检查的字符串', search: '要匹配的子串' },
|
|
27
|
+
paramsType: { str: 'string', search: 'string' },
|
|
28
|
+
returnsType: 'boolean',
|
|
29
|
+
examples: ['starts_with("mira", "mi") // true'],
|
|
30
|
+
},
|
|
31
|
+
);
|
|
32
|
+
export const ends_with = VmLib(
|
|
33
|
+
(str, search) => {
|
|
34
|
+
required('str', str, null);
|
|
35
|
+
required('search', search, null);
|
|
36
|
+
return $ToString(str).endsWith($ToString(search));
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
summary: '检查字符串是否以指定子串结尾',
|
|
40
|
+
params: { str: '要检查的字符串', search: '要匹配的子串' },
|
|
41
|
+
paramsType: { str: 'string', search: 'string' },
|
|
42
|
+
returnsType: 'boolean',
|
|
43
|
+
examples: ['ends_with("mira", "ra") // true'],
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
export const contains = VmLib(
|
|
48
|
+
(str, search) => {
|
|
49
|
+
required('str', str, null);
|
|
50
|
+
required('search', search, null);
|
|
51
|
+
return $ToString(str).includes($ToString(search));
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
summary: '检查字符串是否包含指定子串',
|
|
55
|
+
params: { str: '要检查的字符串', search: '要匹配的子串' },
|
|
56
|
+
paramsType: { str: 'string', search: 'string' },
|
|
57
|
+
returnsType: 'boolean',
|
|
58
|
+
examples: ['contains("hello", "ll") // true'],
|
|
59
|
+
},
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
export const trim_start = VmLib(
|
|
63
|
+
(str) => {
|
|
64
|
+
required('str', str, null);
|
|
65
|
+
return $ToString(str).trimStart();
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
summary: '去除字符串开头的空白字符',
|
|
69
|
+
params: { str: '要处理的字符串' },
|
|
70
|
+
paramsType: { str: 'string' },
|
|
71
|
+
returnsType: 'string',
|
|
72
|
+
examples: ['trim_start(" mira") // "mira"'],
|
|
73
|
+
},
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
export const trim_end = VmLib(
|
|
77
|
+
(str) => {
|
|
78
|
+
required('str', str, null);
|
|
79
|
+
return $ToString(str).trimEnd();
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
summary: '去除字符串结尾的空白字符',
|
|
83
|
+
params: { str: '要处理的字符串' },
|
|
84
|
+
paramsType: { str: 'string' },
|
|
85
|
+
returnsType: 'string',
|
|
86
|
+
examples: ['trim_end("mira ") // "mira"'],
|
|
87
|
+
},
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
export const trim = VmLib(
|
|
91
|
+
(str) => {
|
|
92
|
+
required('str', str, null);
|
|
93
|
+
return $ToString(str).trim();
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
summary: '去除字符串两端的空白字符',
|
|
97
|
+
params: { str: '要处理的字符串' },
|
|
98
|
+
paramsType: { str: 'string' },
|
|
99
|
+
returnsType: 'string',
|
|
100
|
+
examples: ['trim(" mira ") // "mira"'],
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
export const replace = VmLib(
|
|
105
|
+
(str, search, replacement = '') => {
|
|
106
|
+
required('str', str, null);
|
|
107
|
+
required('search', search, str);
|
|
108
|
+
return $ToString(str).replaceAll($ToString(search), $ToString(replacement));
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
summary: '替换字符串中的指定子串',
|
|
112
|
+
params: { str: '要处理的字符串', search: '要替换的子串', replacement: '替换后的字符串' },
|
|
113
|
+
paramsType: { str: 'string', search: 'string', replacement: 'string' },
|
|
114
|
+
returnsType: 'string',
|
|
115
|
+
examples: ['replace("foo bar foo", "foo", "baz") // "baz bar baz"'],
|
|
116
|
+
},
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
export const split = VmLib(
|
|
120
|
+
(str, separator = '') => {
|
|
121
|
+
required('str', str, null);
|
|
122
|
+
const s = $ToString(str);
|
|
123
|
+
const p = $ToString(separator);
|
|
124
|
+
if (!p) return [...s];
|
|
125
|
+
return s.split(p);
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
summary: '将字符串拆分为子串数组',
|
|
129
|
+
params: { str: '要拆分的字符串', separator: '分隔符' },
|
|
130
|
+
paramsType: { str: 'string', separator: 'string' },
|
|
131
|
+
returnsType: 'string[]',
|
|
132
|
+
examples: ['split("a,b,c", ",") // ["a", "b", "c"]'],
|
|
133
|
+
},
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
export const join = VmLib(
|
|
137
|
+
(arr, separator = '') => {
|
|
138
|
+
expectArray('arr', arr, null);
|
|
139
|
+
const s = $ToString(separator);
|
|
140
|
+
return arr.map((v) => $ToString(v)).join(s);
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
summary: '将字符串数组连接为单个字符串',
|
|
144
|
+
params: { arr: '要连接的字符串数组', separator: '分隔符' },
|
|
145
|
+
paramsType: { arr: 'string[]', separator: 'string' },
|
|
146
|
+
returnsType: 'string',
|
|
147
|
+
examples: ['join(["a", "b", "c"], "-") // "a-b-c"'],
|
|
148
|
+
},
|
|
149
|
+
);
|