@cloudpss/expression 0.6.0-alpha.2 → 0.6.0-alpha.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/dist/analyze.d.ts +6 -3
  2. package/dist/analyze.d.ts.map +1 -1
  3. package/dist/analyze.js +67 -33
  4. package/dist/analyze.js.map +1 -1
  5. package/dist/definitions/argument.d.ts +3 -11
  6. package/dist/definitions/argument.d.ts.map +1 -1
  7. package/dist/definitions/constraint.d.ts +2 -2
  8. package/dist/definitions/constraint.d.ts.map +1 -1
  9. package/dist/definitions/constraint.js +1 -1
  10. package/dist/definitions/constraint.js.map +1 -1
  11. package/dist/definitions/parameter-decoration.d.ts +3 -3
  12. package/dist/definitions/parameter-decoration.d.ts.map +1 -1
  13. package/dist/definitions/parameter-decoration.js +0 -7
  14. package/dist/definitions/parameter-decoration.js.map +1 -1
  15. package/dist/definitions/parameter-group.d.ts +0 -4
  16. package/dist/definitions/parameter-group.d.ts.map +1 -1
  17. package/dist/definitions/parameter-group.js +5 -17
  18. package/dist/definitions/parameter-group.js.map +1 -1
  19. package/dist/definitions/parameter.d.ts +47 -40
  20. package/dist/definitions/parameter.d.ts.map +1 -1
  21. package/dist/definitions/parameter.js +9 -21
  22. package/dist/definitions/parameter.js.map +1 -1
  23. package/dist/definitions/utils.d.ts +28 -0
  24. package/dist/definitions/utils.d.ts.map +1 -0
  25. package/dist/definitions/utils.js +209 -0
  26. package/dist/definitions/utils.js.map +1 -0
  27. package/dist/definitions/variable.d.ts +0 -2
  28. package/dist/definitions/variable.d.ts.map +1 -1
  29. package/dist/definitions/variable.js +1 -5
  30. package/dist/definitions/variable.js.map +1 -1
  31. package/dist/definitions.d.ts +1 -0
  32. package/dist/definitions.d.ts.map +1 -1
  33. package/dist/definitions.js +1 -0
  34. package/dist/definitions.js.map +1 -1
  35. package/dist/eval.d.ts +3 -5
  36. package/dist/eval.d.ts.map +1 -1
  37. package/dist/eval.js +12 -20
  38. package/dist/eval.js.map +1 -1
  39. package/dist/expression.d.ts +10 -4
  40. package/dist/expression.d.ts.map +1 -1
  41. package/dist/expression.js +6 -6
  42. package/dist/expression.js.map +1 -1
  43. package/dist/index.d.ts +3 -1
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +1 -0
  46. package/dist/index.js.map +1 -1
  47. package/dist/interface.d.ts +30 -0
  48. package/dist/interface.d.ts.map +1 -0
  49. package/dist/interface.js +6 -0
  50. package/dist/interface.js.map +1 -0
  51. package/dist/main.d.ts +41 -28
  52. package/dist/main.d.ts.map +1 -1
  53. package/dist/main.js +149 -147
  54. package/dist/main.js.map +1 -1
  55. package/dist/migrate.d.ts +3 -2
  56. package/dist/migrate.d.ts.map +1 -1
  57. package/dist/migrate.js +25 -3
  58. package/dist/migrate.js.map +1 -1
  59. package/dist/migrator/access.d.ts.map +1 -1
  60. package/dist/migrator/access.js +45 -25
  61. package/dist/migrator/access.js.map +1 -1
  62. package/dist/migrator/call.d.ts.map +1 -1
  63. package/dist/migrator/call.js +298 -201
  64. package/dist/migrator/call.js.map +1 -1
  65. package/dist/migrator/concat.d.ts.map +1 -1
  66. package/dist/migrator/concat.js +15 -2
  67. package/dist/migrator/concat.js.map +1 -1
  68. package/dist/migrator/function.d.ts +6 -0
  69. package/dist/migrator/function.d.ts.map +1 -0
  70. package/dist/migrator/function.js +25 -0
  71. package/dist/migrator/function.js.map +1 -0
  72. package/dist/migrator/interface.d.ts +3 -1
  73. package/dist/migrator/interface.d.ts.map +1 -1
  74. package/dist/migrator/interface.js.map +1 -1
  75. package/dist/migrator/node.d.ts.map +1 -1
  76. package/dist/migrator/node.js +35 -6
  77. package/dist/migrator/node.js.map +1 -1
  78. package/dist/migrator/operator.d.ts.map +1 -1
  79. package/dist/migrator/operator.js +107 -60
  80. package/dist/migrator/operator.js.map +1 -1
  81. package/dist/migrator/serialize.d.ts +4 -0
  82. package/dist/migrator/serialize.d.ts.map +1 -0
  83. package/dist/migrator/serialize.js +21 -0
  84. package/dist/migrator/serialize.js.map +1 -0
  85. package/dist/migrator/special.d.ts.map +1 -1
  86. package/dist/migrator/special.js +31 -0
  87. package/dist/migrator/special.js.map +1 -1
  88. package/dist/migrator/state.d.ts +2 -2
  89. package/dist/migrator/state.d.ts.map +1 -1
  90. package/dist/migrator/state.js +30 -33
  91. package/dist/migrator/state.js.map +1 -1
  92. package/dist/migrator/symbol.d.ts.map +1 -1
  93. package/dist/migrator/symbol.js +23 -9
  94. package/dist/migrator/symbol.js.map +1 -1
  95. package/dist/migrator/to-type.d.ts.map +1 -1
  96. package/dist/migrator/to-type.js +21 -4
  97. package/dist/migrator/to-type.js.map +1 -1
  98. package/dist/migrator/utils.d.ts +6 -0
  99. package/dist/migrator/utils.d.ts.map +1 -1
  100. package/dist/migrator/utils.js +35 -0
  101. package/dist/migrator/utils.js.map +1 -1
  102. package/dist/parser.d.ts +2 -2
  103. package/dist/parser.d.ts.map +1 -1
  104. package/dist/parser.js +27 -8
  105. package/dist/parser.js.map +1 -1
  106. package/dist/re-exports.d.ts +4 -0
  107. package/dist/re-exports.d.ts.map +1 -0
  108. package/dist/re-exports.js +3 -0
  109. package/dist/re-exports.js.map +1 -0
  110. package/dist/scope.d.ts +17 -18
  111. package/dist/scope.d.ts.map +1 -1
  112. package/dist/scope.js +84 -53
  113. package/dist/scope.js.map +1 -1
  114. package/dist/type.d.ts +27 -6
  115. package/dist/type.d.ts.map +1 -1
  116. package/dist/type.js +34 -15
  117. package/dist/type.js.map +1 -1
  118. package/package.json +8 -5
  119. package/src/analyze.ts +77 -37
  120. package/src/definitions/argument.ts +3 -13
  121. package/src/definitions/constraint.ts +3 -3
  122. package/src/definitions/parameter-decoration.ts +3 -9
  123. package/src/definitions/parameter-group.ts +4 -19
  124. package/src/definitions/parameter.ts +70 -62
  125. package/src/definitions/utils.ts +224 -0
  126. package/src/definitions/variable.ts +1 -6
  127. package/src/definitions.ts +1 -0
  128. package/src/eval.ts +16 -25
  129. package/src/expression.ts +16 -8
  130. package/src/index.ts +3 -1
  131. package/src/interface.ts +35 -0
  132. package/src/main.ts +217 -199
  133. package/src/migrate.ts +30 -6
  134. package/src/migrator/access.ts +50 -33
  135. package/src/migrator/call.ts +287 -190
  136. package/src/migrator/concat.ts +15 -2
  137. package/src/migrator/function.ts +27 -0
  138. package/src/migrator/interface.ts +3 -1
  139. package/src/migrator/node.ts +36 -5
  140. package/src/migrator/operator.ts +110 -64
  141. package/src/migrator/serialize.ts +21 -0
  142. package/src/migrator/special.ts +31 -0
  143. package/src/migrator/state.ts +30 -33
  144. package/src/migrator/symbol.ts +23 -9
  145. package/src/migrator/to-type.ts +23 -4
  146. package/src/migrator/utils.ts +38 -0
  147. package/src/parser.ts +33 -8
  148. package/src/re-exports.ts +47 -0
  149. package/src/scope.ts +101 -65
  150. package/src/type.ts +52 -18
  151. package/tests/analyze.ts +40 -6
  152. package/tests/compile.ts +65 -0
  153. package/tests/condition.ts +33 -17
  154. package/tests/definition.ts +237 -18
  155. package/tests/eval-complex.ts +19 -11
  156. package/tests/eval.ts +59 -12
  157. package/tests/import.ts +21 -7
  158. package/tests/main.ts +58 -0
  159. package/tests/migrate.ts +308 -0
  160. package/tests/scope.ts +3 -3
  161. package/tests/template.ts +36 -0
  162. package/dist/context.d.ts +0 -41
  163. package/dist/context.d.ts.map +0 -1
  164. package/dist/context.js +0 -18
  165. package/dist/context.js.map +0 -1
  166. package/jest.config.js +0 -3
  167. package/src/context.ts +0 -54
  168. package/tests/tsconfig.json +0 -3
  169. package/tsconfig.json +0 -3
