typescript-to-lua 1.0.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/CompilerOptions.d.ts +4 -3
  3. package/dist/LuaAST.d.ts +1 -0
  4. package/dist/LuaAST.js +14 -6
  5. package/dist/LuaLib.d.ts +4 -3
  6. package/dist/LuaLib.js +6 -5
  7. package/dist/LuaPrinter.d.ts +15 -4
  8. package/dist/LuaPrinter.js +81 -29
  9. package/dist/cli/diagnostics.js +2 -2
  10. package/dist/cli/parse.d.ts +1 -1
  11. package/dist/cli/parse.js +14 -0
  12. package/dist/cli/report.js +1 -1
  13. package/dist/cli/tsconfig.js +4 -4
  14. package/dist/lualib/ArrayFlat.lua +1 -1
  15. package/dist/lualib/ArrayFlatMap.lua +1 -1
  16. package/dist/lualib/ArrayIsArray.lua +1 -1
  17. package/dist/lualib/ArrayReduce.lua +7 -1
  18. package/dist/lualib/ArrayReduceRight.lua +7 -1
  19. package/dist/lualib/ArraySetLength.lua +1 -1
  20. package/dist/lualib/ArraySplice.lua +5 -5
  21. package/dist/lualib/Await.lua +43 -19
  22. package/dist/lualib/CloneDescriptor.lua +7 -7
  23. package/dist/lualib/Decorate.lua +1 -1
  24. package/dist/lualib/DelegatedYield.lua +1 -3
  25. package/dist/lualib/Delete.lua +6 -6
  26. package/dist/lualib/Error.lua +47 -44
  27. package/dist/lualib/Generator.lua +1 -5
  28. package/dist/lualib/InstanceOf.lua +1 -1
  29. package/dist/lualib/InstanceOfObject.lua +1 -1
  30. package/dist/lualib/Map.lua +130 -134
  31. package/dist/lualib/Number.lua +1 -1
  32. package/dist/lualib/NumberIsFinite.lua +1 -1
  33. package/dist/lualib/NumberToString.lua +3 -5
  34. package/dist/lualib/ObjectDefineProperty.lua +40 -8
  35. package/dist/lualib/ParseFloat.lua +9 -5
  36. package/dist/lualib/ParseInt.lua +15 -3
  37. package/dist/lualib/Promise.lua +44 -26
  38. package/dist/lualib/Set.lua +119 -123
  39. package/dist/lualib/SetDescriptor.lua +7 -1
  40. package/dist/lualib/SourceMapTraceBack.lua +19 -9
  41. package/dist/lualib/SparseArrayNew.lua +5 -0
  42. package/dist/lualib/SparseArrayPush.lua +9 -0
  43. package/dist/lualib/SparseArraySpread.lua +4 -0
  44. package/dist/lualib/StringAccess.lua +1 -1
  45. package/dist/lualib/StringCharCodeAt.lua +1 -1
  46. package/dist/lualib/StringEndsWith.lua +2 -2
  47. package/dist/lualib/StringPadEnd.lua +2 -2
  48. package/dist/lualib/StringPadStart.lua +2 -2
  49. package/dist/lualib/StringReplace.lua +12 -11
  50. package/dist/lualib/StringReplaceAll.lua +35 -0
  51. package/dist/lualib/StringSlice.lua +2 -2
  52. package/dist/lualib/StringSplit.lua +3 -3
  53. package/dist/lualib/StringStartsWith.lua +1 -1
  54. package/dist/lualib/StringSubstr.lua +1 -1
  55. package/dist/lualib/StringSubstring.lua +2 -2
  56. package/dist/lualib/Symbol.lua +3 -5
  57. package/dist/lualib/WeakMap.lua +40 -42
  58. package/dist/lualib/WeakSet.lua +36 -38
  59. package/dist/lualib/lualib_bundle.lua +876 -745
  60. package/dist/transformation/builtins/array.js +29 -30
  61. package/dist/transformation/builtins/console.js +2 -2
  62. package/dist/transformation/builtins/function.js +14 -12
  63. package/dist/transformation/builtins/global.js +8 -8
  64. package/dist/transformation/builtins/index.d.ts +1 -1
  65. package/dist/transformation/builtins/index.js +69 -36
  66. package/dist/transformation/builtins/math.js +4 -4
  67. package/dist/transformation/builtins/number.js +7 -7
  68. package/dist/transformation/builtins/object.d.ts +2 -1
  69. package/dist/transformation/builtins/object.js +12 -13
  70. package/dist/transformation/builtins/promise.js +9 -9
  71. package/dist/transformation/builtins/string.js +32 -31
  72. package/dist/transformation/builtins/symbol.js +3 -3
  73. package/dist/transformation/context/context.d.ts +12 -0
  74. package/dist/transformation/context/context.js +105 -6
  75. package/dist/transformation/index.js +1 -1
  76. package/dist/transformation/utils/annotations.d.ts +1 -3
  77. package/dist/transformation/utils/annotations.js +0 -2
  78. package/dist/transformation/utils/assignment-validation.js +8 -7
  79. package/dist/transformation/utils/diagnostics.d.ts +9 -0
  80. package/dist/transformation/utils/diagnostics.js +8 -5
  81. package/dist/transformation/utils/export.d.ts +3 -2
  82. package/dist/transformation/utils/export.js +14 -7
  83. package/dist/transformation/utils/function-context.js +8 -8
  84. package/dist/transformation/utils/language-extensions.d.ts +2 -0
  85. package/dist/transformation/utils/language-extensions.js +7 -1
  86. package/dist/transformation/utils/lua-ast.d.ts +0 -1
  87. package/dist/transformation/utils/lua-ast.js +25 -35
  88. package/dist/transformation/utils/lualib.js +1 -1
  89. package/dist/transformation/utils/preceding-statements.d.ts +3 -0
  90. package/dist/transformation/utils/preceding-statements.js +11 -0
  91. package/dist/transformation/utils/safe-names.d.ts +4 -2
  92. package/dist/transformation/utils/safe-names.js +13 -7
  93. package/dist/transformation/utils/scope.d.ts +9 -1
  94. package/dist/transformation/utils/scope.js +78 -40
  95. package/dist/transformation/utils/symbols.js +6 -6
  96. package/dist/transformation/utils/typescript/index.d.ts +1 -0
  97. package/dist/transformation/utils/typescript/index.js +16 -1
  98. package/dist/transformation/utils/typescript/nodes.d.ts +2 -0
  99. package/dist/transformation/utils/typescript/nodes.js +21 -1
  100. package/dist/transformation/utils/typescript/types.d.ts +3 -1
  101. package/dist/transformation/utils/typescript/types.js +40 -13
  102. package/dist/transformation/visitors/access.d.ts +3 -0
  103. package/dist/transformation/visitors/access.js +74 -47
  104. package/dist/transformation/visitors/async-await.js +5 -4
  105. package/dist/transformation/visitors/binary-expression/assignments.d.ts +3 -2
  106. package/dist/transformation/visitors/binary-expression/assignments.js +86 -77
  107. package/dist/transformation/visitors/binary-expression/bit.js +4 -4
  108. package/dist/transformation/visitors/binary-expression/compound.d.ts +5 -4
  109. package/dist/transformation/visitors/binary-expression/compound.js +69 -71
  110. package/dist/transformation/visitors/binary-expression/destructuring-assignments.d.ts +2 -2
  111. package/dist/transformation/visitors/binary-expression/destructuring-assignments.js +65 -36
  112. package/dist/transformation/visitors/binary-expression/index.d.ts +3 -1
  113. package/dist/transformation/visitors/binary-expression/index.js +84 -42
  114. package/dist/transformation/visitors/block.js +6 -6
  115. package/dist/transformation/visitors/break-continue.js +2 -2
  116. package/dist/transformation/visitors/call.d.ts +3 -2
  117. package/dist/transformation/visitors/call.js +130 -143
  118. package/dist/transformation/visitors/class/decorators.js +3 -3
  119. package/dist/transformation/visitors/class/index.js +43 -39
  120. package/dist/transformation/visitors/class/members/accessors.js +6 -6
  121. package/dist/transformation/visitors/class/members/constructor.js +7 -7
  122. package/dist/transformation/visitors/class/members/fields.js +6 -6
  123. package/dist/transformation/visitors/class/members/method.js +6 -6
  124. package/dist/transformation/visitors/class/new.js +14 -16
  125. package/dist/transformation/visitors/class/setup.js +11 -11
  126. package/dist/transformation/visitors/class/utils.js +2 -2
  127. package/dist/transformation/visitors/conditional.js +36 -43
  128. package/dist/transformation/visitors/delete.js +8 -4
  129. package/dist/transformation/visitors/enum.js +8 -8
  130. package/dist/transformation/visitors/errors.js +35 -33
  131. package/dist/transformation/visitors/expression-list.d.ts +7 -0
  132. package/dist/transformation/visitors/expression-list.js +120 -0
  133. package/dist/transformation/visitors/expression-statement.js +10 -6
  134. package/dist/transformation/visitors/function.d.ts +2 -0
  135. package/dist/transformation/visitors/function.js +80 -33
  136. package/dist/transformation/visitors/identifier.js +26 -22
  137. package/dist/transformation/visitors/index.js +2 -2
  138. package/dist/transformation/visitors/language-extensions/iterable.js +7 -7
  139. package/dist/transformation/visitors/language-extensions/multi.d.ts +1 -1
  140. package/dist/transformation/visitors/language-extensions/multi.js +3 -3
  141. package/dist/transformation/visitors/language-extensions/operators.js +6 -6
  142. package/dist/transformation/visitors/language-extensions/pairsIterable.d.ts +5 -0
  143. package/dist/transformation/visitors/language-extensions/pairsIterable.js +53 -0
  144. package/dist/transformation/visitors/language-extensions/range.js +6 -6
  145. package/dist/transformation/visitors/language-extensions/table.js +5 -5
  146. package/dist/transformation/visitors/literal.d.ts +1 -2
  147. package/dist/transformation/visitors/literal.js +87 -57
  148. package/dist/transformation/visitors/loops/do-while.js +35 -9
  149. package/dist/transformation/visitors/loops/for-in.js +4 -4
  150. package/dist/transformation/visitors/loops/for-of.js +17 -13
  151. package/dist/transformation/visitors/loops/for.js +28 -8
  152. package/dist/transformation/visitors/loops/utils.d.ts +1 -0
  153. package/dist/transformation/visitors/loops/utils.js +26 -10
  154. package/dist/transformation/visitors/modules/export.js +14 -15
  155. package/dist/transformation/visitors/modules/import.js +10 -10
  156. package/dist/transformation/visitors/namespace.js +13 -13
  157. package/dist/transformation/visitors/optional-chaining.d.ts +16 -0
  158. package/dist/transformation/visitors/optional-chaining.js +172 -0
  159. package/dist/transformation/visitors/return.d.ts +1 -0
  160. package/dist/transformation/visitors/return.js +40 -26
  161. package/dist/transformation/visitors/sourceFile.js +12 -9
  162. package/dist/transformation/visitors/spread.js +23 -16
  163. package/dist/transformation/visitors/switch.js +63 -20
  164. package/dist/transformation/visitors/template.js +10 -7
  165. package/dist/transformation/visitors/typeof.js +4 -2
  166. package/dist/transformation/visitors/typescript.js +1 -1
  167. package/dist/transformation/visitors/unary-expression.js +9 -9
  168. package/dist/transformation/visitors/variable-declaration.js +55 -32
  169. package/dist/transformation/visitors/void.d.ts +6 -0
  170. package/dist/transformation/visitors/void.js +20 -0
  171. package/dist/transpilation/bundle.d.ts +3 -0
  172. package/dist/transpilation/bundle.js +52 -10
  173. package/dist/transpilation/diagnostics.js +3 -3
  174. package/dist/transpilation/index.js +2 -2
  175. package/dist/transpilation/output-collector.js +2 -2
  176. package/dist/transpilation/plugins.js +1 -1
  177. package/dist/transpilation/resolve.js +20 -13
  178. package/dist/transpilation/transformers.js +45 -25
  179. package/dist/transpilation/transpile.js +6 -6
  180. package/dist/transpilation/transpiler.js +8 -8
  181. package/dist/transpilation/utils.js +5 -3
  182. package/dist/tstl.js +8 -8
  183. package/dist/utils.js +2 -2
  184. package/language-extensions/index.d.ts +11 -1
  185. package/package.json +15 -12
  186. package/dist/lualib/OptionalChainAccess.lua +0 -6
  187. package/dist/lualib/OptionalFunctionCall.lua +0 -6
  188. package/dist/lualib/OptionalMethodCall.lua +0 -11
  189. package/dist/transformation/utils/transform.d.ts +0 -8
  190. package/dist/transformation/utils/transform.js +0 -14
  191. package/dist/transformation/visitors/jsx/jsx.d.ts +0 -9
  192. package/dist/transformation/visitors/jsx/jsx.js +0 -237
  193. package/dist/transformation/visitors/jsx/xhtml.d.ts +0 -3
  194. package/dist/transformation/visitors/jsx/xhtml.js +0 -260
