typescript-to-lua 1.1.0 → 1.3.1

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 (141) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/LuaAST.d.ts +1 -0
  3. package/dist/LuaAST.js +10 -2
  4. package/dist/LuaLib.d.ts +3 -3
  5. package/dist/LuaLib.js +5 -5
  6. package/dist/LuaPrinter.d.ts +11 -4
  7. package/dist/LuaPrinter.js +58 -15
  8. package/dist/cli/parse.d.ts +1 -1
  9. package/dist/cli/parse.js +14 -0
  10. package/dist/lualib/ArrayFlat.lua +1 -1
  11. package/dist/lualib/ArrayFlatMap.lua +1 -1
  12. package/dist/lualib/ArrayIsArray.lua +1 -1
  13. package/dist/lualib/ArrayReduce.lua +7 -1
  14. package/dist/lualib/ArrayReduceRight.lua +7 -1
  15. package/dist/lualib/ArraySetLength.lua +1 -1
  16. package/dist/lualib/ArraySplice.lua +5 -5
  17. package/dist/lualib/Await.lua +21 -13
  18. package/dist/lualib/CloneDescriptor.lua +7 -7
  19. package/dist/lualib/Decorate.lua +1 -1
  20. package/dist/lualib/DelegatedYield.lua +1 -3
  21. package/dist/lualib/Delete.lua +6 -6
  22. package/dist/lualib/Error.lua +47 -44
  23. package/dist/lualib/Generator.lua +1 -5
  24. package/dist/lualib/InstanceOf.lua +1 -1
  25. package/dist/lualib/InstanceOfObject.lua +1 -1
  26. package/dist/lualib/Map.lua +130 -134
  27. package/dist/lualib/Number.lua +1 -1
  28. package/dist/lualib/NumberIsFinite.lua +1 -1
  29. package/dist/lualib/NumberToString.lua +3 -5
  30. package/dist/lualib/ObjectDefineProperty.lua +40 -8
  31. package/dist/lualib/ParseFloat.lua +9 -5
  32. package/dist/lualib/ParseInt.lua +15 -3
  33. package/dist/lualib/Promise.lua +28 -24
  34. package/dist/lualib/Set.lua +119 -123
  35. package/dist/lualib/SetDescriptor.lua +7 -1
  36. package/dist/lualib/SourceMapTraceBack.lua +1 -1
  37. package/dist/lualib/SparseArrayNew.lua +5 -0
  38. package/dist/lualib/SparseArrayPush.lua +9 -0
  39. package/dist/lualib/SparseArraySpread.lua +4 -0
  40. package/dist/lualib/StringAccess.lua +1 -1
  41. package/dist/lualib/StringCharCodeAt.lua +1 -1
  42. package/dist/lualib/StringEndsWith.lua +2 -2
  43. package/dist/lualib/StringPadEnd.lua +2 -2
  44. package/dist/lualib/StringPadStart.lua +2 -2
  45. package/dist/lualib/StringReplace.lua +7 -1
  46. package/dist/lualib/StringSlice.lua +2 -2
  47. package/dist/lualib/StringSplit.lua +3 -3
  48. package/dist/lualib/StringStartsWith.lua +1 -1
  49. package/dist/lualib/StringSubstr.lua +1 -1
  50. package/dist/lualib/StringSubstring.lua +2 -2
  51. package/dist/lualib/Symbol.lua +3 -5
  52. package/dist/lualib/WeakMap.lua +40 -42
  53. package/dist/lualib/WeakSet.lua +36 -38
  54. package/dist/lualib/lualib_bundle.lua +795 -735
  55. package/dist/transformation/builtins/array.js +1 -2
  56. package/dist/transformation/builtins/function.js +6 -4
  57. package/dist/transformation/builtins/index.d.ts +1 -1
  58. package/dist/transformation/builtins/index.js +41 -6
  59. package/dist/transformation/builtins/object.d.ts +2 -1
  60. package/dist/transformation/builtins/object.js +1 -2
  61. package/dist/transformation/builtins/string.js +1 -2
  62. package/dist/transformation/context/context.d.ts +12 -0
  63. package/dist/transformation/context/context.js +102 -3
  64. package/dist/transformation/utils/diagnostics.d.ts +9 -6
  65. package/dist/transformation/utils/diagnostics.js +4 -3
  66. package/dist/transformation/utils/export.d.ts +3 -2
  67. package/dist/transformation/utils/export.js +10 -3
  68. package/dist/transformation/utils/language-extensions.d.ts +2 -0
  69. package/dist/transformation/utils/language-extensions.js +7 -1
  70. package/dist/transformation/utils/lua-ast.d.ts +0 -1
  71. package/dist/transformation/utils/lua-ast.js +14 -23
  72. package/dist/transformation/utils/preceding-statements.d.ts +3 -0
  73. package/dist/transformation/utils/preceding-statements.js +11 -0
  74. package/dist/transformation/utils/safe-names.d.ts +4 -2
  75. package/dist/transformation/utils/safe-names.js +11 -5
  76. package/dist/transformation/utils/scope.d.ts +3 -1
  77. package/dist/transformation/utils/scope.js +9 -1
  78. package/dist/transformation/utils/typescript/index.d.ts +1 -0
  79. package/dist/transformation/utils/typescript/index.js +16 -1
  80. package/dist/transformation/utils/typescript/types.d.ts +3 -1
  81. package/dist/transformation/utils/typescript/types.js +40 -13
  82. package/dist/transformation/visitors/access.d.ts +3 -0
  83. package/dist/transformation/visitors/access.js +63 -36
  84. package/dist/transformation/visitors/binary-expression/assignments.d.ts +3 -2
  85. package/dist/transformation/visitors/binary-expression/assignments.js +66 -57
  86. package/dist/transformation/visitors/binary-expression/compound.d.ts +5 -4
  87. package/dist/transformation/visitors/binary-expression/compound.js +66 -68
  88. package/dist/transformation/visitors/binary-expression/destructuring-assignments.d.ts +2 -2
  89. package/dist/transformation/visitors/binary-expression/destructuring-assignments.js +54 -25
  90. package/dist/transformation/visitors/binary-expression/index.d.ts +3 -1
  91. package/dist/transformation/visitors/binary-expression/index.js +65 -23
  92. package/dist/transformation/visitors/call.d.ts +3 -2
  93. package/dist/transformation/visitors/call.js +95 -141
  94. package/dist/transformation/visitors/class/index.js +13 -9
  95. package/dist/transformation/visitors/class/new.js +4 -6
  96. package/dist/transformation/visitors/conditional.js +30 -37
  97. package/dist/transformation/visitors/delete.js +4 -0
  98. package/dist/transformation/visitors/errors.js +11 -9
  99. package/dist/transformation/visitors/expression-list.d.ts +7 -0
  100. package/dist/transformation/visitors/expression-list.js +120 -0
  101. package/dist/transformation/visitors/expression-statement.d.ts +3 -1
  102. package/dist/transformation/visitors/expression-statement.js +21 -19
  103. package/dist/transformation/visitors/function.d.ts +2 -0
  104. package/dist/transformation/visitors/function.js +63 -13
  105. package/dist/transformation/visitors/identifier.js +5 -0
  106. package/dist/transformation/visitors/language-extensions/index.d.ts +4 -0
  107. package/dist/transformation/visitors/language-extensions/index.js +17 -0
  108. package/dist/transformation/visitors/language-extensions/operators.d.ts +1 -1
  109. package/dist/transformation/visitors/language-extensions/operators.js +7 -2
  110. package/dist/transformation/visitors/language-extensions/pairsIterable.d.ts +5 -0
  111. package/dist/transformation/visitors/language-extensions/pairsIterable.js +53 -0
  112. package/dist/transformation/visitors/language-extensions/table.d.ts +1 -8
  113. package/dist/transformation/visitors/language-extensions/table.js +55 -53
  114. package/dist/transformation/visitors/literal.js +69 -16
  115. package/dist/transformation/visitors/loops/do-while.js +34 -8
  116. package/dist/transformation/visitors/loops/for-of.js +4 -0
  117. package/dist/transformation/visitors/loops/for.js +25 -5
  118. package/dist/transformation/visitors/loops/utils.d.ts +1 -0
  119. package/dist/transformation/visitors/loops/utils.js +19 -3
  120. package/dist/transformation/visitors/modules/export.js +4 -5
  121. package/dist/transformation/visitors/namespace.js +1 -1
  122. package/dist/transformation/visitors/optional-chaining.d.ts +16 -0
  123. package/dist/transformation/visitors/optional-chaining.js +172 -0
  124. package/dist/transformation/visitors/sourceFile.js +4 -1
  125. package/dist/transformation/visitors/spread.js +14 -7
  126. package/dist/transformation/visitors/switch.js +29 -9
  127. package/dist/transformation/visitors/template.js +5 -2
  128. package/dist/transformation/visitors/typeof.js +3 -1
  129. package/dist/transformation/visitors/variable-declaration.js +37 -8
  130. package/dist/transformation/visitors/void.d.ts +1 -4
  131. package/dist/transformation/visitors/void.js +7 -12
  132. package/dist/transpilation/resolve.js +1 -1
  133. package/dist/transpilation/transformers.js +4 -1
  134. package/dist/transpilation/utils.js +2 -1
  135. package/language-extensions/index.d.ts +11 -1
  136. package/package.json +5 -5
  137. package/dist/lualib/OptionalChainAccess.lua +0 -6
  138. package/dist/lualib/OptionalFunctionCall.lua +0 -6
  139. package/dist/lualib/OptionalMethodCall.lua +0 -11
  140. package/dist/transformation/utils/transform.d.ts +0 -8
  141. package/dist/transformation/utils/transform.js +0 -14
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.transformCallExpression = exports.transformContextualCallExpression = exports.transformArguments = exports.flattenSpreadExpressions = void 0;
3
+ exports.transformCallExpression = exports.transformContextualCallExpression = exports.transformCallAndArguments = exports.transformArguments = exports.validateArguments = void 0;
4
4
  const ts = require("typescript");
