ts2workflows 0.3.0 → 0.5.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.
@@ -1,105 +1,92 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument */
2
- import { AST_NODE_TYPES } from '@typescript-eslint/utils';
3
- import { AssignStepAST, CallStepAST, ForStepAST, JumpTargetAST, NextStepAST, ParallelStepAST, RaiseStepAST, ReturnStepAST, StepsStepAST, SwitchStepAST, TryStepAST, stepWithLabel, } from '../ast/steps.js';
1
+ 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';
4
3
  import { BinaryExpression, FunctionInvocationExpression, PrimitiveExpression, VariableReferenceExpression, isExpression, isFullyQualifiedName, isLiteral, } from '../ast/expressions.js';
5
4
  import { InternalTranspilingError, WorkflowSyntaxError } from '../errors.js';
6
5
  import { isRecord } from '../utils.js';
7
6
  import { transformAST } from './transformations.js';
8
- import { assertType } from './asserts.js';
9
- import { convertExpression, convertMemberExpression, convertObjectExpression, convertObjectAsExpressionValues, } from './expressions.js';
7
+ import { convertExpression, convertMemberExpression, convertObjectExpression, convertObjectAsExpressionValues, isMagicFunction, throwIfSpread, isMagicFunctionStatmentOnly, } from './expressions.js';
10
8
  import { blockingFunctions } from './generated/functionMetadata.js';
