From 2d0a4f4b993a5e87ed92e8fc1ea09203b2704240 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sat, 2 May 2020 16:20:19 +0200 Subject: [PATCH 1/6] Replaced error throw with diagnostic --- src/transformation/context/context.ts | 4 +++- src/transformation/utils/diagnostics.ts | 4 ++++ test/unit/__snapshots__/unsupported.spec.ts.snap | 8 ++++++++ test/unit/unsupported.spec.ts | 11 +++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 test/unit/__snapshots__/unsupported.spec.ts.snap create mode 100644 test/unit/unsupported.spec.ts diff --git a/src/transformation/context/context.ts b/src/transformation/context/context.ts index ea375766b..ddfe3d289 100644 --- a/src/transformation/context/context.ts +++ b/src/transformation/context/context.ts @@ -4,6 +4,7 @@ import * as lua from "../../LuaAST"; import { castArray } from "../../utils"; import { unwrapVisitorResult } from "../utils/lua-ast"; import { ExpressionLikeNode, ObjectVisitor, StatementLikeNode, VisitorMap } from "./visitors"; +import { unsupportedNodeKind } from "../utils/diagnostics"; export interface AllAccessorDeclarations { firstAccessor: ts.AccessorDeclaration; @@ -54,7 +55,8 @@ export class TransformationContext { const nodeVisitors = this.visitorMap.get(node.kind); if (!nodeVisitors || nodeVisitors.length === 0) { - throw new Error(`Unsupported node kind: ${ts.SyntaxKind[node.kind]}.`); + this.diagnostics.push(unsupportedNodeKind(node, node.kind)); + return []; } const previousNodeVisitors = this.currentNodeVisitors; diff --git a/src/transformation/utils/diagnostics.ts b/src/transformation/utils/diagnostics.ts index 5b7b2de38..bf4743be7 100644 --- a/src/transformation/utils/diagnostics.ts +++ b/src/transformation/utils/diagnostics.ts @@ -11,6 +11,10 @@ const createDiagnosticFactory = (message: string | ((...arg messageText: typeof message === "string" ? message : message(...args), })); +export const unsupportedNodeKind = createDiagnosticFactory( + (kind: ts.SyntaxKind) => `Unsupported node kind ${ts.SyntaxKind[kind]}` +); + export const forbiddenForIn = createDiagnosticFactory(`Iterating over arrays with 'for ... in' is not allowed.`); export const unsupportedNoSelfFunctionConversion = createDiagnosticFactory((name?: string) => { diff --git a/test/unit/__snapshots__/unsupported.spec.ts.snap b/test/unit/__snapshots__/unsupported.spec.ts.snap new file mode 100644 index 000000000..d16dde3a7 --- /dev/null +++ b/test/unit/__snapshots__/unsupported.spec.ts.snap @@ -0,0 +1,8 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Unsupported node adds diagnostic: code 1`] = ` +"a = function() +end" +`; + +exports[`Unsupported node adds diagnostic: diagnostics 1`] = `"main.ts(3,13): error TSTL: Unsupported node kind LabeledStatement"`; diff --git a/test/unit/unsupported.spec.ts b/test/unit/unsupported.spec.ts new file mode 100644 index 000000000..0f475d9bd --- /dev/null +++ b/test/unit/unsupported.spec.ts @@ -0,0 +1,11 @@ +import * as util from "../util"; +import { unsupportedNodeKind } from "../../src/transformation/utils/diagnostics"; + +// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/860 +test("Unsupported node adds diagnostic", () => { + util.testModule` + const a = () => { + foo: "bar" + }; + `.expectDiagnosticsToMatchSnapshot([unsupportedNodeKind.code]); +}); From 1ce5093dab926359c1da0abb0307d4220ec208f2 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sat, 2 May 2020 17:12:50 +0200 Subject: [PATCH 2/6] Return nil if node is not a statement --- src/transformation/context/context.ts | 3 ++- src/transformation/utils/typescript/nodes.ts | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/transformation/context/context.ts b/src/transformation/context/context.ts index ddfe3d289..0b0e1d21d 100644 --- a/src/transformation/context/context.ts +++ b/src/transformation/context/context.ts @@ -5,6 +5,7 @@ import { castArray } from "../../utils"; import { unwrapVisitorResult } from "../utils/lua-ast"; import { ExpressionLikeNode, ObjectVisitor, StatementLikeNode, VisitorMap } from "./visitors"; import { unsupportedNodeKind } from "../utils/diagnostics"; +import { isStatement } from "../utils/typescript"; export interface AllAccessorDeclarations { firstAccessor: ts.AccessorDeclaration; @@ -56,7 +57,7 @@ export class TransformationContext { const nodeVisitors = this.visitorMap.get(node.kind); if (!nodeVisitors || nodeVisitors.length === 0) { this.diagnostics.push(unsupportedNodeKind(node, node.kind)); - return []; + return isStatement(node) ? [] : [lua.createNilLiteral()]; } const previousNodeVisitors = this.currentNodeVisitors; diff --git a/src/transformation/utils/typescript/nodes.ts b/src/transformation/utils/typescript/nodes.ts index db0f85641..1dbdfdbf4 100644 --- a/src/transformation/utils/typescript/nodes.ts +++ b/src/transformation/utils/typescript/nodes.ts @@ -1,5 +1,9 @@ import * as ts from "typescript"; +export function isStatement(node: ts.Node): node is ts.Statement { + return node.kind >= ts.SyntaxKind.FirstStatement && node.kind <= ts.SyntaxKind.LastStatement; +} + export function isAssignmentPattern(node: ts.Node): node is ts.AssignmentPattern { return ts.isObjectLiteralExpression(node) || ts.isArrayLiteralExpression(node); } From 7a7d337a56d008fe788c8f29912d21904729d807 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sat, 2 May 2020 20:54:43 +0200 Subject: [PATCH 3/6] Handle expression case in transformExpression --- src/transformation/context/context.ts | 9 ++++----- src/transformation/utils/typescript/nodes.ts | 4 ---- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/transformation/context/context.ts b/src/transformation/context/context.ts index 0b0e1d21d..8cd3bb3b4 100644 --- a/src/transformation/context/context.ts +++ b/src/transformation/context/context.ts @@ -2,10 +2,9 @@ import * as ts from "typescript"; import { CompilerOptions, LuaTarget } from "../../CompilerOptions"; import * as lua from "../../LuaAST"; import { castArray } from "../../utils"; +import { unsupportedNodeKind } from "../utils/diagnostics"; import { unwrapVisitorResult } from "../utils/lua-ast"; import { ExpressionLikeNode, ObjectVisitor, StatementLikeNode, VisitorMap } from "./visitors"; -import { unsupportedNodeKind } from "../utils/diagnostics"; -import { isStatement } from "../utils/typescript"; export interface AllAccessorDeclarations { firstAccessor: ts.AccessorDeclaration; @@ -57,7 +56,7 @@ export class TransformationContext { const nodeVisitors = this.visitorMap.get(node.kind); if (!nodeVisitors || nodeVisitors.length === 0) { this.diagnostics.push(unsupportedNodeKind(node, node.kind)); - return isStatement(node) ? [] : [lua.createNilLiteral()]; + return []; } const previousNodeVisitors = this.currentNodeVisitors; @@ -81,8 +80,8 @@ export class TransformationContext { } public transformExpression(node: ExpressionLikeNode): lua.Expression { - const [result] = this.transformNode(node); - return result as lua.Expression; + const result = this.transformNode(node)[0] as lua.Expression | undefined; + return result ?? lua.createNilLiteral(); } public superTransformExpression(node: ExpressionLikeNode): lua.Expression { diff --git a/src/transformation/utils/typescript/nodes.ts b/src/transformation/utils/typescript/nodes.ts index 1dbdfdbf4..db0f85641 100644 --- a/src/transformation/utils/typescript/nodes.ts +++ b/src/transformation/utils/typescript/nodes.ts @@ -1,9 +1,5 @@ import * as ts from "typescript"; -export function isStatement(node: ts.Node): node is ts.Statement { - return node.kind >= ts.SyntaxKind.FirstStatement && node.kind <= ts.SyntaxKind.LastStatement; -} - export function isAssignmentPattern(node: ts.Node): node is ts.AssignmentPattern { return ts.isObjectLiteralExpression(node) || ts.isArrayLiteralExpression(node); } From 073032f3e0f7ec66a3946145e8b830834102a481 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sat, 2 May 2020 21:30:20 +0200 Subject: [PATCH 4/6] Throw error when expression visitor returns nothing --- src/transformation/context/context.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/transformation/context/context.ts b/src/transformation/context/context.ts index 8cd3bb3b4..1173bec32 100644 --- a/src/transformation/context/context.ts +++ b/src/transformation/context/context.ts @@ -47,7 +47,11 @@ export class TransformationContext { } private currentNodeVisitors: Array> = []; - public transformNode(node: ts.Node): lua.Node[] { + + public transformNode(node: ts.Node): lua.Node[]; + /** @internal */ + public transformNode(node: ts.Node, isExpression?: boolean): lua.Node[]; + public transformNode(node: ts.Node, isExpression?: boolean): lua.Node[] { // TODO: Move to visitors? if (node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.DeclareKeyword)) { return []; @@ -56,7 +60,7 @@ export class TransformationContext { const nodeVisitors = this.visitorMap.get(node.kind); if (!nodeVisitors || nodeVisitors.length === 0) { this.diagnostics.push(unsupportedNodeKind(node, node.kind)); - return []; + return isExpression ? [lua.createNilLiteral()] : []; } const previousNodeVisitors = this.currentNodeVisitors; @@ -80,8 +84,13 @@ export class TransformationContext { } public transformExpression(node: ExpressionLikeNode): lua.Expression { - const result = this.transformNode(node)[0] as lua.Expression | undefined; - return result ?? lua.createNilLiteral(); + const [result] = this.transformNode(node, true); + + if (result === undefined) { + throw new Error(`Expression visitor for node type ${ts.SyntaxKind[node.kind]} did not return any result.`); + } + + return result as lua.Expression; } public superTransformExpression(node: ExpressionLikeNode): lua.Expression { From b2d856893a035105b55f8c8b76533c0b15bd8d68 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sun, 3 May 2020 11:55:14 +0200 Subject: [PATCH 5/6] Moved tests around --- ...{unsupported.spec.ts.snap => statements.spec.ts.snap} | 0 test/unit/expressions.spec.ts | 9 --------- test/unit/{unsupported.spec.ts => statements.spec.ts} | 8 ++++++++ 3 files changed, 8 insertions(+), 9 deletions(-) rename test/unit/__snapshots__/{unsupported.spec.ts.snap => statements.spec.ts.snap} (100%) rename test/unit/{unsupported.spec.ts => statements.spec.ts} (71%) diff --git a/test/unit/__snapshots__/unsupported.spec.ts.snap b/test/unit/__snapshots__/statements.spec.ts.snap similarity index 100% rename from test/unit/__snapshots__/unsupported.spec.ts.snap rename to test/unit/__snapshots__/statements.spec.ts.snap diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index 90211b78c..25f4c20ed 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -2,15 +2,6 @@ import * as tstl from "../../src"; import { unsupportedForTarget, unsupportedRightShiftOperator } from "../../src/transformation/utils/diagnostics"; import * as util from "../util"; -// TODO: -test("Block statement", () => { - util.testFunction` - let a = 4; - { let a = 42; } - return a; - `.expectToMatchJsResult(); -}); - test.each([ "i++", "++i", diff --git a/test/unit/unsupported.spec.ts b/test/unit/statements.spec.ts similarity index 71% rename from test/unit/unsupported.spec.ts rename to test/unit/statements.spec.ts index 0f475d9bd..d653a8885 100644 --- a/test/unit/unsupported.spec.ts +++ b/test/unit/statements.spec.ts @@ -1,6 +1,14 @@ import * as util from "../util"; import { unsupportedNodeKind } from "../../src/transformation/utils/diagnostics"; +test("Block statement", () => { + util.testFunction` + let a = 4; + { let a = 42; } + return a; + `.expectToMatchJsResult(); +}); + // https://github.com/TypeScriptToLua/TypeScriptToLua/issues/860 test("Unsupported node adds diagnostic", () => { util.testModule` From d6cbb67d5b327f5f9718b581e1fe73b334494627 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sat, 9 May 2020 15:16:59 +0200 Subject: [PATCH 6/6] Added error incase superTransform expression visitor returns nothing --- src/transformation/context/context.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/transformation/context/context.ts b/src/transformation/context/context.ts index 1173bec32..965b3d7b9 100644 --- a/src/transformation/context/context.ts +++ b/src/transformation/context/context.ts @@ -95,6 +95,11 @@ export class TransformationContext { public superTransformExpression(node: ExpressionLikeNode): lua.Expression { const [result] = this.superTransformNode(node); + + if (result === undefined) { + throw new Error(`Expression visitor for node type ${ts.SyntaxKind[node.kind]} did not return any result.`); + } + return result as lua.Expression; }