Skip to content

Commit 8d9a91b

Browse files
committed
Replace UnsupportedKind errors with diagnostics or better types
1 parent 0306f28 commit 8d9a91b

18 files changed

Lines changed: 307 additions & 285 deletions

File tree

src/transformation/context/context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export class TransformationContext {
4747

4848
const nodeVisitors = this.visitorMap.get(node.kind);
4949
if (!nodeVisitors || nodeVisitors.length === 0) {
50-
throw new Error(`${ts.SyntaxKind[node.kind]} is not supported`);
50+
throw new Error(`Unsupported node kind: ${ts.SyntaxKind[node.kind]}.`);
5151
}
5252

5353
const previousNodeVisitors = this.currentNodeVisitors;

src/transformation/utils/diagnostics.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ export const luaTableInvalidInstanceOf = createDiagnosticFactory(
8282
"The instanceof operator cannot be used with a '@luaTable' class."
8383
);
8484

85+
export const luaTableCannotBeAccessedDynamically = createDiagnosticFactory("@luaTable cannot be accessed dynamically.");
86+
8587
export const luaTableForbiddenUsage = createDiagnosticFactory(
8688
(description: string) => `Invalid @luaTable usage: ${description}.`
8789
);
@@ -91,3 +93,17 @@ export const luaIteratorForbiddenUsage = createDiagnosticFactory(
9193
"You must use a destructuring statement to catch results from a lua iterator with " +
9294
"the '@tupleReturn' annotation."
9395
);
96+
97+
export const unsupportedSyntaxKind = createDiagnosticFactory(
98+
(description: string, kind: ts.SyntaxKind) => `Unsupported ${description} kind: ${ts.SyntaxKind[kind]}`
99+
);
100+
101+
export const unsupportedNullishCoalescing = createDiagnosticFactory("Nullish coalescing is not supported.");
102+
103+
export const unsupportedAccessorInObjectLiteral = createDiagnosticFactory(
104+
"Accessors in object literal are not supported."
105+
);
106+
107+
export const unsupportedRightShiftOperator = createDiagnosticFactory(
108+
"Right shift operator is not supported. Use `>>>` instead."
109+
);

src/transformation/utils/errors.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ export const UnsupportedForInVariable = (node: ts.Node) =>
2121

2222
export const UndefinedScope = () => new Error("Expected to pop a scope, but found undefined.");
2323

24-
export const UnsupportedKind = (description: string, kind: ts.SyntaxKind, node: ts.Node) =>
25-
new TranspileError(`Unsupported ${description} kind: ${ts.SyntaxKind[kind]}`, node);
26-
2724
export const UnsupportedProperty = (parentName: string, property: string, node: ts.Node) =>
2825
new TranspileError(`Unsupported property on ${parentName}: ${property}`, node);
2926

src/transformation/visitors/access.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { AnnotationKind, getTypeAnnotations } from "../utils/annotations";
66
import { createExpressionPlusOne } from "../utils/lua-ast";
77
import { isArrayType, isNumberType, isStringType } from "../utils/typescript";
88
import { tryGetConstEnumValue } from "./enum";
9-
import { transformLuaTableElementAccessExpression, transformLuaTablePropertyAccessExpression } from "./lua-table";
9+
import { transformLuaTablePropertyAccessExpression, validateLuaTableElementAccessExpression } from "./lua-table";
1010

1111
export function transformElementAccessArgument(
1212
context: TransformationContext,
@@ -24,7 +24,7 @@ export function transformElementAccessArgument(
2424
}
2525

2626
export const transformElementAccessExpression: FunctionVisitor<ts.ElementAccessExpression> = (expression, context) => {
27-
transformLuaTableElementAccessExpression(context, expression);
27+
validateLuaTableElementAccessExpression(context, expression);
2828

2929
const constEnumValue = tryGetConstEnumValue(context, expression);
3030
if (constEnumValue) {

src/transformation/visitors/binary-expression/bit.ts

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,58 @@
11
import * as ts from "typescript";
22
import { LuaTarget } from "../../../CompilerOptions";
33
import * as lua from "../../../LuaAST";
4+
import { assertNever } from "../../../utils";
45
import { TransformationContext } from "../../context";
5-
import { UnsupportedForTarget, UnsupportedKind } from "../../utils/errors";
6-
import { transformBinaryOperator } from "../binary-expression";
6+
import { unsupportedRightShiftOperator } from "../../utils/diagnostics";
7+
import { UnsupportedForTarget } from "../../utils/errors";
8+
9+
export type BitOperator = ts.ShiftOperator | ts.BitwiseOperator;
10+
export const isBitOperator = (operator: ts.BinaryOperator): operator is BitOperator =>
11+
operator in bitOperatorToLibOperation;
12+
13+
const bitOperatorToLibOperation: Record<BitOperator, string> = {
14+
[ts.SyntaxKind.AmpersandToken]: "band",
15+
[ts.SyntaxKind.BarToken]: "bor",
16+
[ts.SyntaxKind.CaretToken]: "bxor",
17+
[ts.SyntaxKind.LessThanLessThanToken]: "lshift",
18+
[ts.SyntaxKind.GreaterThanGreaterThanToken]: "arshift",
19+
[ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken]: "rshift",
20+
};
721

8-
type BitOperator = ts.ShiftOperator | ts.BitwiseOperator;
922
function transformBinaryBitLibOperation(
1023
node: ts.Node,
1124
left: lua.Expression,
1225
right: lua.Expression,
1326
operator: BitOperator,
1427
lib: string
1528
): lua.Expression {
16-
let bitFunction: string;
29+
const functionName = bitOperatorToLibOperation[operator];
30+
return lua.createCallExpression(
31+
lua.createTableIndexExpression(lua.createIdentifier(lib), lua.createStringLiteral(functionName)),
32+
[left, right],
33+
node
34+
);
35+
}
36+
37+
function transformBitOperatorToLuaOperator(
38+
context: TransformationContext,
39+
node: ts.Node,
40+
operator: BitOperator
41+
): lua.BinaryOperator {
1742
switch (operator) {
18-
case ts.SyntaxKind.AmpersandToken:
19-
bitFunction = "band";
20-
break;
2143
case ts.SyntaxKind.BarToken:
22-
bitFunction = "bor";
23-
break;
44+
return lua.SyntaxKind.BitwiseOrOperator;
2445
case ts.SyntaxKind.CaretToken:
25-
bitFunction = "bxor";
26-
break;
46+
return lua.SyntaxKind.BitwiseExclusiveOrOperator;
47+
case ts.SyntaxKind.AmpersandToken:
48+
return lua.SyntaxKind.BitwiseAndOperator;
2749
case ts.SyntaxKind.LessThanLessThanToken:
28-
bitFunction = "lshift";
29-
break;
30-
case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
31-
bitFunction = "rshift";
32-
break;
50+
return lua.SyntaxKind.BitwiseLeftShiftOperator;
3351
case ts.SyntaxKind.GreaterThanGreaterThanToken:
34-
bitFunction = "arshift";
35-
break;
36-
default:
37-
throw UnsupportedKind("binary bitwise operator", operator, node);
52+
context.diagnostics.push(unsupportedRightShiftOperator(node));
53+
case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
54+
return lua.SyntaxKind.BitwiseRightShiftOperator;
3855
}
39-
40-
return lua.createCallExpression(
41-
lua.createTableIndexExpression(lua.createIdentifier(lib), lua.createStringLiteral(bitFunction)),
42-
[left, right],
43-
node
44-
);
4556
}
4657

4758
export function transformBinaryBitOperation(
@@ -62,7 +73,7 @@ export function transformBinaryBitOperation(
6273
return transformBinaryBitLibOperation(node, left, right, operator, "bit");
6374

6475
default:
65-
const luaOperator = transformBinaryOperator(context, node, operator);
76+
const luaOperator = transformBitOperatorToLuaOperator(context, node, operator);
6677
return lua.createBinaryExpression(left, right, luaOperator, node);
6778
}
6879
}
@@ -79,7 +90,7 @@ function transformUnaryBitLibOperation(
7990
bitFunction = "bnot";
8091
break;
8192
default:
82-
throw UnsupportedKind("unary bitwise operator", operator, node);
93+
assertNever(operator);
8394
}
8495

8596
return lua.createCallExpression(

src/transformation/visitors/binary-expression/compound.ts

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,22 @@ export function parseAccessExpressionWithEvaluationEffects(
3333
return [];
3434
}
3535

36-
const compoundToAssignmentTokens: Record<ts.CompoundAssignmentOperator, ts.BinaryOperator> = {
36+
// TODO: `as const` doesn't work on enum members
37+
type CompoundAssignmentToken =
38+
| ts.SyntaxKind.BarToken
39+
| ts.SyntaxKind.PlusToken
40+
| ts.SyntaxKind.CaretToken
41+
| ts.SyntaxKind.MinusToken
42+
| ts.SyntaxKind.SlashToken
43+
| ts.SyntaxKind.PercentToken
44+
| ts.SyntaxKind.AsteriskToken
45+
| ts.SyntaxKind.AmpersandToken
46+
| ts.SyntaxKind.AsteriskAsteriskToken
47+
| ts.SyntaxKind.LessThanLessThanToken
48+
| ts.SyntaxKind.GreaterThanGreaterThanToken
49+
| ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken;
50+
51+
const compoundToAssignmentTokens: Record<ts.CompoundAssignmentOperator, CompoundAssignmentToken> = {
3752
[ts.SyntaxKind.BarEqualsToken]: ts.SyntaxKind.BarToken,
3853
[ts.SyntaxKind.PlusEqualsToken]: ts.SyntaxKind.PlusToken,
3954
[ts.SyntaxKind.CaretEqualsToken]: ts.SyntaxKind.CaretToken,
@@ -51,7 +66,7 @@ const compoundToAssignmentTokens: Record<ts.CompoundAssignmentOperator, ts.Binar
5166
export const isCompoundAssignmentToken = (token: ts.BinaryOperator): token is ts.CompoundAssignmentOperator =>
5267
token in compoundToAssignmentTokens;
5368

54-
export const unwrapCompoundAssignmentToken = (token: ts.CompoundAssignmentOperator) =>
69+
export const unwrapCompoundAssignmentToken = (token: ts.CompoundAssignmentOperator): CompoundAssignmentToken =>
5570
compoundToAssignmentTokens[token];
5671

5772
export function transformCompoundAssignmentExpression(
@@ -60,7 +75,7 @@ export function transformCompoundAssignmentExpression(
6075
// TODO: Change type to ts.LeftHandSideExpression?
6176
lhs: ts.Expression,
6277
rhs: ts.Expression,
63-
replacementOperator: ts.BinaryOperator,
78+
operator: CompoundAssignmentToken,
6479
isPostfix: boolean
6580
): lua.CallExpression {
6681
const left = cast(context.transformExpression(lhs), lua.isAssignmentLeftHandSideExpression);
@@ -86,7 +101,7 @@ export function transformCompoundAssignmentExpression(
86101
// local ____tmp = ____obj[____index];
87102
// ____obj[____index] = ____tmp ${replacementOperator} ${right};
88103
tmpDeclaration = lua.createVariableDeclarationStatement(tmp, accessExpression);
89-
const operatorExpression = transformBinaryOperation(context, tmp, right, replacementOperator, expression);
104+
const operatorExpression = transformBinaryOperation(context, tmp, right, operator, expression);
90105
assignStatement = lua.createAssignmentStatement(accessExpression, operatorExpression);
91106
} else {
92107
// local ____tmp = ____obj[____index] ${replacementOperator} ${right};
@@ -95,7 +110,7 @@ export function transformCompoundAssignmentExpression(
95110
context,
96111
accessExpression,
97112
right,
98-
replacementOperator,
113+
operator,
99114
expression
100115
);
101116
tmpDeclaration = lua.createVariableDeclarationStatement(tmp, operatorExpression);
@@ -118,7 +133,7 @@ export function transformCompoundAssignmentExpression(
118133
context,
119134
tmpIdentifier,
120135
right,
121-
replacementOperator,
136+
operator,
122137
expression
123138
);
124139
const assignStatement = transformAssignment(context, lhs, operatorExpression);
@@ -129,14 +144,14 @@ export function transformCompoundAssignmentExpression(
129144
// ${left} = ____tmp;
130145
// return ____tmp
131146
const tmpIdentifier = lua.createIdentifier("____tmp");
132-
const operatorExpression = transformBinaryOperation(context, left, right, replacementOperator, expression);
147+
const operatorExpression = transformBinaryOperation(context, left, right, operator, expression);
133148
const tmpDeclaration = lua.createVariableDeclarationStatement(tmpIdentifier, operatorExpression);
134149
const assignStatement = transformAssignment(context, lhs, tmpIdentifier);
135150
return createImmediatelyInvokedFunctionExpression([tmpDeclaration, assignStatement], tmpIdentifier, expression);
136151
} else {
137152
// Simple expressions
138153
// ${left} = ${right}; return ${right}
139-
const operatorExpression = transformBinaryOperation(context, left, right, replacementOperator, expression);
154+
const operatorExpression = transformBinaryOperation(context, left, right, operator, expression);
140155
const assignStatement = transformAssignment(context, lhs, operatorExpression);
141156
return createImmediatelyInvokedFunctionExpression([assignStatement], left, expression);
142157
}
@@ -147,7 +162,7 @@ export function transformCompoundAssignmentStatement(
147162
node: ts.Node,
148163
lhs: ts.Expression,
149164
rhs: ts.Expression,
150-
replacementOperator: ts.BinaryOperator
165+
operator: CompoundAssignmentToken
151166
): lua.Statement {
152167
const left = cast(context.transformExpression(lhs), lua.isAssignmentLeftHandSideExpression);
153168
const right = context.transformExpression(rhs);
@@ -168,15 +183,15 @@ export function transformCompoundAssignmentStatement(
168183
context,
169184
accessExpression,
170185
lua.createParenthesizedExpression(right),
171-
replacementOperator,
186+
operator,
172187
node
173188
);
174189
const assignStatement = lua.createAssignmentStatement(accessExpression, operatorExpression);
175190
return lua.createDoStatement([objAndIndexDeclaration, assignStatement]);
176191
} else {
177192
// Simple statements
178193
// ${left} = ${left} ${replacementOperator} ${right}
179-
const operatorExpression = transformBinaryOperation(context, left, right, replacementOperator, node);
194+
const operatorExpression = transformBinaryOperation(context, left, right, operator, node);
180195
return transformAssignment(context, lhs, operatorExpression);
181196
}
182197
}

src/transformation/visitors/binary-expression/destructuring-assignments.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import * as ts from "typescript";
22
import * as lua from "../../../LuaAST";
3-
import { flatMap } from "../../../utils";
3+
import { assertNever, flatMap } from "../../../utils";
44
import { TransformationContext } from "../../context";
5-
import { UnsupportedKind } from "../../utils/errors";
65
import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib";
76
import { isArrayType, isAssignmentPattern } from "../../utils/typescript";
87
import { transformIdentifier } from "../identifier";
@@ -111,7 +110,10 @@ function transformArrayLiteralAssignmentPattern(
111110
case ts.SyntaxKind.ElementAccessExpression:
112111
return transformAssignment(context, element, indexedRoot);
113112
case ts.SyntaxKind.SpreadElement:
114-
if (index !== node.elements.length - 1) return [];
113+
if (index !== node.elements.length - 1) {
114+
// TypeScript error
115+
return [];
116+
}
115117

116118
const restElements = transformLuaLibFunction(
117119
context,
@@ -125,7 +127,8 @@ function transformArrayLiteralAssignmentPattern(
125127
case ts.SyntaxKind.OmittedExpression:
126128
return [];
127129
default:
128-
throw UnsupportedKind("Array Destructure Assignment Element", element.kind, element);
130+
// TypeScript error
131+
return [];
129132
}
130133
});
131134
}
@@ -156,8 +159,13 @@ function transformObjectLiteralAssignmentPattern(
156159
case ts.SyntaxKind.SpreadAssignment:
157160
result.push(...transformSpreadAssignment(context, property, root, node.properties));
158161
break;
162+
case ts.SyntaxKind.MethodDeclaration:
163+
case ts.SyntaxKind.GetAccessor:
164+
case ts.SyntaxKind.SetAccessor:
165+
// TypeScript error
166+
break;
159167
default:
160-
throw UnsupportedKind("Object Destructure Property", property.kind, property);
168+
assertNever(property);
161169
}
162170
}
163171

0 commit comments

Comments
 (0)