Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/transformation/utils/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ const createDiagnosticFactory = <TArgs extends any[]>(
message: MessageProvider<TArgs>
) =>
createSerialDiagnosticFactory((node: ts.Node, ...args: TArgs) => ({
file: node.getSourceFile(),
start: node.getStart(),
length: node.getWidth(),
file: ts.getOriginalNode(node).getSourceFile(),
start: ts.getOriginalNode(node).getStart(),
length: ts.getOriginalNode(node).getWidth(),
messageText: typeof message === "string" ? message : message(...args),
category,
}));
Expand Down
5 changes: 5 additions & 0 deletions src/transformation/visitors/expression-statement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
transformTableSetExpression,
} from "./language-extensions/table";
import { transformUnaryExpressionStatement } from "./unary-expression";
import { transformVoidExpressionStatement } from "./void";

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

if (ts.isVoidExpression(expression)) {
return transformVoidExpressionStatement(expression, context);
}

const unaryExpressionResult = transformUnaryExpressionStatement(context, node);
if (unaryExpressionResult) {
return unaryExpressionResult;
Expand Down
2 changes: 2 additions & 0 deletions src/transformation/visitors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { typescriptVisitors } from "./typescript";
import { transformPostfixUnaryExpression, transformPrefixUnaryExpression } from "./unary-expression";
import { transformVariableStatement } from "./variable-declaration";
import { transformAwaitExpression } from "./async-await";
import { transformVoidExpression } from "./void";

const transformEmptyStatement: FunctionVisitor<ts.EmptyStatement> = () => undefined;
const transformParenthesizedExpression: FunctionVisitor<ts.ParenthesizedExpression> = (node, context) =>
Expand Down Expand Up @@ -98,4 +99,5 @@ export const standardVisitors: Visitors = {
[ts.SyntaxKind.VariableStatement]: transformVariableStatement,
[ts.SyntaxKind.WhileStatement]: transformWhileStatement,
[ts.SyntaxKind.YieldExpression]: transformYieldExpression,
[ts.SyntaxKind.VoidExpression]: transformVoidExpression,
};
33 changes: 33 additions & 0 deletions src/transformation/visitors/void.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as ts from "typescript";
import * as lua from "../../LuaAST";
import { TransformationContext } from "../context";
import { FunctionVisitor } from "../context/visitors";
import { createImmediatelyInvokedFunctionExpression } from "../utils/lua-ast";

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void
export const transformVoidExpression: FunctionVisitor<ts.VoidExpression> = (node, context) => {
// If content is a literal it is safe to replace the entire expression with nil
if (ts.isLiteralExpression(node.expression)) {
return lua.createNilLiteral(node);
}

// (function() local ____ = <expression> end)()
return createImmediatelyInvokedFunctionExpression(
[
lua.createVariableDeclarationStatement(
lua.createAnonymousIdentifier(),
context.transformExpression(node.expression)
),
],
[],
node
);
};

export const transformVoidExpressionStatement = (node: ts.VoidExpression, context: TransformationContext) =>
// In case of a void expression statement we can omit the IIFE
lua.createVariableDeclarationStatement(
lua.createAnonymousIdentifier(),
context.transformExpression(node.expression),
node
);
2 changes: 2 additions & 0 deletions src/transpilation/transformers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ export const stripParenthesisExpressionsTransformer: ts.TransformerFactory<ts.So
node.typeArguments,
node.arguments
);
} else if (ts.isVoidExpression(node)) {
return ts.factory.updateVoidExpression(node, unwrapParentheses(node.expression));
}

return ts.visitEachChild(node, visit, context);
Expand Down
34 changes: 34 additions & 0 deletions test/unit/void.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as util from "../util";

test.each(["0", "1", '"a"'])("void evaluates to undefined (%p)", value => {
util.testExpression`void (${value})`.expectToMatchJsResult();
});

test("void applies to function declarations", () => {
util.testFunction`
let result = 0;
void function setResult() {
result = 1;
}();
return result;
`.expectToMatchJsResult();
});

test("void used to ignore function return values", () => {
util.testFunction`
let result = 0;
function setResult() {
result = 1;
return 3
};

void(setResult());

return result;
`.expectToMatchJsResult();
});

// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1102
test("void works with lambdas", () => {
util.testExpression`void (() => {})()`.expectToMatchJsResult();
});