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
@@ -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)) {
@@ -21,15 +25,15 @@ const transformDeleteExpression = (node, context) => {
21
25
  propertyExpression = context.transformExpression(node.expression.argumentExpression);
22
26
  const type = context.checker.getTypeAtLocation(node.expression.expression);
23
27
  const argumentType = context.checker.getTypeAtLocation(node.expression.argumentExpression);
24
- if (typescript_1.isArrayType(context, type) && typescript_1.isNumberType(context, argumentType)) {
25
- propertyExpression = lua_ast_1.addToNumericExpression(propertyExpression, 1);
28
+ if ((0, typescript_1.isArrayType)(context, type) && (0, typescript_1.isNumberType)(context, argumentType)) {
29
+ propertyExpression = (0, lua_ast_1.addToNumericExpression)(propertyExpression, 1);
26
30
  }
27
31
  }
28
32
  if (!ownerExpression || !propertyExpression) {
29
- context.diagnostics.push(diagnostics_1.unsupportedProperty(node, "delete", ts.SyntaxKind[node.kind]));
33
+ context.diagnostics.push((0, diagnostics_1.unsupportedProperty)(node, "delete", ts.SyntaxKind[node.kind]));
30
34
  return lua.createNilLiteral();
31
35
  }
32
- return lualib_1.transformLuaLibFunction(context, lualib_1.LuaLibFeature.Delete, node, ownerExpression, propertyExpression);
36
+ return (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.Delete, node, ownerExpression, propertyExpression);
33
37
  };
34
38
  exports.transformDeleteExpression = transformDeleteExpression;
35
39
  //# sourceMappingURL=delete.js.map
@@ -24,16 +24,16 @@ const transformEnumDeclaration = (node, context) => {
24
24
  return undefined;
25
25
  }
26
26
  const type = context.checker.getTypeAtLocation(node);
27
- const membersOnly = annotations_1.getTypeAnnotations(type).has(annotations_1.AnnotationKind.CompileMembersOnly);
27
+ const membersOnly = (0, annotations_1.getTypeAnnotations)(type).has(annotations_1.AnnotationKind.CompileMembersOnly);
28
28
  const result = [];
29
- if (!membersOnly && typescript_1.isFirstDeclaration(context, node)) {
30
- const name = identifier_1.transformIdentifier(context, node.name);
29
+ if (!membersOnly && (0, typescript_1.isFirstDeclaration)(context, node)) {
30
+ const name = (0, identifier_1.transformIdentifier)(context, node.name);
31
31
  const table = lua.createBinaryExpression(lua.cloneIdentifier(name), lua.createTableExpression(), lua.SyntaxKind.OrOperator);
32
- result.push(...lua_ast_1.createLocalOrExportedOrGlobalDeclaration(context, name, table, node));
32
+ result.push(...(0, lua_ast_1.createLocalOrExportedOrGlobalDeclaration)(context, name, table, node));
33
33
  }
34
34
  const enumReference = context.transformExpression(node.name);
35
35
  for (const member of node.members) {
36
- const memberName = literal_1.transformPropertyName(context, member.name);
36
+ const memberName = (0, literal_1.transformPropertyName)(context, member.name);
37
37
  let valueExpression;
38
38
  const constEnumValue = tryGetConstEnumValue(context, member);
39
39
  if (constEnumValue) {
@@ -45,7 +45,7 @@ const transformEnumDeclaration = (node, context) => {
45
45
  if ((symbol === null || symbol === void 0 ? void 0 : symbol.valueDeclaration) &&
46
46
  ts.isEnumMember(symbol.valueDeclaration) &&
47
47
  symbol.valueDeclaration.parent === node) {
48
- const otherMemberName = literal_1.transformPropertyName(context, symbol.valueDeclaration.name);
48
+ const otherMemberName = (0, literal_1.transformPropertyName)(context, symbol.valueDeclaration.name);
49
49
  valueExpression = lua.createTableIndexExpression(enumReference, otherMemberName);
50
50
  }
51
51
  }
@@ -58,8 +58,8 @@ const transformEnumDeclaration = (node, context) => {
58
58
  }
59
59
  if (membersOnly) {
60
60
  const enumSymbol = context.checker.getSymbolAtLocation(node.name);
61
- const exportScope = enumSymbol ? export_1.getSymbolExportScope(context, enumSymbol) : undefined;
62
- result.push(...lua_ast_1.createLocalOrExportedOrGlobalDeclaration(context, lua.isIdentifier(memberName)
61
+ const exportScope = enumSymbol ? (0, export_1.getSymbolExportScope)(context, enumSymbol) : undefined;
62
+ result.push(...(0, lua_ast_1.createLocalOrExportedOrGlobalDeclaration)(context, lua.isIdentifier(memberName)
63
63
  ? memberName
64
64
  : lua.createIdentifier(member.name.getText(), member.name), valueExpression, node, exportScope));
65
65
  }
@@ -1,52 +1,63 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.transformThrowStatement = exports.transformTryStatement = void 0;
4
+ const __1 = require("../..");
4
5
  const lua = require("../../LuaAST");
6
+ const diagnostics_1 = require("../utils/diagnostics");
5
7
  const lua_ast_1 = require("../utils/lua-ast");
6
8
  const scope_1 = require("../utils/scope");
9
+ const typescript_1 = require("../utils/typescript");
7
10
  const block_1 = require("./block");
8
11
  const identifier_1 = require("./identifier");
9
12
  const multi_1 = require("./language-extensions/multi");
13
+ const return_1 = require("./return");
10
14
  const transformTryStatement = (statement, context) => {
11
- const [tryBlock, tryScope] = block_1.transformScopeBlock(context, statement.tryBlock, scope_1.ScopeType.Try);
15
+ var _a;
16
+ const [tryBlock, tryScope] = (0, block_1.transformScopeBlock)(context, statement.tryBlock, scope_1.ScopeType.Try);
17
+ if (context.options.luaTarget === __1.LuaTarget.Lua51 && (0, typescript_1.isInAsyncFunction)(statement)) {
18
+ context.diagnostics.push((0, diagnostics_1.unsupportedForTarget)(statement, "try/catch inside async functions", __1.LuaTarget.Lua51));
19
+ return tryBlock.statements;
20
+ }
21
+ if (context.options.luaTarget === __1.LuaTarget.Lua51 && (0, typescript_1.isInGeneratorFunction)(statement)) {
22
+ context.diagnostics.push((0, diagnostics_1.unsupportedForTarget)(statement, "try/catch inside generator functions", __1.LuaTarget.Lua51));
23
+ return tryBlock.statements;
24
+ }
12
25
  const tryResultIdentifier = lua.createIdentifier("____try");
13
26
  const returnValueIdentifier = lua.createIdentifier("____returnValue");
14
27
  const result = [];
15
- let returnedIdentifier;
28
+ const returnedIdentifier = lua.createIdentifier("____hasReturned");
16
29
  let returnCondition;
17
30
  const pCall = lua.createIdentifier("pcall");
18
31
  const tryCall = lua.createCallExpression(pCall, [lua.createFunctionExpression(tryBlock)]);
19
32
  if (statement.catchClause && statement.catchClause.block.statements.length > 0) {
20
33
  // try with catch
21
- let [catchBlock, catchScope] = block_1.transformScopeBlock(context, statement.catchClause.block, scope_1.ScopeType.Catch);
22
- if (statement.catchClause.variableDeclaration) {
23
- // Replace ____returned with catch variable
24
- returnedIdentifier = identifier_1.transformIdentifier(context, statement.catchClause.variableDeclaration.name);
25
- }
26
- else if (tryScope.functionReturned || catchScope.functionReturned) {
27
- returnedIdentifier = lua.createIdentifier("____returned");
28
- }
34
+ const [catchBlock, catchScope] = (0, block_1.transformScopeBlock)(context, statement.catchClause.block, scope_1.ScopeType.Catch);
35
+ const catchParameter = statement.catchClause.variableDeclaration
36
+ ? (0, identifier_1.transformIdentifier)(context, statement.catchClause.variableDeclaration.name)
37
+ : undefined;
38
+ const catchFunction = lua.createFunctionExpression(catchBlock, catchParameter ? [lua.cloneIdentifier(catchParameter)] : []);
39
+ const catchIdentifier = lua.createIdentifier("____catch");
40
+ result.push(lua.createVariableDeclarationStatement(catchIdentifier, catchFunction));
41
+ const hasReturn = (_a = tryScope.functionReturned) !== null && _a !== void 0 ? _a : catchScope.functionReturned;
29
42
  const tryReturnIdentifiers = [tryResultIdentifier]; // ____try
30
- if (returnedIdentifier) {
31
- tryReturnIdentifiers.push(returnedIdentifier); // ____returned or catch variable
32
- if (tryScope.functionReturned || catchScope.functionReturned) {
43
+ if (hasReturn || statement.catchClause.variableDeclaration) {
44
+ tryReturnIdentifiers.push(returnedIdentifier); // ____returned
45
+ if (hasReturn) {
33
46
  tryReturnIdentifiers.push(returnValueIdentifier); // ____returnValue
34
47
  returnCondition = lua.cloneIdentifier(returnedIdentifier);
35
48
  }
36
49
  }
37
50
  result.push(lua.createVariableDeclarationStatement(tryReturnIdentifiers, tryCall));
38
- if ((tryScope.functionReturned || catchScope.functionReturned) && returnedIdentifier) {
39
- // Wrap catch in function if try or catch has return
40
- const catchCall = lua.createCallExpression(lua.createFunctionExpression(catchBlock), []);
41
- const catchAssign = lua.createAssignmentStatement([lua.cloneIdentifier(returnedIdentifier), lua.cloneIdentifier(returnValueIdentifier)], catchCall);
42
- catchBlock = lua.createBlock([catchAssign]);
43
- }
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);
44
55
  const notTryCondition = lua.createUnaryExpression(tryResultIdentifier, lua.SyntaxKind.NotOperator);
45
- result.push(lua.createIfStatement(notTryCondition, catchBlock));
56
+ result.push(lua.createIfStatement(notTryCondition, lua.createBlock([catchCallStatement])));
46
57
  }
47
58
  else if (tryScope.functionReturned) {
48
59
  // try with return, but no catch
49
- returnedIdentifier = lua.createIdentifier("____returned");
60
+ // returnedIdentifier = lua.createIdentifier("____returned");
50
61
  const returnedVariables = [tryResultIdentifier, returnedIdentifier, returnValueIdentifier];
51
62
  result.push(lua.createVariableDeclarationStatement(returnedVariables, tryCall));
52
63
  // change return condition from '____returned' to '____try and ____returned'
@@ -60,23 +71,14 @@ const transformTryStatement = (statement, context) => {
60
71
  result.push(...context.transformStatements(statement.finallyBlock));
61
72
  }
62
73
  if (returnCondition && returnedIdentifier) {
63
- // With catch clause:
64
- // if ____returned then return ____returnValue end
65
- // No catch clause:
66
- // if ____try and ____returned then return ____returnValue end
67
74
  const returnValues = [];
68
- const parentTryCatch = scope_1.findScope(context, scope_1.ScopeType.Function | scope_1.ScopeType.Try | scope_1.ScopeType.Catch);
69
- if (parentTryCatch && parentTryCatch.type !== scope_1.ScopeType.Function) {
70
- // Nested try/catch needs to prefix a 'true' return value
71
- returnValues.push(lua.createBooleanLiteral(true));
72
- }
73
- if (multi_1.isInMultiReturnFunction(context, statement)) {
74
- returnValues.push(lua_ast_1.createUnpackCall(context, lua.cloneIdentifier(returnValueIdentifier)));
75
+ if ((0, multi_1.isInMultiReturnFunction)(context, statement)) {
76
+ returnValues.push((0, lua_ast_1.createUnpackCall)(context, lua.cloneIdentifier(returnValueIdentifier)));
75
77
  }
76
78
  else {
77
79
  returnValues.push(lua.cloneIdentifier(returnValueIdentifier));
78
80
  }
79
- const returnStatement = lua.createReturnStatement(returnValues);
81
+ const returnStatement = (0, return_1.createReturnStatement)(context, returnValues, statement);
80
82
  const ifReturnedStatement = lua.createIfStatement(returnCondition, lua.createBlock([returnStatement]));
81
83
  result.push(ifReturnedStatement);
82
84
  }
@@ -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[];
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transformOrderedExpressions = exports.transformExpressionList = exports.moveToPrecedingTemp = exports.shouldMoveToTemp = void 0;
4
+ const assert = require("assert");
5
+ const ts = require("typescript");
6
+ const lua = require("../../LuaAST");
7
+ const context_1 = require("../context");
8
+ const lualib_1 = require("../utils/lualib");
9
+ const preceding_statements_1 = require("../utils/preceding-statements");
10
+ const typescript_1 = require("../utils/typescript");
11
+ const optional_chaining_1 = require("./optional-chaining");
12
+ function shouldMoveToTemp(context, expression, tsOriginal) {
13
+ return (!lua.isLiteral(expression) &&
14
+ !(lua.isIdentifier(expression) && expression.symbolId === context_1.tempSymbolId) && // Treat generated temps as consts
15
+ !(tsOriginal && ((0, typescript_1.isConstIdentifier)(context, tsOriginal) || (0, optional_chaining_1.isOptionalContinuation)(tsOriginal))));
16
+ }
17
+ exports.shouldMoveToTemp = shouldMoveToTemp;
18
+ // Cache an expression in a preceding statement and return the temp identifier
19
+ function moveToPrecedingTemp(context, expression, tsOriginal) {
20
+ if (!shouldMoveToTemp(context, expression, tsOriginal)) {
21
+ return expression;
22
+ }
23
+ const tempIdentifier = context.createTempNameForLuaExpression(expression);
24
+ const tempDeclaration = lua.createVariableDeclarationStatement(tempIdentifier, expression, tsOriginal);
25
+ context.addPrecedingStatements(tempDeclaration);
26
+ return lua.cloneIdentifier(tempIdentifier, tsOriginal);
27
+ }
28
+ exports.moveToPrecedingTemp = moveToPrecedingTemp;
29
+ function transformExpressions(context, expressions) {
30
+ const precedingStatements = [];
31
+ const transformedExpressions = [];
32
+ let lastPrecedingStatementsIndex = -1;
33
+ for (let i = 0; i < expressions.length; ++i) {
34
+ const [expressionPrecedingStatements, expression] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => context.transformExpression(expressions[i]));
35
+ transformedExpressions.push(expression);
36
+ if (expressionPrecedingStatements.length > 0) {
37
+ lastPrecedingStatementsIndex = i;
38
+ }
39
+ precedingStatements.push(expressionPrecedingStatements);
40
+ }
41
+ return { transformedExpressions, precedingStatements, lastPrecedingStatementsIndex };
42
+ }
43
+ function transformExpressionsUsingTemps(context, expressions, transformedExpressions, precedingStatements, lastPrecedingStatementsIndex) {
44
+ for (let i = 0; i < transformedExpressions.length; ++i) {
45
+ context.addPrecedingStatements(precedingStatements[i]);
46
+ if (i < lastPrecedingStatementsIndex) {
47
+ transformedExpressions[i] = moveToPrecedingTemp(context, transformedExpressions[i], expressions[i]);
48
+ }
49
+ }
50
+ return transformedExpressions;
51
+ }
52
+ function pushToSparseArray(context, arrayIdentifier, expressions) {
53
+ if (!arrayIdentifier) {
54
+ arrayIdentifier = lua.createIdentifier(context.createTempName("array"));
55
+ const libCall = (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.SparseArrayNew, undefined, ...expressions);
56
+ const declaration = lua.createVariableDeclarationStatement(arrayIdentifier, libCall);
57
+ context.addPrecedingStatements(declaration);
58
+ }
59
+ else {
60
+ const libCall = (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.SparseArrayPush, undefined, arrayIdentifier, ...expressions);
61
+ context.addPrecedingStatements(lua.createExpressionStatement(libCall));
62
+ }
63
+ return arrayIdentifier;
64
+ }
65
+ function transformExpressionsUsingSparseArray(context, expressions, transformedExpressions, precedingStatements) {
66
+ let arrayIdentifier;
67
+ let expressionBatch = [];
68
+ for (let i = 0; i < expressions.length; ++i) {
69
+ // Expressions with preceding statements should always be at the start of a batch
70
+ if (precedingStatements[i].length > 0 && expressionBatch.length > 0) {
71
+ arrayIdentifier = pushToSparseArray(context, arrayIdentifier, expressionBatch);
72
+ expressionBatch = [];
73
+ }
74
+ context.addPrecedingStatements(precedingStatements[i]);
75
+ expressionBatch.push(transformedExpressions[i]);
76
+ // Spread expressions should always be at the end of a batch
77
+ if (ts.isSpreadElement(expressions[i])) {
78
+ arrayIdentifier = pushToSparseArray(context, arrayIdentifier, expressionBatch);
79
+ expressionBatch = [];
80
+ }
81
+ }
82
+ if (expressionBatch.length > 0) {
83
+ arrayIdentifier = pushToSparseArray(context, arrayIdentifier, expressionBatch);
84
+ }
85
+ assert(arrayIdentifier);
86
+ return [(0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.SparseArraySpread, undefined, arrayIdentifier)];
87
+ }
88
+ function countNeededTemps(context, expressions, transformedExpressions, lastPrecedingStatementsIndex) {
89
+ if (lastPrecedingStatementsIndex < 0) {
90
+ return 0;
91
+ }
92
+ return transformedExpressions
93
+ .slice(0, lastPrecedingStatementsIndex)
94
+ .filter((e, i) => shouldMoveToTemp(context, e, expressions[i])).length;
95
+ }
96
+ // Transforms a list of expressions while flattening spreads and maintaining execution order
97
+ function transformExpressionList(context, expressions) {
98
+ const { transformedExpressions, precedingStatements, lastPrecedingStatementsIndex } = transformExpressions(context, expressions);
99
+ // If more than this number of temps are required to preserve execution order, we'll fall back to using the
100
+ // sparse array lib functions instead to prevent excessive locals.
101
+ const maxTemps = 2;
102
+ // Use sparse array lib if there are spreads before the last expression
103
+ // or if too many temps are needed to preserve order
104
+ const lastSpread = expressions.findIndex(e => ts.isSpreadElement(e));
105
+ if ((lastSpread >= 0 && lastSpread < expressions.length - 1) ||
106
+ countNeededTemps(context, expressions, transformedExpressions, lastPrecedingStatementsIndex) > maxTemps) {
107
+ return transformExpressionsUsingSparseArray(context, expressions, transformedExpressions, precedingStatements);
108
+ }
109
+ else {
110
+ return transformExpressionsUsingTemps(context, expressions, transformedExpressions, precedingStatements, lastPrecedingStatementsIndex);
111
+ }
112
+ }
113
+ exports.transformExpressionList = transformExpressionList;
114
+ // Transforms a series of expressions while maintaining execution order
115
+ function transformOrderedExpressions(context, expressions) {
116
+ const { transformedExpressions, precedingStatements, lastPrecedingStatementsIndex } = transformExpressions(context, expressions);
117
+ return transformExpressionsUsingTemps(context, expressions, transformedExpressions, precedingStatements, lastPrecedingStatementsIndex);
118
+ }
119
+ exports.transformOrderedExpressions = transformOrderedExpressions;
120
+ //# sourceMappingURL=expression-list.js.map
@@ -6,19 +6,23 @@ const lua = require("../../LuaAST");
6
6
  const binary_expression_1 = require("./binary-expression");
7
7
  const table_1 = require("./language-extensions/table");
8
8
  const unary_expression_1 = require("./unary-expression");
9
+ const void_1 = require("./void");
9
10
  const transformExpressionStatement = (node, context) => {
10
11
  const expression = node.expression;
11
- if (ts.isCallExpression(expression) && table_1.isTableDeleteCall(context, expression)) {
12
- return table_1.transformTableDeleteExpression(context, expression);
12
+ if (ts.isCallExpression(expression) && (0, table_1.isTableDeleteCall)(context, expression)) {
13
+ return (0, table_1.transformTableDeleteExpression)(context, expression);
13
14
  }
14
- if (ts.isCallExpression(expression) && table_1.isTableSetCall(context, expression)) {
15
- return table_1.transformTableSetExpression(context, expression);
15
+ if (ts.isCallExpression(expression) && (0, table_1.isTableSetCall)(context, expression)) {
16
+ return (0, table_1.transformTableSetExpression)(context, expression);
16
17
  }
17
- const unaryExpressionResult = unary_expression_1.transformUnaryExpressionStatement(context, node);
18
+ if (ts.isVoidExpression(expression)) {
19
+ return (0, void_1.transformVoidExpressionStatement)(expression, context);
20
+ }
21
+ const unaryExpressionResult = (0, unary_expression_1.transformUnaryExpressionStatement)(context, node);
18
22
  if (unaryExpressionResult) {
19
23
  return unaryExpressionResult;
20
24
  }
21
- const binaryExpressionResult = binary_expression_1.transformBinaryExpressionStatement(context, node);
25
+ const binaryExpressionResult = (0, binary_expression_1.transformBinaryExpressionStatement)(context, node);
22
26
  if (binaryExpressionResult) {
23
27
  return binaryExpressionResult;
24
28
  }
@@ -2,6 +2,8 @@ import * as ts from "typescript";
2
2
  import * as lua from "../../LuaAST";
3
3
  import { FunctionVisitor, TransformationContext } from "../context";
4
4
  import { Scope } from "../utils/scope";
5
+ export declare function createCallableTable(functionExpression: lua.Expression): lua.Expression;
6
+ export declare function isFunctionTypeWithProperties(functionType: ts.Type): boolean;
5
7
  export declare function transformFunctionBodyContent(context: TransformationContext, body: ts.ConciseBody): lua.Statement[];
6
8
  export declare function transformFunctionBodyHeader(context: TransformationContext, bodyScope: Scope, parameters: ts.NodeArray<ts.ParameterDeclaration>, spreadIdentifier?: lua.Identifier): lua.Statement[];
7
9
  export declare function transformFunctionBody(context: TransformationContext, parameters: ts.NodeArray<ts.ParameterDeclaration>, body: ts.ConciseBody, spreadIdentifier?: lua.Identifier, node?: ts.FunctionLikeDeclaration): [lua.Statement[], Scope];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.transformYieldExpression = exports.transformFunctionDeclaration = exports.transformFunctionLikeDeclaration = exports.transformFunctionToExpression = exports.transformParameters = exports.transformFunctionBody = exports.transformFunctionBodyHeader = exports.transformFunctionBodyContent = void 0;
3
+ exports.transformYieldExpression = exports.transformFunctionDeclaration = exports.transformFunctionLikeDeclaration = exports.transformFunctionToExpression = exports.transformParameters = exports.transformFunctionBody = exports.transformFunctionBodyHeader = exports.transformFunctionBodyContent = exports.isFunctionTypeWithProperties = exports.createCallableTable = void 0;
4
4
  const ts = require("typescript");
5
5
  const lua = require("../../LuaAST");
6
6
  const utils_1 = require("../../utils");
@@ -8,9 +8,12 @@ const annotations_1 = require("../utils/annotations");
8
8
  const diagnostics_1 = require("../utils/diagnostics");
9
9
  const export_1 = require("../utils/export");
10
10
  const function_context_1 = require("../utils/function-context");
11
+ const language_extensions_1 = require("../utils/language-extensions");
11
12
  const lua_ast_1 = require("../utils/lua-ast");
12
13
  const lualib_1 = require("../utils/lualib");
14
+ const preceding_statements_1 = require("../utils/preceding-statements");
13
15
  const scope_1 = require("../utils/scope");
16
+ const typescript_1 = require("../utils/typescript");
14
17
  const async_await_1 = require("./async-await");
15
18
  const identifier_1 = require("./identifier");
16
19
  const return_1 = require("./return");
@@ -32,12 +35,45 @@ function isRestParameterReferenced(identifier, scope) {
32
35
  const references = scope.referencedSymbols.get(identifier.symbolId);
33
36
  return references !== undefined && references.length > 0;
34
37
  }
38
+ function createCallableTable(functionExpression) {
39
+ var _a;
40
+ // __call metamethod receives the table as the first argument, so we need to add a dummy parameter
41
+ if (lua.isFunctionExpression(functionExpression)) {
42
+ (_a = functionExpression.params) === null || _a === void 0 ? void 0 : _a.unshift(lua.createAnonymousIdentifier());
43
+ }
44
+ else {
45
+ // functionExpression may have been replaced (lib functions, etc...),
46
+ // so we create a forwarding function to eat the extra argument
47
+ functionExpression = lua.createFunctionExpression(lua.createBlock([
48
+ lua.createReturnStatement([lua.createCallExpression(functionExpression, [lua.createDotsLiteral()])]),
49
+ ]), [lua.createAnonymousIdentifier()], lua.createDotsLiteral(), lua.FunctionExpressionFlags.Inline);
50
+ }
51
+ return lua.createCallExpression(lua.createIdentifier("setmetatable"), [
52
+ lua.createTableExpression(),
53
+ lua.createTableExpression([
54
+ lua.createTableFieldExpression(functionExpression, lua.createStringLiteral("__call")),
55
+ ]),
56
+ ]);
57
+ }
58
+ exports.createCallableTable = createCallableTable;
59
+ function isFunctionTypeWithProperties(functionType) {
60
+ if (functionType.isUnion()) {
61
+ return functionType.types.some(isFunctionTypeWithProperties);
62
+ }
63
+ else {
64
+ return ((0, typescript_1.isFunctionType)(functionType) &&
65
+ functionType.getProperties().length > 0 &&
66
+ (0, language_extensions_1.getExtensionKinds)(functionType).length === 0 // ignore TSTL extension functions like $range
67
+ );
68
+ }
69
+ }
70
+ exports.isFunctionTypeWithProperties = isFunctionTypeWithProperties;
35
71
  function transformFunctionBodyContent(context, body) {
36
72
  if (!ts.isBlock(body)) {
37
- const returnStatement = return_1.transformExpressionBodyToReturnStatement(context, body);
38
- return [returnStatement];
73
+ const [precedingStatements, returnStatement] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, return_1.transformExpressionBodyToReturnStatement)(context, body));
74
+ return [...precedingStatements, returnStatement];
39
75
  }
40
- const bodyStatements = scope_1.performHoisting(context, context.transformStatements(body.statements));
76
+ const bodyStatements = (0, scope_1.performHoisting)(context, context.transformStatements(body.statements));
41
77
  return bodyStatements;
42
78
  }
43
79
  exports.transformFunctionBodyContent = transformFunctionBodyContent;
@@ -54,16 +90,18 @@ function transformFunctionBodyHeader(context, bodyScope, parameters, spreadIdent
54
90
  headerStatements.push(transformParameterDefaultValueDeclaration(context, identifier, declaration.initializer));
55
91
  }
56
92
  // Binding pattern
57
- bindingPatternDeclarations.push(...variable_declaration_1.transformBindingPattern(context, declaration.name, identifier));
93
+ const name = declaration.name;
94
+ const [precedingStatements, bindings] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, variable_declaration_1.transformBindingPattern)(context, name, identifier));
95
+ bindingPatternDeclarations.push(...precedingStatements, ...bindings);
58
96
  }
59
97
  else if (declaration.initializer !== undefined) {
60
98
  // Default parameter
61
- headerStatements.push(transformParameterDefaultValueDeclaration(context, identifier_1.transformIdentifier(context, declaration.name), declaration.initializer));
99
+ headerStatements.push(transformParameterDefaultValueDeclaration(context, (0, identifier_1.transformIdentifier)(context, declaration.name), declaration.initializer));
62
100
  }
63
101
  }
64
102
  // Push spread operator here
65
103
  if (spreadIdentifier && isRestParameterReferenced(spreadIdentifier, bodyScope)) {
66
- const spreadTable = lua_ast_1.wrapInTable(lua.createDotsLiteral());
104
+ const spreadTable = (0, lua_ast_1.wrapInTable)(lua.createDotsLiteral());
67
105
  headerStatements.push(lua.createVariableDeclarationStatement(spreadIdentifier, spreadTable));
68
106
  }
69
107
  // Binding pattern statements need to be after spread table is declared
@@ -72,14 +110,14 @@ function transformFunctionBodyHeader(context, bodyScope, parameters, spreadIdent
72
110
  }
73
111
  exports.transformFunctionBodyHeader = transformFunctionBodyHeader;
74
112
  function transformFunctionBody(context, parameters, body, spreadIdentifier, node) {
75
- const scope = scope_1.pushScope(context, scope_1.ScopeType.Function);
113
+ const scope = (0, scope_1.pushScope)(context, scope_1.ScopeType.Function);
76
114
  scope.node = node;
77
115
  let bodyStatements = transformFunctionBodyContent(context, body);
78
- if (node && async_await_1.isAsyncFunction(node)) {
79
- bodyStatements = async_await_1.wrapInAsyncAwaiter(context, bodyStatements);
116
+ if (node && (0, async_await_1.isAsyncFunction)(node)) {
117
+ bodyStatements = (0, async_await_1.wrapInAsyncAwaiter)(context, bodyStatements);
80
118
  }
81
119
  const headerStatements = transformFunctionBodyHeader(context, scope, parameters, spreadIdentifier);
82
- scope_1.popScope(context);
120
+ (0, scope_1.popScope)(context);
83
121
  return [[...headerStatements, ...bodyStatements], scope];
84
122
  }
85
123
  exports.transformFunctionBody = transformFunctionBody;
@@ -101,7 +139,7 @@ function transformParameters(context, parameters, functionContext) {
101
139
  // See transformFunctionBody for how these values are destructured
102
140
  const paramName = ts.isObjectBindingPattern(param.name) || ts.isArrayBindingPattern(param.name)
103
141
  ? lua.createIdentifier(`____bindingPattern${identifierIndex++}`)
104
- : identifier_1.transformIdentifier(context, param.name);
142
+ : (0, identifier_1.transformIdentifier)(context, param.name);
105
143
  // This parameter is a spread parameter (...param)
106
144
  if (!param.dotDotDotToken) {
107
145
  paramNames.push(paramName);
@@ -116,10 +154,10 @@ function transformParameters(context, parameters, functionContext) {
116
154
  }
117
155
  exports.transformParameters = transformParameters;
118
156
  function transformFunctionToExpression(context, node) {
119
- utils_1.assert(node.body);
157
+ (0, utils_1.assert)(node.body);
120
158
  const type = context.checker.getTypeAtLocation(node);
121
159
  let functionContext;
122
- if (function_context_1.getFunctionContextType(context, type) !== function_context_1.ContextType.Void) {
160
+ if ((0, function_context_1.getFunctionContextType)(context, type) !== function_context_1.ContextType.Void) {
123
161
  if (ts.isArrowFunction(node)) {
124
162
  // dummy context for arrow functions with parameters
125
163
  if (node.parameters.length > 0) {
@@ -128,7 +166,7 @@ function transformFunctionToExpression(context, node) {
128
166
  }
129
167
  else {
130
168
  // self context
131
- functionContext = lua_ast_1.createSelfIdentifier();
169
+ functionContext = (0, lua_ast_1.createSelfIdentifier)();
132
170
  }
133
171
  }
134
172
  let flags = lua.FunctionExpressionFlags.None;
@@ -142,7 +180,7 @@ function transformFunctionToExpression(context, node) {
142
180
  const functionExpression = lua.createFunctionExpression(lua.createBlock(transformedBody), paramNames, dotsLiteral, flags, node);
143
181
  return [
144
182
  node.asteriskToken
145
- ? lualib_1.transformLuaLibFunction(context, lualib_1.LuaLibFeature.Generator, undefined, functionExpression)
183
+ ? (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.Generator, undefined, functionExpression)
146
184
  : functionExpression,
147
185
  functionScope,
148
186
  ];
@@ -153,8 +191,8 @@ function transformFunctionLikeDeclaration(node, context) {
153
191
  // This code can be reached only from object methods, which is TypeScript error
154
192
  return lua.createNilLiteral();
155
193
  }
156
- if (annotations_1.getNodeAnnotations(node).has(annotations_1.AnnotationKind.TupleReturn)) {
157
- context.diagnostics.push(diagnostics_1.annotationRemoved(node, annotations_1.AnnotationKind.TupleReturn));
194
+ if ((0, annotations_1.getNodeAnnotations)(node).has(annotations_1.AnnotationKind.TupleReturn)) {
195
+ context.diagnostics.push((0, diagnostics_1.annotationRemoved)(node, annotations_1.AnnotationKind.TupleReturn));
158
196
  }
159
197
  const [functionExpression, functionScope] = transformFunctionToExpression(context, node);
160
198
  // Handle named function expressions which reference themselves
@@ -163,14 +201,19 @@ function transformFunctionLikeDeclaration(node, context) {
163
201
  if (symbol) {
164
202
  // TODO: Not using symbol ids because of https://github.com/microsoft/TypeScript/issues/37131
165
203
  const isReferenced = [...functionScope.referencedSymbols].some(([, nodes]) => nodes.some(n => { var _a; return ((_a = context.checker.getSymbolAtLocation(n)) === null || _a === void 0 ? void 0 : _a.valueDeclaration) === symbol.valueDeclaration; }));
166
- // Only wrap if the name is actually referenced inside the function
204
+ // Only handle if the name is actually referenced inside the function
167
205
  if (isReferenced) {
168
- const nameIdentifier = identifier_1.transformIdentifier(context, node.name);
169
- // We cannot use transformToImmediatelyInvokedFunctionExpression() here because we need to transpile
170
- // the function first to determine if it's self-referencing. Fortunately, this does not cause issues
171
- // with var-arg optimization because the IIFE is just wrapping another function which will already push
172
- // another scope.
173
- return lua_ast_1.createImmediatelyInvokedFunctionExpression([lua.createVariableDeclarationStatement(nameIdentifier, functionExpression)], lua.cloneIdentifier(nameIdentifier));
206
+ const nameIdentifier = (0, identifier_1.transformIdentifier)(context, node.name);
207
+ if (isFunctionTypeWithProperties(context.checker.getTypeAtLocation(node))) {
208
+ context.addPrecedingStatements([
209
+ lua.createVariableDeclarationStatement(nameIdentifier),
210
+ lua.createAssignmentStatement(nameIdentifier, createCallableTable(functionExpression)),
211
+ ]);
212
+ }
213
+ else {
214
+ context.addPrecedingStatements(lua.createVariableDeclarationStatement(nameIdentifier, functionExpression));
215
+ }
216
+ return lua.cloneIdentifier(nameIdentifier);
174
217
  }
175
218
  }
176
219
  }
@@ -179,35 +222,39 @@ function transformFunctionLikeDeclaration(node, context) {
179
222
  exports.transformFunctionLikeDeclaration = transformFunctionLikeDeclaration;
180
223
  const transformFunctionDeclaration = (node, context) => {
181
224
  var _a;
182
- if (annotations_1.getNodeAnnotations(node).has(annotations_1.AnnotationKind.TupleReturn)) {
183
- context.diagnostics.push(diagnostics_1.annotationRemoved(node, annotations_1.AnnotationKind.TupleReturn));
225
+ if ((0, annotations_1.getNodeAnnotations)(node).has(annotations_1.AnnotationKind.TupleReturn)) {
226
+ context.diagnostics.push((0, diagnostics_1.annotationRemoved)(node, annotations_1.AnnotationKind.TupleReturn));
184
227
  }
185
228
  // Don't transform functions without body (overload declarations)
186
229
  if (node.body === undefined) {
187
230
  return undefined;
188
231
  }
189
- if (export_1.hasDefaultExportModifier(node)) {
190
- return lua.createAssignmentStatement(lua.createTableIndexExpression(lua_ast_1.createExportsIdentifier(), export_1.createDefaultExportStringLiteral(node)), transformFunctionLikeDeclaration(node, context));
232
+ if ((0, export_1.hasDefaultExportModifier)(node)) {
233
+ return lua.createAssignmentStatement(lua.createTableIndexExpression((0, lua_ast_1.createExportsIdentifier)(), (0, export_1.createDefaultExportStringLiteral)(node)), transformFunctionLikeDeclaration(node, context));
191
234
  }
192
235
  const [functionExpression, functionScope] = transformFunctionToExpression(context, node);
193
236
  // Name being undefined without default export is a TypeScript error
194
- const name = node.name ? identifier_1.transformIdentifier(context, node.name) : lua.createAnonymousIdentifier();
237
+ const name = node.name ? (0, identifier_1.transformIdentifier)(context, node.name) : lua.createAnonymousIdentifier();
195
238
  // Remember symbols referenced in this function for hoisting later
196
239
  if (name.symbolId !== undefined) {
197
- const scope = scope_1.peekScope(context);
240
+ const scope = (0, scope_1.peekScope)(context);
198
241
  if (!scope.functionDefinitions) {
199
242
  scope.functionDefinitions = new Map();
200
243
  }
201
244
  const functionInfo = { referencedSymbols: (_a = functionScope.referencedSymbols) !== null && _a !== void 0 ? _a : new Map() };
202
245
  scope.functionDefinitions.set(name.symbolId, functionInfo);
203
246
  }
204
- return lua_ast_1.createLocalOrExportedOrGlobalDeclaration(context, name, functionExpression, node);
247
+ // Wrap functions with properties into a callable table
248
+ const wrappedFunction = node.name && isFunctionTypeWithProperties(context.checker.getTypeAtLocation(node.name))
249
+ ? createCallableTable(functionExpression)
250
+ : functionExpression;
251
+ return (0, lua_ast_1.createLocalOrExportedOrGlobalDeclaration)(context, name, wrappedFunction, node);
205
252
  };
206
253
  exports.transformFunctionDeclaration = transformFunctionDeclaration;
207
254
  const transformYieldExpression = (expression, context) => {
208
255
  const parameters = expression.expression ? [context.transformExpression(expression.expression)] : [];
209
256
  return expression.asteriskToken
210
- ? lualib_1.transformLuaLibFunction(context, lualib_1.LuaLibFeature.DelegatedYield, expression, ...parameters)
257
+ ? (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.DelegatedYield, expression, ...parameters)
211
258
  : lua.createCallExpression(lua.createTableIndexExpression(lua.createIdentifier("coroutine"), lua.createStringLiteral("yield")), parameters, expression);
212
259
  };
213
260
  exports.transformYieldExpression = transformYieldExpression;