|
1 | 1 | import * as ts from "typescript"; |
2 | 2 | import * as lua from "../../../LuaAST"; |
3 | | -import { cast, castEach } from "../../../utils"; |
| 3 | +import { assert, cast, castEach } from "../../../utils"; |
4 | 4 | import { FunctionVisitor, TransformationContext } from "../../context"; |
5 | 5 | import { AnnotationKind, getTypeAnnotations, isForRangeType, isLuaIteratorType } from "../../utils/annotations"; |
| 6 | +import { invalidForRangeCall } from "../../utils/diagnostics"; |
6 | 7 | import { |
7 | | - InvalidForRangeCall, |
8 | 8 | MissingForOfVariables, |
9 | 9 | UnsupportedNonDestructuringLuaIterator, |
10 | 10 | UnsupportedObjectDestructuringInForOf, |
@@ -74,38 +74,50 @@ function transformForRangeStatement( |
74 | 74 | statement: ts.ForOfStatement, |
75 | 75 | block: lua.Block |
76 | 76 | ): lua.Statement { |
77 | | - if (!ts.isCallExpression(statement.expression)) { |
78 | | - throw InvalidForRangeCall(statement.expression, "Expression must be a call expression."); |
79 | | - } |
| 77 | + assert(ts.isCallExpression(statement.expression)); |
80 | 78 |
|
81 | | - if (statement.expression.arguments.length < 2 || statement.expression.arguments.length > 3) { |
82 | | - throw InvalidForRangeCall(statement.expression, "@forRange function must take 2 or 3 arguments."); |
| 79 | + const callArguments = statement.expression.arguments; |
| 80 | + if (callArguments.length !== 2 && callArguments.length !== 3) { |
| 81 | + context.diagnostics.push( |
| 82 | + invalidForRangeCall(statement.expression, `Expected 2-3 arguments, but got ${callArguments.length}`) |
| 83 | + ); |
83 | 84 | } |
84 | 85 |
|
85 | 86 | if (statement.expression.arguments.some(a => !isNumberType(context, context.checker.getTypeAtLocation(a)))) { |
86 | | - throw InvalidForRangeCall(statement.expression, "@forRange arguments must be number types."); |
| 87 | + context.diagnostics.push(invalidForRangeCall(statement.expression, "arguments must be numbers")); |
87 | 88 | } |
88 | 89 |
|
89 | | - if (!ts.isVariableDeclarationList(statement.initializer)) { |
90 | | - throw InvalidForRangeCall(statement.initializer, "@forRange loop must declare its own control variable."); |
91 | | - } |
| 90 | + const controlVariable = getControlVariable() ?? lua.createAnonymousIdentifier(); |
| 91 | + function getControlVariable(): lua.Identifier | undefined { |
| 92 | + if (!ts.isVariableDeclarationList(statement.initializer)) { |
| 93 | + context.diagnostics.push( |
| 94 | + invalidForRangeCall(statement.initializer, "loop must declare it's own control variable") |
| 95 | + ); |
| 96 | + return; |
| 97 | + } |
92 | 98 |
|
93 | | - const controlDeclaration = statement.initializer.declarations[0]; |
94 | | - if (!ts.isIdentifier(controlDeclaration.name)) { |
95 | | - throw InvalidForRangeCall(statement.initializer, "@forRange loop cannot use destructuring."); |
96 | | - } |
| 99 | + const controlDeclaration = statement.initializer.declarations[0]; |
| 100 | + if (!ts.isIdentifier(controlDeclaration.name)) { |
| 101 | + context.diagnostics.push(invalidForRangeCall(statement.initializer, "destructuring cannot be used")); |
| 102 | + return; |
| 103 | + } |
97 | 104 |
|
98 | | - if (!isNumberType(context, context.checker.getTypeAtLocation(controlDeclaration))) { |
99 | | - throw InvalidForRangeCall( |
100 | | - statement.expression, |
101 | | - "@forRange function must return Iterable<number> or Array<number>." |
102 | | - ); |
| 105 | + if (!isNumberType(context, context.checker.getTypeAtLocation(controlDeclaration))) { |
| 106 | + context.diagnostics.push( |
| 107 | + invalidForRangeCall(statement.expression, "function must return Iterable<number>") |
| 108 | + ); |
| 109 | + } |
| 110 | + |
| 111 | + return transformIdentifier(context, controlDeclaration.name); |
103 | 112 | } |
104 | 113 |
|
105 | | - const control = transformIdentifier(context, controlDeclaration.name); |
106 | | - const signature = context.checker.getResolvedSignature(statement.expression); |
107 | | - const [start, limit, step] = transformArguments(context, statement.expression.arguments, signature); |
108 | | - return lua.createForStatement(block, control, start, limit, step, statement); |
| 114 | + const [start = lua.createNumericLiteral(0), limit = lua.createNumericLiteral(0), step] = transformArguments( |
| 115 | + context, |
| 116 | + callArguments, |
| 117 | + context.checker.getResolvedSignature(statement.expression) |
| 118 | + ); |
| 119 | + |
| 120 | + return lua.createForStatement(block, controlVariable, start, limit, step, statement); |
109 | 121 | } |
110 | 122 |
|
111 | 123 | function transformForOfLuaIteratorStatement( |
|
0 commit comments