Skip to content

Commit 8f70f50

Browse files
authored
Implement support for void expression (#1148)
* Implement support for void expression * PR feedback
1 parent 3235c6c commit 8f70f50

File tree

6 files changed

+79
-3
lines changed

6 files changed

+79
-3
lines changed

src/transformation/utils/diagnostics.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ const createDiagnosticFactory = <TArgs extends any[]>(
1010
message: MessageProvider<TArgs>
1111
) =>
1212
createSerialDiagnosticFactory((node: ts.Node, ...args: TArgs) => ({
13-
file: node.getSourceFile(),
14-
start: node.getStart(),
15-
length: node.getWidth(),
13+
file: ts.getOriginalNode(node).getSourceFile(),
14+
start: ts.getOriginalNode(node).getStart(),
15+
length: ts.getOriginalNode(node).getWidth(),
1616
messageText: typeof message === "string" ? message : message(...args),
1717
category,
1818
}));

src/transformation/visitors/expression-statement.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
transformTableSetExpression,
1010
} from "./language-extensions/table";
1111
import { transformUnaryExpressionStatement } from "./unary-expression";
12+
import { transformVoidExpressionStatement } from "./void";
1213

1314
export const transformExpressionStatement: FunctionVisitor<ts.ExpressionStatement> = (node, context) => {
1415
const expression = node.expression;
@@ -21,6 +22,10 @@ export const transformExpressionStatement: FunctionVisitor<ts.ExpressionStatemen
2122
return transformTableSetExpression(context, expression);
2223
}
2324

25+
if (ts.isVoidExpression(expression)) {
26+
return transformVoidExpressionStatement(expression, context);
27+
}
28+
2429
const unaryExpressionResult = transformUnaryExpressionStatement(context, node);
2530
if (unaryExpressionResult) {
2631
return unaryExpressionResult;

src/transformation/visitors/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import { typescriptVisitors } from "./typescript";
4141
import { transformPostfixUnaryExpression, transformPrefixUnaryExpression } from "./unary-expression";
4242
import { transformVariableStatement } from "./variable-declaration";
4343
import { transformAwaitExpression } from "./async-await";
44+
import { transformVoidExpression } from "./void";
4445

4546
const transformEmptyStatement: FunctionVisitor<ts.EmptyStatement> = () => undefined;
4647
const transformParenthesizedExpression: FunctionVisitor<ts.ParenthesizedExpression> = (node, context) =>
@@ -98,4 +99,5 @@ export const standardVisitors: Visitors = {
9899
[ts.SyntaxKind.VariableStatement]: transformVariableStatement,
99100
[ts.SyntaxKind.WhileStatement]: transformWhileStatement,
100101
[ts.SyntaxKind.YieldExpression]: transformYieldExpression,
102+
[ts.SyntaxKind.VoidExpression]: transformVoidExpression,
101103
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import * as ts from "typescript";
2+
import * as lua from "../../LuaAST";
3+
import { TransformationContext } from "../context";
4+
import { FunctionVisitor } from "../context/visitors";
5+
import { createImmediatelyInvokedFunctionExpression } from "../utils/lua-ast";
6+
7+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void
8+
export const transformVoidExpression: FunctionVisitor<ts.VoidExpression> = (node, context) => {
9+
// If content is a literal it is safe to replace the entire expression with nil
10+
if (ts.isLiteralExpression(node.expression)) {
11+
return lua.createNilLiteral(node);
12+
}
13+
14+
// (function() local ____ = <expression> end)()
15+
return createImmediatelyInvokedFunctionExpression(
16+
[
17+
lua.createVariableDeclarationStatement(
18+
lua.createAnonymousIdentifier(),
19+
context.transformExpression(node.expression)
20+
),
21+
],
22+
[],
23+
node
24+
);
25+
};
26+
27+
export const transformVoidExpressionStatement = (node: ts.VoidExpression, context: TransformationContext) =>
28+
// In case of a void expression statement we can omit the IIFE
29+
lua.createVariableDeclarationStatement(
30+
lua.createAnonymousIdentifier(),
31+
context.transformExpression(node.expression),
32+
node
33+
);

src/transpilation/transformers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ export const stripParenthesisExpressionsTransformer: ts.TransformerFactory<ts.So
7171
node.typeArguments,
7272
node.arguments
7373
);
74+
} else if (ts.isVoidExpression(node)) {
75+
return ts.factory.updateVoidExpression(node, unwrapParentheses(node.expression));
7476
}
7577

7678
return ts.visitEachChild(node, visit, context);

test/unit/void.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import * as util from "../util";
2+
3+
test.each(["0", "1", '"a"'])("void evaluates to undefined (%p)", value => {
4+
util.testExpression`void (${value})`.expectToMatchJsResult();
5+
});
6+
7+
test("void applies to function declarations", () => {
8+
util.testFunction`
9+
let result = 0;
10+
void function setResult() {
11+
result = 1;
12+
}();
13+
return result;
14+
`.expectToMatchJsResult();
15+
});
16+
17+
test("void used to ignore function return values", () => {
18+
util.testFunction`
19+
let result = 0;
20+
function setResult() {
21+
result = 1;
22+
return 3
23+
};
24+
25+
void(setResult());
26+
27+
return result;
28+
`.expectToMatchJsResult();
29+
});
30+
31+
// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1102
32+
test("void works with lambdas", () => {
33+
util.testExpression`void (() => {})()`.expectToMatchJsResult();
34+
});

0 commit comments

Comments
 (0)