@cloudpss/expression 0.6.0-alpha.9 → 0.6.0-beta.1
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/analyze.d.ts +6 -3
- package/dist/analyze.d.ts.map +1 -1
- package/dist/analyze.js +13 -33
- package/dist/analyze.js.map +1 -1
- package/dist/definitions/argument.d.ts +3 -11
- package/dist/definitions/argument.d.ts.map +1 -1
- package/dist/definitions/constraint.d.ts +2 -2
- package/dist/definitions/constraint.d.ts.map +1 -1
- package/dist/definitions/constraint.js +1 -1
- package/dist/definitions/constraint.js.map +1 -1
- package/dist/definitions/parameter-group.js +4 -4
- package/dist/definitions/parameter-group.js.map +1 -1
- package/dist/definitions/parameter.d.ts +22 -14
- package/dist/definitions/parameter.d.ts.map +1 -1
- package/dist/definitions/parameter.js +10 -1
- package/dist/definitions/parameter.js.map +1 -1
- package/dist/definitions/utils.d.ts +28 -0
- package/dist/definitions/utils.d.ts.map +1 -0
- package/dist/definitions/utils.js +272 -0
- package/dist/definitions/utils.js.map +1 -0
- package/dist/definitions/variable.js +1 -1
- package/dist/definitions/variable.js.map +1 -1
- package/dist/definitions.d.ts +1 -2
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +1 -1
- package/dist/definitions.js.map +1 -1
- package/dist/eval.d.ts +3 -5
- package/dist/eval.d.ts.map +1 -1
- package/dist/eval.js +12 -20
- package/dist/eval.js.map +1 -1
- package/dist/expression.d.ts +10 -4
- package/dist/expression.d.ts.map +1 -1
- package/dist/expression.js +6 -6
- package/dist/expression.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/interface.d.ts +30 -0
- package/dist/interface.d.ts.map +1 -0
- package/dist/interface.js +6 -0
- package/dist/interface.js.map +1 -0
- package/dist/main.d.ts +41 -28
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +165 -149
- package/dist/main.js.map +1 -1
- package/dist/migrate.d.ts +1 -1
- package/dist/migrate.d.ts.map +1 -1
- package/dist/migrate.js +25 -4
- package/dist/migrate.js.map +1 -1
- package/dist/migrator/access.d.ts.map +1 -1
- package/dist/migrator/access.js +64 -29
- package/dist/migrator/access.js.map +1 -1
- package/dist/migrator/call.d.ts.map +1 -1
- package/dist/migrator/call.js +298 -201
- package/dist/migrator/call.js.map +1 -1
- package/dist/migrator/concat.d.ts.map +1 -1
- package/dist/migrator/concat.js +15 -2
- package/dist/migrator/concat.js.map +1 -1
- package/dist/migrator/function.d.ts +6 -0
- package/dist/migrator/function.d.ts.map +1 -0
- package/dist/migrator/function.js +25 -0
- package/dist/migrator/function.js.map +1 -0
- package/dist/migrator/interface.d.ts +3 -1
- package/dist/migrator/interface.d.ts.map +1 -1
- package/dist/migrator/interface.js.map +1 -1
- package/dist/migrator/node.d.ts.map +1 -1
- package/dist/migrator/node.js +55 -7
- package/dist/migrator/node.js.map +1 -1
- package/dist/migrator/operator.d.ts.map +1 -1
- package/dist/migrator/operator.js +107 -60
- package/dist/migrator/operator.js.map +1 -1
- package/dist/migrator/serialize.d.ts +4 -0
- package/dist/migrator/serialize.d.ts.map +1 -0
- package/dist/migrator/serialize.js +21 -0
- package/dist/migrator/serialize.js.map +1 -0
- package/dist/migrator/special.d.ts.map +1 -1
- package/dist/migrator/special.js +31 -0
- package/dist/migrator/special.js.map +1 -1
- package/dist/migrator/state.d.ts +4 -4
- package/dist/migrator/state.d.ts.map +1 -1
- package/dist/migrator/state.js +29 -31
- package/dist/migrator/state.js.map +1 -1
- package/dist/migrator/symbol.d.ts.map +1 -1
- package/dist/migrator/symbol.js +34 -12
- package/dist/migrator/symbol.js.map +1 -1
- package/dist/migrator/to-type.d.ts.map +1 -1
- package/dist/migrator/to-type.js +21 -4
- package/dist/migrator/to-type.js.map +1 -1
- package/dist/migrator/utils.d.ts +6 -0
- package/dist/migrator/utils.d.ts.map +1 -1
- package/dist/migrator/utils.js +49 -1
- package/dist/migrator/utils.js.map +1 -1
- package/dist/parser.d.ts +2 -2
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +27 -8
- package/dist/parser.js.map +1 -1
- package/dist/re-exports.d.ts +4 -0
- package/dist/re-exports.d.ts.map +1 -0
- package/dist/re-exports.js +3 -0
- package/dist/re-exports.js.map +1 -0
- package/dist/scope.d.ts +16 -17
- package/dist/scope.d.ts.map +1 -1
- package/dist/scope.js +84 -53
- package/dist/scope.js.map +1 -1
- package/dist/type.d.ts +22 -10
- package/dist/type.d.ts.map +1 -1
- package/dist/type.js +21 -24
- package/dist/type.js.map +1 -1
- package/package.json +8 -5
- package/src/analyze.ts +20 -39
- package/src/definitions/argument.ts +3 -13
- package/src/definitions/constraint.ts +3 -3
- package/src/definitions/parameter-group.ts +4 -4
- package/src/definitions/parameter.ts +47 -24
- package/src/definitions/utils.ts +288 -0
- package/src/definitions/variable.ts +1 -1
- package/src/definitions.ts +1 -28
- package/src/eval.ts +16 -25
- package/src/expression.ts +16 -8
- package/src/index.ts +3 -1
- package/src/interface.ts +35 -0
- package/src/main.ts +232 -200
- package/src/migrate.ts +27 -4
- package/src/migrator/access.ts +67 -37
- package/src/migrator/call.ts +287 -190
- package/src/migrator/concat.ts +15 -2
- package/src/migrator/function.ts +27 -0
- package/src/migrator/interface.ts +3 -1
- package/src/migrator/node.ts +56 -6
- package/src/migrator/operator.ts +110 -64
- package/src/migrator/serialize.ts +21 -0
- package/src/migrator/special.ts +31 -0
- package/src/migrator/state.ts +31 -34
- package/src/migrator/symbol.ts +33 -12
- package/src/migrator/to-type.ts +23 -4
- package/src/migrator/utils.ts +49 -1
- package/src/parser.ts +33 -8
- package/src/re-exports.ts +47 -0
- package/src/scope.ts +98 -62
- package/src/type.ts +40 -25
- package/tests/analyze.ts +45 -6
- package/tests/compile.ts +65 -0
- package/tests/condition.ts +33 -17
- package/tests/definition.ts +237 -18
- package/tests/eval-complex.ts +19 -11
- package/tests/eval.ts +59 -12
- package/tests/import.ts +21 -7
- package/tests/main.ts +58 -0
- package/tests/migrate.ts +317 -0
- package/tests/scope.ts +3 -3
- package/tests/template.ts +36 -0
- package/dist/context.d.ts +0 -41
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js +0 -18
- package/dist/context.js.map +0 -1
- package/src/context.ts +0 -54
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { FunctionAssignmentNode } from 'mathjs';
|
|
2
|
+
import type { Result } from './interface.js';
|
|
3
|
+
import { migrateAtomic } from './node.js';
|
|
4
|
+
import { type State, FunctionState } from './state.js';
|
|
5
|
+
import { migrateSymbolName } from './utils.js';
|
|
6
|
+
|
|
7
|
+
/** 转换函数定义语句 */
|
|
8
|
+
export function migrateFunctionAssignment(state: State, node: FunctionAssignmentNode): Result {
|
|
9
|
+
state.loose();
|
|
10
|
+
const { name, params, expr } = node;
|
|
11
|
+
const fState = new FunctionState(state, params);
|
|
12
|
+
let body = migrateAtomic(fState, expr);
|
|
13
|
+
if (!(body.code.startsWith('{') && body.code.endsWith('}'))) {
|
|
14
|
+
body = { ...body, code: `{ ${body.code} }` };
|
|
15
|
+
}
|
|
16
|
+
if (state.locals.has(name)) {
|
|
17
|
+
state.err(`重复定义函数: '${name}'`);
|
|
18
|
+
}
|
|
19
|
+
state.locals.set(name, {
|
|
20
|
+
type: 'function',
|
|
21
|
+
code: body.code,
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
type: 'function',
|
|
25
|
+
code: `fn ${migrateSymbolName(name, true)}(${params.join(', ')}) ${body.code}`,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TypeName, VmConst } from '@mirascript/mirascript';
|
|
1
|
+
import type { TypeName, VmConst, VmValue } from '@mirascript/mirascript';
|
|
2
2
|
|
|
3
3
|
/** 转换选项 */
|
|
4
4
|
export interface Options {
|
|
@@ -12,6 +12,8 @@ export interface Result {
|
|
|
12
12
|
readonly type?: TypeName;
|
|
13
13
|
/** 为字面量 */
|
|
14
14
|
readonly literal?: VmConst;
|
|
15
|
+
/** 为全局变量 */
|
|
16
|
+
readonly global?: VmValue;
|
|
15
17
|
/** 转换后的代码 */
|
|
16
18
|
readonly code: string;
|
|
17
19
|
/** 转换后的代码 */
|
package/src/migrator/node.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { serializeRecordKey } from '@mirascript/mirascript/subtle';
|
|
2
2
|
import {
|
|
3
3
|
type MathNode,
|
|
4
4
|
isAccessorNode,
|
|
@@ -12,16 +12,21 @@ import {
|
|
|
12
12
|
isRelationalNode,
|
|
13
13
|
type OperatorNodeFn,
|
|
14
14
|
isSymbolNode,
|
|
15
|
+
isFunctionAssignmentNode,
|
|
16
|
+
isRangeNode,
|
|
15
17
|
} from 'mathjs';
|
|
16
18
|
import type { State } from './state.js';
|
|
17
19
|
import type { Options, Result } from './interface.js';
|
|
18
20
|
import type { VmConst } from '@mirascript/mirascript';
|
|
19
|
-
import { unsupportedNode } from './utils.js';
|
|
21
|
+
import { constantValue, unsupportedNode } from './utils.js';
|
|
20
22
|
import { migrateAccess } from './access.js';
|
|
21
23
|
import { migrateCall } from './call.js';
|
|
22
24
|
import { migrateOperator } from './operator.js';
|
|
23
25
|
import { migrateSymbol } from './symbol.js';
|
|
24
26
|
import { migrateCondition } from './condition.js';
|
|
27
|
+
import { migrateFunctionAssignment } from './function.js';
|
|
28
|
+
import { serialize } from './serialize.js';
|
|
29
|
+
import { toNumber } from './to-type.js';
|
|
25
30
|
|
|
26
31
|
/** 转换 AST */
|
|
27
32
|
export function migrateAtomic(state: State, node: MathNode): Result {
|
|
@@ -79,7 +84,7 @@ export function migrateNode(state: State, node: MathNode, options: Options): Res
|
|
|
79
84
|
} else {
|
|
80
85
|
literals[key] = item.literal;
|
|
81
86
|
}
|
|
82
|
-
code.push(`${
|
|
87
|
+
code.push(`${serializeRecordKey(key)}: ${item.code}`);
|
|
83
88
|
}
|
|
84
89
|
return {
|
|
85
90
|
type: 'record',
|
|
@@ -110,6 +115,26 @@ export function migrateNode(state: State, node: MathNode, options: Options): Res
|
|
|
110
115
|
}
|
|
111
116
|
if (isRelationalNode(node)) {
|
|
112
117
|
const { conditionals, params } = node;
|
|
118
|
+
// 优化范围判断 a <= b <= c
|
|
119
|
+
if (
|
|
120
|
+
conditionals.length === 2 &&
|
|
121
|
+
params.length === 3 &&
|
|
122
|
+
conditionals[0] === 'smallerEq' &&
|
|
123
|
+
conditionals[1] === 'smallerEq'
|
|
124
|
+
) {
|
|
125
|
+
// 模式匹配只支持常量
|
|
126
|
+
const l = constantValue(params[0]!);
|
|
127
|
+
const r = constantValue(params[2]!);
|
|
128
|
+
if (typeof l == 'number' && typeof r == 'number' && l < r) {
|
|
129
|
+
const v = toNumber(state, migrateNode(state, params[1]!, options));
|
|
130
|
+
let code = `${v.code} is ${l}..${r}`;
|
|
131
|
+
if (options.format !== 'no-paren') code = `(${code})`;
|
|
132
|
+
return {
|
|
133
|
+
type: 'boolean',
|
|
134
|
+
code,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
113
138
|
const exprs = [];
|
|
114
139
|
for (let i = 0; i < conditionals.length; i++) {
|
|
115
140
|
const fn = conditionals[i]! as OperatorNodeFn;
|
|
@@ -117,15 +142,40 @@ export function migrateNode(state: State, node: MathNode, options: Options): Res
|
|
|
117
142
|
const r = params[i + 1]!;
|
|
118
143
|
exprs.push(migrateOperator(state, { fn, args: [l, r] }, options));
|
|
119
144
|
}
|
|
120
|
-
let code = exprs.join(' && ');
|
|
145
|
+
let code = exprs.map((e) => e.code).join(' && ');
|
|
121
146
|
if (options.format !== 'no-paren') code = `(${code})`;
|
|
122
147
|
return {
|
|
123
148
|
type: 'boolean',
|
|
124
149
|
code,
|
|
125
150
|
};
|
|
126
151
|
}
|
|
127
|
-
|
|
152
|
+
if (isFunctionAssignmentNode(node)) {
|
|
153
|
+
const result = migrateFunctionAssignment(state, node);
|
|
154
|
+
state.helper(result.code);
|
|
155
|
+
return {
|
|
156
|
+
type: 'function',
|
|
157
|
+
code: node.name,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
if (isRangeNode(node)) {
|
|
161
|
+
const { start, end, step } = node;
|
|
162
|
+
const stepValue = step == null ? 1 : constantValue(step);
|
|
163
|
+
// Math.js 的 : 与 MiraScript 的 .. 优先级相同,因此直接转换即可
|
|
164
|
+
const startNode = migrateExpr(state, start);
|
|
165
|
+
const endNode = migrateExpr(state, end);
|
|
166
|
+
if (stepValue === 1) {
|
|
167
|
+
return {
|
|
168
|
+
type: 'array',
|
|
169
|
+
code: `[${startNode.code}..${endNode.code}]`,
|
|
170
|
+
};
|
|
171
|
+
} else if (stepValue === -1) {
|
|
172
|
+
return {
|
|
173
|
+
type: 'array',
|
|
174
|
+
code: `[${endNode.code}..${startNode.code}]`,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return unsupportedNode(state, node);
|
|
178
|
+
}
|
|
128
179
|
// if (isIndexNode(node)) {
|
|
129
|
-
// if (isFunctionAssignmentNode(node)) {
|
|
130
180
|
return unsupportedNode(state, node);
|
|
131
181
|
}
|
package/src/migrator/operator.ts
CHANGED
|
@@ -8,61 +8,71 @@ import {
|
|
|
8
8
|
isOperatorNode,
|
|
9
9
|
isNode,
|
|
10
10
|
} from 'mathjs';
|
|
11
|
-
import {
|
|
11
|
+
import { isVmArray, type TypeName, type VmAny } from '@mirascript/mirascript';
|
|
12
|
+
import { operations } from '@mirascript/mirascript/subtle';
|
|
13
|
+
import { symbolName, constantValue, equalText, scalar, globalFnName } from './utils.js';
|
|
12
14
|
import type { State } from './state.js';
|
|
13
15
|
import type { Options, Result } from './interface.js';
|
|
14
|
-
import { migrateAtomic, migrateExpr } from './node.js';
|
|
16
|
+
import { migrateAtomic, migrateExpr, migrateParen } from './node.js';
|
|
15
17
|
import { toBoolean, toNumber } from './to-type.js';
|
|
16
18
|
import { migrateSymbol } from './symbol.js';
|
|
17
|
-
import {
|
|
19
|
+
import { serialize } from './serialize.js';
|
|
18
20
|
|
|
19
21
|
const BINARY_MATH_OPERATORS = {
|
|
20
22
|
add: [
|
|
21
23
|
' + ',
|
|
22
|
-
(l, r) => ({
|
|
24
|
+
(state, l, r) => ({
|
|
23
25
|
type: l.type === 'array' || r.type === 'array' ? 'array' : l.type && r.type ? 'number' : undefined,
|
|
24
|
-
code:
|
|
26
|
+
code: `${globalFnName(state, 'matrix')}.add(${l.code}, ${r.code})`,
|
|
25
27
|
}),
|
|
26
28
|
],
|
|
27
29
|
subtract: [
|
|
28
30
|
' - ',
|
|
29
|
-
(l, r) => ({
|
|
31
|
+
(state, l, r) => ({
|
|
30
32
|
type: l.type === 'array' || r.type === 'array' ? 'array' : l.type && r.type ? 'number' : undefined,
|
|
31
|
-
code:
|
|
33
|
+
code: `${globalFnName(state, 'matrix')}.subtract(${l.code}, ${r.code})`,
|
|
32
34
|
}),
|
|
33
35
|
],
|
|
34
36
|
multiply: [
|
|
35
37
|
' * ',
|
|
36
|
-
(l, r) => ({
|
|
38
|
+
(state, l, r) => ({
|
|
37
39
|
type: l.type === 'array' || r.type === 'array' ? 'array' : l.type && r.type ? 'number' : undefined,
|
|
38
|
-
code:
|
|
40
|
+
code: `${globalFnName(state, 'matrix')}.multiply(${l.code}, ${r.code})`,
|
|
39
41
|
}),
|
|
40
42
|
],
|
|
41
43
|
dotMultiply: [
|
|
42
44
|
' * ',
|
|
43
|
-
(l, r) => ({
|
|
45
|
+
(state, l, r) => ({
|
|
44
46
|
type: l.type === 'array' || r.type === 'array' ? 'array' : l.type && r.type ? 'number' : undefined,
|
|
45
|
-
code:
|
|
47
|
+
code: `${globalFnName(state, 'matrix')}.entrywise_multiply(${l.code}, ${r.code})`,
|
|
46
48
|
}),
|
|
47
49
|
],
|
|
48
50
|
divide: [
|
|
49
51
|
' / ',
|
|
50
|
-
(l, r) =>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
(state, l, r) => {
|
|
53
|
+
if (r.type === 'array' || !r.type) {
|
|
54
|
+
return {
|
|
55
|
+
type: l.type === 'array' || r.type === 'array' ? 'array' : l.type && r.type ? 'number' : undefined,
|
|
56
|
+
code: `${globalFnName(state, 'matrix')}.multiply(${l.code}, ${globalFnName(state, 'matrix')}.invert(${r.code}))`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
type: l.type === 'array' ? 'array' : l.type ? 'number' : undefined,
|
|
61
|
+
code: `${globalFnName(state, 'matrix')}.entrywise_divide(${l.code}, ${r.code})`,
|
|
62
|
+
};
|
|
63
|
+
},
|
|
54
64
|
],
|
|
55
65
|
dotDivide: [
|
|
56
66
|
' / ',
|
|
57
|
-
(l, r) => ({
|
|
67
|
+
(state, l, r) => ({
|
|
58
68
|
type: l.type === 'array' || r.type === 'array' ? 'array' : l.type && r.type ? 'number' : undefined,
|
|
59
|
-
code:
|
|
69
|
+
code: `${globalFnName(state, 'matrix')}.entrywise_divide(${l.code}, ${r.code})`,
|
|
60
70
|
}),
|
|
61
71
|
],
|
|
62
72
|
mod: [' % '],
|
|
63
73
|
pow: ['^', false],
|
|
64
74
|
dotPow: ['^'],
|
|
65
|
-
} satisfies Record<string, [op: string, alt?: ((l: Result, r: Result) => Result) | false]>;
|
|
75
|
+
} satisfies Record<string, [op: string, alt?: ((state: State, l: Result, r: Result) => Result) | false]>;
|
|
66
76
|
|
|
67
77
|
const MATH_FUNCTIONS = {
|
|
68
78
|
factorial: 'factorial',
|
|
@@ -76,70 +86,92 @@ const MATH_FUNCTIONS = {
|
|
|
76
86
|
} as const;
|
|
77
87
|
|
|
78
88
|
const BIT_OPS_TO_BOOL_OPS = {
|
|
79
|
-
bitAnd: '&&',
|
|
80
|
-
bitOr: '||',
|
|
81
|
-
bitXor: '!=',
|
|
89
|
+
bitAnd: ['&&', false],
|
|
90
|
+
bitOr: ['||', false],
|
|
91
|
+
bitXor: ['!=', true],
|
|
82
92
|
} as const;
|
|
83
93
|
|
|
84
94
|
const COMPARE_OPERATORS = {
|
|
85
|
-
smaller: '<',
|
|
86
|
-
smallerEq: '<=',
|
|
87
|
-
larger: '>',
|
|
88
|
-
largerEq: '>=',
|
|
95
|
+
smaller: ['<'],
|
|
96
|
+
smallerEq: ['<='],
|
|
97
|
+
larger: ['>'],
|
|
98
|
+
largerEq: ['>='],
|
|
99
|
+
equal: ['=~', '=='],
|
|
100
|
+
unequal: ['!~', '!='],
|
|
89
101
|
} as const;
|
|
90
102
|
|
|
91
103
|
/** 转换为 boolean */
|
|
92
|
-
function b(op: string, state: State, node: MathNode): string {
|
|
93
|
-
const re =
|
|
104
|
+
function b(op: string, state: State, node: MathNode, migrator = migrateExpr): string {
|
|
105
|
+
const re = migrator(state, node);
|
|
94
106
|
return toBoolean(state, scalar(op, state, re)).code;
|
|
95
107
|
}
|
|
96
108
|
|
|
109
|
+
/** 数组元素类型 */
|
|
110
|
+
function elementType(lit: VmAny): TypeName | undefined {
|
|
111
|
+
if (!isVmArray(lit) || !lit.length) return undefined;
|
|
112
|
+
let type: TypeName | undefined = undefined;
|
|
113
|
+
for (const e of lit) {
|
|
114
|
+
const t = operations.$Type(e as VmAny);
|
|
115
|
+
if (!type) {
|
|
116
|
+
type = t;
|
|
117
|
+
} else if (type !== t) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return type;
|
|
122
|
+
}
|
|
123
|
+
|
|
97
124
|
/** 二元操作 */
|
|
98
125
|
function binary(
|
|
99
126
|
state: State,
|
|
100
127
|
l: Result,
|
|
101
128
|
r: Result,
|
|
102
|
-
op: (l: Result, r: Result) => Result,
|
|
103
|
-
alt?: (l: Result, r: Result) => Result,
|
|
129
|
+
op: (state: State, l: Result, r: Result) => Result,
|
|
130
|
+
alt?: (state: State, l: Result, r: Result) => Result,
|
|
104
131
|
): Result {
|
|
105
132
|
if (l.type && r.type && l.type !== 'array' && r.type !== 'array') {
|
|
106
|
-
return op(l, r);
|
|
133
|
+
return op(state, l, r);
|
|
107
134
|
}
|
|
108
135
|
if (Array.isArray(l.literal) && l.literal.every((e) => !Array.isArray(e))) {
|
|
136
|
+
const it = { code: 'it', type: elementType(l.literal) };
|
|
109
137
|
return {
|
|
110
138
|
type: 'array',
|
|
111
|
-
code: `${l.code}
|
|
139
|
+
code: `${l.code}::${globalFnName(state, 'map')}(fn { ${op(state, it, r).code} })`,
|
|
112
140
|
};
|
|
113
141
|
}
|
|
114
142
|
if (Array.isArray(r.literal) && r.literal.every((e) => !Array.isArray(e))) {
|
|
143
|
+
const it = { code: 'it', type: elementType(r.literal) };
|
|
115
144
|
return {
|
|
116
145
|
type: 'array',
|
|
117
|
-
code: `${r.code}
|
|
146
|
+
code: `${r.code}::${globalFnName(state, 'map')}(fn { ${op(state, l, it).code} })`,
|
|
118
147
|
};
|
|
119
148
|
}
|
|
120
149
|
if (alt) {
|
|
121
|
-
return alt(l, r);
|
|
150
|
+
return alt(state, l, r);
|
|
122
151
|
}
|
|
152
|
+
const a = { code: 'a', type: l.type === 'array' ? elementType(l.literal) : l.type };
|
|
153
|
+
const b = { code: 'b', type: r.type === 'array' ? elementType(r.literal) : r.type };
|
|
123
154
|
return {
|
|
124
155
|
type: l.type === 'array' || r.type === 'array' ? 'array' : undefined,
|
|
125
|
-
code:
|
|
156
|
+
code: `${globalFnName(state, 'matrix')}.entrywise(${l.code}, ${r.code}, fn (a, b) { ${op(state, a, b).code} })`,
|
|
126
157
|
};
|
|
127
158
|
}
|
|
128
159
|
|
|
129
160
|
/** 一元操作 */
|
|
130
|
-
function unary(state: State, v: Result, op: (v: Result) => Result): Result {
|
|
161
|
+
function unary(state: State, v: Result, op: (state: State, v: Result) => Result): Result {
|
|
131
162
|
if (v.type && v.type !== 'array') {
|
|
132
|
-
return op(v);
|
|
163
|
+
return op(state, v);
|
|
133
164
|
}
|
|
134
165
|
if (Array.isArray(v.literal) && v.literal.every((e) => !Array.isArray(e))) {
|
|
166
|
+
const it = { code: 'it', type: elementType(v.literal) };
|
|
135
167
|
return {
|
|
136
168
|
type: 'array',
|
|
137
|
-
code: `${v.code}
|
|
169
|
+
code: `${v.code}::${globalFnName(state, 'map')}(fn { ${op(state, it).code} })`,
|
|
138
170
|
};
|
|
139
171
|
}
|
|
140
172
|
return {
|
|
141
173
|
type: 'array',
|
|
142
|
-
code:
|
|
174
|
+
code: `${globalFnName(state, 'matrix')}.entrywise(${v.code}, nil, fn { ${op(state, { code: 'it' }).code} })`,
|
|
143
175
|
};
|
|
144
176
|
}
|
|
145
177
|
|
|
@@ -171,14 +203,14 @@ export function migrateOperator(
|
|
|
171
203
|
state,
|
|
172
204
|
migrateExpr(state, a0),
|
|
173
205
|
migrateExpr(state, a1),
|
|
174
|
-
(l, r) => ({
|
|
206
|
+
(state, l, r) => ({
|
|
175
207
|
type: 'number',
|
|
176
208
|
code: `${l.code}${op}${r.code}`,
|
|
177
209
|
}),
|
|
178
210
|
alt === false
|
|
179
|
-
? (l, r) => {
|
|
211
|
+
? (state, l, r) => {
|
|
180
212
|
state.warn(`'${op.trim()}' 不支持矩阵,计算结果可能不一致`);
|
|
181
|
-
return { code: `${l.code}
|
|
213
|
+
return { code: `${l.code}${op}${r.code}` };
|
|
182
214
|
}
|
|
183
215
|
: alt,
|
|
184
216
|
);
|
|
@@ -187,9 +219,9 @@ export function migrateOperator(
|
|
|
187
219
|
case 'unaryMinus':
|
|
188
220
|
case 'unaryPlus': {
|
|
189
221
|
const op = fn === 'unaryMinus' ? '-' : '+';
|
|
190
|
-
const f = fn === 'unaryMinus' ? operations.$Neg : operations.$Pos;
|
|
191
222
|
const exp = migrateExpr(state, a0);
|
|
192
223
|
if (typeof exp.literal == 'number') {
|
|
224
|
+
const f = fn === 'unaryMinus' ? operations.$Neg : operations.$Pos;
|
|
193
225
|
const v = f(exp.literal);
|
|
194
226
|
return {
|
|
195
227
|
type: 'number',
|
|
@@ -197,7 +229,7 @@ export function migrateOperator(
|
|
|
197
229
|
code: serialize(v),
|
|
198
230
|
};
|
|
199
231
|
}
|
|
200
|
-
return unary(state, migrateExpr(state, a0), (v) => ({
|
|
232
|
+
return unary(state, migrateExpr(state, a0), (state, v) => ({
|
|
201
233
|
type: 'number',
|
|
202
234
|
code: `${op}${v.code}`,
|
|
203
235
|
}));
|
|
@@ -217,8 +249,10 @@ export function migrateOperator(
|
|
|
217
249
|
return scalar(f, state, r);
|
|
218
250
|
});
|
|
219
251
|
if (codes.every((c) => c.type === 'boolean' || c.as_boolean) && fn in BIT_OPS_TO_BOOL_OPS) {
|
|
220
|
-
const boolOp = BIT_OPS_TO_BOOL_OPS[fn as keyof typeof BIT_OPS_TO_BOOL_OPS];
|
|
221
|
-
const code =
|
|
252
|
+
const [boolOp, needParen] = BIT_OPS_TO_BOOL_OPS[fn as keyof typeof BIT_OPS_TO_BOOL_OPS];
|
|
253
|
+
const code = args
|
|
254
|
+
.map((a) => toBoolean(state, (needParen ? migrateParen : migrateExpr)(state, a)).code)
|
|
255
|
+
.join(` ${boolOp} `);
|
|
222
256
|
return {
|
|
223
257
|
type: 'number',
|
|
224
258
|
code: `to_number(${code})`,
|
|
@@ -253,7 +287,7 @@ export function migrateOperator(
|
|
|
253
287
|
case 'xor': {
|
|
254
288
|
return {
|
|
255
289
|
type: 'boolean',
|
|
256
|
-
code: `${open}${b('!=', state, a0)} != ${b('!=', state, a1)}${close}`,
|
|
290
|
+
code: `${open}${b('!=', state, a0, migrateParen)} != ${b('!=', state, a1, migrateParen)}${close}`,
|
|
257
291
|
};
|
|
258
292
|
}
|
|
259
293
|
case 'not': {
|
|
@@ -279,17 +313,21 @@ export function migrateOperator(
|
|
|
279
313
|
}
|
|
280
314
|
|
|
281
315
|
case 'equal':
|
|
282
|
-
case 'unequal':
|
|
283
|
-
|
|
316
|
+
case 'unequal':
|
|
317
|
+
case 'smaller':
|
|
318
|
+
case 'smallerEq':
|
|
319
|
+
case 'larger':
|
|
320
|
+
case 'largerEq': {
|
|
321
|
+
const [op, eqOp] = COMPARE_OPERATORS[fn];
|
|
284
322
|
const c0 = constantValue(a0);
|
|
285
323
|
const c1 = constantValue(a1);
|
|
286
|
-
if (c0 === null || c1 === null) {
|
|
287
|
-
|
|
288
|
-
const p0 = c0 === null ? { code: `nil` } :
|
|
289
|
-
const p1 = c1 === null ? { code: `nil` } :
|
|
324
|
+
if (eqOp && (c0 === null || c1 === null)) {
|
|
325
|
+
// Mathjs 只支持标量与 null 比较
|
|
326
|
+
const p0 = c0 === null ? { code: `nil` } : migrateExpr(state, a0);
|
|
327
|
+
const p1 = c1 === null ? { code: `nil` } : migrateExpr(state, a1);
|
|
290
328
|
return {
|
|
291
329
|
type: 'boolean',
|
|
292
|
-
code: `${open}${p0.code} ${
|
|
330
|
+
code: `${open}${p0.code} ${eqOp} ${p1.code}${close}`,
|
|
293
331
|
};
|
|
294
332
|
}
|
|
295
333
|
// PI, E 与常量比较时,不进行转换
|
|
@@ -307,23 +345,31 @@ export function migrateOperator(
|
|
|
307
345
|
return r;
|
|
308
346
|
};
|
|
309
347
|
|
|
310
|
-
return binary(state, a(a0), a(a1), (l, r) => {
|
|
348
|
+
return binary(state, a(a0), a(a1), (state, l, r) => {
|
|
349
|
+
if (l.literal !== undefined) {
|
|
350
|
+
return {
|
|
351
|
+
type: 'boolean',
|
|
352
|
+
code: `${toNumber(state, l).code} ${op} ${r.code}`,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
if (r.literal !== undefined) {
|
|
356
|
+
return {
|
|
357
|
+
type: 'boolean',
|
|
358
|
+
code: `${l.code} ${op} ${toNumber(state, r).code}`,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
if (l.type === 'number' || r.type === 'number') {
|
|
362
|
+
return {
|
|
363
|
+
type: 'boolean',
|
|
364
|
+
code: `${l.code} ${op} ${r.code}`,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
311
367
|
return {
|
|
312
368
|
type: 'boolean',
|
|
313
369
|
code: `${toNumber(state, l).code} ${op} ${toNumber(state, r).code}`,
|
|
314
370
|
};
|
|
315
371
|
});
|
|
316
372
|
}
|
|
317
|
-
case 'smaller':
|
|
318
|
-
case 'smallerEq':
|
|
319
|
-
case 'larger':
|
|
320
|
-
case 'largerEq': {
|
|
321
|
-
const op = COMPARE_OPERATORS[fn];
|
|
322
|
-
return {
|
|
323
|
-
type: 'boolean',
|
|
324
|
-
code: `${open}${scalar(op, state, migrateExpr(state, a0)).code} ${op} ${scalar(op, state, migrateExpr(state, a1)).code}${close}`,
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
373
|
|
|
328
374
|
default: {
|
|
329
375
|
state.err(`不支持的运算符: ${fn}`);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { VmValue } from '@mirascript/mirascript';
|
|
2
|
+
import { serialize as s, serializeNumber } from '@mirascript/mirascript/subtle';
|
|
3
|
+
|
|
4
|
+
/** 序列化 */
|
|
5
|
+
export function serialize(value: VmValue): string {
|
|
6
|
+
return s(value, {
|
|
7
|
+
serializeNumber: (value: number): string => {
|
|
8
|
+
if (!Number.isFinite(value) || value === 0) {
|
|
9
|
+
return serializeNumber(value);
|
|
10
|
+
}
|
|
11
|
+
const p1 = value.toString();
|
|
12
|
+
const p2 = value.toExponential();
|
|
13
|
+
// 还是优先选择默认的形式,除非指数形式更短很多
|
|
14
|
+
if (p2.length + 2 < p1.length) {
|
|
15
|
+
return p2;
|
|
16
|
+
} else {
|
|
17
|
+
return p1;
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
}
|
package/src/migrator/special.ts
CHANGED
|
@@ -12,6 +12,37 @@ const pairs: ReadonlyArray<{ find: string; mathjs: MathNode; mira: string }> = (
|
|
|
12
12
|
let d2 = matrix.diagonal([$yc, $yc, $yc], +3);
|
|
13
13
|
d0::matrix.add(d1)::matrix.add(d2)`,
|
|
14
14
|
],
|
|
15
|
+
// 长导线校正移到后台处理
|
|
16
|
+
[
|
|
17
|
+
'sinh(gamma',
|
|
18
|
+
`rpl = $R1pu * $Vbase * $Vbase / $Sbase; xpl = $X1pu * $Vbase * $Vbase / $Sbase;bpl = $B1pu / $Vbase / $Vbase * $Sbase; zp = rpl + i * xpl; yp = i * bpl; gamma = sqrt(zp * yp); z = $Length * zp * (gamma == 0 ? 1 : (sinh(gamma * $Length)/(gamma * $Length))); re(z)`,
|
|
19
|
+
'$R1pu * $Vbase * $Vbase / $Sbase * $Length',
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
'sinh(gamma',
|
|
23
|
+
`rpl = $R1pu * $Vbase * $Vbase / $Sbase; xpl = $X1pu * $Vbase * $Vbase / $Sbase;bpl = $B1pu / $Vbase / $Vbase * $Sbase; zp = rpl + i * xpl; yp = i * bpl; gamma = sqrt(zp * yp); z = $Length * zp * (gamma == 0 ? 1 : (sinh(gamma * $Length)/(gamma * $Length))); im(z)`,
|
|
24
|
+
'$X1pu * $Vbase * $Vbase / $Sbase * $Length',
|
|
25
|
+
],
|
|
26
|
+
[
|
|
27
|
+
'tanh(gamma',
|
|
28
|
+
`rpl = $R1pu * $Vbase * $Vbase / $Sbase; xpl = $X1pu * $Vbase * $Vbase / $Sbase;bpl = $B1pu / $Vbase / $Vbase * $Sbase; zp = rpl + i * xpl; yp = i * bpl; gamma = sqrt(zp * yp); y = $Length * yp * (gamma == 0 ? 1 : (tanh(gamma * $Length / 2) / (gamma * $Length / 2))); im(y)`,
|
|
29
|
+
'$B1pu / $Vbase / $Vbase * $Sbase * $Length',
|
|
30
|
+
],
|
|
31
|
+
[
|
|
32
|
+
'sinh(gamma',
|
|
33
|
+
`rpl = $R1; xpl = $Xl1; bpl = 1e-6 / $Xc1; zp = rpl + i * xpl; yp = i * bpl; gamma = sqrt(zp * yp); z = $Length * zp * (gamma == 0 ? 1 : (sinh(gamma * $Length)/(gamma * $Length))); re(z)`,
|
|
34
|
+
'$R1 * $Length',
|
|
35
|
+
],
|
|
36
|
+
[
|
|
37
|
+
'sinh(gamma',
|
|
38
|
+
`rpl = $R1; xpl = $Xl1; bpl = 1e-6 / $Xc1; zp = rpl + i * xpl; yp = i * bpl; gamma = sqrt(zp * yp); z = $Length * zp * (gamma == 0 ? 1 : (sinh(gamma * $Length)/(gamma * $Length))); im(z)`,
|
|
39
|
+
'$Xl1 * $Length',
|
|
40
|
+
],
|
|
41
|
+
[
|
|
42
|
+
'tanh(gamma',
|
|
43
|
+
`rpl = $R1; xpl = $Xl1; bpl = 1e-6 / $Xc1; zp = rpl + i * xpl; yp = i * bpl; gamma = sqrt(zp * yp); y = $Length * yp * (gamma == 0 ? 1 : (tanh(gamma * $Length / 2) / (gamma * $Length / 2))); im(y)`,
|
|
44
|
+
'1e-6 / $Xc1 * $Length',
|
|
45
|
+
],
|
|
15
46
|
] satisfies ReadonlyArray<[find: string, mathjs: string, mira: string]>
|
|
16
47
|
).map(([find, mathjs, mira]) => ({
|
|
17
48
|
find,
|