11
- const { ArrayExpression, ArrowFunctionExpression, AssignmentExpression, BlockStatement, BreakStatement, CallExpression, ContinueStatement, DoWhileStatement, EmptyStatement, ExpressionStatement, ForInStatement, ForOfStatement, FunctionDeclaration, Identifier, IfStatement, LabeledStatement, MemberExpression, ObjectExpression, ReturnStatement, SwitchCase, SwitchStatement, ThrowStatement, TryStatement, TSDeclareFunction, TSTypeAliasDeclaration, TSInterfaceDeclaration, VariableDeclaration, VariableDeclarator, WhileStatement, } = AST_NODE_TYPES;
12
- export function parseBlockStatement(node, ctx) {
13
- assertType(node, BlockStatement);
14
- const body = node.body;
15
- return transformAST(body.flatMap((x) => parseStep(x, ctx)));
9
+ export function parseStatement(node, ctx, postSteps) {
10
+ const steps = parseStatementRecursively(node, ctx);
11
+ return transformAST(steps.concat(postSteps ?? []));
16
12
  }
17
- function parseStep(node, ctx) {
13
+ function parseStatementRecursively(node, ctx) {
18
14
  switch (node.type) {
19
- case VariableDeclaration:
20
- return convertVariableDeclarations(node.declarations);
21
- case ExpressionStatement:
22
- if (node.expression.type === AssignmentExpression) {
23
- return assignmentExpressionToSteps(node.expression);
15
+ case AST_NODE_TYPES.BlockStatement:
16
+ return node.body.flatMap((statement) => parseStatementRecursively(statement, ctx));
17
+ case AST_NODE_TYPES.VariableDeclaration:
18
+ return convertVariableDeclarations(node.declarations, ctx);
19
+ case AST_NODE_TYPES.ExpressionStatement:
20
+ if (node.expression.type === AST_NODE_TYPES.AssignmentExpression) {
21
+ return assignmentExpressionToSteps(node.expression, ctx);
24
22
  }
25
- else if (node.expression.type === CallExpression) {
26
- return [callExpressionToStep(node.expression, ctx)];
23
+ else if (node.expression.type === AST_NODE_TYPES.CallExpression) {
24
+ return [callExpressionToStep(node.expression, undefined, ctx)];
27
25
  }
28
26
  else {
29
27
  return [generalExpressionToAssignStep(node.expression)];
30
28
  }
31
- case ReturnStatement:
29
+ case AST_NODE_TYPES.ReturnStatement:
32
30
  return [returnStatementToReturnStep(node)];
33
- case ThrowStatement:
31
+ case AST_NODE_TYPES.ThrowStatement:
34
32
  return [throwStatementToRaiseStep(node)];
35
- case IfStatement:
33
+ case AST_NODE_TYPES.IfStatement:
36
34
  return [ifStatementToSwitchStep(node, ctx)];
37
- case SwitchStatement:
35
+ case AST_NODE_TYPES.SwitchStatement:
38
36
  return switchStatementToSteps(node, ctx);
39
- case ForInStatement:
37
+ case AST_NODE_TYPES.ForInStatement:
40
38
  throw new WorkflowSyntaxError('for...in is not a supported construct. Use for...of.', node.loc);
41
- case ForOfStatement:
39
+ case AST_NODE_TYPES.ForOfStatement:
42
40
  return [forOfStatementToForStep(node, ctx)];
43
- case DoWhileStatement:
41
+ case AST_NODE_TYPES.DoWhileStatement:
44
42
  return doWhileStatementSteps(node, ctx);
45
- case WhileStatement:
43
+ case AST_NODE_TYPES.WhileStatement:
46
44
  return whileStatementSteps(node, ctx);
47
- case BreakStatement:
45
+ case AST_NODE_TYPES.BreakStatement:
48
46
  return [breakStatementToNextStep(node, ctx)];
49
- case ContinueStatement:
47
+ case AST_NODE_TYPES.ContinueStatement:
50
48
  return [continueStatementToNextStep(node, ctx)];
51
- case TryStatement:
49
+ case AST_NODE_TYPES.TryStatement:
52
50
  return [tryStatementToTryStep(node, ctx)];
53
- case LabeledStatement:
51
+ case AST_NODE_TYPES.LabeledStatement:
54
52
  return labeledStep(node, ctx);
55
- case EmptyStatement:
53
+ case AST_NODE_TYPES.EmptyStatement:
56
54
  return [];
57
- case FunctionDeclaration:
55
+ case AST_NODE_TYPES.FunctionDeclaration:
58
56
  throw new WorkflowSyntaxError('Functions must be defined at the top level of a source file', node.loc);
59
- case TSInterfaceDeclaration:
60
- case TSTypeAliasDeclaration:
61
- case TSDeclareFunction:
57
+ case AST_NODE_TYPES.TSInterfaceDeclaration:
58
+ case AST_NODE_TYPES.TSTypeAliasDeclaration:
59
+ case AST_NODE_TYPES.TSDeclareFunction:
62
60
  // Ignore "type", "interface" and "declare function"
63
61
  return [];
64
62
  default:
65
63
  throw new WorkflowSyntaxError(`TODO: encountered unsupported type: ${node.type}`, node.loc);
66
64
  }
67
65
  }
68
- function convertVariableDeclarations(declarations) {
66
+ function convertVariableDeclarations(declarations, ctx) {
69
67
  return declarations.map((decl) => {
70
- if (decl.type !== VariableDeclarator) {
71
- throw new WorkflowSyntaxError('Not a VariableDeclarator', decl.loc);
72
- }
73
- if (decl.id.type !== Identifier) {
68
+ if (decl.id.type !== AST_NODE_TYPES.Identifier) {
74
69
  throw new WorkflowSyntaxError('Expected Identifier', decl.loc);
75
70
  }
76
71
  const targetName = decl.id.name;
77
- if (!decl.init) {
78
- return new AssignStepAST([[targetName, new PrimitiveExpression(null)]]);
79
- }
80
- else if (decl.init.type === CallExpression) {
81
- const maybeBlockingcall = getBlockingCallParameters(decl.init);
82
- if (maybeBlockingcall.isBlockingCall) {
83
- // This branch could be removed. The transform step for extracting
84
- // blocking function would take care of this, but it creates an
85
- // unnecessary temporary variable assignment step.
86
- return blockingFunctionCallStep(maybeBlockingcall.functionName, maybeBlockingcall.argumentNames, decl.init.arguments, targetName);
87
- }
88
- else if (decl.init.callee.type === Identifier &&
89
- decl.init.callee.name === 'call_step') {
90
- return createCallStep(decl.init.arguments, targetName);
91
- }
92
- else {
93
- return new AssignStepAST([[targetName, convertExpression(decl.init)]]);
72
+ if (decl.init?.type === AST_NODE_TYPES.CallExpression) {
73
+ const calleeName = decl.init.callee.type === AST_NODE_TYPES.Identifier
74
+ ? decl.init.callee.name
75
+ : undefined;
76
+ if (calleeName && isMagicFunctionStatmentOnly(calleeName)) {
77
+ throw new WorkflowSyntaxError(`"${calleeName}" can't be called as part of an expression`, decl.init.callee.loc);
94
78
  }
79
+ return callExpressionToStep(decl.init, targetName, ctx);
95
80
  }
96
81
  else {
97
- return new AssignStepAST([[targetName, convertExpression(decl.init)]]);
82
+ const value = decl.init == null
83
+ ? new PrimitiveExpression(null)
84
+ : convertExpression(decl.init);
85
+ return new AssignStepAST([[targetName, value]]);
98
86
  }
99
87
  });
100
88
  }
101
- function assignmentExpressionToSteps(node) {
102
- assertType(node, AssignmentExpression);
89
+ function assignmentExpressionToSteps(node, ctx) {
103
90
  let compoundOperator = undefined;
104
91
  switch (node.operator) {
105
92
  case '=':
@@ -133,25 +120,35 @@ function assignmentExpressionToSteps(node) {
133
120
  if (!isFullyQualifiedName(targetExpression)) {
134
121
  throw new WorkflowSyntaxError('The left-hand side of an assignment must be an identifier or a property access', node.loc);
135
122
  }
123
+ let valueExpression;
124
+ const steps = [];
136
125
  const targetName = targetExpression.toString();
137
- let valueExpression = convertExpression(node.right);
126
+ if (node.right.type === AST_NODE_TYPES.CallExpression &&
127
+ node.right.callee.type === AST_NODE_TYPES.Identifier &&
128
+ isMagicFunction(node.right.callee.name)) {
129
+ const calleeName = node.right.callee.name;
130
+ if (isMagicFunctionStatmentOnly(calleeName)) {
131
+ throw new WorkflowSyntaxError(`"${calleeName}" can't be called as part of an expression`, node.right.callee.loc);
132
+ }
133
+ const needsTempVariable = compoundOperator === undefined ||
134
+ node.left.type !== AST_NODE_TYPES.Identifier;
135
+ const resultVariable = needsTempVariable ? '__temp' : targetName;
136
+ steps.push(callExpressionToStep(node.right, resultVariable, ctx));
137
+ if (!needsTempVariable) {
138
+ return steps;
139
+ }
140
+ valueExpression = new VariableReferenceExpression('__temp');
141
+ }
142
+ else {
143
+ valueExpression = convertExpression(node.right);
144
+ }
138
145
  if (compoundOperator) {
139
146
  valueExpression = new BinaryExpression(new VariableReferenceExpression(targetName), compoundOperator, valueExpression);
140
147
  }
141
- return [new AssignStepAST([[targetName, valueExpression]])];
142
- }
143
- function getBlockingCallParameters(node) {
144
- if (node?.type === CallExpression) {
145
- const functionName = convertExpression(node.callee).toString();
146
- const argumentNames = blockingFunctions.get(functionName);
147
- if (argumentNames) {
148
- return { isBlockingCall: true, functionName, argumentNames };
149
- }
150
- }
151
- return { isBlockingCall: false };
148
+ steps.push(new AssignStepAST([[targetName, valueExpression]]));
149
+ return steps;
152
150
  }
153
- function callExpressionToStep(node, ctx) {
154
- assertType(node, CallExpression);
151
+ function callExpressionToStep(node, resultVariable, ctx) {
155
152
  const calleeExpression = convertExpression(node.callee);
156
153
  if (isFullyQualifiedName(calleeExpression)) {
157
154
  const calleeName = calleeExpression.toString();
@@ -160,48 +157,49 @@ function callExpressionToStep(node, ctx) {
160
157
  return callExpressionToParallelStep(node, ctx);
161
158
  }
162
159
  else if (calleeName === 'retry_policy') {
163
- return callExpressionToCallStep(calleeName, node.arguments);
160
+ return callExpressionToCallStep(calleeName, node.arguments, resultVariable);
164
161
  }
165
162
  else if (calleeName === 'call_step') {
166
- return createCallStep(node.arguments);
163
+ return createCallStep(node.arguments, resultVariable);
167
164
  }
168
165
  else if (blockingFunctions.has(calleeName)) {
169
166
  const argumentNames = blockingFunctions.get(calleeName) ?? [];
170
- return blockingFunctionCallStep(calleeName, argumentNames, node.arguments);
167
+ return blockingFunctionCallStep(calleeName, argumentNames, node.arguments, resultVariable);
171
168
  }
172
169
  else {
173
- return callExpressionAssignStep(calleeName, node.arguments);
170
+ return callExpressionAssignStep(calleeName, node.arguments, resultVariable);
174
171
  }
175
172
  }
176
173
  else {
177
174
  throw new WorkflowSyntaxError('Expeced a subworkflow or a standard library function name', node.callee.loc);
178
175
  }
179
176
  }
180
- function callExpressionAssignStep(functionName, argumentsNode) {
181
- const argumentExpressions = argumentsNode.map(convertExpression);
177
+ function callExpressionAssignStep(functionName, argumentsNode, resultVariable) {
178
+ const argumentExpressions = throwIfSpread(argumentsNode).map(convertExpression);
182
179
  return new AssignStepAST([
183
180
  [
184
- '__temp',
181
+ resultVariable ?? '__temp',
185
182
  new FunctionInvocationExpression(functionName, argumentExpressions),
186
183
  ],
187
184
  ]);
188
185
  }
189
- function callExpressionToCallStep(functionName, argumentsNode) {
190
- if (argumentsNode.length < 1 || argumentsNode[0].type !== ObjectExpression) {
186
+ function callExpressionToCallStep(functionName, argumentsNode, resultVariable) {
187
+ if (argumentsNode.length < 1 ||
188
+ argumentsNode[0].type !== AST_NODE_TYPES.ObjectExpression) {
191
189
  throw new WorkflowSyntaxError('Expected one object parameter', argumentsNode[0].loc);
192
190
  }
193
191
  const workflowArguments = convertObjectAsExpressionValues(argumentsNode[0]);
194
- return new CallStepAST(functionName, workflowArguments);
192
+ return new CallStepAST(functionName, workflowArguments, resultVariable);
195
193
  }
196
194
  function createCallStep(argumentsNode, resultVariable) {
197
195
  if (argumentsNode.length < 1) {
198
196
  throw new WorkflowSyntaxError('The first argument must be a Function', argumentsNode[0].loc);
199
197
  }
200
198
  let functionName;
201
- if (argumentsNode[0].type === Identifier) {
199
+ if (argumentsNode[0].type === AST_NODE_TYPES.Identifier) {
202
200
  functionName = argumentsNode[0].name;
203
201
  }
204
- else if (argumentsNode[0].type === MemberExpression) {
202
+ else if (argumentsNode[0].type === AST_NODE_TYPES.MemberExpression) {
205
203
  const memberExp = convertMemberExpression(argumentsNode[0]);
206
204
  if (!isFullyQualifiedName(memberExp)) {
207
205
  throw new WorkflowSyntaxError('Function name must be a fully-qualified name', argumentsNode[0].loc);
@@ -213,7 +211,7 @@ function createCallStep(argumentsNode, resultVariable) {
213
211
  }
214
212
  let args = {};
215
213
  if (argumentsNode.length >= 2) {
216
- if (argumentsNode[1].type !== ObjectExpression) {
214
+ if (argumentsNode[1].type !== AST_NODE_TYPES.ObjectExpression) {
217
215
  throw new WorkflowSyntaxError('The second argument must be an object', argumentsNode[1].loc);
218
216
  }
219
217
  args = convertObjectAsExpressionValues(argumentsNode[1]);
@@ -221,12 +219,12 @@ function createCallStep(argumentsNode, resultVariable) {
221
219
  return new CallStepAST(functionName, args, resultVariable);
222
220
  }
223
221
  function blockingFunctionCallStep(functionName, argumentNames, argumentsNode, resultName) {
224
- const argumentExpressions = argumentsNode.map(convertExpression);
222
+ const argumentExpressions = throwIfSpread(argumentsNode).map(convertExpression);
225
223
  const args = Object.fromEntries(argumentNames.flatMap((argName, i) => {
226
224
  if (i >= argumentExpressions.length) {
227
225
  return [];
228
226
  }
229
- else if (argumentsNode[i].type === Identifier &&
227
+ else if (argumentsNode[i].type === AST_NODE_TYPES.Identifier &&
230
228
  argumentsNode[i].name === 'undefined') {
231
229
  return [];
232
230
  }
@@ -237,18 +235,17 @@ function blockingFunctionCallStep(functionName, argumentNames, argumentsNode, re
237
235
  return new CallStepAST(functionName, args, resultName);
238
236
  }
239
237
  function callExpressionToParallelStep(node, ctx) {
240
- assertType(node, CallExpression);
241
- assertType(node.callee, Identifier);
242
- if (node.callee.name !== 'parallel') {
243
- throw new TypeError(`The parameter must be a call to "parallel"`);
238
+ if (node.callee.type !== AST_NODE_TYPES.Identifier ||
239
+ node.callee.name !== 'parallel') {
240
+ throw new InternalTranspilingError(`The parameter must be a call to "parallel"`);
244
241
  }
245
242
  let steps = {};
246
243
  if (node.arguments.length > 0) {
247
244
  switch (node.arguments[0].type) {
248
- case ArrayExpression:
245
+ case AST_NODE_TYPES.ArrayExpression:
249
246
  steps = parseParallelBranches(node.arguments[0]);
250
247
  break;
251
- case ArrowFunctionExpression:
248
+ case AST_NODE_TYPES.ArrowFunctionExpression:
252
249
  steps = parseParallelIteration(node.arguments[0], ctx);
253
250
  break;
254
251
  default:
@@ -267,18 +264,19 @@ function callExpressionToParallelStep(node, ctx) {
267
264
  return new ParallelStepAST(steps, shared, concurrencyLimit, exceptionPolicy);
268
265
  }
269
266
  function parseParallelBranches(node) {
270
- assertType(node, ArrayExpression);
271
- const nodeElements = node.elements;
272
- const stepsArray = nodeElements.map((arg, idx) => {
267
+ const stepsArray = node.elements.map((arg, idx) => {
273
268
  const branchName = `branch${idx + 1}`;
269
+ if (arg === null) {
270
+ throw new WorkflowSyntaxError('Argument should be a function call of type () => void', node.loc);
271
+ }
274
272
  switch (arg.type) {
275
- case Identifier:
273
+ case AST_NODE_TYPES.Identifier:
276
274
  return [branchName, new StepsStepAST([new CallStepAST(arg.name)])];
277
- case ArrowFunctionExpression:
278
- return [
279
- branchName,
280
- new StepsStepAST(parseBlockStatement(arg.body, {})),
281
- ];
275
+ case AST_NODE_TYPES.ArrowFunctionExpression:
276
+ if (arg.body.type !== AST_NODE_TYPES.BlockStatement) {
277
+ throw new WorkflowSyntaxError('The body must be a block statement', arg.body.loc);
278
+ }
279
+ return [branchName, new StepsStepAST(parseStatement(arg.body, {}))];
282
280
  default:
283
281
  throw new WorkflowSyntaxError('Argument should be a function call of type () => void', arg.loc);
284
282
  }
@@ -286,15 +284,15 @@ function parseParallelBranches(node) {
286
284
  return Object.fromEntries(stepsArray);
287
285
  }
288
286
  function parseParallelIteration(node, ctx) {
289
- assertType(node, ArrowFunctionExpression);
290
- if (node.body.body.length !== 1 ||
291
- node.body.body[0].type !== ForOfStatement) {
287
+ if (node.body.type !== AST_NODE_TYPES.BlockStatement ||
288
+ node.body.body.length !== 1 ||
289
+ node.body.body[0].type !== AST_NODE_TYPES.ForOfStatement) {
292
290
  throw new WorkflowSyntaxError('The parallel function body must be a single for...of statement', node.body.loc);
293
291
  }
294
292
  return forOfStatementToForStep(node.body.body[0], ctx);
295
293
  }
296
294
  function parseParallelOptions(node) {
297
- if (node.type !== ObjectExpression) {
295
+ if (node.type !== AST_NODE_TYPES.ObjectExpression) {
298
296
  throw new WorkflowSyntaxError('The second parameter must be an object', node.loc);
299
297
  }
300
298
  const parallelOptions = convertObjectExpression(node);
@@ -330,53 +328,42 @@ function generalExpressionToAssignStep(node) {
330
328
  return new AssignStepAST([['__temp', convertExpression(node)]]);
331
329
  }
332
330
  function returnStatementToReturnStep(node) {
333
- assertType(node, ReturnStatement);
334
331
  const value = node.argument ? convertExpression(node.argument) : undefined;
335
332
  return new ReturnStepAST(value);
336
333
  }
337
334
  function throwStatementToRaiseStep(node) {
338
- assertType(node, ThrowStatement);
339
335
  return new RaiseStepAST(convertExpression(node.argument));
340
336
  }
341
337
  function ifStatementToSwitchStep(node, ctx) {
342
- assertType(node, IfStatement);
343
338
  return new SwitchStepAST(flattenIfBranches(node, ctx));
344
339
  }
345
340
  function flattenIfBranches(ifStatement, ctx) {
346
- assertType(ifStatement, IfStatement);
347
- assertType(ifStatement.consequent, BlockStatement);
348
341
  const branches = [
349
342
  {
350
343
  condition: convertExpression(ifStatement.test),
351
- steps: parseBlockStatement(ifStatement.consequent, ctx),
344
+ steps: parseStatement(ifStatement.consequent, ctx),
352
345
  },
353
346
  ];
354
347
  if (ifStatement.alternate) {
355
- if (ifStatement.alternate.type === BlockStatement) {
356
- branches.push({
357
- condition: new PrimitiveExpression(true),
358
- steps: parseBlockStatement(ifStatement.alternate, ctx),
359
- });
360
- }
361
- else if (ifStatement.alternate.type === IfStatement) {
348
+ if (ifStatement.alternate.type === AST_NODE_TYPES.IfStatement) {
362
349
  branches.push(...flattenIfBranches(ifStatement.alternate, ctx));
363
350
  }
364
351
  else {
365
- throw new InternalTranspilingError(`Expected BlockStatement or IfStatement, got ${ifStatement.alternate.type}`);
352
+ branches.push({
353
+ condition: new PrimitiveExpression(true),
354
+ steps: parseStatement(ifStatement.alternate, ctx),
355
+ });
366
356
  }
367
357
  }
368
358
  return branches;
369
359
  }
370
360
  function switchStatementToSteps(node, ctx) {
371
- assertType(node, SwitchStatement);
372
361
  const endOfSwitch = new JumpTargetAST();
373
362
  const switchCtx = Object.assign({}, ctx, { breakTarget: endOfSwitch.label });
374
363
  const steps = [];
375
364
  const branches = [];
376
365
  const discriminant = convertExpression(node.discriminant);
377
- const cases = node.cases;
378
- cases.forEach((caseNode) => {
379
- assertType(caseNode, SwitchCase);
366
+ node.cases.forEach((caseNode) => {
380
367
  let condition;
381
368
  if (caseNode.test) {
382
369
  const test = convertExpression(caseNode.test);
@@ -386,8 +373,7 @@ function switchStatementToSteps(node, ctx) {
386
373
  condition = new PrimitiveExpression(true);
387
374
  }
388
375
  const jumpTarget = new JumpTargetAST();
389
- const consequent = caseNode.consequent;
390
- const body = transformAST(consequent.flatMap((x) => parseStep(x, switchCtx)));
376
+ const body = transformAST(caseNode.consequent.flatMap((x) => parseStatement(x, switchCtx)));
391
377
  steps.push(jumpTarget);
392
378
  steps.push(...body);
393
379
  branches.push({
@@ -401,18 +387,16 @@ function switchStatementToSteps(node, ctx) {
401
387
  return steps;
402
388
  }
403
389
  function forOfStatementToForStep(node, ctx) {
404
- assertType(node, ForOfStatement);
405
- assertType(node.body, BlockStatement);
406
390
  const bodyCtx = Object.assign({}, ctx, {
407
391
  continueTarget: undefined,
408
392
  breakTarget: undefined,
409
393
  });
410
- const steps = parseBlockStatement(node.body, bodyCtx);
394
+ const steps = parseStatement(node.body, bodyCtx);
411
395
  let loopVariableName;
412
- if (node.left.type === Identifier) {
396
+ if (node.left.type === AST_NODE_TYPES.Identifier) {
413
397
  loopVariableName = node.left.name;
414
398
  }
415
- else if (node.left.type === VariableDeclaration) {
399
+ else if (node.left.type === AST_NODE_TYPES.VariableDeclaration) {
416
400
  if (node.left.declarations.length !== 1) {
417
401
  throw new WorkflowSyntaxError('Only one variable can be declared here', node.left.loc);
418
402
  }
@@ -420,7 +404,9 @@ function forOfStatementToForStep(node, ctx) {
420
404
  if (declaration.init !== null) {
421
405
  throw new WorkflowSyntaxError('Initial value not allowed', declaration.init.loc);
422
406
  }
423
- assertType(declaration.id, Identifier);
407
+ if (declaration.id.type !== AST_NODE_TYPES.Identifier) {
408
+ throw new WorkflowSyntaxError(`Expected identifier, got ${declaration.id.type}`, declaration.id.loc);
409
+ }
424
410
  loopVariableName = declaration.id.name;
425
411
  }
426
412
  else {
@@ -439,15 +425,14 @@ function forOfStatementToForStep(node, ctx) {
439
425
  return new ForStepAST(steps, loopVariableName, listExpression);
440
426
  }
441
427
  function whileStatementSteps(node, ctx) {
442
- assertType(node, WhileStatement);
443
428
  const startOfLoop = new JumpTargetAST();
444
429
  const endOfLoop = new JumpTargetAST();
445
430
  const ctx2 = Object.assign({}, ctx, {
446
431
  continueTarget: startOfLoop.label,
447
432
  breakTarget: endOfLoop.label,
448
433
  });
449
- const steps = parseBlockStatement(node.body, ctx2);
450
- steps.push(new NextStepAST(startOfLoop.label));
434
+ const postSteps = [new NextStepAST(startOfLoop.label)];
435
+ const steps = parseStatement(node.body, ctx2, postSteps);
451
436
  return [
452
437
  startOfLoop,
453
438
  new SwitchStepAST([
@@ -460,7 +445,6 @@ function whileStatementSteps(node, ctx) {
460
445
  ];
461
446
  }
462
447
  function doWhileStatementSteps(node, ctx) {
463
- assertType(node, DoWhileStatement);
464
448
  const startOfLoop = new JumpTargetAST();
465
449
  const endOfLoop = new JumpTargetAST();
466
450
  const ctx2 = Object.assign({}, ctx, {
@@ -468,7 +452,7 @@ function doWhileStatementSteps(node, ctx) {
468
452
  breakTarget: endOfLoop.label,
469
453
  });
470
454
  const steps = [startOfLoop];
471
- steps.push(...parseBlockStatement(node.body, ctx2));
455
+ steps.push(...parseStatement(node.body, ctx2));
472
456
  steps.push(new SwitchStepAST([
473
457
  {
474
458
  condition: convertExpression(node.test),
@@ -480,10 +464,8 @@ function doWhileStatementSteps(node, ctx) {
480
464
  return steps;
481
465
  }
482
466
  function breakStatementToNextStep(node, ctx) {
483
- assertType(node, BreakStatement);
484
467
  let target;
485
468
  if (node.label) {
486
- assertType(node.label, Identifier);
487
469
  target = node.label.name;
488
470
  }
489
471
  else if (ctx.breakTarget) {
@@ -495,10 +477,8 @@ function breakStatementToNextStep(node, ctx) {
495
477
  return new NextStepAST(target);
496
478
  }
497
479
  function continueStatementToNextStep(node, ctx) {
498
- assertType(node, ContinueStatement);
499
480
  let target;
500
481
  if (node.label) {
501
- assertType(node.label, Identifier);
502
482
  target = node.label.name;
503
483
  }
504
484
  else if (ctx.continueTarget) {
@@ -510,14 +490,18 @@ function continueStatementToNextStep(node, ctx) {
510
490
  return new NextStepAST(target);
511
491
  }
512
492
  function tryStatementToTryStep(node, ctx) {
513
- assertType(node, TryStatement);
514
- const steps = parseBlockStatement(node.block, ctx);
515
- const exceptSteps = parseBlockStatement(node.handler.body, ctx);
493
+ const steps = parseStatement(node.block, ctx);
494
+ let exceptSteps = [];
516
495
  let errorVariable = undefined;
517
- const handlerParam = node.handler.param;
518
- if (handlerParam) {
519
- assertType(handlerParam, Identifier);
520
- errorVariable = handlerParam.name;
496
+ if (node.handler) {
497
+ exceptSteps = parseStatement(node.handler.body, ctx);
498
+ const handlerParam = node.handler.param;
499
+ if (handlerParam) {
500
+ if (handlerParam.type !== AST_NODE_TYPES.Identifier) {
501
+ throw new WorkflowSyntaxError('The error variable must be an identifier', handlerParam.loc);
502
+ }
503
+ errorVariable = handlerParam.name;
504
+ }
521
505
  }
522
506
  if (node.finalizer !== null) {
523
507
  // TODO
@@ -526,11 +510,9 @@ function tryStatementToTryStep(node, ctx) {
526
510
  return new TryStepAST(steps, exceptSteps, undefined, errorVariable);
527
511
  }
528
512
  function labeledStep(node, ctx) {
529
- assertType(node, LabeledStatement);
530
- const steps = parseStep(node.body, ctx);
531
- if (steps.length > 0) {
532
- steps[0] = stepWithLabel(steps[0], node.label.name);
533
- return steps;
513
+ const steps = parseStatement(node.body, ctx);
514
+ if (steps.length > 0 && steps[0].tag !== 'jumptarget') {
515
+ steps[0] = steps[0].withLabel(node.label.name);
534
516
  }
535
517
  return steps;
536
518
  }
@@ -1 +1 @@
1
- {"version":3,"file":"transformations.d.ts","sourceRoot":"","sources":["../../src/transpiler/transformations.ts"],"names":[],"mappings":"AAAA,OAAO,EAUL,eAAe,EAChB,MAAM,iBAAiB,CAAA;AAuBxB;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE,CAUxE;AA0JD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,eAAe,EAAE,GACvB,eAAe,EAAE,CAoBnB"}
1
+ {"version":3,"file":"transformations.d.ts","sourceRoot":"","sources":["../../src/transpiler/transformations.ts"],"names":[],"mappings":"AAAA,OAAO,EAWL,eAAe,EAChB,MAAM,iBAAiB,CAAA;AAwBxB;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE,CAUxE;AA6JD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,eAAe,EAAE,GACvB,eAAe,EAAE,CAqBnB"}