@@ -1,8 +1,9 @@
1
- import { isAccessorNode, isArrayNode, isConstantNode, isObjectNode, isOperatorNode, } from 'mathjs';
2
- import { constantValue, equalText, symbolName } from './utils.js';
1
+ import { isAccessorNode, isArrayNode, isConstantNode, isObjectNode, } from 'mathjs';
2
+ import { constantValue, equalText, globalFnName, len, symbolName } from './utils.js';
3
3
  import { migrateAtomic, migrateExpr, migrateNode } from './node.js';
4
4
  import { concat } from './concat.js';
5
5
  import { toNumber, toString } from './to-type.js';
6
+ import { isVmArray, isVmPrimitive } from '@mirascript/mirascript';
6
7
  const EXACT_UNARY_FUNCTION = new Map([
7
8
  // 只支持标量的 mathjs 函数
8
9
  ['sin', 'number'],
@@ -27,6 +28,8 @@ const EXACT_UNARY_FUNCTION = new Map([
27
28
  // XStudio 提供的函数
28
29
  ['service', 'extern'],
29
30
  ]);
31
+ /** 只接受一个参数,返回数字的函数 */
32
+ const ENTRYWISE_UNARY_MATH_FUNCTION = new Set(['abs', 'ceil', 'floor', 'round', 'sign']);
30
33
  /** 兜底 */
31
34
  function call(state, node, done) {
32
35
  const { fn, args } = node;
@@ -37,232 +40,323 @@ function call(state, node, done) {
37
40
  code: `${fnRet.code}(${argList.map((a) => a.code).join(', ')})`,
38
41
  };
39
42
  }
40
- /** 转换 AST */
41
- export function migrateCall(state, node, options) {
42
- const { fn, args } = node;
43
- const fnName = symbolName(fn);
44
- if (fnName && !state.locals.has(fnName)) {
45
- const openE = options.format !== 'no-paren' ? '(' : '';
46
- const closeE = options.format !== 'no-paren' ? ')' : '';
47
- if (EXACT_UNARY_FUNCTION.has(fnName) && args.length === 1) {
48
- const arg = migrateAtomic(state, args[0]);
49
- return {
50
- type: EXACT_UNARY_FUNCTION.get(fnName),
51
- code: `${fnName}(${arg.code})`,
52
- };
53
- }
54
- else if (fnName === 're' || fnName === 'im') {
55
- const m = migrateAtomic(state, args[0]);
56
- state.err(`不支持复数`);
57
- return {
58
- type: 'number',
59
- code: `/* ${fnName} */(${m.code})`,
60
- };
61
- }
62
- else if (fnName === 'date' && args.length === 1) {
43
+ /** 函数调用 */
44
+ function migrateFunctionCall(state, node, fnName, args, options) {
45
+ const openE = options.format !== 'no-paren' ? '(' : '';
46
+ const closeE = options.format !== 'no-paren' ? ')' : '';
47
+ const g = (fnName) => globalFnName(state, fnName);
48
+ if (EXACT_UNARY_FUNCTION.has(fnName) && args.length === 1) {
49
+ const arg = migrateAtomic(state, args[0]);
50
+ return {
51
+ type: EXACT_UNARY_FUNCTION.get(fnName),
52
+ code: `${fnName}(${arg.code})`,
53
+ };
54
+ }
55
+ else if (fnName === 'random' && args.length === 0) {
56
+ return {
57
+ type: 'number',
58
+ code: `${g('random')}()`,
59
+ };
60
+ }
61
+ else if (ENTRYWISE_UNARY_MATH_FUNCTION.has(fnName) && args.length === 1) {
62
+ const arg = migrateAtomic(state, args[0]);
63
+ if (arg.type === 'number' || arg.type === 'boolean' || arg.type === 'string') {
63
64
  return {
64
65
  type: 'number',
65
- code: `to_timestamp(${migrateAtomic(state, args[0]).code})`,
66
+ code: `${g(fnName)}(${arg.code})`,
66
67
  };
67
68
  }
68
- else if (fnName === 'inv' && args.length === 1) {
69
+ return {
70
+ type: arg.type,
71
+ code: `${g('matrix')}.entrywise(${arg.code}, nil, ${g(fnName)})`,
72
+ };
73
+ }
74
+ else if (fnName === 'max' || fnName === 'min') {
75
+ if (args.length === 1) {
69
76
  const arg = migrateAtomic(state, args[0]);
70
77
  return {
71
- type: arg.type,
72
- code: `matrix.invert(${arg.code})`,
78
+ type: 'number',
79
+ code: `${g(fnName)}(${arg.code})`,
73
80
  };
74
81
  }
75
- else if (fnName === 'transpose' && args.length === 1) {
76
- const arg = migrateAtomic(state, args[0]);
82
+ else {
83
+ const argList = args.map((a) => migrateAtomic(state, a));
84
+ if (!argList.every((a) => a.type === 'number' || a.type === 'boolean' || a.type === 'string')) {
85
+ state.warn(`函数行为可能不一致: ${fnName}`);
86
+ }
77
87
  return {
78
- type: arg.type,
79
- code: `matrix.transpose(${arg.code})`,
88
+ type: 'number',
89
+ code: `${g(fnName)}(${argList.map((a) => a.code).join(', ')})`,
80
90
  };
81
91
  }
82
- else if (fnName === 'diag' && (args.length === 1 || args.length === 2)) {
83
- const a = args.map((a) => migrateAtomic(state, a).code).join(', ');
84
- return {
85
- type: 'array',
86
- code: `matrix.diagonal(${a})`,
87
- };
92
+ }
93
+ else if (fnName === 're' || fnName === 'im') {
94
+ const m = migrateAtomic(state, args[0]);
95
+ state.err(`不支持复数`);
96
+ return {
97
+ type: 'number',
98
+ code: `/* ${fnName} */(${m.code})`,
99
+ };
100
+ }
101
+ else if (fnName === 'date' && args.length === 1) {
102
+ return {
103
+ type: 'number',
104
+ code: `${g('to_timestamp')}(${migrateAtomic(state, args[0]).code})`,
105
+ };
106
+ }
107
+ else if (fnName === 'size' && args.length === 1) {
108
+ const arg = migrateAtomic(state, args[0]);
109
+ return {
110
+ type: arg.type,
111
+ code: `${g('matrix')}.size(${arg.code})`,
112
+ };
113
+ }
114
+ else if (fnName === 'inv' && args.length === 1) {
115
+ const arg = migrateAtomic(state, args[0]);
116
+ return {
117
+ type: arg.type,
118
+ code: `${g('matrix')}.invert(${arg.code})`,
119
+ };
120
+ }
121
+ else if (fnName === 'count' && args.length === 1) {
122
+ const arg = migrateAtomic(state, args[0]);
123
+ if (arg.type !== 'string') {
124
+ state.warn(`函数行为可能不一致: count`);
88
125
  }
89
- else if (fnName === 'zeros' || fnName === 'ones' || fnName === 'identity') {
126
+ return len(state, arg);
127
+ }
128
+ else if (fnName === 'transpose' && args.length === 1) {
129
+ const arg = migrateAtomic(state, args[0]);
130
+ return {
131
+ type: arg.type,
132
+ code: `${g('matrix')}.transpose(${arg.code})`,
133
+ };
134
+ }
135
+ else if (fnName === 'diag' && (args.length === 1 || args.length === 2)) {
136
+ const a = args.map((a) => migrateAtomic(state, a).code).join(', ');
137
+ return {
138
+ type: 'array',
139
+ code: `${g('matrix')}.diagonal(${a})`,
140
+ };
141
+ }
142
+ else if (fnName === 'zeros' || fnName === 'ones' || fnName === 'identity') {
143
+ return {
144
+ type: 'array',
145
+ code: `${g('matrix')}.${fnName}(${args.map((a) => migrateAtomic(state, a).code).join(', ')})`,
146
+ };
147
+ }
148
+ else if (fnName === 'concat') {
149
+ const results = args.map((a) => migrateAtomic(state, a));
150
+ if (results.some((r) => r.type === 'string'))
151
+ return concat(state, results);
152
+ if (results.some((r) => r.type === 'array')) {
153
+ state.warn(`矩阵连接时结果可能不一致`);
90
154
  return {
91
155
  type: 'array',
92
- code: `matrix.${fnName}(${args.map((a) => migrateAtomic(state, a).code).join(', ')})`,
156
+ code: `${g('flatten')}([` + results.map((r) => r.code).join(', ') + `])`,
93
157
  };
94
158
  }
95
- else if (fnName === 'concat') {
96
- const results = args.map((a) => migrateAtomic(state, a));
97
- if (results.some((r) => r.type === 'string'))
98
- return concat(state, results);
99
- }
100
- else if (fnName === 'numeric' && args.length === 1) {
101
- return toNumber(state, args[0]);
102
- }
103
- else if (fnName === 'flatten' && args.length === 1) {
159
+ }
160
+ else if (fnName === 'numeric' && args.length === 1) {
161
+ return toNumber(state, args[0]);
162
+ }
163
+ else if (fnName === 'flatten' && args.length === 1) {
164
+ return {
165
+ type: 'array',
166
+ code: `${g('flatten')}(${migrateAtomic(state, args[0]).code})`,
167
+ };
168
+ }
169
+ else if (fnName === 'norm' && args.length === 1) {
170
+ if (isArrayNode(args[0])) {
104
171
  return {
105
- type: 'array',
106
- code: `flatten(${migrateAtomic(state, args[0]).code})`,
172
+ type: 'number',
173
+ code: `${g('hypot')}(${args[0].items.map((a) => migrateAtomic(state, a).code).join(', ')})`,
107
174
  };
108
175
  }
109
- else if (fnName === 'norm' && args.length === 1) {
110
- if (isArrayNode(args[0])) {
176
+ return {
177
+ type: 'number',
178
+ code: `${g('hypot')}(${migrateAtomic(state, args[0]).code})`,
179
+ };
180
+ }
181
+ else if (fnName === 'equalText' && args.length === 2) {
182
+ const p = equalText(state, '==', args[0], args[1]);
183
+ return {
184
+ type: p.type,
185
+ code: `${openE}${p.code}${closeE}`,
186
+ };
187
+ }
188
+ else if (fnName === 'toJson' && args.length === 1) {
189
+ return {
190
+ type: 'string',
191
+ code: `${g('to_json')}(${migrateAtomic(state, args[0]).code})`,
192
+ };
193
+ }
194
+ else if (fnName === 'fromJson' && args.length === 1) {
195
+ return {
196
+ code: `${g('from_json')}(${migrateAtomic(state, args[0]).code})`,
197
+ };
198
+ }
199
+ else if (fnName === 'is' && args.length === 2 && isConstantNode(args[1])) {
200
+ const t = String(args[1].value);
201
+ switch (t) {
202
+ case 'number':
203
+ case 'string':
204
+ case 'boolean':
111
205
  return {
112
- type: 'number',
113
- code: `hypot(${args[0].items.map((a) => migrateAtomic(state, a).code).join(', ')})`,
206
+ type: 'boolean',
207
+ code: `${openE}type(${migrateAtomic(state, args[0]).code}) == '${t}'${closeE}`,
114
208
  };
115
- }
116
- return {
117
- type: 'number',
118
- code: `hypot(${migrateAtomic(state, args[0]).code})`,
119
- };
120
- }
121
- else if (fnName === 'equalText' && args.length === 2) {
122
- const p = equalText(state, '==', args[0], args[1]);
123
- return {
124
- type: p.type,
125
- code: `${openE}${p.code}${closeE}`,
126
- };
127
- }
128
- else if (fnName === 'toJson' && args.length === 1) {
129
- return {
130
- type: 'string',
131
- code: `to_json(${migrateAtomic(state, args[0]).code})`,
132
- };
133
- }
134
- else if (fnName === 'fromJson' && args.length === 1) {
135
- return {
136
- code: `from_json(${migrateAtomic(state, args[0]).code})`,
137
- };
138
- }
139
- else if (fnName === 'is' && args.length === 2 && isConstantNode(args[1])) {
140
- const t = String(args[1].value);
141
- switch (t) {
142
- case 'number':
143
- case 'string':
144
- case 'boolean':
145
- return {
146
- type: 'boolean',
147
- code: `${openE}type(${migrateAtomic(state, args[0]).code}) == '${t}'${closeE}`,
148
- };
149
- case 'null':
150
- case 'undefined':
151
- return {
152
- type: 'boolean',
153
- code: `${openE}type(${migrateAtomic(state, args[0]).code}) == 'nil'${closeE}`,
154
- };
155
- case 'Array':
156
- case 'array':
157
- state.warn(`'type' 与 'is' 结果可能不同`);
158
- return {
159
- type: 'boolean',
160
- code: `${openE}type(${migrateAtomic(state, args[0]).code}) == 'array'${closeE}`,
161
- };
162
- case 'Object':
163
- case 'object':
164
- state.warn(`'type' 与 'is' 结果可能不同`);
209
+ case 'null':
210
+ case 'undefined':
211
+ return {
212
+ type: 'boolean',
213
+ code: `${openE}type(${migrateAtomic(state, args[0]).code}) == 'nil'${closeE}`,
214
+ };
215
+ case 'Array':
216
+ case 'array':
217
+ state.warn(`'type' 与 'is' 结果可能不同`);
218
+ return {
219
+ type: 'boolean',
220
+ code: `${openE}type(${migrateAtomic(state, args[0]).code}) == 'array'${closeE}`,
221
+ };
222
+ case 'Object':
223
+ case 'object': {
224
+ const arg0 = migrateAtomic(state, args[0]);
225
+ if (arg0.code.endsWith('.value.rt_state')) {
165
226
  return {
166
227
  type: 'boolean',
167
- code: `${openE}type(${migrateAtomic(state, args[0]).code}) == 'record'${closeE}`,
228
+ code: `${openE}!!${arg0.code}${closeE}`,
168
229
  };
169
- case 'Function':
170
- case 'function': {
171
- if (symbolName(args[0]) === 'service' && !state.locals.has('service')) {
172
- return {
173
- type: 'boolean',
174
- code: `${openE}type(service) == 'extern'${closeE}`,
175
- };
176
- }
177
- state.warn(`'type' 'is' 结果可能不同`);
230
+ }
231
+ state.warn(`'type' 'is' 结果可能不同`);
232
+ return {
233
+ type: 'boolean',
234
+ code: `${openE}type(${arg0.code}) == 'record'${closeE}`,
235
+ };
236
+ }
237
+ case 'Function':
238
+ case 'function': {
239
+ if (symbolName(args[0]) === 'service' && !state.locals.has('service')) {
178
240
  return {
179
241
  type: 'boolean',
180
- code: `${openE}type(${migrateAtomic(state, args[0]).code}) == 'function'${closeE}`,
242
+ code: `${openE}type(service) == 'extern'${closeE}`,
181
243
  };
182
244
  }
245
+ state.warn(`'type' 与 'is' 结果可能不同`);
246
+ return {
247
+ type: 'boolean',
248
+ code: `${openE}type(${migrateAtomic(state, args[0]).code}) == 'function'${closeE}`,
249
+ };
183
250
  }
184
251
  }
185
- else if (fnName === 'typeOf' && args.length === 1) {
186
- state.warn(`'type' 'typeOf' 结果可能不同`);
187
- return {
188
- type: 'string',
189
- code: `type(${migrateAtomic(state, args[0]).code})`,
190
- };
191
- }
192
- else if (fnName === 'format' && args.length === 1) {
193
- return toString(state, args[0]);
194
- }
195
- else if (fnName === 'print' && args.length === 1) {
196
- state.loose();
197
- return toString(state, args[0]);
198
- }
199
- else if (fnName === 'print' &&
200
- args.length === 2 &&
201
- isConstantNode(args[0]) &&
202
- (isObjectNode(args[1]) || isArrayNode(args[1]))) {
203
- const template = String(args[0].value);
204
- const values = isObjectNode(args[1])
205
- ? args[1].properties
206
- : args[1].items;
207
- return {
208
- type: 'string',
209
- code: '`' +
210
- template.replaceAll(/`|\$([\w.]+)/g, (original, key) => {
211
- if (original === '`')
212
- return '\\`';
213
- const keys = key.split('.').map((part) => {
214
- const nPart = Number.parseInt(part);
215
- if (!Number.isNaN(nPart) && part.length > 0 && nPart >= 1) {
216
- return nPart - 1;
217
- }
218
- else {
219
- return part;
220
- }
221
- });
222
- const value = values[keys.shift()];
223
- if (value == null)
224
- return original.replaceAll('$', String.raw `\$`);
225
- if (!keys.length) {
226
- return `$(${migrateAtomic(state, value).code})`;
252
+ }
253
+ else if (fnName === 'typeOf' && args.length === 1) {
254
+ state.warn(`'type' 与 'typeOf' 结果可能不同`);
255
+ return {
256
+ type: 'string',
257
+ code: `type(${migrateAtomic(state, args[0]).code})`,
258
+ };
259
+ }
260
+ else if (fnName === 'format' && args.length === 1) {
261
+ return toString(state, args[0]);
262
+ }
263
+ else if (fnName === 'print' && args.length === 1) {
264
+ state.loose();
265
+ return toString(state, args[0]);
266
+ }
267
+ else if (fnName === 'print' &&
268
+ args.length === 2 &&
269
+ isConstantNode(args[0]) &&
270
+ (isObjectNode(args[1]) || isArrayNode(args[1]))) {
271
+ const template = String(args[0].value);
272
+ const values = isObjectNode(args[1])
273
+ ? args[1].properties
274
+ : args[1].items;
275
+ return {
276
+ type: 'string',
277
+ code: '`' +
278
+ template.replaceAll(/`|\$([\w.]+)/g, (original, key) => {
279
+ if (original === '`')
280
+ return '\\`';
281
+ const keys = key.split('.').map((part) => {
282
+ const nPart = Number.parseInt(part);
283
+ if (!Number.isNaN(nPart) && part.length > 0 && nPart >= 1) {
284
+ return nPart - 1;
227
285
  }
228
- return `$(${migrateNode(state, value, { format: 'paren' }).code}.${keys.join('.')})`;
229
- }) +
230
- '`',
231
- };
232
- }
233
- else if (fnName === 'string' && args.length === 1) {
234
- const inner = migrateAtomic(state, args[0]);
286
+ else {
287
+ return part;
288
+ }
289
+ });
290
+ const value = values[keys.shift()];
291
+ if (value == null)
292
+ return original.replaceAll('$', String.raw `\$`);
293
+ if (!keys.length) {
294
+ return `$(${migrateAtomic(state, value).code})`;
295
+ }
296
+ return `$(${migrateNode(state, value, { format: 'paren' }).code}.${keys.join('.')})`;
297
+ }) +
298
+ '`',
299
+ };
300
+ }
301
+ else if (fnName === 'string' && args.length === 1) {
302
+ const inner = migrateAtomic(state, args[0]);
303
+ return {
304
+ type: 'string',
305
+ code: `${g('to_string')}(${inner.code})`,
306
+ };
307
+ }
308
+ else if (fnName === 'sum' || fnName === 'prod') {
309
+ const newFnName = fnName === 'sum' ? 'sum' : 'product';
310
+ if (args.length !== 1) {
235
311
  return {
236
- type: 'string',
237
- code: `to_string(${inner.code})`,
312
+ type: 'number',
313
+ code: `${g(newFnName)}(${args.map((a) => migrateAtomic(state, a).code).join(', ')})`,
238
314
  };
239
315
  }
240
- else if (fnName === 'sum' &&
241
- args.length === 1 &&
242
- isArrayNode(args[0]) &&
243
- args[0].items.length === 1 &&
244
- isOperatorNode(args[0].items[0]) &&
245
- ['>=', '>', '<=', '<', '==', '!='].includes(args[0].items[0].op) &&
246
- typeof constantValue(args[0].items[0].args[1]) === 'number') {
247
- // sum([a > v])
248
- const a = migrateAtomic(state, args[0].items[0].args[0]);
249
- const v = migrateAtomic(state, args[0].items[0].args[1]);
316
+ const arg = migrateAtomic(state, args[0]);
317
+ if (arg.literal) {
318
+ if (isVmPrimitive(arg.literal)) {
319
+ return {
320
+ type: 'number',
321
+ code: `${g(newFnName)}(${arg.code})`,
322
+ };
323
+ }
324
+ if (isVmArray(arg.literal) && arg.literal.every((v) => isVmPrimitive(v))) {
325
+ return {
326
+ type: 'number',
327
+ code: `${g(newFnName)}(${arg.code})`,
328
+ };
329
+ }
330
+ }
331
+ if (arg.type === 'array' || !arg.type) {
250
332
  return {
251
333
  type: 'number',
252
- code: `sum(map(${a.code}, fn { it ${args[0].items[0].op} ${v.code} }))`,
334
+ code: `${g(newFnName)}(${arg.code}::${g('flatten')}())`,
253
335
  };
254
336
  }
255
- return call(state, node, (fn, args) => {
256
- const fun = state.globals.get(fnName);
257
- if (typeof fun === 'function') {
258
- if (args.some((a) => a.type !== 'number' && a.type !== 'boolean' && a.type !== 'string')) {
259
- state.warn(`函数行为可能不一致: ${fnName}`);
260
- }
261
- }
262
- else {
263
- state.err(`不支持的函数: ${fnName}`);
337
+ return {
338
+ type: 'number',
339
+ code: `${g(newFnName)}(${arg.code})`,
340
+ };
341
+ }
342
+ return call(state, node, (fn, args) => {
343
+ const fun = state.globals.has(fnName) ? state.globals.get(fnName) : undefined;
344
+ if (typeof fun === 'function') {
345
+ if (args.some((a) => a.type !== 'number' && a.type !== 'boolean' && a.type !== 'string')) {
346
+ state.warn(`函数行为可能不一致: ${fnName}`);
264
347
  }
265
- });
348
+ }
349
+ else {
350
+ state.err(`不支持的函数: ${fnName}`);
351
+ }
352
+ });
353
+ }
354
+ /** 转换 AST */
355
+ export function migrateCall(state, node, options) {
356
+ const { fn, args } = node;
357
+ const fnName = symbolName(fn);
358
+ if (fnName && !state.locals.has(fnName)) {
359
+ return migrateFunctionCall(state, node, fnName, args, options);
266
360
  }
267
361
  if (isAccessorNode(fn) &&
268
362
  fn.index.dimensions.length === 1 &&
@@ -270,10 +364,11 @@ export function migrateCall(state, node, options) {
270
364
  typeof fn.index.dimensions[0].value == 'string') {
271
365
  const thisArg = migrateExpr(state, fn.object);
272
366
  const fnName = String(fn.index.dimensions[0].value);
367
+ const g = (fnName) => globalFnName(state, fnName);
273
368
  if (fnName === 'toString' && args.length === 0) {
274
369
  return {
275
370
  type: 'string',
276
- code: `${thisArg.code}::to_string()`,
371
+ code: `${thisArg.code}::${g('to_string')}()`,
277
372
  };
278
373
  }
279
374
  else if (fnName === 'includes' && args.length === 1) {
@@ -286,7 +381,7 @@ export function migrateCall(state, node, options) {
286
381
  if (thisArg.type === 'string') {
287
382
  return {
288
383
  type: 'boolean',
289
- code: `${thisArg.code}::contains(${migrateAtomic(state, args[0]).code})`,
384
+ code: `${thisArg.code}::${g('contains')}(${migrateAtomic(state, args[0]).code})`,
290
385
  };
291
386
  }
292
387
  state.helper(`fn @@includes(it, el) { match it::type() { case 'string' { it::contains(el) } case 'array' { el in it } case _ { false } } }`);
@@ -298,30 +393,30 @@ export function migrateCall(state, node, options) {
298
393
  else if ((fnName === 'map' || fnName === 'filter') && args.length === 1) {
299
394
  return {
300
395
  type: 'array',
301
- code: `${thisArg.code}::${fnName}(${migrateAtomic(state, args[0]).code})`,
396
+ code: `${thisArg.code}::${g(fnName)}(${migrateAtomic(state, args[0]).code})`,
302
397
  };
303
398
  }
304
399
  else if (fnName === 'find' && args.length === 1) {
305
400
  return {
306
- code: `${thisArg.code}::find(${migrateAtomic(state, args[0]).code}).1`,
401
+ code: `${thisArg.code}::${g('find')}(${migrateAtomic(state, args[0]).code}).1`,
307
402
  };
308
403
  }
309
404
  else if (fnName === 'findIndex' && args.length === 1) {
310
405
  return {
311
406
  type: 'number',
312
- code: `(${thisArg.code}::find(${migrateAtomic(state, args[0]).code}).0 ?? -1)`,
407
+ code: `(${thisArg.code}::${g('find')}(${migrateAtomic(state, args[0]).code}).0 ?? -1)`,
313
408
  };
314
409
  }
315
410
  else if (fnName === 'flatMap' && args.length === 1) {
316
411
  return {
317
412
  type: 'array',
318
- code: `${thisArg.code}::map(${migrateAtomic(state, args[0]).code})::flatten()`,
413
+ code: `${thisArg.code}::${g('map')}(${migrateAtomic(state, args[0]).code})::flatten()`,
319
414
  };
320
415
  }
321
416
  else if (fnName === 'reverse' && args.length === 0) {
322
417
  return {
323
418
  type: 'array',
324
- code: `${thisArg.code}::reverse()`,
419
+ code: `${thisArg.code}::${g('reverse')}()`,
325
420
  };
326
421
  }
327
422
  else if ((fnName === 'replaceAll' || fnName === 'replace') && args.length === 2) {
@@ -330,13 +425,13 @@ export function migrateCall(state, node, options) {
330
425
  }
331
426
  return {
332
427
  type: 'string',
333
- code: `${thisArg.code}::replace(${migrateAtomic(state, args[0]).code}, ${migrateAtomic(state, args[1]).code})`,
428
+ code: `${thisArg.code}::${g('replace')}(${migrateAtomic(state, args[0]).code}, ${migrateAtomic(state, args[1]).code})`,
334
429
  };
335
430
  }
336
431
  else if (fnName === 'split' && args.length === 1) {
337
432
  return {
338
433
  type: 'array',
339
- code: `${thisArg.code}::split(${migrateAtomic(state, args[0]).code})`,
434
+ code: `${thisArg.code}::${g('split')}(${migrateAtomic(state, args[0]).code})`,
340
435
  };
341
436
  }
342
437
  else if (fnName === 'concat') {
@@ -349,7 +444,9 @@ export function migrateCall(state, node, options) {
349
444
  }
350
445
  return {
351
446
  type: 'array',
352
- code: `flatten([` + [fn.object, ...args].map((a) => migrateAtomic(state, a).code).join(', ') + `])`,
447
+ code: `${g('flatten')}([` +
448
+ [fn.object, ...args].map((a) => migrateAtomic(state, a).code).join(', ') +
449
+ `])`,
353
450
  };
354
451
  }
355
452
  else if (fnName === 'toFixed' &&
@@ -357,7 +454,7 @@ export function migrateCall(state, node, options) {
357
454
  const digits = constantValue(args[0]) ?? 0;
358
455
  return {
359
456
  type: 'string',
360
- code: `${thisArg.code}::format('.${digits}')`,
457
+ code: `${thisArg.code}::${g('format')}('.${digits}')`,
361
458
  };
362
459
  }
363
460
  else if (isArrayNode(fn.object) && fnName === 'join' && args.length <= 1) {
@@ -391,7 +488,7 @@ export function migrateCall(state, node, options) {
391
488
  else if (thisArg.type === 'extern') {
392
489
  const argList = args.map((a) => migrateAtomic(state, a).code);
393
490
  return {
394
- code: `${thisArg.code}(${argList.join(', ')})`,
491
+ code: `${thisArg.code}.${fnName}(${argList.join(', ')})`,
395
492
  };
396
493
  }
397
494
  state.err(`不支持的方法: ${fnName}`);