@@ -31,7 +31,7 @@ function transformBitOperatorToLuaOperator(context, node, operator) {
31
31
  case ts.SyntaxKind.LessThanLessThanToken:
32
32
  return lua.SyntaxKind.BitwiseLeftShiftOperator;
33
33
  case ts.SyntaxKind.GreaterThanGreaterThanToken:
34
- context.diagnostics.push(diagnostics_1.unsupportedRightShiftOperator(node));
34
+ context.diagnostics.push((0, diagnostics_1.unsupportedRightShiftOperator)(node));
35
35
  case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
36
36
  return lua.SyntaxKind.BitwiseRightShiftOperator;
37
37
  }
@@ -40,7 +40,7 @@ function transformBinaryBitOperation(context, node, left, right, operator) {
40
40
  switch (context.luaTarget) {
41
41
  case CompilerOptions_1.LuaTarget.Universal:
42
42
  case CompilerOptions_1.LuaTarget.Lua51:
43
- context.diagnostics.push(diagnostics_1.unsupportedForTarget(node, "Bitwise operations", CompilerOptions_1.LuaTarget.Lua51));
43
+ context.diagnostics.push((0, diagnostics_1.unsupportedForTarget)(node, "Bitwise operations", CompilerOptions_1.LuaTarget.Lua51));
44
44
  case CompilerOptions_1.LuaTarget.LuaJIT:
45
45
  return transformBinaryBitLibOperation(node, left, right, operator, "bit");
46
46
  case CompilerOptions_1.LuaTarget.Lua52:
@@ -58,7 +58,7 @@ function transformUnaryBitLibOperation(node, expression, operator, lib) {
58
58
  bitFunction = "bnot";
59
59
  break;
60
60
  default:
61
- utils_1.assertNever(operator);
61
+ (0, utils_1.assertNever)(operator);
62
62
  }
63
63
  return lua.createCallExpression(lua.createTableIndexExpression(lua.createIdentifier(lib), lua.createStringLiteral(bitFunction)), [expression], node);
64
64
  }
@@ -66,7 +66,7 @@ function transformUnaryBitOperation(context, node, expression, operator) {
66
66
  switch (context.luaTarget) {
67
67
  case CompilerOptions_1.LuaTarget.Universal:
68
68
  case CompilerOptions_1.LuaTarget.Lua51:
69
- context.diagnostics.push(diagnostics_1.unsupportedForTarget(node, "Bitwise operations", CompilerOptions_1.LuaTarget.Lua51));
69
+ context.diagnostics.push((0, diagnostics_1.unsupportedForTarget)(node, "Bitwise operations", CompilerOptions_1.LuaTarget.Lua51));
70
70
  case CompilerOptions_1.LuaTarget.LuaJIT:
71
71
  return transformUnaryBitLibOperation(node, expression, operator, "bit");
72
72
  case CompilerOptions_1.LuaTarget.Lua52:
@@ -1,12 +1,13 @@
1
1
  import * as ts from "typescript";
2
2
  import * as lua from "../../../LuaAST";
3
3
  import { TransformationContext } from "../../context";
4
- import { ImmediatelyInvokedFunctionParameters } from "../../utils/transform";
5
- export declare function parseAccessExpressionWithEvaluationEffects(context: TransformationContext, node: ts.Expression): [ts.Expression, ts.Expression] | [];
6
4
  declare type CompoundAssignmentToken = ts.SyntaxKind.BarToken | ts.SyntaxKind.PlusToken | ts.SyntaxKind.CaretToken | ts.SyntaxKind.MinusToken | ts.SyntaxKind.SlashToken | ts.SyntaxKind.PercentToken | ts.SyntaxKind.AsteriskToken | ts.SyntaxKind.AmpersandToken | ts.SyntaxKind.AsteriskAsteriskToken | ts.SyntaxKind.LessThanLessThanToken | ts.SyntaxKind.GreaterThanGreaterThanToken | ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken | ts.SyntaxKind.BarBarToken | ts.SyntaxKind.AmpersandAmpersandToken | ts.SyntaxKind.QuestionQuestionToken;
7
5
  export declare const isCompoundAssignmentToken: (token: ts.BinaryOperator) => token is ts.CompoundAssignmentOperator;
8
6
  export declare const unwrapCompoundAssignmentToken: (token: ts.CompoundAssignmentOperator) => CompoundAssignmentToken;
9
- export declare function transformCompoundAssignment(context: TransformationContext, expression: ts.Expression, lhs: ts.Expression, rhs: ts.Expression, operator: CompoundAssignmentToken, isPostfix: boolean): ImmediatelyInvokedFunctionParameters;
10
- export declare function transformCompoundAssignmentExpression(context: TransformationContext, expression: ts.Expression, lhs: ts.Expression, rhs: ts.Expression, operator: CompoundAssignmentToken, isPostfix: boolean): lua.CallExpression;
7
+ export declare function transformCompoundAssignment(context: TransformationContext, expression: ts.Expression, lhs: ts.Expression, rhs: ts.Expression, operator: CompoundAssignmentToken, isPostfix: boolean): {
8
+ statements: lua.Statement[];
9
+ result: lua.AssignmentLeftHandSideExpression;
10
+ };
11
+ export declare function transformCompoundAssignmentExpression(context: TransformationContext, expression: ts.Expression, lhs: ts.Expression, rhs: ts.Expression, operator: CompoundAssignmentToken, isPostfix: boolean): lua.Expression;
11
12
  export declare function transformCompoundAssignmentStatement(context: TransformationContext, node: ts.Node, lhs: ts.Expression, rhs: ts.Expression, operator: CompoundAssignmentToken): lua.Statement[];
12
13
  export {};
@@ -1,35 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.transformCompoundAssignmentStatement = exports.transformCompoundAssignmentExpression = exports.transformCompoundAssignment = exports.unwrapCompoundAssignmentToken = exports.isCompoundAssignmentToken = exports.parseAccessExpressionWithEvaluationEffects = void 0;
3
+ exports.transformCompoundAssignmentStatement = exports.transformCompoundAssignmentExpression = exports.transformCompoundAssignment = exports.unwrapCompoundAssignmentToken = exports.isCompoundAssignmentToken = void 0;
4
4
  const ts = require("typescript");
5
5
  const lua = require("../../../LuaAST");
6
6
  const utils_1 = require("../../../utils");
7
- const transform_1 = require("../../utils/transform");
8
- const typescript_1 = require("../../utils/typescript");
7
+ const preceding_statements_1 = require("../../utils/preceding-statements");
9
8
  const binary_expression_1 = require("../binary-expression");
10
9
  const assignments_1 = require("./assignments");
11
- // If expression is property/element access with possible effects from being evaluated, returns separated object and index expressions.
12
- function parseAccessExpressionWithEvaluationEffects(context, node) {
13
- if (ts.isElementAccessExpression(node) &&
14
- (typescript_1.isExpressionWithEvaluationEffect(node.expression) || typescript_1.isExpressionWithEvaluationEffect(node.argumentExpression))) {
15
- const type = context.checker.getTypeAtLocation(node.expression);
16
- if (typescript_1.isArrayType(context, type)) {
17
- // Offset arrays by one
18
- const oneLit = ts.factory.createNumericLiteral("1");
19
- const exp = ts.factory.createParenthesizedExpression(node.argumentExpression);
20
- const addExp = ts.factory.createBinaryExpression(exp, ts.SyntaxKind.PlusToken, oneLit);
21
- return [node.expression, addExp];
22
- }
23
- else {
24
- return [node.expression, node.argumentExpression];
25
- }
26
- }
27
- else if (ts.isPropertyAccessExpression(node) && typescript_1.isExpressionWithEvaluationEffect(node.expression)) {
28
- return [node.expression, ts.factory.createStringLiteral(node.name.text)];
29
- }
30
- return [];
10
+ function isLuaExpressionWithSideEffect(expression) {
11
+ return !(lua.isLiteral(expression) || lua.isIdentifier(expression));
12
+ }
13
+ function shouldCacheTableIndexExpressions(expression, rightPrecedingStatements) {
14
+ return (isLuaExpressionWithSideEffect(expression.table) ||
15
+ isLuaExpressionWithSideEffect(expression.index) ||
16
+ rightPrecedingStatements.length > 0);
31
17
  }
32
- exports.parseAccessExpressionWithEvaluationEffects = parseAccessExpressionWithEvaluationEffects;
33
18
  const compoundToAssignmentTokens = {
34
19
  [ts.SyntaxKind.BarEqualsToken]: ts.SyntaxKind.BarToken,
35
20
  [ts.SyntaxKind.PlusEqualsToken]: ts.SyntaxKind.PlusToken,
@@ -52,70 +37,81 @@ exports.isCompoundAssignmentToken = isCompoundAssignmentToken;
52
37
  const unwrapCompoundAssignmentToken = (token) => compoundToAssignmentTokens[token];
53
38
  exports.unwrapCompoundAssignmentToken = unwrapCompoundAssignmentToken;
54
39
  function transformCompoundAssignment(context, expression, lhs, rhs, operator, isPostfix) {
55
- const left = utils_1.cast(context.transformExpression(lhs), lua.isAssignmentLeftHandSideExpression);
56
- const right = context.transformExpression(rhs);
57
- const [objExpression, indexExpression] = parseAccessExpressionWithEvaluationEffects(context, lhs);
58
- if (objExpression && indexExpression) {
40
+ const left = (0, utils_1.cast)(context.transformExpression(lhs), lua.isAssignmentLeftHandSideExpression);
41
+ const [rightPrecedingStatements, right] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(rhs));
42
+ if (lua.isTableIndexExpression(left) && shouldCacheTableIndexExpressions(left, rightPrecedingStatements)) {
59
43
  // Complex property/element accesses need to cache object/index expressions to avoid repeating side-effects
60
44
  // local __obj, __index = ${objExpression}, ${indexExpression};
61
- const obj = lua.createIdentifier("____obj");
62
- const index = lua.createIdentifier("____index");
63
- const objAndIndexDeclaration = lua.createVariableDeclarationStatement([obj, index], [context.transformExpression(objExpression), context.transformExpression(indexExpression)]);
45
+ const obj = context.createTempNameForLuaExpression(left.table);
46
+ const index = context.createTempNameForLuaExpression(left.index);
47
+ const objAndIndexDeclaration = lua.createVariableDeclarationStatement([obj, index], [left.table, left.index]);
64
48
  const accessExpression = lua.createTableIndexExpression(obj, index);
65
- const tmp = lua.createIdentifier("____tmp");
66
- let tmpDeclaration;
67
- let assignStatement;
49
+ const tmp = context.createTempNameForLuaExpression(left);
68
50
  if (isPostfix) {
69
51
  // local ____tmp = ____obj[____index];
70
52
  // ____obj[____index] = ____tmp ${replacementOperator} ${right};
71
- tmpDeclaration = lua.createVariableDeclarationStatement(tmp, accessExpression);
72
- const operatorExpression = binary_expression_1.transformBinaryOperation(context, tmp, right, operator, expression);
73
- assignStatement = lua.createAssignmentStatement(accessExpression, operatorExpression);
53
+ // return ____tmp
54
+ const tmpDeclaration = lua.createVariableDeclarationStatement(tmp, accessExpression);
55
+ const [precedingStatements, operatorExpression] = (0, binary_expression_1.transformBinaryOperation)(context, tmp, right, rightPrecedingStatements, operator, expression);
56
+ const assignStatement = lua.createAssignmentStatement(accessExpression, operatorExpression);
57
+ return {
58
+ statements: [objAndIndexDeclaration, ...precedingStatements, tmpDeclaration, assignStatement],
59
+ result: tmp,
60
+ };
74
61
  }
75
62
  else {
76
63
  // local ____tmp = ____obj[____index] ${replacementOperator} ${right};
77
64
  // ____obj[____index] = ____tmp;
78
- const operatorExpression = binary_expression_1.transformBinaryOperation(context, accessExpression, right, operator, expression);
79
- tmpDeclaration = lua.createVariableDeclarationStatement(tmp, operatorExpression);
80
- assignStatement = lua.createAssignmentStatement(accessExpression, tmp);
65
+ // return ____tmp
66
+ const [precedingStatements, operatorExpression] = (0, binary_expression_1.transformBinaryOperation)(context, accessExpression, right, rightPrecedingStatements, operator, expression);
67
+ const tmpDeclaration = lua.createVariableDeclarationStatement(tmp, operatorExpression);
68
+ const assignStatement = lua.createAssignmentStatement(accessExpression, tmp);
69
+ return {
70
+ statements: [objAndIndexDeclaration, ...precedingStatements, tmpDeclaration, assignStatement],
71
+ result: tmp,
72
+ };
81
73
  }
82
- // return ____tmp
83
- return { statements: [objAndIndexDeclaration, tmpDeclaration, assignStatement], result: tmp };
84
74
  }
85
75
  else if (isPostfix) {
86
76
  // Postfix expressions need to cache original value in temp
87
77
  // local ____tmp = ${left};
88
78
  // ${left} = ____tmp ${replacementOperator} ${right};
89
79
  // return ____tmp
90
- const tmpIdentifier = lua.createIdentifier("____tmp");
80
+ const tmpIdentifier = context.createTempNameForLuaExpression(left);
91
81
  const tmpDeclaration = lua.createVariableDeclarationStatement(tmpIdentifier, left);
92
- const operatorExpression = binary_expression_1.transformBinaryOperation(context, tmpIdentifier, right, operator, expression);
93
- const assignStatements = assignments_1.transformAssignment(context, lhs, operatorExpression);
94
- return { statements: [tmpDeclaration, ...assignStatements], result: tmpIdentifier };
82
+ const [precedingStatements, operatorExpression] = (0, binary_expression_1.transformBinaryOperation)(context, tmpIdentifier, right, rightPrecedingStatements, operator, expression);
83
+ const assignStatements = (0, assignments_1.transformAssignmentWithRightPrecedingStatements)(context, lhs, operatorExpression, rightPrecedingStatements);
84
+ return { statements: [tmpDeclaration, ...precedingStatements, ...assignStatements], result: tmpIdentifier };
95
85
  }
96
86
  else if (ts.isPropertyAccessExpression(lhs) || ts.isElementAccessExpression(lhs)) {
97
87
  // Simple property/element access expressions need to cache in temp to avoid double-evaluation
98
88
  // local ____tmp = ${left} ${replacementOperator} ${right};
99
89
  // ${left} = ____tmp;
100
90
  // return ____tmp
101
- const tmpIdentifier = lua.createIdentifier("____tmp");
102
- const operatorExpression = binary_expression_1.transformBinaryOperation(context, left, right, operator, expression);
91
+ const tmpIdentifier = context.createTempNameForLuaExpression(left);
92
+ const [precedingStatements, operatorExpression] = (0, binary_expression_1.transformBinaryOperation)(context, left, right, rightPrecedingStatements, operator, expression);
103
93
  const tmpDeclaration = lua.createVariableDeclarationStatement(tmpIdentifier, operatorExpression);
104
- const assignStatements = assignments_1.transformAssignment(context, lhs, tmpIdentifier);
105
94
  if (isSetterSkippingCompoundAssignmentOperator(operator)) {
106
95
  const statements = [
107
96
  tmpDeclaration,
108
- ...transformSetterSkippingCompoundAssignment(context, tmpIdentifier, operator, rhs),
97
+ ...transformSetterSkippingCompoundAssignment(tmpIdentifier, operator, right, precedingStatements),
109
98
  ];
110
99
  return { statements, result: tmpIdentifier };
111
100
  }
101
+ const assignStatements = (0, assignments_1.transformAssignmentWithRightPrecedingStatements)(context, lhs, tmpIdentifier, precedingStatements);
112
102
  return { statements: [tmpDeclaration, ...assignStatements], result: tmpIdentifier };
113
103
  }
114
104
  else {
105
+ if (rightPrecedingStatements.length > 0 && isSetterSkippingCompoundAssignmentOperator(operator)) {
106
+ return {
107
+ statements: transformSetterSkippingCompoundAssignment(left, operator, right, rightPrecedingStatements),
108
+ result: left,
109
+ };
110
+ }
115
111
  // Simple expressions
116
- // ${left} = ${right}; return ${right}
117
- const operatorExpression = binary_expression_1.transformBinaryOperation(context, left, right, operator, expression);
118
- const statements = assignments_1.transformAssignment(context, lhs, operatorExpression);
112
+ // ${left} = ${left} ${operator} ${right}
113
+ const [precedingStatements, operatorExpression] = (0, binary_expression_1.transformBinaryOperation)(context, left, right, rightPrecedingStatements, operator, expression);
114
+ const statements = (0, assignments_1.transformAssignmentWithRightPrecedingStatements)(context, lhs, operatorExpression, precedingStatements);
119
115
  return { statements, result: left };
120
116
  }
121
117
  }
@@ -123,40 +119,42 @@ exports.transformCompoundAssignment = transformCompoundAssignment;
123
119
  function transformCompoundAssignmentExpression(context, expression,
124
120
  // TODO: Change type to ts.LeftHandSideExpression?
125
121
  lhs, rhs, operator, isPostfix) {
126
- return transform_1.transformToImmediatelyInvokedFunctionExpression(context, () => transformCompoundAssignment(context, expression, lhs, rhs, operator, isPostfix), expression);
122
+ const { statements, result } = transformCompoundAssignment(context, expression, lhs, rhs, operator, isPostfix);
123
+ context.addPrecedingStatements(statements);
124
+ return result;
127
125
  }
128
126
  exports.transformCompoundAssignmentExpression = transformCompoundAssignmentExpression;
129
127
  function transformCompoundAssignmentStatement(context, node, lhs, rhs, operator) {
130
- const left = utils_1.cast(context.transformExpression(lhs), lua.isAssignmentLeftHandSideExpression);
131
- const right = context.transformExpression(rhs);
132
- const [objExpression, indexExpression] = parseAccessExpressionWithEvaluationEffects(context, lhs);
133
- if (objExpression && indexExpression) {
128
+ const left = (0, utils_1.cast)(context.transformExpression(lhs), lua.isAssignmentLeftHandSideExpression);
129
+ let [rightPrecedingStatements, right] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(rhs));
130
+ if (lua.isTableIndexExpression(left) && shouldCacheTableIndexExpressions(left, rightPrecedingStatements)) {
134
131
  // Complex property/element accesses need to cache object/index expressions to avoid repeating side-effects
135
132
  // local __obj, __index = ${objExpression}, ${indexExpression};
136
133
  // ____obj[____index] = ____obj[____index] ${replacementOperator} ${right};
137
- const obj = lua.createIdentifier("____obj");
138
- const index = lua.createIdentifier("____index");
139
- const objAndIndexDeclaration = lua.createVariableDeclarationStatement([obj, index], [context.transformExpression(objExpression), context.transformExpression(indexExpression)]);
134
+ const obj = context.createTempNameForLuaExpression(left.table);
135
+ const index = context.createTempNameForLuaExpression(left.index);
136
+ const objAndIndexDeclaration = lua.createVariableDeclarationStatement([obj, index], [left.table, left.index]);
140
137
  const accessExpression = lua.createTableIndexExpression(obj, index);
141
138
  if (isSetterSkippingCompoundAssignmentOperator(operator)) {
142
139
  return [
143
140
  objAndIndexDeclaration,
144
- ...transformSetterSkippingCompoundAssignment(context, accessExpression, operator, rhs, node),
141
+ ...transformSetterSkippingCompoundAssignment(accessExpression, operator, right, rightPrecedingStatements, node),
145
142
  ];
146
143
  }
147
- const operatorExpression = binary_expression_1.transformBinaryOperation(context, accessExpression, right, operator, node);
144
+ let operatorExpression;
145
+ [rightPrecedingStatements, operatorExpression] = (0, binary_expression_1.transformBinaryOperation)(context, accessExpression, right, rightPrecedingStatements, operator, node);
148
146
  const assignStatement = lua.createAssignmentStatement(accessExpression, operatorExpression);
149
- return [objAndIndexDeclaration, assignStatement];
147
+ return [objAndIndexDeclaration, ...rightPrecedingStatements, assignStatement];
150
148
  }
151
149
  else {
152
150
  if (isSetterSkippingCompoundAssignmentOperator(operator)) {
153
- const luaLhs = context.transformExpression(lhs);
154
- return transformSetterSkippingCompoundAssignment(context, luaLhs, operator, rhs, node);
151
+ return transformSetterSkippingCompoundAssignment(left, operator, right, rightPrecedingStatements, node);
155
152
  }
156
153
  // Simple statements
157
154
  // ${left} = ${left} ${replacementOperator} ${right}
158
- const operatorExpression = binary_expression_1.transformBinaryOperation(context, left, right, operator, node);
159
- return assignments_1.transformAssignment(context, lhs, operatorExpression);
155
+ let operatorExpression;
156
+ [rightPrecedingStatements, operatorExpression] = (0, binary_expression_1.transformBinaryOperation)(context, left, right, rightPrecedingStatements, operator, node);
157
+ return (0, assignments_1.transformAssignmentWithRightPrecedingStatements)(context, lhs, operatorExpression, rightPrecedingStatements);
160
158
  }
161
159
  }
162
160
  exports.transformCompoundAssignmentStatement = transformCompoundAssignmentStatement;
@@ -165,7 +163,7 @@ function isSetterSkippingCompoundAssignmentOperator(operator) {
165
163
  operator === ts.SyntaxKind.BarBarToken ||
166
164
  operator === ts.SyntaxKind.QuestionQuestionToken);
167
165
  }
168
- function transformSetterSkippingCompoundAssignment(context, lhs, operator, rhs, node) {
166
+ function transformSetterSkippingCompoundAssignment(lhs, operator, right, rightPrecedingStatements, node) {
169
167
  // These assignments have the form 'if x then y = z', figure out what condition x is first.
170
168
  let condition;
171
169
  if (operator === ts.SyntaxKind.AmpersandAmpersandToken) {
@@ -178,11 +176,11 @@ function transformSetterSkippingCompoundAssignment(context, lhs, operator, rhs,
178
176
  condition = lua.createBinaryExpression(lhs, lua.createNilLiteral(), lua.SyntaxKind.EqualityOperator);
179
177
  }
180
178
  else {
181
- utils_1.assertNever(operator);
179
+ (0, utils_1.assertNever)(operator);
182
180
  }
183
181
  // if condition then lhs = rhs end
184
182
  return [
185
- lua.createIfStatement(condition, lua.createBlock([lua.createAssignmentStatement(lhs, context.transformExpression(rhs))]), undefined, node),
183
+ lua.createIfStatement(condition, lua.createBlock([...rightPrecedingStatements, lua.createAssignmentStatement(lhs, right, node)]), undefined, node),
186
184
  ];
187
185
  }
188
186
  //# sourceMappingURL=compound.js.map
@@ -2,5 +2,5 @@ import * as ts from "typescript";
2
2
  import * as lua from "../../../LuaAST";
3
3
  import { TransformationContext } from "../../context";
4
4
  export declare function isArrayLength(context: TransformationContext, expression: ts.Expression): expression is ts.PropertyAccessExpression | ts.ElementAccessExpression;
5
- export declare function transformDestructuringAssignment(context: TransformationContext, node: ts.DestructuringAssignment, root: lua.Expression): lua.Statement[];
6
- export declare function transformAssignmentPattern(context: TransformationContext, node: ts.AssignmentPattern, root: lua.Expression): lua.Statement[];
5
+ export declare function transformDestructuringAssignment(context: TransformationContext, node: ts.DestructuringAssignment, root: lua.Expression, rightHasPrecedingStatements: boolean): lua.Statement[];
6
+ export declare function transformAssignmentPattern(context: TransformationContext, node: ts.AssignmentPattern, root: lua.Expression, rightHasPrecedingStatements: boolean): lua.Statement[];
@@ -2,10 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.transformAssignmentPattern = exports.transformDestructuringAssignment = exports.isArrayLength = void 0;
4
4
  const ts = require("typescript");
5
+ const _1 = require(".");
5
6
  const lua = require("../../../LuaAST");
6
7
  const utils_1 = require("../../../utils");
7
8
  const lualib_1 = require("../../utils/lualib");
9
+ const preceding_statements_1 = require("../../utils/preceding-statements");
8
10
  const typescript_1 = require("../../utils/typescript");
11
+ const expression_list_1 = require("../expression-list");
9
12
  const literal_1 = require("../literal");
10
13
  const assignments_1 = require("./assignments");
11
14
  function isArrayLength(context, expression) {
@@ -13,7 +16,7 @@ function isArrayLength(context, expression) {
13
16
  return false;
14
17
  }
15
18
  const type = context.checker.getTypeAtLocation(expression.expression);
16
- if (!typescript_1.isArrayType(context, type)) {
19
+ if (!(0, typescript_1.isArrayType)(context, type)) {
17
20
  return false;
18
21
  }
19
22
  const name = ts.isPropertyAccessExpression(expression)
@@ -24,33 +27,35 @@ function isArrayLength(context, expression) {
24
27
  return name === "length";
25
28
  }
26
29
  exports.isArrayLength = isArrayLength;
27
- function transformDestructuringAssignment(context, node, root) {
28
- return transformAssignmentPattern(context, node.left, root);
30
+ function transformDestructuringAssignment(context, node, root, rightHasPrecedingStatements) {
31
+ return transformAssignmentPattern(context, node.left, root, rightHasPrecedingStatements);
29
32
  }
30
33
  exports.transformDestructuringAssignment = transformDestructuringAssignment;
31
- function transformAssignmentPattern(context, node, root) {
34
+ function transformAssignmentPattern(context, node, root, rightHasPrecedingStatements) {
32
35
  switch (node.kind) {
33
36
  case ts.SyntaxKind.ObjectLiteralExpression:
34
- return transformObjectLiteralAssignmentPattern(context, node, root);
37
+ return transformObjectLiteralAssignmentPattern(context, node, root, rightHasPrecedingStatements);
35
38
  case ts.SyntaxKind.ArrayLiteralExpression:
36
- return transformArrayLiteralAssignmentPattern(context, node, root);
39
+ return transformArrayLiteralAssignmentPattern(context, node, root, rightHasPrecedingStatements);
37
40
  }
38
41
  }
39
42
  exports.transformAssignmentPattern = transformAssignmentPattern;
40
- function transformArrayLiteralAssignmentPattern(context, node, root) {
43
+ function transformArrayLiteralAssignmentPattern(context, node, root, rightHasPrecedingStatements) {
41
44
  return node.elements.flatMap((element, index) => {
42
45
  const indexedRoot = lua.createTableIndexExpression(root, lua.createNumericLiteral(index + 1), element);
43
46
  switch (element.kind) {
44
47
  case ts.SyntaxKind.ObjectLiteralExpression:
45
- return transformObjectLiteralAssignmentPattern(context, element, indexedRoot);
48
+ return transformObjectLiteralAssignmentPattern(context, element, indexedRoot, rightHasPrecedingStatements);
46
49
  case ts.SyntaxKind.ArrayLiteralExpression:
47
- return transformArrayLiteralAssignmentPattern(context, element, indexedRoot);
50
+ return transformArrayLiteralAssignmentPattern(context, element, indexedRoot, rightHasPrecedingStatements);
48
51
  case ts.SyntaxKind.BinaryExpression:
49
- const assignedVariable = lua.createIdentifier("____bindingAssignmentValue");
52
+ const assignedVariable = context.createTempNameForLuaExpression(indexedRoot);
50
53
  const assignedVariableDeclaration = lua.createVariableDeclarationStatement(assignedVariable, indexedRoot);
51
54
  const nilCondition = lua.createBinaryExpression(assignedVariable, lua.createNilLiteral(), lua.SyntaxKind.EqualityOperator);
52
- const defaultAssignmentStatements = assignments_1.transformAssignment(context, element.left, context.transformExpression(element.right));
53
- const elseAssignmentStatements = assignments_1.transformAssignment(context, element.left, assignedVariable);
55
+ const [defaultPrecedingStatements, defaultAssignmentStatements] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, assignments_1.transformAssignment)(context, element.left, context.transformExpression(element.right)));
56
+ // Keep preceding statements inside if block
57
+ defaultAssignmentStatements.unshift(...defaultPrecedingStatements);
58
+ const elseAssignmentStatements = (0, assignments_1.transformAssignment)(context, element.left, assignedVariable);
54
59
  const ifBlock = lua.createBlock(defaultAssignmentStatements);
55
60
  const elseBlock = lua.createBlock(elseAssignmentStatements);
56
61
  const ifStatement = lua.createIfStatement(nilCondition, ifBlock, elseBlock, node);
@@ -58,14 +63,16 @@ function transformArrayLiteralAssignmentPattern(context, node, root) {
58
63
  case ts.SyntaxKind.Identifier:
59
64
  case ts.SyntaxKind.PropertyAccessExpression:
60
65
  case ts.SyntaxKind.ElementAccessExpression:
61
- return assignments_1.transformAssignment(context, element, indexedRoot);
66
+ const [precedingStatements, statements] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, assignments_1.transformAssignment)(context, element, indexedRoot, rightHasPrecedingStatements));
67
+ return [...precedingStatements, ...statements]; // Keep preceding statements in order
62
68
  case ts.SyntaxKind.SpreadElement:
63
69
  if (index !== node.elements.length - 1) {
64
70
  // TypeScript error
65
71
  return [];
66
72
  }
67
- const restElements = lualib_1.transformLuaLibFunction(context, lualib_1.LuaLibFeature.ArraySlice, undefined, root, lua.createNumericLiteral(index));
68
- return assignments_1.transformAssignment(context, element.expression, restElements);
73
+ const restElements = (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.ArraySlice, undefined, root, lua.createNumericLiteral(index));
74
+ const [spreadPrecedingStatements, spreadStatements] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, assignments_1.transformAssignment)(context, element.expression, restElements, rightHasPrecedingStatements));
75
+ return [...spreadPrecedingStatements, ...spreadStatements]; // Keep preceding statements in order
69
76
  case ts.SyntaxKind.OmittedExpression:
70
77
  return [];
71
78
  default:
@@ -74,7 +81,7 @@ function transformArrayLiteralAssignmentPattern(context, node, root) {
74
81
  }
75
82
  });
76
83
  }
77
- function transformObjectLiteralAssignmentPattern(context, node, root) {
84
+ function transformObjectLiteralAssignmentPattern(context, node, root, rightHasPrecedingStatements) {
78
85
  const result = [];
79
86
  for (const property of node.properties) {
80
87
  switch (property.kind) {
@@ -82,7 +89,7 @@ function transformObjectLiteralAssignmentPattern(context, node, root) {
82
89
  result.push(...transformShorthandPropertyAssignment(context, property, root));
83
90
  break;
84
91
  case ts.SyntaxKind.PropertyAssignment:
85
- result.push(...transformPropertyAssignment(context, property, root));
92
+ result.push(...transformPropertyAssignment(context, property, root, rightHasPrecedingStatements));
86
93
  break;
87
94
  case ts.SyntaxKind.SpreadAssignment:
88
95
  result.push(...transformSpreadAssignment(context, property, root, node.properties));
@@ -93,51 +100,73 @@ function transformObjectLiteralAssignmentPattern(context, node, root) {
93
100
  // TypeScript error
94
101
  break;
95
102
  default:
96
- utils_1.assertNever(property);
103
+ (0, utils_1.assertNever)(property);
97
104
  }
98
105
  }
99
106
  return result;
100
107
  }
101
108
  function transformShorthandPropertyAssignment(context, node, root) {
102
109
  const result = [];
103
- const assignmentVariableName = assignments_1.transformAssignmentLeftHandSideExpression(context, node.name);
110
+ const assignmentVariableName = (0, assignments_1.transformAssignmentLeftHandSideExpression)(context, node.name);
104
111
  const extractionIndex = lua.createStringLiteral(node.name.text);
105
- const variableExtractionAssignmentStatements = assignments_1.transformAssignment(context, node.name, lua.createTableIndexExpression(root, extractionIndex));
112
+ const variableExtractionAssignmentStatements = (0, assignments_1.transformAssignment)(context, node.name, lua.createTableIndexExpression(root, extractionIndex));
106
113
  result.push(...variableExtractionAssignmentStatements);
107
114
  const defaultInitializer = node.objectAssignmentInitializer
108
115
  ? context.transformExpression(node.objectAssignmentInitializer)
109
116
  : undefined;
110
117
  if (defaultInitializer) {
111
118
  const nilCondition = lua.createBinaryExpression(assignmentVariableName, lua.createNilLiteral(), lua.SyntaxKind.EqualityOperator);
112
- const assignmentStatements = assignments_1.transformAssignment(context, node.name, defaultInitializer);
119
+ const assignmentStatements = (0, assignments_1.transformAssignment)(context, node.name, defaultInitializer);
113
120
  const ifBlock = lua.createBlock(assignmentStatements);
114
121
  result.push(lua.createIfStatement(nilCondition, ifBlock, undefined, node));
115
122
  }
116
123
  return result;
117
124
  }
118
- function transformPropertyAssignment(context, node, root) {
125
+ function transformPropertyAssignment(context, node, root, rightHasPrecedingStatements) {
119
126
  const result = [];
120
- if (typescript_1.isAssignmentPattern(node.initializer)) {
121
- const propertyAccessString = literal_1.transformPropertyName(context, node.name);
127
+ if ((0, typescript_1.isAssignmentPattern)(node.initializer)) {
128
+ const propertyAccessString = (0, literal_1.transformPropertyName)(context, node.name);
122
129
  const newRootAccess = lua.createTableIndexExpression(root, propertyAccessString);
123
130
  if (ts.isObjectLiteralExpression(node.initializer)) {
124
- return transformObjectLiteralAssignmentPattern(context, node.initializer, newRootAccess);
131
+ return transformObjectLiteralAssignmentPattern(context, node.initializer, newRootAccess, rightHasPrecedingStatements);
125
132
  }
126
133
  if (ts.isArrayLiteralExpression(node.initializer)) {
127
- return transformArrayLiteralAssignmentPattern(context, node.initializer, newRootAccess);
134
+ return transformArrayLiteralAssignmentPattern(context, node.initializer, newRootAccess, rightHasPrecedingStatements);
128
135
  }
129
136
  }
130
- const leftExpression = ts.isBinaryExpression(node.initializer) ? node.initializer.left : node.initializer;
131
- const variableToExtract = literal_1.transformPropertyName(context, node.name);
137
+ context.pushPrecedingStatements();
138
+ let variableToExtract = (0, literal_1.transformPropertyName)(context, node.name);
139
+ // Must be evaluated before left's preceding statements
140
+ variableToExtract = (0, expression_list_1.moveToPrecedingTemp)(context, variableToExtract, node.name);
132
141
  const extractingExpression = lua.createTableIndexExpression(root, variableToExtract);
133
- const destructureAssignmentStatements = assignments_1.transformAssignment(context, leftExpression, extractingExpression);
134
- result.push(...destructureAssignmentStatements);
142
+ let destructureAssignmentStatements;
135
143
  if (ts.isBinaryExpression(node.initializer)) {
136
- const assignmentLeftHandSide = context.transformExpression(node.initializer.left);
137
- const nilCondition = lua.createBinaryExpression(assignmentLeftHandSide, lua.createNilLiteral(), lua.SyntaxKind.EqualityOperator);
138
- const ifBlock = lua.createBlock(assignments_1.transformAssignmentStatement(context, node.initializer));
139
- result.push(lua.createIfStatement(nilCondition, ifBlock, undefined, node));
144
+ if (ts.isPropertyAccessExpression(node.initializer.left) ||
145
+ ts.isElementAccessExpression(node.initializer.left)) {
146
+ // Access expressions need their table and index expressions cached to preserve execution order
147
+ const left = (0, utils_1.cast)(context.transformExpression(node.initializer.left), lua.isTableIndexExpression);
148
+ const rightExpression = node.initializer.right;
149
+ const [defaultPrecedingStatements, defaultExpression] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(rightExpression));
150
+ const tableTemp = context.createTempNameForLuaExpression(left.table);
151
+ const indexTemp = context.createTempNameForLuaExpression(left.index);
152
+ const tempsDeclaration = lua.createVariableDeclarationStatement([tableTemp, indexTemp], [left.table, left.index]);
153
+ // obj[index] = extractingExpression ?? defaultExpression
154
+ const [rightPrecedingStatements, rhs] = (0, _1.transformBinaryOperation)(context, extractingExpression, defaultExpression, defaultPrecedingStatements, ts.SyntaxKind.QuestionQuestionToken, node.initializer);
155
+ const assignStatement = lua.createAssignmentStatement(lua.createTableIndexExpression(tableTemp, indexTemp), rhs);
156
+ destructureAssignmentStatements = [tempsDeclaration, ...rightPrecedingStatements, assignStatement];
157
+ }
158
+ else {
159
+ const assignmentLeftHandSide = context.transformExpression(node.initializer.left);
160
+ const nilCondition = lua.createBinaryExpression(assignmentLeftHandSide, lua.createNilLiteral(), lua.SyntaxKind.EqualityOperator);
161
+ const ifBlock = lua.createBlock((0, assignments_1.transformAssignmentStatement)(context, node.initializer));
162
+ destructureAssignmentStatements = [lua.createIfStatement(nilCondition, ifBlock, undefined, node)];
163
+ }
164
+ }
165
+ else {
166
+ destructureAssignmentStatements = (0, assignments_1.transformAssignment)(context, node.initializer, extractingExpression, rightHasPrecedingStatements);
140
167
  }
168
+ result.push(...context.popPrecedingStatements());
169
+ result.push(...destructureAssignmentStatements);
141
170
  return result;
142
171
  }
143
172
  function transformSpreadAssignment(context, node, root, properties) {
@@ -152,7 +181,7 @@ function transformSpreadAssignment(context, node, root, properties) {
152
181
  usedProperties.push(lua.createTableFieldExpression(lua.createBooleanLiteral(true), name));
153
182
  }
154
183
  }
155
- const extractingExpression = lualib_1.transformLuaLibFunction(context, lualib_1.LuaLibFeature.ObjectRest, undefined, root, lua.createTableExpression(usedProperties));
156
- return assignments_1.transformAssignment(context, node.expression, extractingExpression);
184
+ const extractingExpression = (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.ObjectRest, undefined, root, lua.createTableExpression(usedProperties));
185
+ return (0, assignments_1.transformAssignment)(context, node.expression, extractingExpression);
157
186
  }
158
187
  //# sourceMappingURL=destructuring-assignments.js.map
@@ -2,8 +2,10 @@ import * as ts from "typescript";
2
2
  import * as lua from "../../../LuaAST";
3
3
  import { FunctionVisitor, TransformationContext } from "../../context";
4
4
  import { BitOperator } from "./bit";
5
+ declare type ShortCircuitOperator = ts.SyntaxKind.AmpersandAmpersandToken | ts.SyntaxKind.BarBarToken | ts.SyntaxKind.QuestionQuestionToken;
5
6
  declare type SimpleOperator = ts.AdditiveOperatorOrHigher | Exclude<ts.RelationalOperator, ts.SyntaxKind.InstanceOfKeyword | ts.SyntaxKind.InKeyword> | ts.EqualityOperator | ts.LogicalOperator;
6
- export declare function transformBinaryOperation(context: TransformationContext, left: lua.Expression, right: lua.Expression, operator: BitOperator | SimpleOperator | ts.SyntaxKind.QuestionQuestionToken, node: ts.Node): lua.Expression;
7
+ export declare function createShortCircuitBinaryExpressionPrecedingStatements(context: TransformationContext, lhs: lua.Expression, rhs: lua.Expression, rightPrecedingStatements: lua.Statement[], operator: ShortCircuitOperator, node?: ts.BinaryExpression): [lua.Statement[], lua.Expression];
8
+ export declare function transformBinaryOperation(context: TransformationContext, left: lua.Expression, right: lua.Expression, rightPrecedingStatements: lua.Statement[], operator: BitOperator | SimpleOperator | ts.SyntaxKind.QuestionQuestionToken, node: ts.Node): [lua.Statement[], lua.Expression];
7
9
  export declare const transformBinaryExpression: FunctionVisitor<ts.BinaryExpression>;
8
10
  export declare function transformBinaryExpressionStatement(context: TransformationContext, node: ts.ExpressionStatement): lua.Statement[] | lua.Statement | undefined;
9
11
  export {};