5
5
  const lua = require("../../LuaAST");
6
6
  const builtins_1 = require("../builtins");
@@ -8,124 +8,103 @@ const annotations_1 = require("../utils/annotations");
8
8
  const assignment_validation_1 = require("../utils/assignment-validation");
9
9
  const function_context_1 = require("../utils/function-context");
10
10
  const lua_ast_1 = require("../utils/lua-ast");
11
- const lualib_1 = require("../utils/lualib");
12
11
  const safe_names_1 = require("../utils/safe-names");
13
12
  const typescript_1 = require("../utils/typescript");
14
13
  const access_1 = require("./access");
15
14
  const multi_1 = require("./language-extensions/multi");
16
- const operators_1 = require("./language-extensions/operators");
17
- const table_1 = require("./language-extensions/table");
18
15
  const diagnostics_1 = require("../utils/diagnostics");
19
- const transform_1 = require("../utils/transform");
20
- function getExpressionsBeforeAndAfterFirstSpread(expressions) {
21
- // [a, b, ...c, d, ...e] --> [a, b] and [...c, d, ...e]
22
- const index = expressions.findIndex(ts.isSpreadElement);
23
- const hasSpreadElement = index !== -1;
24
- const before = hasSpreadElement ? expressions.slice(0, index) : expressions;
25
- const after = hasSpreadElement ? expressions.slice(index) : [];
26
- return [before, after];
27
- }
28
- function transformSpreadableExpressionsIntoArrayConcatArguments(context, expressions) {
29
- // [...array, a, b, ...tuple()] --> [ [...array], [a, b], [...tuple()] ]
30
- // chunk non-spread arguments together so they don't concat
31
- const chunks = [];
32
- for (const [index, expression] of expressions.entries()) {
33
- if (ts.isSpreadElement(expression)) {
34
- chunks.push([expression]);
35
- const next = expressions[index + 1];
36
- if (next && !ts.isSpreadElement(next)) {
37
- chunks.push([]);
38
- }
39
- }
40
- else {
41
- let lastChunk = chunks[chunks.length - 1];
42
- if (!lastChunk) {
43
- lastChunk = [];
44
- chunks.push(lastChunk);
45
- }
46
- lastChunk.push(expression);
16
+ const expression_list_1 = require("./expression-list");
17
+ const preceding_statements_1 = require("../utils/preceding-statements");
18
+ const optional_chaining_1 = require("./optional-chaining");
19
+ const language_extensions_1 = require("./language-extensions");
20
+ function validateArguments(context, params, signature) {
21
+ if (!signature || signature.parameters.length < params.length) {
22
+ return;
23
+ }
24
+ for (const [index, param] of params.entries()) {
25
+ const signatureParameter = signature.parameters[index];
26
+ const paramType = context.checker.getTypeAtLocation(param);
27
+ if (signatureParameter.valueDeclaration !== undefined) {
28
+ const signatureType = context.checker.getTypeAtLocation(signatureParameter.valueDeclaration);
29
+ (0, assignment_validation_1.validateAssignment)(context, param, paramType, signatureType, signatureParameter.name);
47
30
  }
48
31
  }
49
- return chunks.map(chunk => (0, lua_ast_1.wrapInTable)(...chunk.map(expression => context.transformExpression(expression))));
50
32
  }
51
- function flattenSpreadExpressions(context, expressions) {
52
- const [preSpreadExpressions, postSpreadExpressions] = getExpressionsBeforeAndAfterFirstSpread(expressions);
53
- const transformedPreSpreadExpressions = preSpreadExpressions.map(a => context.transformExpression(a));
54
- // Nothing special required
55
- if (postSpreadExpressions.length === 0) {
56
- return transformedPreSpreadExpressions;
57
- }
58
- // Only one spread element at the end? Will work as expected
59
- if (postSpreadExpressions.length === 1) {
60
- return [...transformedPreSpreadExpressions, context.transformExpression(postSpreadExpressions[0])];
61
- }
62
- // Use Array.concat and unpack the result of that as the last Expression
63
- const concatArguments = transformSpreadableExpressionsIntoArrayConcatArguments(context, postSpreadExpressions);
64
- const lastExpression = (0, lua_ast_1.createUnpackCall)(context, (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.ArrayConcat, undefined, ...concatArguments));
65
- return [...transformedPreSpreadExpressions, lastExpression];
66
- }
67
- exports.flattenSpreadExpressions = flattenSpreadExpressions;
33
+ exports.validateArguments = validateArguments;
68
34
  function transformArguments(context, params, signature, callContext) {
69
- const parameters = flattenSpreadExpressions(context, params);
70
- // Add context as first param if present
35
+ validateArguments(context, params, signature);
36
+ return (0, expression_list_1.transformExpressionList)(context, callContext ? [callContext, ...params] : params);
37
+ }
38
+ exports.transformArguments = transformArguments;
39
+ function transformCallWithArguments(context, callExpression, transformedArguments, argPrecedingStatements, callContext) {
40
+ let call = context.transformExpression(callExpression);
41
+ let transformedContext;
71
42
  if (callContext) {
72
- parameters.unshift(context.transformExpression(callContext));
73
- }
74
- if (signature && signature.parameters.length >= params.length) {
75
- for (const [index, param] of params.entries()) {
76
- const signatureParameter = signature.parameters[index];
77
- const paramType = context.checker.getTypeAtLocation(param);
78
- if (signatureParameter.valueDeclaration !== undefined) {
79
- const signatureType = context.checker.getTypeAtLocation(signatureParameter.valueDeclaration);
80
- (0, assignment_validation_1.validateAssignment)(context, param, paramType, signatureType, signatureParameter.name);
81
- }
43
+ transformedContext = context.transformExpression(callContext);
44
+ }
45
+ if (argPrecedingStatements.length > 0) {
46
+ if (transformedContext) {
47
+ transformedContext = (0, expression_list_1.moveToPrecedingTemp)(context, transformedContext, callContext);
82
48
  }
49
+ call = (0, expression_list_1.moveToPrecedingTemp)(context, call, callExpression);
50
+ context.addPrecedingStatements(argPrecedingStatements);
83
51
  }
84
- return parameters;
52
+ if (transformedContext) {
53
+ transformedArguments.unshift(transformedContext);
54
+ }
55
+ return [call, transformedArguments];
85
56
  }
86
- exports.transformArguments = transformArguments;
87
- function transformElementAccessCall(context, left, args, signature) {
88
- const transformedArguments = transformArguments(context, args, signature, ts.factory.createIdentifier("____self"));
57
+ function transformCallAndArguments(context, callExpression, params, signature, callContext) {
58
+ const [argPrecedingStatements, transformedArguments] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => transformArguments(context, params, signature, callContext));
59
+ return transformCallWithArguments(context, callExpression, transformedArguments, argPrecedingStatements);
60
+ }
61
+ exports.transformCallAndArguments = transformCallAndArguments;
62
+ function transformElementAccessCall(context, left, transformedArguments, argPrecedingStatements) {
89
63
  // Cache left-side if it has effects
90
- // (function() local ____self = context; return ____self[argument](parameters); end)()
64
+ // local ____self = context; return ____self[argument](parameters);
65
+ const selfIdentifier = lua.createIdentifier(context.createTempName("self"));
66
+ const callContext = context.transformExpression(left.expression);
67
+ const selfAssignment = lua.createVariableDeclarationStatement(selfIdentifier, callContext);
68
+ context.addPrecedingStatements(selfAssignment);
91
69
  const argument = ts.isElementAccessExpression(left)
92
70
  ? (0, access_1.transformElementAccessArgument)(context, left)
93
71
  : lua.createStringLiteral(left.name.text);
94
- const selfIdentifier = lua.createIdentifier("____self");
95
- const callContext = context.transformExpression(left.expression);
96
- const selfAssignment = lua.createVariableDeclarationStatement(selfIdentifier, callContext);
97
- const index = lua.createTableIndexExpression(selfIdentifier, argument);
98
- const callExpression = lua.createCallExpression(index, transformedArguments);
99
- return { statements: selfAssignment, result: callExpression };
72
+ let index = lua.createTableIndexExpression(selfIdentifier, argument);
73
+ if (argPrecedingStatements.length > 0) {
74
+ // Cache index in temp if args had preceding statements
75
+ index = (0, expression_list_1.moveToPrecedingTemp)(context, index);
76
+ context.addPrecedingStatements(argPrecedingStatements);
77
+ }
78
+ return lua.createCallExpression(index, [selfIdentifier, ...transformedArguments]);
100
79
  }
101
80
  function transformContextualCallExpression(context, node, args, signature) {
81
+ if (ts.isOptionalChain(node)) {
82
+ return (0, optional_chaining_1.transformOptionalChain)(context, node);
83
+ }
102
84
  const left = ts.isCallExpression(node) ? node.expression : node.tag;
103
- if (ts.isPropertyAccessExpression(left) && ts.isIdentifier(left.name) && (0, safe_names_1.isValidLuaIdentifier)(left.name.text)) {
85
+ let [argPrecedingStatements, transformedArguments] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => transformArguments(context, args, signature));
86
+ if (ts.isPropertyAccessExpression(left) &&
87
+ ts.isIdentifier(left.name) &&
88
+ (0, safe_names_1.isValidLuaIdentifier)(left.name.text, context.options) &&
89
+ argPrecedingStatements.length === 0) {
104
90
  // table:name()
105
91
  const table = context.transformExpression(left.expression);
106
- if (ts.isOptionalChain(node)) {
107
- return (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.OptionalMethodCall, node, table, lua.createStringLiteral(left.name.text, left.name), lua.createBooleanLiteral(node.questionDotToken !== undefined), // Require method is present if no ?.() call
108
- ...transformArguments(context, args, signature));
109
- }
110
- else {
111
- return lua.createMethodCallExpression(table, lua.createIdentifier(left.name.text, left.name), transformArguments(context, args, signature), node);
112
- }
92
+ return lua.createMethodCallExpression(table, lua.createIdentifier(left.name.text, left.name), transformedArguments, node);
113
93
  }
114
94
  else if (ts.isElementAccessExpression(left) || ts.isPropertyAccessExpression(left)) {
115
95
  if ((0, typescript_1.isExpressionWithEvaluationEffect)(left.expression)) {
116
- return (0, transform_1.transformToImmediatelyInvokedFunctionExpression)(context, () => transformElementAccessCall(context, left, args, signature), node);
96
+ return transformElementAccessCall(context, left, transformedArguments, argPrecedingStatements);
117
97
  }
118
98
  else {
119
- const callContext = context.transformExpression(left.expression);
120
- const expression = context.transformExpression(left);
121
- const transformedArguments = transformArguments(context, args, signature);
122
- return lua.createCallExpression(expression, [callContext, ...transformedArguments]);
99
+ let expression;
100
+ [expression, transformedArguments] = transformCallWithArguments(context, left, transformedArguments, argPrecedingStatements, left.expression);
101
+ return lua.createCallExpression(expression, transformedArguments, node);
123
102
  }
124
103
  }
125
104
  else if (ts.isIdentifier(left)) {
126
105
  const callContext = context.isStrict ? ts.factory.createNull() : ts.factory.createIdentifier("_G");
127
- const transformedArguments = transformArguments(context, args, signature, callContext);
128
- const expression = context.transformExpression(left);
106
+ let expression;
107
+ [expression, transformedArguments] = transformCallWithArguments(context, left, transformedArguments, argPrecedingStatements, callContext);
129
108
  return lua.createCallExpression(expression, transformedArguments, node);
130
109
  }
131
110
  else {
@@ -147,14 +126,8 @@ function transformPropertyCall(context, node) {
147
126
  }
148
127
  else {
149
128
  // table.name()
150
- const callPath = context.transformExpression(node.expression);
151
- const parameters = transformArguments(context, node.arguments, signature);
152
- if (ts.isOptionalChain(node)) {
153
- return (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.OptionalFunctionCall, node, callPath, ...parameters);
154
- }
155
- else {
156
- return lua.createCallExpression(callPath, parameters, node);
157
- }
129
+ const [callPath, parameters] = transformCallAndArguments(context, node.expression, node.arguments, signature);
130
+ return lua.createCallExpression(callPath, parameters, node);
158
131
  }
159
132
  }
160
133
  function transformElementCall(context, node) {
@@ -166,37 +139,26 @@ function transformElementCall(context, node) {
166
139
  }
167
140
  else {
168
141
  // No context
169
- const expression = context.transformExpression(node.expression);
170
- const parameters = transformArguments(context, node.arguments, signature);
142
+ const [expression, parameters] = transformCallAndArguments(context, node.expression, node.arguments, signature);
171
143
  return lua.createCallExpression(expression, parameters);
172
144
  }
173
145
  }
174
146
  const transformCallExpression = (node, context) => {
175
- const wrapResultInTable = (0, multi_1.isMultiReturnCall)(context, node) && (0, multi_1.shouldMultiReturnCallBeWrapped)(context, node);
176
- const wrapResultInOptional = ts.isOptionalChain(node);
177
- const builtinResult = (0, builtins_1.transformBuiltinCallExpression)(context, node);
178
- if (builtinResult) {
179
- return wrapResultInTable ? (0, lua_ast_1.wrapInTable)(builtinResult) : builtinResult;
147
+ var _a;
148
+ if (ts.isOptionalChain(node)) {
149
+ return (0, optional_chaining_1.transformOptionalChain)(context, node);
180
150
  }
151
+ const optionalContinuation = ts.isIdentifier(node.expression)
152
+ ? (0, optional_chaining_1.getOptionalContinuationData)(node.expression)
153
+ : undefined;
154
+ const wrapResultInTable = (0, multi_1.isMultiReturnCall)(context, node) && (0, multi_1.shouldMultiReturnCallBeWrapped)(context, node);
181
155
  if ((0, annotations_1.isTupleReturnCall)(context, node)) {
182
156
  context.diagnostics.push((0, diagnostics_1.annotationRemoved)(node, annotations_1.AnnotationKind.TupleReturn));
183
157
  }
184
- if ((0, operators_1.isOperatorMapping)(context, node)) {
185
- return (0, operators_1.transformOperatorMappingExpression)(context, node);
186
- }
187
- if ((0, table_1.isTableDeleteCall)(context, node)) {
188
- context.diagnostics.push((0, diagnostics_1.invalidTableDeleteExpression)(node));
189
- return (0, transform_1.transformToImmediatelyInvokedFunctionExpression)(context, () => ({ statements: (0, table_1.transformTableDeleteExpression)(context, node), result: lua.createNilLiteral() }), node);
190
- }
191
- if ((0, table_1.isTableGetCall)(context, node)) {
192
- return (0, table_1.transformTableGetExpression)(context, node);
193
- }
194
- if ((0, table_1.isTableHasCall)(context, node)) {
195
- return (0, table_1.transformTableHasExpression)(context, node);
196
- }
197
- if ((0, table_1.isTableSetCall)(context, node)) {
198
- context.diagnostics.push((0, diagnostics_1.invalidTableSetExpression)(node));
199
- return (0, transform_1.transformToImmediatelyInvokedFunctionExpression)(context, () => ({ statements: (0, table_1.transformTableSetExpression)(context, node), result: lua.createNilLiteral() }), node);
158
+ const builtinOrExtensionResult = (_a = (0, builtins_1.transformBuiltinCallExpression)(context, node, optionalContinuation !== undefined)) !== null && _a !== void 0 ? _a : (0, language_extensions_1.transformLanguageExtensionCallExpression)(context, node, optionalContinuation !== undefined);
159
+ if (builtinOrExtensionResult) {
160
+ // unsupportedOptionalCall diagnostic already present
161
+ return wrapResultInTable ? (0, lua_ast_1.wrapInTable)(builtinOrExtensionResult) : builtinOrExtensionResult;
200
162
  }
201
163
  if (ts.isPropertyAccessExpression(node.expression)) {
202
164
  const ownerType = context.checker.getTypeAtLocation(node.expression.expression);
@@ -205,12 +167,11 @@ const transformCallExpression = (node, context) => {
205
167
  context.diagnostics.push((0, diagnostics_1.annotationRemoved)(node, annotations_1.AnnotationKind.LuaTable));
206
168
  }
207
169
  const result = transformPropertyCall(context, node);
208
- // transformPropertyCall already wraps optional so no need to do so here
209
170
  return wrapResultInTable ? (0, lua_ast_1.wrapInTable)(result) : result;
210
171
  }
211
172
  if (ts.isElementAccessExpression(node.expression)) {
212
173
  const result = transformElementCall(context, node);
213
- return wrapIfRequired(context, wrapResultInTable, wrapResultInOptional, result, node);
174
+ return wrapResultInTable ? (0, lua_ast_1.wrapInTable)(result) : result;
214
175
  }
215
176
  const signature = context.checker.getResolvedSignature(node);
216
177
  // Handle super calls properly
@@ -218,31 +179,24 @@ const transformCallExpression = (node, context) => {
218
179
  const parameters = transformArguments(context, node.arguments, signature, ts.factory.createThis());
219
180
  return lua.createCallExpression(lua.createTableIndexExpression(context.transformExpression(ts.factory.createSuper()), lua.createStringLiteral("____constructor")), parameters);
220
181
  }
221
- const callPath = context.transformExpression(node.expression);
222
182
  const signatureDeclaration = signature === null || signature === void 0 ? void 0 : signature.getDeclaration();
223
- let parameters = [];
224
- if (signatureDeclaration && (0, function_context_1.getDeclarationContextType)(context, signatureDeclaration) === function_context_1.ContextType.Void) {
225
- parameters = transformArguments(context, node.arguments, signature);
183
+ let callPath;
184
+ let parameters;
185
+ const isContextualCall = !signatureDeclaration || (0, function_context_1.getDeclarationContextType)(context, signatureDeclaration) !== function_context_1.ContextType.Void;
186
+ if (!isContextualCall) {
187
+ [callPath, parameters] = transformCallAndArguments(context, node.expression, node.arguments, signature);
226
188
  }
227
189
  else {
228
- const callContext = context.isStrict ? ts.factory.createNull() : ts.factory.createIdentifier("_G");
229
- parameters = transformArguments(context, node.arguments, signature, callContext);
190
+ // if is optionalContinuation, context will be handled by transformOptionalChain.
191
+ const useGlobalContext = !context.isStrict && optionalContinuation === undefined;
192
+ const callContext = useGlobalContext ? ts.factory.createIdentifier("_G") : ts.factory.createNull();
193
+ [callPath, parameters] = transformCallAndArguments(context, node.expression, node.arguments, signature, callContext);
230
194
  }
231
195
  const callExpression = lua.createCallExpression(callPath, parameters, node);
232
- return wrapIfRequired(context, wrapResultInTable, wrapResultInOptional, callExpression, node);
196
+ if (optionalContinuation && isContextualCall) {
197
+ optionalContinuation.contextualCall = callExpression;
198
+ }
199
+ return wrapResultInTable ? (0, lua_ast_1.wrapInTable)(callExpression) : callExpression;
233
200
  };
234
201
  exports.transformCallExpression = transformCallExpression;
235
- function wrapIfRequired(context, shouldWrapInTable, shouldWrapOptional, call, node) {
236
- const wrappedOptional = shouldWrapOptional ? wrapOptionalCall(context, call, node) : call;
237
- return shouldWrapInTable ? (0, lua_ast_1.wrapInTable)(wrappedOptional) : wrappedOptional;
238
- }
239
- function wrapOptionalCall(context, call, node) {
240
- if (lua.isMethodCallExpression(call)) {
241
- return (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.OptionalMethodCall, node, call.prefixExpression, lua.createStringLiteral(call.name.text), lua.createBooleanLiteral(node.questionDotToken !== undefined), // Require method is present if no ?.() call
242
- ...call.params);
243
- }
244
- else {
245
- return (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.OptionalFunctionCall, node, call.expression, ...call.params);
246
- }
247
- }
248
202
  //# sourceMappingURL=call.js.map
@@ -9,7 +9,6 @@ const diagnostics_1 = require("../../utils/diagnostics");
9
9
  const export_1 = require("../../utils/export");
10
10
  const lua_ast_1 = require("../../utils/lua-ast");
11
11
  const safe_names_1 = require("../../utils/safe-names");
12
- const transform_1 = require("../../utils/transform");
13
12
  const identifier_1 = require("../identifier");
14
13
  const decorators_1 = require("./decorators");
15
14
  const accessors_1 = require("./members/accessors");
@@ -22,7 +21,7 @@ const utils_2 = require("./utils");
22
21
  const transformClassDeclaration = (declaration, context) => {
23
22
  // If declaration is a default export, transform to export variable assignment instead
24
23
  if ((0, export_1.hasDefaultExportModifier)(declaration)) {
25
- const left = (0, export_1.createExportedIdentifier)(context, (0, export_1.createDefaultExportIdentifier)(declaration));
24
+ const left = (0, export_1.createDefaultExportExpression)(declaration);
26
25
  const right = transformClassAsExpression(declaration, context);
27
26
  return [lua.createAssignmentStatement(left, right, declaration)];
28
27
  }
@@ -33,10 +32,9 @@ exports.transformClassDeclaration = transformClassDeclaration;
33
32
  const transformThisExpression = node => (0, lua_ast_1.createSelfIdentifier)(node);
34
33
  exports.transformThisExpression = transformThisExpression;
35
34
  function transformClassAsExpression(expression, context) {
36
- return (0, transform_1.transformToImmediatelyInvokedFunctionExpression)(context, () => {
37
- const { statements, name } = transformClassLikeDeclaration(expression, context);
38
- return { statements: (0, lua_ast_1.unwrapVisitorResult)(statements), result: name };
39
- }, expression);
35
+ const { statements, name } = transformClassLikeDeclaration(expression, context);
36
+ context.addPrecedingStatements(statements);
37
+ return name;
40
38
  }
41
39
  exports.transformClassAsExpression = transformClassAsExpression;
42
40
  const classSuperInfos = new WeakMap();
@@ -49,8 +47,7 @@ function transformClassLikeDeclaration(classDeclaration, context, nameOverride)
49
47
  className = (0, identifier_1.transformIdentifier)(context, classDeclaration.name);
50
48
  }
51
49
  else {
52
- // TypeScript error
53
- className = lua.createAnonymousIdentifier();
50
+ className = lua.createIdentifier(context.createTempName("class"), classDeclaration);
54
51
  }
55
52
  const annotations = (0, annotations_1.getTypeAnnotations)(context.checker.getTypeAtLocation(classDeclaration));
56
53
  if (annotations.has(annotations_1.AnnotationKind.Extension)) {
@@ -73,7 +70,7 @@ function transformClassLikeDeclaration(classDeclaration, context, nameOverride)
73
70
  const instanceFields = properties.filter(prop => !(0, utils_2.isStaticNode)(prop));
74
71
  const result = [];
75
72
  let localClassName;
76
- if ((0, safe_names_1.isUnsafeName)(className.text)) {
73
+ if ((0, safe_names_1.isUnsafeName)(className.text, context.options)) {
77
74
  localClassName = lua.createIdentifier((0, safe_names_1.createSafeName)(className.text), undefined, className.symbolId, className.text);
78
75
  lua.setNodePosition(localClassName, className);
79
76
  }
@@ -152,6 +149,13 @@ function transformClassLikeDeclaration(classDeclaration, context, nameOverride)
152
149
  const decoratingExpression = (0, decorators_1.createDecoratingExpression)(context, classDeclaration.kind, classDeclaration.decorators.map(d => (0, decorators_1.transformDecoratorExpression)(context, d)), localClassName);
153
150
  const decoratingStatement = lua.createAssignmentStatement(localClassName, decoratingExpression);
154
151
  result.push(decoratingStatement);
152
+ if ((0, export_1.hasExportModifier)(classDeclaration)) {
153
+ const exportExpression = (0, export_1.hasDefaultExportModifier)(classDeclaration)
154
+ ? (0, export_1.createDefaultExportExpression)(classDeclaration)
155
+ : (0, export_1.createExportedIdentifier)(context, className);
156
+ const classAssignment = lua.createAssignmentStatement(exportExpression, localClassName);
157
+ result.push(classAssignment);
158
+ }
155
159
  }
156
160
  superInfo.pop();
157
161
  return { statements: result, name: className };
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.transformNewExpression = exports.checkForLuaLibType = void 0;
4
+ const ts = require("typescript");
4
5
  const lua = require("../../../LuaAST");
5
6
  const annotations_1 = require("../../utils/annotations");
6
7
  const diagnostics_1 = require("../../utils/diagnostics");
@@ -46,7 +47,7 @@ function checkForLuaLibType(context, type) {
46
47
  }
47
48
  exports.checkForLuaLibType = checkForLuaLibType;
48
49
  const transformNewExpression = (node, context) => {
49
- var _a;
50
+ var _a, _b;
50
51
  const type = context.checker.getTypeAtLocation(node);
51
52
  const annotations = (0, annotations_1.getTypeAnnotations)(type);
52
53
  if (annotations.has(annotations_1.AnnotationKind.LuaTable)) {
@@ -56,15 +57,12 @@ const transformNewExpression = (node, context) => {
56
57
  return lua.createTableExpression(undefined, node);
57
58
  }
58
59
  const signature = context.checker.getResolvedSignature(node);
59
- const params = node.arguments
60
- ? (0, call_1.transformArguments)(context, node.arguments, signature)
61
- : [lua.createBooleanLiteral(true)];
60
+ const [name, params] = (0, call_1.transformCallAndArguments)(context, node.expression, (_a = node.arguments) !== null && _a !== void 0 ? _a : [ts.factory.createTrue()], signature);
62
61
  checkForLuaLibType(context, type);
63
- const name = context.transformExpression(node.expression);
64
62
  const customConstructorAnnotation = annotations.get(annotations_1.AnnotationKind.CustomConstructor);
65
63
  if (customConstructorAnnotation) {
66
64
  if (customConstructorAnnotation.args.length === 1) {
67
- return lua.createCallExpression(lua.createIdentifier(customConstructorAnnotation.args[0]), (0, call_1.transformArguments)(context, (_a = node.arguments) !== null && _a !== void 0 ? _a : []), node);
65
+ return lua.createCallExpression(lua.createIdentifier(customConstructorAnnotation.args[0]), (0, call_1.transformArguments)(context, (_b = node.arguments) !== null && _b !== void 0 ? _b : []), node);
68
66
  }
69
67
  else {
70
68
  context.diagnostics.push((0, diagnostics_1.annotationInvalidArgumentCount)(node, annotations_1.AnnotationKind.CustomConstructor, customConstructorAnnotation.args.length, 1));
@@ -3,47 +3,25 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.transformIfStatement = exports.transformConditionalExpression = void 0;
4
4
  const ts = require("typescript");
5
5
  const lua = require("../../LuaAST");
6
+ const preceding_statements_1 = require("../utils/preceding-statements");
6
7
  const scope_1 = require("../utils/scope");
7
8
  const block_1 = require("./block");
8
- function canBeFalsy(context, type) {
9
- const strictNullChecks = context.options.strict === true || context.options.strictNullChecks === true;
10
- const falsyFlags = ts.TypeFlags.Boolean |
11
- ts.TypeFlags.BooleanLiteral |
12
- ts.TypeFlags.Undefined |
13
- ts.TypeFlags.Null |
14
- ts.TypeFlags.Never |
15
- ts.TypeFlags.Void |
16
- ts.TypeFlags.Any;
17
- if (type.flags & falsyFlags) {
18
- return true;
19
- }
20
- else if (!strictNullChecks && !type.isLiteral()) {
21
- return true;
22
- }
23
- else if (type.isUnion()) {
24
- return type.types.some(subType => canBeFalsy(context, subType));
25
- }
26
- else {
27
- return false;
28
- }
29
- }
30
- function wrapInFunctionCall(expression) {
31
- const returnStatement = lua.createReturnStatement([expression]);
32
- return lua.createFunctionExpression(lua.createBlock([returnStatement]), undefined, undefined, lua.FunctionExpressionFlags.Inline);
33
- }
9
+ const typescript_1 = require("../utils/typescript");
34
10
  function transformProtectedConditionalExpression(context, expression) {
11
+ const tempVar = context.createTempNameForNode(expression.condition);
35
12
  const condition = context.transformExpression(expression.condition);
36
- const val1 = context.transformExpression(expression.whenTrue);
37
- const val2 = context.transformExpression(expression.whenFalse);
38
- const val1Function = wrapInFunctionCall(val1);
39
- const val2Function = wrapInFunctionCall(val2);
40
- // (condition and (() => v1) or (() => v2))()
41
- const conditionAnd = lua.createBinaryExpression(condition, val1Function, lua.SyntaxKind.AndOperator);
42
- const orExpression = lua.createBinaryExpression(conditionAnd, val2Function, lua.SyntaxKind.OrOperator);
43
- return lua.createCallExpression(orExpression, [], expression);
13
+ const [trueStatements, val1] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(expression.whenTrue));
14
+ trueStatements.push(lua.createAssignmentStatement(lua.cloneIdentifier(tempVar), val1, expression.whenTrue));
15
+ const [falseStatements, val2] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(expression.whenFalse));
16
+ falseStatements.push(lua.createAssignmentStatement(lua.cloneIdentifier(tempVar), val2, expression.whenFalse));
17
+ context.addPrecedingStatements([
18
+ lua.createVariableDeclarationStatement(tempVar, undefined, expression.condition),
19
+ lua.createIfStatement(condition, lua.createBlock(trueStatements, expression.whenTrue), lua.createBlock(falseStatements, expression.whenFalse), expression),
20
+ ]);
21
+ return lua.cloneIdentifier(tempVar);
44
22
  }
45
23
  const transformConditionalExpression = (expression, context) => {
46
- if (canBeFalsy(context, context.checker.getTypeAtLocation(expression.whenTrue))) {
24
+ if ((0, typescript_1.canBeFalsy)(context, context.checker.getTypeAtLocation(expression.whenTrue))) {
47
25
  return transformProtectedConditionalExpression(context, expression);
48
26
  }
49
27
  const condition = context.transformExpression(expression.condition);
@@ -62,8 +40,23 @@ function transformIfStatement(statement, context) {
62
40
  const ifBlock = lua.createBlock(statements);
63
41
  if (statement.elseStatement) {
64
42
  if (ts.isIfStatement(statement.elseStatement)) {
65
- const elseStatement = transformIfStatement(statement.elseStatement, context);
66
- return lua.createIfStatement(condition, ifBlock, elseStatement);
43
+ const tsElseStatement = statement.elseStatement;
44
+ const [precedingStatements, elseStatement] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => transformIfStatement(tsElseStatement, context));
45
+ // If else-if condition generates preceding statements, we can't use elseif, we have to break it down:
46
+ // if conditionA then
47
+ // ...
48
+ // else
49
+ // conditionB's preceding statements
50
+ // if conditionB then
51
+ // end
52
+ // end
53
+ if (precedingStatements.length > 0) {
54
+ const elseBlock = lua.createBlock([...precedingStatements, elseStatement]);
55
+ return lua.createIfStatement(condition, ifBlock, elseBlock);
56
+ }
57
+ else {
58
+ return lua.createIfStatement(condition, ifBlock, elseStatement);
59
+ }
67
60
  }
68
61
  else {
69
62
  (0, scope_1.pushScope)(context, scope_1.ScopeType.Conditional);
@@ -7,7 +7,11 @@ const lualib_1 = require("../utils/lualib");
7
7
  const diagnostics_1 = require("../utils/diagnostics");
8
8
  const typescript_1 = require("../utils/typescript");
9
9
  const lua_ast_1 = require("../utils/lua-ast");
10
+ const optional_chaining_1 = require("./optional-chaining");
10
11
  const transformDeleteExpression = (node, context) => {
12
+ if (ts.isOptionalChain(node.expression)) {
13
+ return (0, optional_chaining_1.transformOptionalDeleteExpression)(context, node, node.expression);
14
+ }
11
15
  let ownerExpression;
12
16
  let propertyExpression;
13
17
  if (ts.isPropertyAccessExpression(node.expression)) {
@@ -12,6 +12,7 @@ const identifier_1 = require("./identifier");
12
12
  const multi_1 = require("./language-extensions/multi");
13
13
  const return_1 = require("./return");
14
14
  const transformTryStatement = (statement, context) => {
15
+ var _a;
15
16
  const [tryBlock, tryScope] = (0, block_1.transformScopeBlock)(context, statement.tryBlock, scope_1.ScopeType.Try);
16
17
  if (context.options.luaTarget === __1.LuaTarget.Lua51 && (0, typescript_1.isInAsyncFunction)(statement)) {
17
18
  context.diagnostics.push((0, diagnostics_1.unsupportedForTarget)(statement, "try/catch inside async functions", __1.LuaTarget.Lua51));
@@ -34,24 +35,25 @@ const transformTryStatement = (statement, context) => {
34
35
  const catchParameter = statement.catchClause.variableDeclaration
35
36
  ? (0, identifier_1.transformIdentifier)(context, statement.catchClause.variableDeclaration.name)
36
37
  : undefined;
37
- const catchParameters = () => (catchParameter ? [lua.cloneIdentifier(catchParameter)] : []);
38
+ const catchFunction = lua.createFunctionExpression(catchBlock, catchParameter ? [lua.cloneIdentifier(catchParameter)] : []);
38
39
  const catchIdentifier = lua.createIdentifier("____catch");
39
- const catchFunction = lua.createFunctionExpression(catchBlock, catchParameters());
40
40
  result.push(lua.createVariableDeclarationStatement(catchIdentifier, catchFunction));
41
+ const hasReturn = (_a = tryScope.functionReturned) !== null && _a !== void 0 ? _a : catchScope.functionReturned;
41
42
  const tryReturnIdentifiers = [tryResultIdentifier]; // ____try
42
- if (returnedIdentifier) {
43
- tryReturnIdentifiers.push(returnedIdentifier); // ____returned or catch variable
44
- if (tryScope.functionReturned || catchScope.functionReturned) {
43
+ if (hasReturn || statement.catchClause.variableDeclaration) {
44
+ tryReturnIdentifiers.push(returnedIdentifier); // ____returned
45
+ if (hasReturn) {
45
46
  tryReturnIdentifiers.push(returnValueIdentifier); // ____returnValue
46
47
  returnCondition = lua.cloneIdentifier(returnedIdentifier);
47
48
  }
48
49
  }
49
50
  result.push(lua.createVariableDeclarationStatement(tryReturnIdentifiers, tryCall));
50
- // Wrap catch in function if try or catch has return
51
- const catchCall = lua.createCallExpression(catchIdentifier, [lua.cloneIdentifier(returnedIdentifier)]);
52
- const catchAssign = lua.createAssignmentStatement([lua.cloneIdentifier(returnedIdentifier), lua.cloneIdentifier(returnValueIdentifier)], catchCall);
51
+ const catchCall = lua.createCallExpression(catchIdentifier, statement.catchClause.variableDeclaration ? [lua.cloneIdentifier(returnedIdentifier)] : []);
52
+ const catchCallStatement = hasReturn
53
+ ? lua.createAssignmentStatement([lua.cloneIdentifier(returnedIdentifier), lua.cloneIdentifier(returnValueIdentifier)], catchCall)
54
+ : lua.createExpressionStatement(catchCall);
53
55
  const notTryCondition = lua.createUnaryExpression(tryResultIdentifier, lua.SyntaxKind.NotOperator);
54
- result.push(lua.createIfStatement(notTryCondition, lua.createBlock([catchAssign])));
56
+ result.push(lua.createIfStatement(notTryCondition, lua.createBlock([catchCallStatement])));
55
57
  }
56
58
  else if (tryScope.functionReturned) {
57
59
  // try with return, but no catch
@@ -0,0 +1,7 @@
1
+ import * as ts from "typescript";
2
+ import * as lua from "../../LuaAST";
3
+ import { TransformationContext } from "../context";
4
+ export declare function shouldMoveToTemp(context: TransformationContext, expression: lua.Expression, tsOriginal?: ts.Node): boolean;
5
+ export declare function moveToPrecedingTemp(context: TransformationContext, expression: lua.Expression, tsOriginal?: ts.Node): lua.Expression;
6
+ export declare function transformExpressionList(context: TransformationContext, expressions: readonly ts.Expression[]): lua.Expression[];
7
+ export declare function transformOrderedExpressions(context: TransformationContext, expressions: readonly ts.Expression[]): lua.Expression[];