From 63c7b482e41e751d6cd04363da1386654766defa Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sat, 11 Feb 2023 19:38:08 +0100 Subject: [PATCH 1/2] Refactor WithPrecedingStatements type --- .../utils/preceding-statements.ts | 4 +- .../visitors/binary-expression/assignments.ts | 9 ++-- .../visitors/binary-expression/compound.ts | 35 +++++++------ .../destructuring-assignments.ts | 33 ++++++------ .../visitors/binary-expression/index.ts | 44 ++++++++++------ src/transformation/visitors/call.ts | 10 ++-- src/transformation/visitors/class/index.ts | 2 +- .../visitors/class/members/fields.ts | 2 +- src/transformation/visitors/conditional.ts | 34 ++++++------ .../visitors/expression-list.ts | 5 +- src/transformation/visitors/function.ts | 4 +- src/transformation/visitors/loops/do-while.ts | 10 ++-- src/transformation/visitors/loops/for.ts | 7 +-- src/transformation/visitors/loops/utils.ts | 2 +- .../visitors/optional-chaining.ts | 52 ++++++++++--------- src/transformation/visitors/sourceFile.ts | 2 +- src/transformation/visitors/switch.ts | 28 ++++++---- src/transformation/visitors/typeof.ts | 2 +- .../visitors/variable-declaration.ts | 12 ++--- 19 files changed, 160 insertions(+), 137 deletions(-) diff --git a/src/transformation/utils/preceding-statements.ts b/src/transformation/utils/preceding-statements.ts index 8ce121f0d..16cefac12 100644 --- a/src/transformation/utils/preceding-statements.ts +++ b/src/transformation/utils/preceding-statements.ts @@ -10,9 +10,9 @@ export interface WithPrecedingStatements< export function transformInPrecedingStatementScope< TReturn extends lua.Statement | lua.Statement[] | lua.Expression | lua.Expression[] ->(context: TransformationContext, transformer: () => TReturn): [lua.Statement[], TReturn] { +>(context: TransformationContext, transformer: () => TReturn): WithPrecedingStatements { context.pushPrecedingStatements(); const statementOrStatements = transformer(); const precedingStatements = context.popPrecedingStatements(); - return [precedingStatements, statementOrStatements]; + return { precedingStatements, result: statementOrStatements }; } diff --git a/src/transformation/visitors/binary-expression/assignments.ts b/src/transformation/visitors/binary-expression/assignments.ts index efd7180cb..2cceff755 100644 --- a/src/transformation/visitors/binary-expression/assignments.ts +++ b/src/transformation/visitors/binary-expression/assignments.ts @@ -107,8 +107,9 @@ function transformDestructuredAssignmentExpression( context: TransformationContext, expression: ts.DestructuringAssignment ) { - let [rightPrecedingStatements, right] = transformInPrecedingStatementScope(context, () => - context.transformExpression(expression.right) + let { precedingStatements: rightPrecedingStatements, result: right } = transformInPrecedingStatementScope( + context, + () => context.transformExpression(expression.right) ); context.addPrecedingStatements(rightPrecedingStatements); if (isMultiReturnCall(context, expression.right)) { @@ -153,7 +154,7 @@ export function transformAssignmentExpression( } if (ts.isPropertyAccessExpression(expression.left) || ts.isElementAccessExpression(expression.left)) { - const [precedingStatements, right] = transformInPrecedingStatementScope(context, () => + const { precedingStatements, result: right } = transformInPrecedingStatementScope(context, () => context.transformExpression(expression.right) ); @@ -233,7 +234,7 @@ export function transformAssignmentStatement( const { statements } = transformDestructuredAssignmentExpression(context, expression); return statements; } else { - const [precedingStatements, right] = transformInPrecedingStatementScope(context, () => + const { precedingStatements, result: right } = transformInPrecedingStatementScope(context, () => context.transformExpression(expression.right) ); return transformAssignmentWithRightPrecedingStatements(context, expression.left, right, precedingStatements); diff --git a/src/transformation/visitors/binary-expression/compound.ts b/src/transformation/visitors/binary-expression/compound.ts index 43bcab9cb..437f66a61 100644 --- a/src/transformation/visitors/binary-expression/compound.ts +++ b/src/transformation/visitors/binary-expression/compound.ts @@ -86,8 +86,9 @@ function transformCompoundAssignment( } const left = cast(context.transformExpression(lhs), lua.isAssignmentLeftHandSideExpression); - const [rightPrecedingStatements, right] = transformInPrecedingStatementScope(context, () => - context.transformExpression(rhs) + const { precedingStatements: rightPrecedingStatements, result: right } = transformInPrecedingStatementScope( + context, + () => context.transformExpression(rhs) ); if (lua.isTableIndexExpression(left)) { @@ -105,7 +106,7 @@ function transformCompoundAssignment( // ____obj[____index] = ____tmp ${replacementOperator} ${right}; // return ____tmp const tmpDeclaration = lua.createVariableDeclarationStatement(tmp, accessExpression); - const [precedingStatements, operatorExpression] = transformBinaryOperation( + const { precedingStatements, result: operatorExpression } = transformBinaryOperation( context, tmp, right, @@ -136,7 +137,7 @@ function transformCompoundAssignment( // local ____tmp = ____obj[____index] ${replacementOperator} ${right}; // ____obj[____index] = ____tmp; // return ____tmp - const [precedingStatements, operatorExpression] = transformBinaryOperation( + const { precedingStatements, result: operatorExpression } = transformBinaryOperation( context, accessExpression, right, @@ -158,7 +159,7 @@ function transformCompoundAssignment( // return ____tmp const tmpIdentifier = context.createTempNameForLuaExpression(left); const tmpDeclaration = lua.createVariableDeclarationStatement(tmpIdentifier, left); - const [precedingStatements, operatorExpression] = transformBinaryOperation( + const { precedingStatements, result: operatorExpression } = transformBinaryOperation( context, tmpIdentifier, right, @@ -191,7 +192,7 @@ function transformCompoundAssignment( // Simple expressions // ${left} = ${left} ${operator} ${right} - const [precedingStatements, operatorExpression] = transformBinaryOperation( + const { precedingStatements, result: operatorExpression } = transformBinaryOperation( context, left, right, @@ -250,8 +251,9 @@ export function transformCompoundAssignmentStatement( } const left = cast(context.transformExpression(lhs), lua.isAssignmentLeftHandSideExpression); - let [rightPrecedingStatements, right] = transformInPrecedingStatementScope(context, () => - context.transformExpression(rhs) + const { precedingStatements: rightPrecedingStatements, result: right } = transformInPrecedingStatementScope( + context, + () => context.transformExpression(rhs) ); if (lua.isTableIndexExpression(left) && shouldCacheTableIndexExpressions(left, rightPrecedingStatements)) { @@ -277,8 +279,7 @@ export function transformCompoundAssignmentStatement( ]; } - let operatorExpression: lua.Expression; - [rightPrecedingStatements, operatorExpression] = transformBinaryOperation( + const { precedingStatements: rightPrecedingStatements2, result: operatorExpression } = transformBinaryOperation( context, accessExpression, right, @@ -287,7 +288,7 @@ export function transformCompoundAssignmentStatement( node ); const assignStatement = lua.createAssignmentStatement(accessExpression, operatorExpression); - return [objAndIndexDeclaration, ...rightPrecedingStatements, assignStatement]; + return [objAndIndexDeclaration, ...rightPrecedingStatements2, assignStatement]; } else { if (isSetterSkippingCompoundAssignmentOperator(operator)) { return transformSetterSkippingCompoundAssignment(left, operator, right, rightPrecedingStatements, node); @@ -295,8 +296,7 @@ export function transformCompoundAssignmentStatement( // Simple statements // ${left} = ${left} ${replacementOperator} ${right} - let operatorExpression: lua.Expression; - [rightPrecedingStatements, operatorExpression] = transformBinaryOperation( + const { precedingStatements: rightPrecedingStatements2, result: operatorExpression } = transformBinaryOperation( context, left, right, @@ -308,7 +308,7 @@ export function transformCompoundAssignmentStatement( context, lhs, operatorExpression, - rightPrecedingStatements + rightPrecedingStatements2 ); } } @@ -368,12 +368,13 @@ function transformCompoundLengthSetter( rhs: ts.Expression, operator: CompoundAssignmentToken ): WithPrecedingStatements { - const [rightPrecedingStatements, right] = transformInPrecedingStatementScope(context, () => - context.transformExpression(rhs) + const { precedingStatements: rightPrecedingStatements, result: right } = transformInPrecedingStatementScope( + context, + () => context.transformExpression(rhs) ); const table = context.transformExpression(lhs.expression); const lengthExpression = lua.createUnaryExpression(table, lua.SyntaxKind.LengthOperator, lhs); - const [precedingStatements, operatorExpression] = transformBinaryOperation( + const { precedingStatements, result: operatorExpression } = transformBinaryOperation( context, lengthExpression, right, diff --git a/src/transformation/visitors/binary-expression/destructuring-assignments.ts b/src/transformation/visitors/binary-expression/destructuring-assignments.ts index d3d0086c0..aa7042727 100644 --- a/src/transformation/visitors/binary-expression/destructuring-assignments.ts +++ b/src/transformation/visitors/binary-expression/destructuring-assignments.ts @@ -97,15 +97,14 @@ function transformArrayLiteralAssignmentPattern( lua.SyntaxKind.EqualityOperator ); - const [defaultPrecedingStatements, defaultAssignmentStatements] = transformInPrecedingStatementScope( - context, - () => + const { precedingStatements: defaultPrecedingStatements, result: defaultAssignmentStatements } = + transformInPrecedingStatementScope(context, () => transformAssignment( context, (element as ts.BinaryExpression).left, context.transformExpression((element as ts.BinaryExpression).right) ) - ); + ); // Keep preceding statements inside if block defaultAssignmentStatements.unshift(...defaultPrecedingStatements); @@ -126,7 +125,7 @@ function transformArrayLiteralAssignmentPattern( case ts.SyntaxKind.Identifier: case ts.SyntaxKind.PropertyAccessExpression: case ts.SyntaxKind.ElementAccessExpression: - const [precedingStatements, statements] = transformInPrecedingStatementScope(context, () => + const { precedingStatements, result: statements } = transformInPrecedingStatementScope(context, () => transformAssignment(context, element, indexedRoot, rightHasPrecedingStatements) ); return [...precedingStatements, ...statements]; // Keep preceding statements in order @@ -144,14 +143,15 @@ function transformArrayLiteralAssignmentPattern( lua.createNumericLiteral(index) ); - const [spreadPrecedingStatements, spreadStatements] = transformInPrecedingStatementScope(context, () => - transformAssignment( - context, - (element as ts.SpreadElement).expression, - restElements, - rightHasPrecedingStatements - ) - ); + const { precedingStatements: spreadPrecedingStatements, result: spreadStatements } = + transformInPrecedingStatementScope(context, () => + transformAssignment( + context, + (element as ts.SpreadElement).expression, + restElements, + rightHasPrecedingStatements + ) + ); return [...spreadPrecedingStatements, ...spreadStatements]; // Keep preceding statements in order case ts.SyntaxKind.OmittedExpression: return []; @@ -279,9 +279,8 @@ function transformPropertyAssignment( const left = cast(context.transformExpression(node.initializer.left), lua.isTableIndexExpression); const rightExpression = node.initializer.right; - const [defaultPrecedingStatements, defaultExpression] = transformInPrecedingStatementScope(context, () => - context.transformExpression(rightExpression) - ); + const { precedingStatements: defaultPrecedingStatements, result: defaultExpression } = + transformInPrecedingStatementScope(context, () => context.transformExpression(rightExpression)); const tableTemp = context.createTempNameForLuaExpression(left.table); const indexTemp = context.createTempNameForLuaExpression(left.index); @@ -292,7 +291,7 @@ function transformPropertyAssignment( ); // obj[index] = extractingExpression ?? defaultExpression - const [rightPrecedingStatements, rhs] = transformBinaryOperation( + const { precedingStatements: rightPrecedingStatements, result: rhs } = transformBinaryOperation( context, extractingExpression, defaultExpression, diff --git a/src/transformation/visitors/binary-expression/index.ts b/src/transformation/visitors/binary-expression/index.ts index e02615be7..f2b0acb16 100644 --- a/src/transformation/visitors/binary-expression/index.ts +++ b/src/transformation/visitors/binary-expression/index.ts @@ -16,7 +16,7 @@ import { } from "./compound"; import { assert } from "../../../utils"; import { transformOrderedExpressions } from "../expression-list"; -import { transformInPrecedingStatementScope } from "../../utils/preceding-statements"; +import { transformInPrecedingStatementScope, WithPrecedingStatements } from "../../utils/preceding-statements"; type ShortCircuitOperator = | ts.SyntaxKind.AmpersandAmpersandToken @@ -100,7 +100,7 @@ export function createShortCircuitBinaryExpressionPrecedingStatements( rightPrecedingStatements: lua.Statement[], operator: ShortCircuitOperator, node?: ts.BinaryExpression -): [lua.Statement[], lua.Expression] { +): WithPrecedingStatements { const conditionIdentifier = context.createTempNameForLuaExpression(lhs); const assignmentStatement = lua.createVariableDeclarationStatement(conditionIdentifier, lhs, node?.left); @@ -132,19 +132,19 @@ export function createShortCircuitBinaryExpressionPrecedingStatements( undefined, node?.left ); - return [[assignmentStatement, ifStatement], conditionIdentifier]; + return { precedingStatements: [assignmentStatement, ifStatement], result: conditionIdentifier }; } function transformShortCircuitBinaryExpression( context: TransformationContext, node: ts.BinaryExpression, operator: ShortCircuitOperator -): [lua.Statement[], lua.Expression] { +): WithPrecedingStatements { const lhs = context.transformExpression(node.left); - const [rightPrecedingStatements, rhs] = transformInPrecedingStatementScope(context, () => + const { precedingStatements, result } = transformInPrecedingStatementScope(context, () => context.transformExpression(node.right) ); - return transformBinaryOperation(context, lhs, rhs, rightPrecedingStatements, operator, node); + return transformBinaryOperation(context, lhs, result, precedingStatements, operator, node); } export function transformBinaryOperation( @@ -154,7 +154,7 @@ export function transformBinaryOperation( rightPrecedingStatements: lua.Statement[], operator: BitOperator | SimpleOperator | ts.SyntaxKind.QuestionQuestionToken, node: ts.Node -): [lua.Statement[], lua.Expression] { +): WithPrecedingStatements { if (rightPrecedingStatements.length > 0 && isShortCircuitOperator(operator)) { assert(ts.isBinaryExpression(node)); return createShortCircuitBinaryExpressionPrecedingStatements( @@ -167,10 +167,10 @@ export function transformBinaryOperation( ); } - return [ - rightPrecedingStatements, - transformBinaryOperationWithNoPrecedingStatements(context, left, right, operator, node), - ]; + return { + precedingStatements: rightPrecedingStatements, + result: transformBinaryOperationWithNoPrecedingStatements(context, left, right, operator, node), + }; } export const transformBinaryExpression: FunctionVisitor = (node, context) => { @@ -216,7 +216,7 @@ export const transformBinaryExpression: FunctionVisitor = ( case ts.SyntaxKind.CommaToken: { const statements = context.transformStatements(ts.factory.createExpressionStatement(node.left)); - const [precedingStatements, result] = transformInPrecedingStatementScope(context, () => + const { precedingStatements, result } = transformInPrecedingStatementScope(context, () => context.transformExpression(node.right) ); statements.push(...precedingStatements); @@ -227,17 +227,27 @@ export const transformBinaryExpression: FunctionVisitor = ( case ts.SyntaxKind.QuestionQuestionToken: case ts.SyntaxKind.AmpersandAmpersandToken: case ts.SyntaxKind.BarBarToken: { - const [precedingStatements, result] = transformShortCircuitBinaryExpression(context, node, operator); + const { precedingStatements, result } = transformShortCircuitBinaryExpression(context, node, operator); context.addPrecedingStatements(precedingStatements); return result; } } - let [precedingStatements, [lhs, rhs]] = transformInPrecedingStatementScope(context, () => + const { + precedingStatements: orderedExpressionPrecedingStatements, + result: [lhs, rhs], + } = transformInPrecedingStatementScope(context, () => transformOrderedExpressions(context, [node.left, node.right]) ); - let result: lua.Expression; - [precedingStatements, result] = transformBinaryOperation(context, lhs, rhs, precedingStatements, operator, node); + + const { precedingStatements, result } = transformBinaryOperation( + context, + lhs, + rhs, + orderedExpressionPrecedingStatements, + operator, + node + ); context.addPrecedingStatements(precedingStatements); return result; }; @@ -277,7 +287,7 @@ function transformNullishCoalescingOperationNoPrecedingStatements( // Check if we can take a shortcut to 'lhs or rhs' if the left-hand side cannot be 'false'. if (canBeFalsyWhenNotNull(context, lhsType)) { // reuse logic from case with preceding statements - const [precedingStatements, result] = createShortCircuitBinaryExpressionPrecedingStatements( + const { precedingStatements, result } = createShortCircuitBinaryExpressionPrecedingStatements( context, transformedLeft, transformedRight, diff --git a/src/transformation/visitors/call.ts b/src/transformation/visitors/call.ts index 9fac8aa0f..679ae6dc1 100644 --- a/src/transformation/visitors/call.ts +++ b/src/transformation/visitors/call.ts @@ -80,9 +80,8 @@ export function transformCallAndArguments( signature?: ts.Signature, callContext?: ts.Expression ): [lua.Expression, lua.Expression[]] { - const [argPrecedingStatements, transformedArguments] = transformInPrecedingStatementScope(context, () => - transformArguments(context, params, signature, callContext) - ); + const { precedingStatements: argPrecedingStatements, result: transformedArguments } = + transformInPrecedingStatementScope(context, () => transformArguments(context, params, signature, callContext)); return transformCallWithArguments(context, callExpression, transformedArguments, argPrecedingStatements); } @@ -125,9 +124,8 @@ export function transformContextualCallExpression( } const left = ts.isCallExpression(node) ? getCalledExpression(node) : node.tag; - let [argPrecedingStatements, transformedArguments] = transformInPrecedingStatementScope(context, () => - transformArguments(context, args, signature) - ); + let { precedingStatements: argPrecedingStatements, result: transformedArguments } = + transformInPrecedingStatementScope(context, () => transformArguments(context, args, signature)); if ( ts.isPropertyAccessExpression(left) && diff --git a/src/transformation/visitors/class/index.ts b/src/transformation/visitors/class/index.ts index 4235c722d..4fe5f1fd9 100644 --- a/src/transformation/visitors/class/index.ts +++ b/src/transformation/visitors/class/index.ts @@ -29,7 +29,7 @@ export const transformClassDeclaration: FunctionVisitor // If declaration is a default export, transform to export variable assignment instead if (hasDefaultExportModifier(declaration)) { // Class declaration including assignment to ____exports.default are in preceding statements - const [precedingStatements] = transformInPrecedingStatementScope(context, () => { + const { precedingStatements } = transformInPrecedingStatementScope(context, () => { transformClassAsExpression(declaration, context); return []; }); diff --git a/src/transformation/visitors/class/members/fields.ts b/src/transformation/visitors/class/members/fields.ts index 27075bf6e..0e7c3e51f 100644 --- a/src/transformation/visitors/class/members/fields.ts +++ b/src/transformation/visitors/class/members/fields.ts @@ -33,7 +33,7 @@ export function transformClassInstanceFields( const statements: lua.Statement[] = []; for (const f of instanceFields) { - const [precedingStatements, statement] = transformInPrecedingStatementScope(context, () => { + const { precedingStatements, result: statement } = transformInPrecedingStatementScope(context, () => { // Get identifier const fieldName = transformPropertyName(context, f.name); diff --git a/src/transformation/visitors/conditional.ts b/src/transformation/visitors/conditional.ts index a9b7b8d1c..178f6ac2d 100644 --- a/src/transformation/visitors/conditional.ts +++ b/src/transformation/visitors/conditional.ts @@ -1,36 +1,34 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { FunctionVisitor, TransformationContext } from "../context"; -import { transformInPrecedingStatementScope } from "../utils/preceding-statements"; +import { transformInPrecedingStatementScope, WithPrecedingStatements } from "../utils/preceding-statements"; import { performHoisting, ScopeType } from "../utils/scope"; import { transformBlockOrStatement } from "./block"; import { canBeFalsy } from "../utils/typescript"; import { truthyOnlyConditionalValue } from "../utils/diagnostics"; -type EvaluatedExpression = [precedingStatemens: lua.Statement[], value: lua.Expression]; - function transformProtectedConditionalExpression( context: TransformationContext, expression: ts.ConditionalExpression, - condition: EvaluatedExpression, - whenTrue: EvaluatedExpression, - whenFalse: EvaluatedExpression + condition: WithPrecedingStatements, + whenTrue: WithPrecedingStatements, + whenFalse: WithPrecedingStatements ): lua.Expression { const tempVar = context.createTempNameForNode(expression.condition); - const trueStatements = whenTrue[0].concat( - lua.createAssignmentStatement(lua.cloneIdentifier(tempVar), whenTrue[1], expression.whenTrue) + const trueStatements = whenTrue.precedingStatements.concat( + lua.createAssignmentStatement(lua.cloneIdentifier(tempVar), whenTrue.result, expression.whenTrue) ); - const falseStatements = whenFalse[0].concat( - lua.createAssignmentStatement(lua.cloneIdentifier(tempVar), whenFalse[1], expression.whenFalse) + const falseStatements = whenFalse.precedingStatements.concat( + lua.createAssignmentStatement(lua.cloneIdentifier(tempVar), whenFalse.result, expression.whenFalse) ); context.addPrecedingStatements([ lua.createVariableDeclarationStatement(tempVar, undefined, expression.condition), - ...condition[0], + ...condition.precedingStatements, lua.createIfStatement( - condition[1], + condition.result, lua.createBlock(trueStatements, expression.whenTrue), lua.createBlock(falseStatements, expression.whenFalse), expression @@ -53,17 +51,17 @@ export const transformConditionalExpression: FunctionVisitor 0 || - whenFalse[0].length > 0 || + whenTrue.precedingStatements.length > 0 || + whenFalse.precedingStatements.length > 0 || canBeFalsy(context, context.checker.getTypeAtLocation(expression.whenTrue)) ) { return transformProtectedConditionalExpression(context, expression, condition, whenTrue, whenFalse); } // condition and v1 or v2 - context.addPrecedingStatements(condition[0]); - const conditionAnd = lua.createBinaryExpression(condition[1], whenTrue[1], lua.SyntaxKind.AndOperator); - return lua.createBinaryExpression(conditionAnd, whenFalse[1], lua.SyntaxKind.OrOperator, expression); + context.addPrecedingStatements(condition.precedingStatements); + const conditionAnd = lua.createBinaryExpression(condition.result, whenTrue.result, lua.SyntaxKind.AndOperator); + return lua.createBinaryExpression(conditionAnd, whenFalse.result, lua.SyntaxKind.OrOperator, expression); }; export function transformIfStatement(statement: ts.IfStatement, context: TransformationContext): lua.IfStatement { @@ -80,7 +78,7 @@ export function transformIfStatement(statement: ts.IfStatement, context: Transfo if (statement.elseStatement) { if (ts.isIfStatement(statement.elseStatement)) { const tsElseStatement = statement.elseStatement; - const [precedingStatements, elseStatement] = transformInPrecedingStatementScope(context, () => + const { precedingStatements, result: elseStatement } = transformInPrecedingStatementScope(context, () => transformIfStatement(tsElseStatement, context) ); // If else-if condition generates preceding statements, we can't use elseif, we have to break it down: diff --git a/src/transformation/visitors/expression-list.ts b/src/transformation/visitors/expression-list.ts index 475108922..617d09d4a 100644 --- a/src/transformation/visitors/expression-list.ts +++ b/src/transformation/visitors/expression-list.ts @@ -47,9 +47,8 @@ function transformExpressions( const transformedExpressions: lua.Expression[] = []; let lastPrecedingStatementsIndex = -1; for (let i = 0; i < expressions.length; ++i) { - const [expressionPrecedingStatements, expression] = transformInPrecedingStatementScope(context, () => - context.transformExpression(expressions[i]) - ); + const { precedingStatements: expressionPrecedingStatements, result: expression } = + transformInPrecedingStatementScope(context, () => context.transformExpression(expressions[i])); transformedExpressions.push(expression); if (expressionPrecedingStatements.length > 0) { lastPrecedingStatementsIndex = i; diff --git a/src/transformation/visitors/function.ts b/src/transformation/visitors/function.ts index dbcd76549..f79682223 100644 --- a/src/transformation/visitors/function.ts +++ b/src/transformation/visitors/function.ts @@ -90,7 +90,7 @@ export function isFunctionTypeWithProperties(context: TransformationContext, fun export function transformFunctionBodyContent(context: TransformationContext, body: ts.ConciseBody): lua.Statement[] { if (!ts.isBlock(body)) { - const [precedingStatements, returnStatement] = transformInPrecedingStatementScope(context, () => + const { precedingStatements, result: returnStatement } = transformInPrecedingStatementScope(context, () => transformExpressionBodyToReturnStatement(context, body) ); return [...precedingStatements, returnStatement]; @@ -123,7 +123,7 @@ export function transformFunctionBodyHeader( // Binding pattern const name = declaration.name; - const [precedingStatements, bindings] = transformInPrecedingStatementScope(context, () => + const { precedingStatements, result: bindings } = transformInPrecedingStatementScope(context, () => transformBindingPattern(context, name, identifier) ); bindingPatternDeclarations.push(...precedingStatements, ...bindings); diff --git a/src/transformation/visitors/loops/do-while.ts b/src/transformation/visitors/loops/do-while.ts index 806876631..f4c714c71 100644 --- a/src/transformation/visitors/loops/do-while.ts +++ b/src/transformation/visitors/loops/do-while.ts @@ -11,8 +11,9 @@ export const transformWhileStatement: FunctionVisitor = (stat const body = transformLoopBody(context, statement); - let [conditionPrecedingStatements, condition] = transformInPrecedingStatementScope(context, () => - context.transformExpression(statement.expression) + let { precedingStatements: conditionPrecedingStatements, result: condition } = transformInPrecedingStatementScope( + context, + () => context.transformExpression(statement.expression) ); // If condition has preceding statements, ensure they are executed every iteration by using the form: @@ -46,8 +47,9 @@ export const transformDoStatement: FunctionVisitor = (statement, const body = lua.createDoStatement(transformLoopBody(context, statement)); - let [conditionPrecedingStatements, condition] = transformInPrecedingStatementScope(context, () => - invertCondition(context.transformExpression(statement.expression)) + let { precedingStatements: conditionPrecedingStatements, result: condition } = transformInPrecedingStatementScope( + context, + () => invertCondition(context.transformExpression(statement.expression)) ); // If condition has preceding statements, ensure they are executed every iteration by using the form: diff --git a/src/transformation/visitors/loops/for.ts b/src/transformation/visitors/loops/for.ts index 3fbbb6353..3a82b5a24 100644 --- a/src/transformation/visitors/loops/for.ts +++ b/src/transformation/visitors/loops/for.ts @@ -22,11 +22,12 @@ export const transformForStatement: FunctionVisitor = (statemen let condition: lua.Expression; if (statement.condition) { - let conditionPrecedingStatements: lua.Statement[]; const tsCondition = statement.condition; - [conditionPrecedingStatements, condition] = transformInPrecedingStatementScope(context, () => - context.transformExpression(tsCondition) + const { precedingStatements: conditionPrecedingStatements, result } = transformInPrecedingStatementScope( + context, + () => context.transformExpression(tsCondition) ); + condition = result; // If condition has preceding statements, ensure they are executed every iteration by using the form: // diff --git a/src/transformation/visitors/loops/utils.ts b/src/transformation/visitors/loops/utils.ts index e24a92269..7f522edb2 100644 --- a/src/transformation/visitors/loops/utils.ts +++ b/src/transformation/visitors/loops/utils.ts @@ -57,7 +57,7 @@ export function transformForInitializer( const binding = getVariableDeclarationBinding(context, initializer); if (ts.isArrayBindingPattern(binding) || ts.isObjectBindingPattern(binding)) { - const [precedingStatements, bindings] = transformInPrecedingStatementScope(context, () => + const { precedingStatements, result: bindings } = transformInPrecedingStatementScope(context, () => transformBindingPattern(context, binding, valueVariable) ); block.statements.unshift(...precedingStatements, ...bindings); diff --git a/src/transformation/visitors/optional-chaining.ts b/src/transformation/visitors/optional-chaining.ts index 73f32b1e6..893add0f0 100644 --- a/src/transformation/visitors/optional-chaining.ts +++ b/src/transformation/visitors/optional-chaining.ts @@ -128,19 +128,20 @@ export function transformOptionalChainWithCapture( // transform right expression first to check if thisValue capture is needed // capture and return thisValue if requested from outside let returnThisValue: lua.Expression | undefined; - const [rightPrecedingStatements, rightExpression] = transformInPrecedingStatementScope(context, () => { - if (!thisValueCapture) { - return context.transformExpression(tsRightExpression); - } + const { precedingStatements: rightPrecedingStatements, result: rightExpression } = + transformInPrecedingStatementScope(context, () => { + if (!thisValueCapture) { + return context.transformExpression(tsRightExpression); + } - const { expression: result, thisValue } = transformExpressionWithThisValueCapture( - context, - tsRightExpression, - thisValueCapture - ); - returnThisValue = thisValue; - return result; - }); + const { expression: result, thisValue } = transformExpressionWithThisValueCapture( + context, + tsRightExpression, + thisValueCapture + ); + returnThisValue = thisValue; + return result; + }); // transform left expression, handle thisValue if needed by rightExpression const thisValueCaptureName = context.createTempName("this"); @@ -149,19 +150,22 @@ export function transformOptionalChainWithCapture( const optionalContinuationData = getOptionalContinuationData(tsTemp); const rightContextualCall = optionalContinuationData?.contextualCall; - const [leftPrecedingStatements, leftExpression] = transformInPrecedingStatementScope(context, () => { - let result: lua.Expression; - if (rightContextualCall) { - ({ expression: result, thisValue: capturedThisValue } = transformExpressionWithThisValueCapture( - context, - tsLeftExpression, - leftThisValueTemp - )); - } else { - result = context.transformExpression(tsLeftExpression); + const { precedingStatements: leftPrecedingStatements, result: leftExpression } = transformInPrecedingStatementScope( + context, + () => { + let result: lua.Expression; + if (rightContextualCall) { + ({ expression: result, thisValue: capturedThisValue } = transformExpressionWithThisValueCapture( + context, + tsLeftExpression, + leftThisValueTemp + )); + } else { + result = context.transformExpression(tsLeftExpression); + } + return result; } - return result; - }); + ); // handle context if (rightContextualCall) { if (capturedThisValue) { diff --git a/src/transformation/visitors/sourceFile.ts b/src/transformation/visitors/sourceFile.ts index 6870d292b..4a0c62c6d 100644 --- a/src/transformation/visitors/sourceFile.ts +++ b/src/transformation/visitors/sourceFile.ts @@ -13,7 +13,7 @@ export const transformSourceFileNode: FunctionVisitor = (node, co const [statement] = node.statements; if (statement) { assert(ts.isExpressionStatement(statement)); - const [precedingStatements, expression] = transformInPrecedingStatementScope(context, () => + const { precedingStatements, result: expression } = transformInPrecedingStatementScope(context, () => context.transformExpression(statement.expression) ); statements.push(...precedingStatements); diff --git a/src/transformation/visitors/switch.ts b/src/transformation/visitors/switch.ts index 913e6ce71..04323bdbf 100644 --- a/src/transformation/visitors/switch.ts +++ b/src/transformation/visitors/switch.ts @@ -1,7 +1,7 @@ import * as ts from "typescript"; import * as lua from "../../LuaAST"; import { FunctionVisitor, TransformationContext } from "../context"; -import { transformInPrecedingStatementScope } from "../utils/preceding-statements"; +import { transformInPrecedingStatementScope, WithPrecedingStatements } from "../utils/preceding-statements"; import { ScopeType, separateHoistedStatements } from "../utils/scope"; import { createShortCircuitBinaryExpressionPrecedingStatements } from "./binary-expression"; @@ -24,7 +24,7 @@ const createOrExpression = ( left: lua.Expression, right: lua.Expression, rightPrecedingStatements: lua.Statement[] -): [lua.Statement[], lua.Expression] => { +): WithPrecedingStatements => { if (rightPrecedingStatements.length > 0) { return createShortCircuitBinaryExpressionPrecedingStatements( context, @@ -34,7 +34,10 @@ const createOrExpression = ( ts.SyntaxKind.BarBarToken ); } else { - return [rightPrecedingStatements, lua.createBinaryExpression(left, right, lua.SyntaxKind.OrOperator)]; + return { + precedingStatements: rightPrecedingStatements, + result: lua.createBinaryExpression(left, right, lua.SyntaxKind.OrOperator), + }; } }; @@ -44,8 +47,8 @@ const coalesceCondition = ( switchVariable: lua.Identifier, expression: ts.Expression, context: TransformationContext -): [lua.Statement[], lua.Expression] => { - const [precedingStatements, transformedExpression] = transformInPrecedingStatementScope(context, () => +): WithPrecedingStatements => { + const { precedingStatements, result: transformedExpression } = transformInPrecedingStatementScope(context, () => context.transformExpression(expression) ); @@ -60,7 +63,7 @@ const coalesceCondition = ( } // Next condition - return [[...conditionPrecedingStatements, ...precedingStatements], comparison]; + return { precedingStatements: [...conditionPrecedingStatements, ...precedingStatements], result: comparison }; }; export const transformSwitchStatement: FunctionVisitor = (statement, context) => { @@ -108,13 +111,15 @@ export const transformSwitchStatement: FunctionVisitor = (st // Compute the condition for the if statement if (!ts.isDefaultClause(clause)) { - [conditionPrecedingStatements, condition] = coalesceCondition( + const { precedingStatements, result } = coalesceCondition( condition, conditionPrecedingStatements, switchVariable, clause.expression, context ); + conditionPrecedingStatements = precedingStatements; + condition = result; // Skip empty clauses unless final clause (i.e side-effects) if (i !== clauses.length - 1 && clause.statements.length === 0) continue; @@ -126,12 +131,15 @@ export const transformSwitchStatement: FunctionVisitor = (st lua.createVariableDeclarationStatement(conditionVariable, condition) ); } else { - [conditionPrecedingStatements, condition] = createOrExpression( + const { precedingStatements, result } = createOrExpression( context, conditionVariable, condition, conditionPrecedingStatements ); + conditionPrecedingStatements = precedingStatements; + condition = result; + statements.push( ...conditionPrecedingStatements, lua.createAssignmentStatement(conditionVariable, condition) @@ -159,12 +167,14 @@ export const transformSwitchStatement: FunctionVisitor = (st if (i === clauses.length - 1) { // Evaluate the final condition that we may be skipping if (condition) { - [conditionPrecedingStatements, condition] = createOrExpression( + const { precedingStatements, result } = createOrExpression( context, conditionVariable, condition, conditionPrecedingStatements ); + conditionPrecedingStatements = precedingStatements; + condition = result; statements.push( ...conditionPrecedingStatements, lua.createAssignmentStatement(conditionVariable, condition) diff --git a/src/transformation/visitors/typeof.ts b/src/transformation/visitors/typeof.ts index aaa094491..6b70946a3 100644 --- a/src/transformation/visitors/typeof.ts +++ b/src/transformation/visitors/typeof.ts @@ -47,7 +47,7 @@ export function transformTypeOfBinaryExpression( const innerExpression = context.transformExpression(typeOfExpression.expression); const typeCall = lua.createCallExpression(lua.createIdentifier("type"), [innerExpression], typeOfExpression); - const [precedingStatements, result] = transformBinaryOperation( + const { precedingStatements, result } = transformBinaryOperation( context, typeCall, comparedExpression, diff --git a/src/transformation/visitors/variable-declaration.ts b/src/transformation/visitors/variable-declaration.ts index 58dc8a76a..42a2b6538 100644 --- a/src/transformation/visitors/variable-declaration.ts +++ b/src/transformation/visitors/variable-declaration.ts @@ -71,7 +71,7 @@ export function transformBindingPattern( const variableName = transformIdentifier(context, element.name); // The field to extract const elementName = element.propertyName ?? element.name; - const [precedingStatements, propertyName] = transformInPrecedingStatementScope(context, () => + const { precedingStatements, result: propertyName } = transformInPrecedingStatementScope(context, () => transformPropertyName(context, elementName) ); result.push(...precedingStatements); // Keep property's preceding statements in order @@ -135,9 +135,8 @@ export function transformBindingPattern( if (element.initializer) { const identifier = addExportToIdentifier(context, variableName); const tsInitializer = element.initializer; - const [initializerPrecedingStatements, initializer] = transformInPrecedingStatementScope(context, () => - context.transformExpression(tsInitializer) - ); + const { precedingStatements: initializerPrecedingStatements, result: initializer } = + transformInPrecedingStatementScope(context, () => context.transformExpression(tsInitializer)); result.push( lua.createIfStatement( lua.createBinaryExpression(identifier, lua.createNilLiteral(), lua.SyntaxKind.EqualityOperator), @@ -173,8 +172,9 @@ export function transformBindingVariableDeclaration( if (isMultiReturnCall(context, initializer)) { expression = wrapInTable(expression); } - const [moveStatements, movedExpr] = transformInPrecedingStatementScope(context, () => - moveToPrecedingTemp(context, expression, initializer) + const { precedingStatements: moveStatements, result: movedExpr } = transformInPrecedingStatementScope( + context, + () => moveToPrecedingTemp(context, expression, initializer) ); statements.push(...moveStatements); table = movedExpr; From e380b1e9089a5f889b5282a72758b59e605f5b20 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sun, 12 Feb 2023 15:26:59 +0100 Subject: [PATCH 2/2] Remove symlinking from test --- test/transpile/module-resolution.spec.ts | 17 +++++------------ .../{app => }/main.ts | 0 .../dependency1}/package.json | 0 .../dependency1}/src/d1otherfile.ts | 0 .../dependency1}/src/index.ts | 0 .../dependency1}/tsconfig.json | 0 .../{app => }/package.json | 0 .../{app => }/tsconfig.json | 0 8 files changed, 5 insertions(+), 12 deletions(-) rename test/transpile/module-resolution/project-with-tstl-library-has-exports-field/{app => }/main.ts (100%) rename test/transpile/module-resolution/project-with-tstl-library-has-exports-field/{dependency1-ts => node_modules/dependency1}/package.json (100%) rename test/transpile/module-resolution/project-with-tstl-library-has-exports-field/{dependency1-ts => node_modules/dependency1}/src/d1otherfile.ts (100%) rename test/transpile/module-resolution/project-with-tstl-library-has-exports-field/{dependency1-ts => node_modules/dependency1}/src/index.ts (100%) rename test/transpile/module-resolution/project-with-tstl-library-has-exports-field/{dependency1-ts => node_modules/dependency1}/tsconfig.json (100%) rename test/transpile/module-resolution/project-with-tstl-library-has-exports-field/{app => }/package.json (100%) rename test/transpile/module-resolution/project-with-tstl-library-has-exports-field/{app => }/tsconfig.json (100%) diff --git a/test/transpile/module-resolution.spec.ts b/test/transpile/module-resolution.spec.ts index f9e1894d5..bde9e434d 100644 --- a/test/transpile/module-resolution.spec.ts +++ b/test/transpile/module-resolution.spec.ts @@ -2,7 +2,6 @@ import * as path from "path"; import * as tstl from "../../src"; import * as util from "../util"; import * as ts from "typescript"; -import * as fs from "fs-extra"; import { BuildMode } from "../../src"; import { normalizeSlashes } from "../../src/utils"; import { pathsWithoutBaseUrl } from "../../src/transpilation/diagnostics"; @@ -275,17 +274,11 @@ describe("module resolution project with dependencies built by tstl library mode describe("module resolution project with dependencies built by tstl library mode and has exports field", () => { const projectPath = path.resolve(__dirname, "module-resolution", "project-with-tstl-library-has-exports-field"); - const appPath = path.join(projectPath, "app"); // First compile dependencies into node_modules. NOTE: Actually writing to disk, very slow - const dependency1Path = path.join(projectPath, "dependency1-ts"); + const dependency1Path = path.join(projectPath, "node_modules", "dependency1"); tstl.transpileProject(path.join(dependency1Path, "tsconfig.json")); - // Install dependencies. This will create node_modules folder with dependency1-ts in it. - const nodeModulesPath = path.join(appPath, "node_modules"); - fs.ensureDirSync(nodeModulesPath); - fs.ensureSymlinkSync(dependency1Path, path.join(nodeModulesPath, "dependency1"), "dir"); - const expectedResult = { dependency1IndexResult: "function in dependency 1 index: dependency1OtherFileFunc in dependency1/d1otherfile", dependency1OtherFileFuncResult: "dependency1OtherFileFunc in dependency1/d1otherfile", @@ -293,8 +286,8 @@ describe("module resolution project with dependencies built by tstl library mode test("can resolve lua dependencies", () => { const transpileResult = util - .testProject(path.join(appPath, "tsconfig.json")) - .setMainFileName(path.join(appPath, "main.ts")) + .testProject(path.join(projectPath, "tsconfig.json")) + .setMainFileName(path.join(projectPath, "main.ts")) .setOptions({ outDir: "tstl-out", moduleResolution: ts.ModuleResolutionKind.Node16 }) .expectToEqual(expectedResult) .getLuaResult(); @@ -307,8 +300,8 @@ describe("module resolution project with dependencies built by tstl library mode }); test("can resolve dependencies and bundle", () => { - const mainFile = path.join(appPath, "main.ts"); - util.testProject(path.join(appPath, "tsconfig.json")) + const mainFile = path.join(projectPath, "main.ts"); + util.testProject(path.join(projectPath, "tsconfig.json")) .setMainFileName(mainFile) .setOptions({ luaBundle: "bundle.lua", diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/app/main.ts b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/main.ts similarity index 100% rename from test/transpile/module-resolution/project-with-tstl-library-has-exports-field/app/main.ts rename to test/transpile/module-resolution/project-with-tstl-library-has-exports-field/main.ts diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/package.json b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/package.json similarity index 100% rename from test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/package.json rename to test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/package.json diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/src/d1otherfile.ts b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/src/d1otherfile.ts similarity index 100% rename from test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/src/d1otherfile.ts rename to test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/src/d1otherfile.ts diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/src/index.ts b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/src/index.ts similarity index 100% rename from test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/src/index.ts rename to test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/src/index.ts diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/tsconfig.json b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/tsconfig.json similarity index 100% rename from test/transpile/module-resolution/project-with-tstl-library-has-exports-field/dependency1-ts/tsconfig.json rename to test/transpile/module-resolution/project-with-tstl-library-has-exports-field/node_modules/dependency1/tsconfig.json diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/app/package.json b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/package.json similarity index 100% rename from test/transpile/module-resolution/project-with-tstl-library-has-exports-field/app/package.json rename to test/transpile/module-resolution/project-with-tstl-library-has-exports-field/package.json diff --git a/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/app/tsconfig.json b/test/transpile/module-resolution/project-with-tstl-library-has-exports-field/tsconfig.json similarity index 100% rename from test/transpile/module-resolution/project-with-tstl-library-has-exports-field/app/tsconfig.json rename to test/transpile/module-resolution/project-with-tstl-library-has-exports-field/tsconfig.json