ts2workflows 0.7.0 → 0.9.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/README.md +8 -2
- package/dist/ast/expressions.d.ts +9 -0
- package/dist/ast/expressions.d.ts.map +1 -1
- package/dist/ast/expressions.js +43 -19
- package/dist/ast/steps.d.ts +27 -7
- package/dist/ast/steps.d.ts.map +1 -1
- package/dist/ast/steps.js +104 -21
- package/dist/cli.js +85 -28
- package/dist/transpiler/expressions.d.ts +0 -1
- package/dist/transpiler/expressions.d.ts.map +1 -1
- package/dist/transpiler/expressions.js +52 -61
- package/dist/transpiler/index.d.ts +1 -1
- package/dist/transpiler/index.d.ts.map +1 -1
- package/dist/transpiler/index.js +16 -7
- package/dist/transpiler/statements.d.ts +4 -3
- package/dist/transpiler/statements.d.ts.map +1 -1
- package/dist/transpiler/statements.js +379 -103
- package/dist/transpiler/transformations.d.ts +0 -6
- package/dist/transpiler/transformations.d.ts.map +1 -1
- package/dist/transpiler/transformations.js +88 -148
- package/dist/utils.d.ts +1 -5
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +3 -16
- package/language_reference.md +120 -61
- package/package.json +9 -5
|
@@ -1,19 +1,18 @@
|
|
|
1
|
+
import * as R from 'ramda';
|
|
1
2
|
import { AST_NODE_TYPES } from '@typescript-eslint/typescript-estree';
|
|
2
|
-
import { AssignStepAST, CallStepAST, ForStepAST, JumpTargetAST, NextStepAST, ParallelStepAST, RaiseStepAST, ReturnStepAST, StepsStepAST, SwitchStepAST, TryStepAST, } from '../ast/steps.js';
|
|
3
|
-
import { BinaryExpression, FunctionInvocationExpression, PrimitiveExpression, VariableReferenceExpression, isExpression, isFullyQualifiedName, isLiteral, } from '../ast/expressions.js';
|
|
3
|
+
import { AssignStepAST, CallStepAST, ForRangeStepAST, ForStepAST, JumpTargetAST, NextStepAST, ParallelStepAST, RaiseStepAST, ReturnStepAST, StepsStepAST, SwitchStepAST, TryStepAST, } from '../ast/steps.js';
|
|
4
|
+
import { BinaryExpression, FunctionInvocationExpression, MemberExpression, PrimitiveExpression, VariableReferenceExpression, asExpression, isExpression, isFullyQualifiedName, isLiteral, isPure, nullEx, safeAsExpression, trueEx, } from '../ast/expressions.js';
|
|
4
5
|
import { InternalTranspilingError, WorkflowSyntaxError } from '../errors.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { convertExpression, convertMemberExpression, convertObjectExpression, convertObjectAsExpressionValues, isMagicFunction, throwIfSpread, isMagicFunctionStatmentOnly, asExpression, } from './expressions.js';
|
|
6
|
+
import { chainPairs, isRecord } from '../utils.js';
|
|
7
|
+
import { convertExpression, convertMemberExpression, convertObjectExpression, convertObjectAsExpressionValues, isMagicFunction, throwIfSpread, isMagicFunctionStatmentOnly, } from './expressions.js';
|
|
8
8
|
import { blockingFunctions } from './generated/functionMetadata.js';
|
|
9
|
-
export function parseStatement(node, ctx
|
|
10
|
-
|
|
11
|
-
return transformAST(steps.concat(postSteps ?? []));
|
|
9
|
+
export function parseStatement(node, ctx) {
|
|
10
|
+
return parseStatementRecursively(node, undefined, ctx);
|
|
12
11
|
}
|
|
13
12
|
function parseStatementRecursively(node, nextNode, ctx) {
|
|
14
13
|
switch (node.type) {
|
|
15
14
|
case AST_NODE_TYPES.BlockStatement:
|
|
16
|
-
return
|
|
15
|
+
return chainPairs(R.partialRight(parseStatementRecursively, [ctx]), node.body);
|
|
17
16
|
case AST_NODE_TYPES.VariableDeclaration:
|
|
18
17
|
return convertVariableDeclarations(node.declarations, ctx);
|
|
19
18
|
case AST_NODE_TYPES.ExpressionStatement:
|
|
@@ -24,7 +23,7 @@ function parseStatementRecursively(node, nextNode, ctx) {
|
|
|
24
23
|
return callExpressionToStep(node.expression, undefined, ctx);
|
|
25
24
|
}
|
|
26
25
|
else {
|
|
27
|
-
return [generalExpressionToAssignStep(node.expression)];
|
|
26
|
+
return [generalExpressionToAssignStep(node.expression, ctx)];
|
|
28
27
|
}
|
|
29
28
|
case AST_NODE_TYPES.ReturnStatement:
|
|
30
29
|
return [returnStatementToReturnStep(node, ctx)];
|
|
@@ -71,27 +70,279 @@ function parseStatementRecursively(node, nextNode, ctx) {
|
|
|
71
70
|
}
|
|
72
71
|
function convertVariableDeclarations(declarations, ctx) {
|
|
73
72
|
return declarations.flatMap((decl) => {
|
|
74
|
-
if (decl.id.type
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
73
|
+
if (decl.id.type === AST_NODE_TYPES.Identifier) {
|
|
74
|
+
return convertInitializer(decl.id.name, decl.init, ctx);
|
|
75
|
+
}
|
|
76
|
+
else if (decl.id.type === AST_NODE_TYPES.ArrayPattern) {
|
|
77
|
+
return convertArrayDestructuring(decl.id, decl.init, ctx);
|
|
78
|
+
}
|
|
79
|
+
else if (decl.id.type === AST_NODE_TYPES.ObjectPattern) {
|
|
80
|
+
return convertObjectDestructuring(decl.id, decl.init, ctx);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
throw new WorkflowSyntaxError('Unsupported pattern', decl.loc);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function convertInitializer(targetVariableName, initializer, ctx) {
|
|
88
|
+
if (initializer?.type === AST_NODE_TYPES.CallExpression) {
|
|
89
|
+
const calleeName = initializer.callee.type === AST_NODE_TYPES.Identifier
|
|
90
|
+
? initializer.callee.name
|
|
91
|
+
: undefined;
|
|
92
|
+
if (calleeName && isMagicFunctionStatmentOnly(calleeName)) {
|
|
93
|
+
throw new WorkflowSyntaxError(`"${calleeName}" can't be called as part of an expression`, initializer.callee.loc);
|
|
94
|
+
}
|
|
95
|
+
return callExpressionToStep(initializer, targetVariableName, ctx);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
const value = initializer === null ? nullEx : convertExpression(initializer);
|
|
99
|
+
return [new AssignStepAST([[targetVariableName, value]])];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function convertArrayDestructuring(arrayPattern, initializer, ctx) {
|
|
103
|
+
let initExpression;
|
|
104
|
+
const steps = [];
|
|
105
|
+
if (initializer?.type === AST_NODE_TYPES.Identifier ||
|
|
106
|
+
initializer?.type === AST_NODE_TYPES.MemberExpression) {
|
|
107
|
+
// If the initializer is an Identifier or MemberExpression (array variable?),
|
|
108
|
+
// use it directly. This ensures that the recursive variables gets initialized
|
|
109
|
+
// in the correct order. For example:
|
|
110
|
+
// const arr = [1, 2]
|
|
111
|
+
// [arr[1], arr[0]] = arr
|
|
112
|
+
initExpression = convertExpression(initializer);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// Otherwise, assign the expression to a temporary variable first.
|
|
116
|
+
const initName = tempName(ctx);
|
|
117
|
+
steps.push(...convertInitializer(initName, initializer, ctx));
|
|
118
|
+
initExpression = new VariableReferenceExpression(initName);
|
|
119
|
+
}
|
|
120
|
+
steps.push(...arrayDestructuringSteps(arrayPattern.elements, initExpression, ctx));
|
|
121
|
+
return steps;
|
|
122
|
+
}
|
|
123
|
+
function arrayDestructuringSteps(patterns, initializerExpression, ctx) {
|
|
124
|
+
if (patterns.filter((p) => p !== null).length === 0) {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
const __temp_len = `${tempName(ctx)}_len`;
|
|
128
|
+
const initializeVariables = [
|
|
129
|
+
[
|
|
130
|
+
__temp_len,
|
|
131
|
+
new FunctionInvocationExpression('len', [initializerExpression]),
|
|
132
|
+
],
|
|
133
|
+
];
|
|
134
|
+
const branches = R.reverse(patterns).flatMap((pat, i) => {
|
|
135
|
+
if (pat === null) {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
return [
|
|
140
|
+
{
|
|
141
|
+
condition: new BinaryExpression(new VariableReferenceExpression(__temp_len), '>=', new PrimitiveExpression(patterns.length - i)),
|
|
142
|
+
steps: arrayElementsDestructuringSteps(patterns, initializerExpression, patterns.length - i, ctx),
|
|
143
|
+
},
|
|
144
|
+
];
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
branches.push({
|
|
148
|
+
condition: trueEx,
|
|
149
|
+
steps: arrayElementsDestructuringSteps(patterns, initializerExpression, 0, ctx),
|
|
150
|
+
});
|
|
151
|
+
return [new AssignStepAST(initializeVariables), new SwitchStepAST(branches)];
|
|
152
|
+
}
|
|
153
|
+
function arrayElementsDestructuringSteps(patterns, initializerExpression, take, ctx) {
|
|
154
|
+
return patterns.flatMap((pat, i) => {
|
|
155
|
+
if (i >= take) {
|
|
156
|
+
return [
|
|
157
|
+
new AssignStepAST(extractDefaultAssignmentsFromDestructuringPattern(pat)),
|
|
158
|
+
];
|
|
159
|
+
}
|
|
160
|
+
const iElement = new MemberExpression(initializerExpression, new PrimitiveExpression(i), true);
|
|
161
|
+
switch (pat?.type) {
|
|
162
|
+
case AST_NODE_TYPES.MemberExpression:
|
|
163
|
+
case AST_NODE_TYPES.Identifier: {
|
|
164
|
+
const name = convertExpression(pat).toString();
|
|
165
|
+
return [new AssignStepAST([[name, iElement]])];
|
|
166
|
+
}
|
|
167
|
+
case AST_NODE_TYPES.AssignmentPattern: {
|
|
168
|
+
if (pat.left.type !== AST_NODE_TYPES.Identifier) {
|
|
169
|
+
throw new WorkflowSyntaxError('Default value can be used only with an identifier', pat.left.loc);
|
|
170
|
+
}
|
|
171
|
+
return [new AssignStepAST([[pat.left.name, iElement]])];
|
|
84
172
|
}
|
|
85
|
-
|
|
173
|
+
case AST_NODE_TYPES.ObjectPattern:
|
|
174
|
+
return objectDestructuringSteps(pat.properties, iElement, ctx);
|
|
175
|
+
case AST_NODE_TYPES.ArrayPattern:
|
|
176
|
+
return arrayDestructuringSteps(pat.elements, iElement, ctx);
|
|
177
|
+
case AST_NODE_TYPES.RestElement:
|
|
178
|
+
return arrayRestDestructuringSteps(patterns, pat, initializerExpression, patterns.length - 1, ctx);
|
|
179
|
+
default: // pat === null
|
|
180
|
+
return [];
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
function extractDefaultAssignmentsFromDestructuringPattern(pat) {
|
|
185
|
+
if (pat === null) {
|
|
186
|
+
return [];
|
|
187
|
+
}
|
|
188
|
+
switch (pat.type) {
|
|
189
|
+
case AST_NODE_TYPES.ArrayPattern:
|
|
190
|
+
return pat.elements.flatMap(extractDefaultAssignmentsFromDestructuringPattern);
|
|
191
|
+
case AST_NODE_TYPES.AssignmentPattern:
|
|
192
|
+
if (pat.left.type !== AST_NODE_TYPES.Identifier) {
|
|
193
|
+
throw new WorkflowSyntaxError('Default value can be used only with an identifier', pat.left.loc);
|
|
194
|
+
}
|
|
195
|
+
return [[pat.left.name, convertExpression(pat.right)]];
|
|
196
|
+
case AST_NODE_TYPES.Identifier:
|
|
197
|
+
return [[pat.name, nullEx]];
|
|
198
|
+
case AST_NODE_TYPES.MemberExpression:
|
|
199
|
+
return [[convertExpression(pat).toString(), nullEx]];
|
|
200
|
+
case AST_NODE_TYPES.ObjectPattern:
|
|
201
|
+
return pat.properties.flatMap((p) => {
|
|
202
|
+
if (p.type === AST_NODE_TYPES.RestElement) {
|
|
203
|
+
return extractDefaultAssignmentsFromDestructuringPattern(p);
|
|
204
|
+
}
|
|
205
|
+
else if (p.value.type === AST_NODE_TYPES.ArrayPattern ||
|
|
206
|
+
p.value.type === AST_NODE_TYPES.AssignmentPattern ||
|
|
207
|
+
p.value.type === AST_NODE_TYPES.Identifier ||
|
|
208
|
+
p.value.type === AST_NODE_TYPES.MemberExpression ||
|
|
209
|
+
p.value.type === AST_NODE_TYPES.ObjectPattern) {
|
|
210
|
+
return extractDefaultAssignmentsFromDestructuringPattern(p.value);
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
throw new WorkflowSyntaxError('Destructuring pattern expected', p.value.loc);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
case AST_NODE_TYPES.RestElement:
|
|
217
|
+
if (pat.argument.type !== AST_NODE_TYPES.Identifier) {
|
|
218
|
+
throw new WorkflowSyntaxError('Identifier expected', pat.argument.loc);
|
|
219
|
+
}
|
|
220
|
+
return [[pat.argument.name, new PrimitiveExpression([])]];
|
|
221
|
+
default:
|
|
222
|
+
return [];
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function throwIfInvalidRestElement(patterns) {
|
|
226
|
+
const i = patterns.findIndex((p) => p?.type === AST_NODE_TYPES.RestElement);
|
|
227
|
+
if (i >= 0 && i !== patterns.length - 1) {
|
|
228
|
+
throw new WorkflowSyntaxError('A rest element must be last in a destructuring pattern', patterns[i].loc);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function arrayRestDestructuringSteps(patterns, rest, initializerExpression, startIndex, ctx) {
|
|
232
|
+
throwIfInvalidRestElement(patterns);
|
|
233
|
+
if (rest.argument.type !== AST_NODE_TYPES.Identifier) {
|
|
234
|
+
throw new WorkflowSyntaxError('Identifier expected', rest.argument.loc);
|
|
235
|
+
}
|
|
236
|
+
const restName = rest.argument.name;
|
|
237
|
+
const __temp_len = new VariableReferenceExpression(`${tempName(ctx)}_len`);
|
|
238
|
+
const __temp_index = `${tempName(ctx)}_index`;
|
|
239
|
+
const one = new PrimitiveExpression(1);
|
|
240
|
+
const emptyArray = new PrimitiveExpression([]);
|
|
241
|
+
const copyLoop = new ForRangeStepAST([
|
|
242
|
+
new AssignStepAST([
|
|
243
|
+
[
|
|
244
|
+
restName,
|
|
245
|
+
new FunctionInvocationExpression('list.concat', [
|
|
246
|
+
new VariableReferenceExpression(restName),
|
|
247
|
+
new MemberExpression(initializerExpression, new VariableReferenceExpression(__temp_index), true),
|
|
248
|
+
]),
|
|
249
|
+
],
|
|
250
|
+
]),
|
|
251
|
+
], __temp_index, startIndex, new BinaryExpression(__temp_len, '-', one));
|
|
252
|
+
return [new AssignStepAST([[restName, emptyArray]]), copyLoop];
|
|
253
|
+
}
|
|
254
|
+
function convertObjectDestructuring(objectPattern, initializer, ctx) {
|
|
255
|
+
let initExpression;
|
|
256
|
+
const steps = [];
|
|
257
|
+
if (initializer?.type === AST_NODE_TYPES.Identifier ||
|
|
258
|
+
(initializer?.type === AST_NODE_TYPES.MemberExpression &&
|
|
259
|
+
isPure(convertExpression(initializer)))) {
|
|
260
|
+
// If the initializer is an Identifier or MemberExpression (object variable?), use it directly.
|
|
261
|
+
initExpression = convertExpression(initializer);
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
// Otherwise, assign the expression to a temporary variable first.
|
|
265
|
+
const initName = tempName(ctx);
|
|
266
|
+
steps.push(...convertInitializer(initName, initializer, ctx));
|
|
267
|
+
initExpression = new VariableReferenceExpression(initName);
|
|
268
|
+
}
|
|
269
|
+
steps.push(...objectDestructuringSteps(objectPattern.properties, initExpression, ctx));
|
|
270
|
+
return steps;
|
|
271
|
+
}
|
|
272
|
+
function objectDestructuringSteps(properties, initializerExpression, ctx) {
|
|
273
|
+
return properties.flatMap((prop) => {
|
|
274
|
+
if (prop.type === AST_NODE_TYPES.RestElement) {
|
|
275
|
+
return objectDestructuringRestSteps(properties, prop, initializerExpression);
|
|
276
|
+
}
|
|
277
|
+
if (prop.key.type !== AST_NODE_TYPES.Identifier) {
|
|
278
|
+
throw new WorkflowSyntaxError('Identifier expected', prop.key.loc);
|
|
279
|
+
}
|
|
280
|
+
const keyExpression = new MemberExpression(initializerExpression, new VariableReferenceExpression(prop.key.name), false);
|
|
281
|
+
if (prop.value.type === AST_NODE_TYPES.ObjectPattern) {
|
|
282
|
+
return objectDestructuringSteps(prop.value.properties, keyExpression, ctx);
|
|
283
|
+
}
|
|
284
|
+
else if (prop.value.type === AST_NODE_TYPES.ArrayPattern) {
|
|
285
|
+
return arrayDestructuringSteps(prop.value.elements, keyExpression, ctx);
|
|
286
|
+
}
|
|
287
|
+
else if (prop.value.type === AST_NODE_TYPES.Identifier) {
|
|
288
|
+
const safeKeyExpression = new FunctionInvocationExpression('map.get', [
|
|
289
|
+
initializerExpression,
|
|
290
|
+
new PrimitiveExpression(prop.key.name),
|
|
291
|
+
]);
|
|
292
|
+
return [new AssignStepAST([[prop.value.name, safeKeyExpression]])];
|
|
293
|
+
}
|
|
294
|
+
else if (prop.value.type === AST_NODE_TYPES.AssignmentPattern) {
|
|
295
|
+
return objectAssignmentPatternSteps(prop.value, initializerExpression, keyExpression);
|
|
86
296
|
}
|
|
87
297
|
else {
|
|
88
|
-
|
|
89
|
-
? new PrimitiveExpression(null)
|
|
90
|
-
: convertExpression(decl.init);
|
|
91
|
-
return [new AssignStepAST([[targetName, value]])];
|
|
298
|
+
throw new WorkflowSyntaxError(`${prop.value.type} is not allowed in object destructuring`, prop.value.loc);
|
|
92
299
|
}
|
|
93
300
|
});
|
|
94
301
|
}
|
|
302
|
+
function objectAssignmentPatternSteps(pat, initializerExpression, keyExpression) {
|
|
303
|
+
if (pat.left.type !== AST_NODE_TYPES.Identifier) {
|
|
304
|
+
throw new WorkflowSyntaxError('Default value can be used only with an identifier', pat.left.loc);
|
|
305
|
+
}
|
|
306
|
+
// Using Switch step instead of default() because pat.right must be evaluated only
|
|
307
|
+
// in the default value branch (in case it has side effects)
|
|
308
|
+
return [
|
|
309
|
+
new SwitchStepAST([
|
|
310
|
+
{
|
|
311
|
+
condition: new BinaryExpression(new PrimitiveExpression(pat.left.name), 'in', initializerExpression),
|
|
312
|
+
steps: [new AssignStepAST([[pat.left.name, keyExpression]])],
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
condition: trueEx,
|
|
316
|
+
steps: [
|
|
317
|
+
new AssignStepAST([[pat.left.name, convertExpression(pat.right)]]),
|
|
318
|
+
],
|
|
319
|
+
},
|
|
320
|
+
]),
|
|
321
|
+
];
|
|
322
|
+
}
|
|
323
|
+
function objectDestructuringRestSteps(properties, rest, initializerExpression) {
|
|
324
|
+
throwIfInvalidRestElement(properties);
|
|
325
|
+
if (rest.argument.type !== AST_NODE_TYPES.Identifier) {
|
|
326
|
+
throw new WorkflowSyntaxError('Identifier expected', rest.argument.loc);
|
|
327
|
+
}
|
|
328
|
+
const nonRestProperties = properties.filter((x) => x.type !== AST_NODE_TYPES.RestElement);
|
|
329
|
+
const nonRestKeys = nonRestProperties
|
|
330
|
+
.map((p) => p.key)
|
|
331
|
+
.map((p) => {
|
|
332
|
+
if (p.type !== AST_NODE_TYPES.Identifier) {
|
|
333
|
+
throw new WorkflowSyntaxError('Identifier expected', p.loc);
|
|
334
|
+
}
|
|
335
|
+
return p;
|
|
336
|
+
})
|
|
337
|
+
.map((p) => p.name);
|
|
338
|
+
const value = nonRestKeys.reduce((acc, propertyName) =>
|
|
339
|
+
// map.delete returns a copy of the object and removes the specified property
|
|
340
|
+
new FunctionInvocationExpression('map.delete', [
|
|
341
|
+
acc,
|
|
342
|
+
new PrimitiveExpression(propertyName),
|
|
343
|
+
]), initializerExpression);
|
|
344
|
+
return [new AssignStepAST([[rest.argument.name, value]])];
|
|
345
|
+
}
|
|
95
346
|
function assignmentExpressionToSteps(node, ctx) {
|
|
96
347
|
let compoundOperator = undefined;
|
|
97
348
|
switch (node.operator) {
|
|
@@ -122,6 +373,22 @@ function assignmentExpressionToSteps(node, ctx) {
|
|
|
122
373
|
default:
|
|
123
374
|
throw new WorkflowSyntaxError(`Operator ${node.operator} is not supported in assignment expressions`, node.loc);
|
|
124
375
|
}
|
|
376
|
+
if (node.left.type === AST_NODE_TYPES.ArrayPattern) {
|
|
377
|
+
if (node.operator === '=') {
|
|
378
|
+
return convertArrayDestructuring(node.left, node.right, ctx);
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
throw new WorkflowSyntaxError(`Invalid left-hand side in assignment`, node.left.loc);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
else if (node.left.type === AST_NODE_TYPES.ObjectPattern) {
|
|
385
|
+
if (node.operator === '=') {
|
|
386
|
+
return convertObjectDestructuring(node.left, node.right, ctx);
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
throw new WorkflowSyntaxError(`Invalid left-hand side in assignment`, node.left.loc);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
125
392
|
const targetExpression = convertExpression(node.left);
|
|
126
393
|
if (!isFullyQualifiedName(targetExpression)) {
|
|
127
394
|
throw new WorkflowSyntaxError('The left-hand side of an assignment must be an identifier or a property access', node.loc);
|
|
@@ -138,12 +405,12 @@ function assignmentExpressionToSteps(node, ctx) {
|
|
|
138
405
|
}
|
|
139
406
|
const needsTempVariable = compoundOperator === undefined ||
|
|
140
407
|
node.left.type !== AST_NODE_TYPES.Identifier;
|
|
141
|
-
const resultVariable = needsTempVariable ?
|
|
408
|
+
const resultVariable = needsTempVariable ? tempName(ctx) : targetName;
|
|
142
409
|
steps.push(...callExpressionToStep(node.right, resultVariable, ctx));
|
|
143
410
|
if (!needsTempVariable) {
|
|
144
411
|
return steps;
|
|
145
412
|
}
|
|
146
|
-
valueExpression = new VariableReferenceExpression(
|
|
413
|
+
valueExpression = new VariableReferenceExpression(tempName(ctx));
|
|
147
414
|
}
|
|
148
415
|
else {
|
|
149
416
|
valueExpression = convertExpression(node.right);
|
|
@@ -159,7 +426,7 @@ function callExpressionToStep(node, resultVariable, ctx) {
|
|
|
159
426
|
if (isFullyQualifiedName(calleeExpression)) {
|
|
160
427
|
const calleeName = calleeExpression.toString();
|
|
161
428
|
if (calleeName === 'parallel') {
|
|
162
|
-
// A
|
|
429
|
+
// A handle the "parallel" intrinsic
|
|
163
430
|
return [callExpressionToParallelStep(node, ctx)];
|
|
164
431
|
}
|
|
165
432
|
else if (calleeName === 'retry_policy') {
|
|
@@ -176,8 +443,9 @@ function callExpressionToStep(node, resultVariable, ctx) {
|
|
|
176
443
|
];
|
|
177
444
|
}
|
|
178
445
|
else {
|
|
446
|
+
const resultVariable2 = resultVariable ?? tempName(ctx);
|
|
179
447
|
return [
|
|
180
|
-
callExpressionAssignStep(calleeName, node.arguments,
|
|
448
|
+
callExpressionAssignStep(calleeName, node.arguments, resultVariable2),
|
|
181
449
|
];
|
|
182
450
|
}
|
|
183
451
|
}
|
|
@@ -189,7 +457,7 @@ function callExpressionAssignStep(functionName, argumentsNode, resultVariable) {
|
|
|
189
457
|
const argumentExpressions = throwIfSpread(argumentsNode).map(convertExpression);
|
|
190
458
|
return new AssignStepAST([
|
|
191
459
|
[
|
|
192
|
-
resultVariable
|
|
460
|
+
resultVariable,
|
|
193
461
|
new FunctionInvocationExpression(functionName, argumentExpressions),
|
|
194
462
|
],
|
|
195
463
|
]);
|
|
@@ -199,18 +467,21 @@ function createCallStep(node, argumentsNode, resultVariable) {
|
|
|
199
467
|
throw new WorkflowSyntaxError('The first argument must be a Function', node.loc);
|
|
200
468
|
}
|
|
201
469
|
let functionName;
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
470
|
+
const argNode = argumentsNode[0].type === AST_NODE_TYPES.TSInstantiationExpression
|
|
471
|
+
? argumentsNode[0].expression
|
|
472
|
+
: argumentsNode[0];
|
|
473
|
+
if (argNode.type === AST_NODE_TYPES.Identifier) {
|
|
474
|
+
functionName = argNode.name;
|
|
475
|
+
}
|
|
476
|
+
else if (argNode.type === AST_NODE_TYPES.MemberExpression) {
|
|
477
|
+
const memberExp = convertMemberExpression(argNode);
|
|
207
478
|
if (!isFullyQualifiedName(memberExp)) {
|
|
208
|
-
throw new WorkflowSyntaxError('Function name must be a fully-qualified name',
|
|
479
|
+
throw new WorkflowSyntaxError('Function name must be a fully-qualified name', argNode.loc);
|
|
209
480
|
}
|
|
210
481
|
functionName = memberExp.toString();
|
|
211
482
|
}
|
|
212
483
|
else {
|
|
213
|
-
throw new WorkflowSyntaxError('Expected an identifier or a member expression',
|
|
484
|
+
throw new WorkflowSyntaxError('Expected an identifier or a member expression', argNode.loc);
|
|
214
485
|
}
|
|
215
486
|
let args = {};
|
|
216
487
|
if (argumentsNode.length >= 2) {
|
|
@@ -242,14 +513,19 @@ function callExpressionToParallelStep(node, ctx) {
|
|
|
242
513
|
node.callee.name !== 'parallel') {
|
|
243
514
|
throw new InternalTranspilingError(`The parameter must be a call to "parallel"`);
|
|
244
515
|
}
|
|
516
|
+
const ctx2 = Object.assign({}, ctx, {
|
|
517
|
+
parallelNestingLevel: ctx.parallelNestingLevel
|
|
518
|
+
? ctx.parallelNestingLevel + 1
|
|
519
|
+
: 1,
|
|
520
|
+
});
|
|
245
521
|
let steps = {};
|
|
246
522
|
if (node.arguments.length > 0) {
|
|
247
523
|
switch (node.arguments[0].type) {
|
|
248
524
|
case AST_NODE_TYPES.ArrayExpression:
|
|
249
|
-
steps = parseParallelBranches(node.arguments[0]);
|
|
525
|
+
steps = parseParallelBranches(node.arguments[0], ctx2);
|
|
250
526
|
break;
|
|
251
527
|
case AST_NODE_TYPES.ArrowFunctionExpression:
|
|
252
|
-
steps = parseParallelIteration(node.arguments[0],
|
|
528
|
+
steps = parseParallelIteration(node.arguments[0], ctx2);
|
|
253
529
|
break;
|
|
254
530
|
default:
|
|
255
531
|
throw new WorkflowSyntaxError('The first parameter must be an array of functions or an arrow function', node.arguments[0].loc);
|
|
@@ -266,25 +542,21 @@ function callExpressionToParallelStep(node, ctx) {
|
|
|
266
542
|
}
|
|
267
543
|
return new ParallelStepAST(steps, shared, concurrencyLimit, exceptionPolicy);
|
|
268
544
|
}
|
|
269
|
-
function parseParallelBranches(node) {
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
if (arg === null) {
|
|
273
|
-
throw new WorkflowSyntaxError('Argument should be a function call of type () => void', node.loc);
|
|
274
|
-
}
|
|
275
|
-
switch (arg.type) {
|
|
545
|
+
function parseParallelBranches(node, ctx) {
|
|
546
|
+
const branches = node.elements.map((arg) => {
|
|
547
|
+
switch (arg?.type) {
|
|
276
548
|
case AST_NODE_TYPES.Identifier:
|
|
277
|
-
return
|
|
549
|
+
return new StepsStepAST([new CallStepAST(arg.name)]);
|
|
278
550
|
case AST_NODE_TYPES.ArrowFunctionExpression:
|
|
279
551
|
if (arg.body.type !== AST_NODE_TYPES.BlockStatement) {
|
|
280
552
|
throw new WorkflowSyntaxError('The body must be a block statement', arg.body.loc);
|
|
281
553
|
}
|
|
282
|
-
return
|
|
554
|
+
return new StepsStepAST(parseStatement(arg.body, ctx));
|
|
283
555
|
default:
|
|
284
|
-
throw new WorkflowSyntaxError('Argument should be a function
|
|
556
|
+
throw new WorkflowSyntaxError('Argument should be a function of type () => void', arg ? arg.loc : node.loc);
|
|
285
557
|
}
|
|
286
558
|
});
|
|
287
|
-
return Object.fromEntries(
|
|
559
|
+
return Object.fromEntries(branches.map((step, i) => [`branch${i + 1}`, step]));
|
|
288
560
|
}
|
|
289
561
|
function parseParallelIteration(node, ctx) {
|
|
290
562
|
if (node.body.type !== AST_NODE_TYPES.BlockStatement ||
|
|
@@ -327,8 +599,8 @@ function parseParallelOptions(node) {
|
|
|
327
599
|
exceptionPolicy,
|
|
328
600
|
};
|
|
329
601
|
}
|
|
330
|
-
function generalExpressionToAssignStep(node) {
|
|
331
|
-
return new AssignStepAST([[
|
|
602
|
+
function generalExpressionToAssignStep(node, ctx) {
|
|
603
|
+
return new AssignStepAST([[tempName(ctx), convertExpression(node)]]);
|
|
332
604
|
}
|
|
333
605
|
function returnStatementToReturnStep(node, ctx) {
|
|
334
606
|
const value = node.argument ? convertExpression(node.argument) : undefined;
|
|
@@ -358,7 +630,7 @@ function flattenIfBranches(ifStatement, ctx) {
|
|
|
358
630
|
}
|
|
359
631
|
else {
|
|
360
632
|
branches.push({
|
|
361
|
-
condition:
|
|
633
|
+
condition: trueEx,
|
|
362
634
|
steps: parseStatement(ifStatement.alternate, ctx),
|
|
363
635
|
});
|
|
364
636
|
}
|
|
@@ -378,10 +650,10 @@ function switchStatementToSteps(node, ctx) {
|
|
|
378
650
|
condition = new BinaryExpression(discriminant, '==', test);
|
|
379
651
|
}
|
|
380
652
|
else {
|
|
381
|
-
condition =
|
|
653
|
+
condition = trueEx;
|
|
382
654
|
}
|
|
383
655
|
const jumpTarget = new JumpTargetAST();
|
|
384
|
-
const body =
|
|
656
|
+
const body = caseNode.consequent.flatMap((x) => parseStatement(x, switchCtx));
|
|
385
657
|
steps.push(jumpTarget);
|
|
386
658
|
steps.push(...body);
|
|
387
659
|
branches.push({
|
|
@@ -413,12 +685,12 @@ function forOfStatementToForStep(node, ctx) {
|
|
|
413
685
|
throw new WorkflowSyntaxError('Initial value not allowed', declaration.init.loc);
|
|
414
686
|
}
|
|
415
687
|
if (declaration.id.type !== AST_NODE_TYPES.Identifier) {
|
|
416
|
-
throw new WorkflowSyntaxError(`
|
|
688
|
+
throw new WorkflowSyntaxError(`Identifier expected, got ${declaration.id.type}`, declaration.id.loc);
|
|
417
689
|
}
|
|
418
690
|
loopVariableName = declaration.id.name;
|
|
419
691
|
}
|
|
420
692
|
else {
|
|
421
|
-
throw new InternalTranspilingError(`
|
|
693
|
+
throw new InternalTranspilingError(`Identifier or VariableDeclaration expected, got ${node.left.type}`);
|
|
422
694
|
}
|
|
423
695
|
const listExpression = convertExpression(node.right);
|
|
424
696
|
if (isLiteral(listExpression) &&
|
|
@@ -440,7 +712,7 @@ function whileStatementSteps(node, ctx) {
|
|
|
440
712
|
breakTarget: endOfLoop.label,
|
|
441
713
|
});
|
|
442
714
|
const postSteps = [new NextStepAST(startOfLoop.label)];
|
|
443
|
-
const steps = parseStatement(node.body, ctx2
|
|
715
|
+
const steps = parseStatement(node.body, ctx2).concat(postSteps);
|
|
444
716
|
return [
|
|
445
717
|
startOfLoop,
|
|
446
718
|
new SwitchStepAST([
|
|
@@ -580,8 +852,8 @@ function extractErrorVariableName(param) {
|
|
|
580
852
|
*/
|
|
581
853
|
function finalizerInitializer(conditionVariable, valueVariable) {
|
|
582
854
|
return new AssignStepAST([
|
|
583
|
-
[conditionVariable,
|
|
584
|
-
[valueVariable,
|
|
855
|
+
[conditionVariable, nullEx],
|
|
856
|
+
[valueVariable, nullEx],
|
|
585
857
|
]);
|
|
586
858
|
}
|
|
587
859
|
/**
|
|
@@ -597,16 +869,18 @@ function finalizerInitializer(conditionVariable, valueVariable) {
|
|
|
597
869
|
* }
|
|
598
870
|
*/
|
|
599
871
|
function finalizerFooter(conditionVariable, valueVariable) {
|
|
872
|
+
const variable = new VariableReferenceExpression(conditionVariable);
|
|
873
|
+
const val = new VariableReferenceExpression(valueVariable);
|
|
874
|
+
const returnString = new PrimitiveExpression('return');
|
|
875
|
+
const raiseString = new PrimitiveExpression('raise');
|
|
600
876
|
return new SwitchStepAST([
|
|
601
877
|
{
|
|
602
|
-
condition: new BinaryExpression(
|
|
603
|
-
steps: [
|
|
604
|
-
new ReturnStepAST(new VariableReferenceExpression(valueVariable)),
|
|
605
|
-
],
|
|
878
|
+
condition: new BinaryExpression(variable, '==', returnString),
|
|
879
|
+
steps: [new ReturnStepAST(val)],
|
|
606
880
|
},
|
|
607
881
|
{
|
|
608
|
-
condition: new BinaryExpression(
|
|
609
|
-
steps: [new RaiseStepAST(
|
|
882
|
+
condition: new BinaryExpression(variable, '==', raiseString),
|
|
883
|
+
steps: [new RaiseStepAST(val)],
|
|
610
884
|
},
|
|
611
885
|
]);
|
|
612
886
|
}
|
|
@@ -628,7 +902,7 @@ function delayedReturnAndJumpToFinalizer(value, ctx) {
|
|
|
628
902
|
const [conditionVariable, valueVariable] = finalizerVariables(ctx);
|
|
629
903
|
return new AssignStepAST([
|
|
630
904
|
[conditionVariable, new PrimitiveExpression('return')],
|
|
631
|
-
[valueVariable, value ??
|
|
905
|
+
[valueVariable, value ?? nullEx],
|
|
632
906
|
], finalizerTarget);
|
|
633
907
|
}
|
|
634
908
|
function labeledStep(node, ctx) {
|
|
@@ -661,43 +935,45 @@ function parseRetryPolicy(node) {
|
|
|
661
935
|
}
|
|
662
936
|
}
|
|
663
937
|
function retryPolicyFromParams(paramsObject, argsLoc) {
|
|
664
|
-
const params =
|
|
665
|
-
if ('backoff' in params) {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
938
|
+
const params = R.map(asExpression, paramsObject);
|
|
939
|
+
if (!('backoff' in params)) {
|
|
940
|
+
throw new WorkflowSyntaxError('Required parameter "backoff" missing', argsLoc);
|
|
941
|
+
}
|
|
942
|
+
else if (params.backoff.expressionType !== 'primitive' ||
|
|
943
|
+
!isRecord(params.backoff.value)) {
|
|
944
|
+
throw new WorkflowSyntaxError('Expected "backoff" to be an object literal', argsLoc);
|
|
945
|
+
}
|
|
946
|
+
const backoff = params.backoff.value;
|
|
947
|
+
return {
|
|
948
|
+
predicate: predicateFromRetryParams(params, argsLoc),
|
|
949
|
+
maxRetries: params.max_retries,
|
|
950
|
+
backoff: {
|
|
951
|
+
initialDelay: safeAsExpression(backoff.initial_delay),
|
|
952
|
+
maxDelay: safeAsExpression(backoff.max_delay),
|
|
953
|
+
multiplier: safeAsExpression(backoff.multiplier),
|
|
954
|
+
},
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
function predicateFromRetryParams(params, argsLoc) {
|
|
958
|
+
if (!('predicate' in params)) {
|
|
959
|
+
return undefined;
|
|
960
|
+
}
|
|
961
|
+
else if (isFullyQualifiedName(params.predicate)) {
|
|
962
|
+
return params.predicate.toString();
|
|
963
|
+
}
|
|
964
|
+
else {
|
|
965
|
+
throw new WorkflowSyntaxError('"predicate" must be a function name', argsLoc);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
function tempName(ctx) {
|
|
969
|
+
if (ctx.parallelNestingLevel !== undefined) {
|
|
970
|
+
// Temporary variable inside a parallel step can not be the same as temporary
|
|
971
|
+
// variables on the outside. Sharing the variable name would cause deployment
|
|
972
|
+
// error, if the variable is not marked as shared by including it in the
|
|
973
|
+
// "shared" array.
|
|
974
|
+
return `__temp_parallel${ctx.parallelNestingLevel ?? 0}`;
|
|
699
975
|
}
|
|
700
976
|
else {
|
|
701
|
-
|
|
977
|
+
return '__temp';
|
|
702
978
|
}
|
|
703
979
|
}
|