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
@@ -22,8 +22,7 @@ exports.transformArrayConstructorCall = transformArrayConstructorCall;
22
22
  function transformArrayPrototypeCall(context, node) {
23
23
  const expression = node.expression;
24
24
  const signature = context.checker.getResolvedSignature(node);
25
- const params = (0, call_1.transformArguments)(context, node.arguments, signature);
26
- const caller = context.transformExpression(expression.expression);
25
+ const [caller, params] = (0, call_1.transformCallAndArguments)(context, expression.expression, node.arguments, signature);
27
26
  const expressionName = expression.name.text;
28
27
  switch (expressionName) {
29
28
  case "concat":
@@ -15,8 +15,7 @@ function transformFunctionPrototypeCall(context, node) {
15
15
  context.diagnostics.push((0, diagnostics_1.unsupportedSelfFunctionConversion)(node));
16
16
  }
17
17
  const signature = context.checker.getResolvedSignature(node);
18
- const params = (0, call_1.transformArguments)(context, node.arguments, signature);
19
- const caller = context.transformExpression(expression.expression);
18
+ const [caller, params] = (0, call_1.transformCallAndArguments)(context, expression.expression, node.arguments, signature);
20
19
  const expressionName = expression.name.text;
21
20
  switch (expressionName) {
22
21
  case "apply":
@@ -25,7 +24,7 @@ function transformFunctionPrototypeCall(context, node) {
25
24
  return (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.FunctionBind, node, caller, ...params);
26
25
  case "call":
27
26
  return lua.createCallExpression(caller, params, node);
28
- default:
27
+ case "toString":
29
28
  context.diagnostics.push((0, diagnostics_1.unsupportedProperty)(expression.name, "function", expressionName));
30
29
  }
31
30
  }
@@ -43,7 +42,10 @@ function transformFunctionProperty(context, node) {
43
42
  return contextType === function_context_1.ContextType.NonVoid
44
43
  ? lua.createBinaryExpression(nparams, lua.createNumericLiteral(1), lua.SyntaxKind.SubtractionOperator)
45
44
  : nparams;
46
- default:
45
+ case "arguments":
46
+ case "caller":
47
+ case "displayName":
48
+ case "name":
47
49
  context.diagnostics.push((0, diagnostics_1.unsupportedProperty)(node.name, "function", node.name.text));
48
50
  }
49
51
  }
@@ -2,5 +2,5 @@ import * as ts from "typescript";
2
2
  import * as lua from "../../LuaAST";
3
3
  import { TransformationContext } from "../context";
4
4
  export declare function transformBuiltinPropertyAccessExpression(context: TransformationContext, node: ts.PropertyAccessExpression): lua.Expression | undefined;
5
- export declare function transformBuiltinCallExpression(context: TransformationContext, node: ts.CallExpression): lua.Expression | undefined;
5
+ export declare function transformBuiltinCallExpression(context: TransformationContext, node: ts.CallExpression, isOptionalCall: boolean): lua.Expression | undefined;
6
6
  export declare function transformBuiltinIdentifierExpression(context: TransformationContext, node: ts.Identifier): lua.Expression | undefined;
@@ -19,6 +19,7 @@ const object_1 = require("./object");
19
19
  const promise_1 = require("./promise");
20
20
  const string_1 = require("./string");
21
21
  const symbol_1 = require("./symbol");
22
+ const diagnostics_1 = require("../utils/diagnostics");
22
23
  function transformBuiltinPropertyAccessExpression(context, node) {
23
24
  const ownerType = context.checker.getTypeAtLocation(node.expression);
24
25
  if ((0, typescript_1.isStringType)(context, ownerType)) {
@@ -27,7 +28,7 @@ function transformBuiltinPropertyAccessExpression(context, node) {
27
28
  if ((0, typescript_1.isArrayType)(context, ownerType)) {
28
29
  return (0, array_1.transformArrayProperty)(context, node);
29
30
  }
30
- if ((0, typescript_1.isFunctionType)(context, ownerType)) {
31
+ if ((0, typescript_1.isFunctionType)(ownerType)) {
31
32
  return (0, function_1.transformFunctionProperty)(context, node);
32
33
  }
33
34
  if (ts.isIdentifier(node.expression) && (0, typescript_1.isStandardLibraryType)(context, ownerType, undefined)) {
@@ -40,57 +41,91 @@ function transformBuiltinPropertyAccessExpression(context, node) {
40
41
  }
41
42
  }
42
43
  exports.transformBuiltinPropertyAccessExpression = transformBuiltinPropertyAccessExpression;
43
- function transformBuiltinCallExpression(context, node) {
44
+ function transformBuiltinCallExpression(context, node, isOptionalCall) {
45
+ const unsupportedOptionalCall = () => {
46
+ context.diagnostics.push((0, diagnostics_1.unsupportedBuiltinOptionalCall)(node));
47
+ return lua.createNilLiteral();
48
+ };
44
49
  const expressionType = context.checker.getTypeAtLocation(node.expression);
45
50
  if (ts.isIdentifier(node.expression) && (0, typescript_1.isStandardLibraryType)(context, expressionType, undefined)) {
46
51
  // TODO:
47
52
  (0, new_1.checkForLuaLibType)(context, expressionType);
48
53
  const result = (0, global_1.transformGlobalCall)(context, node);
49
54
  if (result) {
55
+ if (isOptionalCall)
56
+ return unsupportedOptionalCall();
50
57
  return result;
51
58
  }
52
59
  }
53
- if (!ts.isPropertyAccessExpression(node.expression)) {
60
+ const expression = ts.getOriginalNode(node.expression);
61
+ if (!ts.isPropertyAccessExpression(expression)) {
54
62
  return;
55
63
  }
64
+ const isOptionalAccess = expression.questionDotToken;
56
65
  (0, utils_1.assume)(node);
57
66
  // If the function being called is of type owner.func, get the type of owner
58
- const ownerType = context.checker.getTypeAtLocation(node.expression.expression);
67
+ const ownerType = context.checker.getTypeAtLocation(expression.expression);
59
68
  if ((0, typescript_1.isStandardLibraryType)(context, ownerType, undefined)) {
60
69
  const symbol = ownerType.getSymbol();
61
70
  switch (symbol === null || symbol === void 0 ? void 0 : symbol.name) {
62
71
  case "ArrayConstructor":
72
+ if (isOptionalCall || isOptionalAccess)
73
+ return unsupportedOptionalCall();
63
74
  return (0, array_1.transformArrayConstructorCall)(context, node);
64
75
  case "Console":
76
+ if (isOptionalCall || isOptionalAccess)
77
+ return unsupportedOptionalCall();
65
78
  return (0, console_1.transformConsoleCall)(context, node);
66
79
  case "Math":
80
+ if (isOptionalCall || isOptionalAccess)
81
+ return unsupportedOptionalCall();
67
82
  return (0, math_1.transformMathCall)(context, node);
68
83
  case "StringConstructor":
84
+ if (isOptionalCall || isOptionalAccess)
85
+ return unsupportedOptionalCall();
69
86
  return (0, string_1.transformStringConstructorCall)(context, node);
70
87
  case "ObjectConstructor":
88
+ if (isOptionalCall || isOptionalAccess)
89
+ return unsupportedOptionalCall();
71
90
  return (0, object_1.transformObjectConstructorCall)(context, node);
72
91
  case "SymbolConstructor":
92
+ if (isOptionalCall || isOptionalAccess)
93
+ return unsupportedOptionalCall();
73
94
  return (0, symbol_1.transformSymbolConstructorCall)(context, node);
74
95
  case "NumberConstructor":
96
+ if (isOptionalCall || isOptionalAccess)
97
+ return unsupportedOptionalCall();
75
98
  return (0, number_1.transformNumberConstructorCall)(context, node);
76
99
  case "PromiseConstructor":
100
+ if (isOptionalCall || isOptionalAccess)
101
+ return unsupportedOptionalCall();
77
102
  return (0, promise_1.transformPromiseConstructorCall)(context, node);
78
103
  }
79
104
  }
80
105
  if ((0, typescript_1.isStringType)(context, ownerType) && (0, typescript_1.hasStandardLibrarySignature)(context, node)) {
106
+ if (isOptionalCall)
107
+ return unsupportedOptionalCall();
81
108
  return (0, string_1.transformStringPrototypeCall)(context, node);
82
109
  }
83
110
  if ((0, typescript_1.isNumberType)(context, ownerType) && (0, typescript_1.hasStandardLibrarySignature)(context, node)) {
111
+ if (isOptionalCall)
112
+ return unsupportedOptionalCall();
84
113
  return (0, number_1.transformNumberPrototypeCall)(context, node);
85
114
  }
86
115
  if ((0, typescript_1.isArrayType)(context, ownerType) && (0, typescript_1.hasStandardLibrarySignature)(context, node)) {
116
+ if (isOptionalCall)
117
+ return unsupportedOptionalCall();
87
118
  return (0, array_1.transformArrayPrototypeCall)(context, node);
88
119
  }
89
- if ((0, typescript_1.isFunctionType)(context, ownerType) && (0, typescript_1.hasStandardLibrarySignature)(context, node)) {
120
+ if ((0, typescript_1.isFunctionType)(ownerType) && (0, typescript_1.hasStandardLibrarySignature)(context, node)) {
121
+ if (isOptionalCall)
122
+ return unsupportedOptionalCall();
90
123
  return (0, function_1.transformFunctionPrototypeCall)(context, node);
91
124
  }
92
- const objectResult = (0, object_1.transformObjectPrototypeCall)(context, node);
125
+ const objectResult = (0, object_1.transformObjectPrototypeCall)(context, node, expression);
93
126
  if (objectResult) {
127
+ if (isOptionalCall)
128
+ return unsupportedOptionalCall();
94
129
  return objectResult;
95
130
  }
96
131
  }
@@ -1,5 +1,6 @@
1
1
  import * as lua from "../../LuaAST";
2
+ import * as ts from "typescript";
2
3
  import { TransformationContext } from "../context";
3
4
  import { PropertyCallExpression } from "../visitors/call";
4
5
  export declare function transformObjectConstructorCall(context: TransformationContext, expression: PropertyCallExpression): lua.Expression | undefined;
5
- export declare function transformObjectPrototypeCall(context: TransformationContext, node: PropertyCallExpression): lua.Expression | undefined;
6
+ export declare function transformObjectPrototypeCall(context: TransformationContext, node: ts.CallExpression, expression: ts.PropertyAccessExpression): lua.Expression | undefined;
@@ -31,8 +31,7 @@ function transformObjectConstructorCall(context, expression) {
31
31
  }
32
32
  }
33
33
  exports.transformObjectConstructorCall = transformObjectConstructorCall;
34
- function transformObjectPrototypeCall(context, node) {
35
- const expression = node.expression;
34
+ function transformObjectPrototypeCall(context, node, expression) {
36
35
  const signature = context.checker.getResolvedSignature(node);
37
36
  const name = expression.name.text;
38
37
  switch (name) {
@@ -13,8 +13,7 @@ function createStringCall(methodName, tsOriginal, ...params) {
13
13
  function transformStringPrototypeCall(context, node) {
14
14
  const expression = node.expression;
15
15
  const signature = context.checker.getResolvedSignature(node);
16
- const params = (0, call_1.transformArguments)(context, node.arguments, signature);
17
- const caller = context.transformExpression(expression.expression);
16
+ const [caller, params] = (0, call_1.transformCallAndArguments)(context, expression.expression, node.arguments, signature);
18
17
  const expressionName = expression.name.text;
19
18
  switch (expressionName) {
20
19
  case "replace":
@@ -2,6 +2,7 @@ import * as ts from "typescript";
2
2
  import { CompilerOptions, LuaTarget } from "../../CompilerOptions";
3
3
  import * as lua from "../../LuaAST";
4
4
  import { ExpressionLikeNode, StatementLikeNode, VisitorMap } from "./visitors";
5
+ export declare const tempSymbolId: lua.SymbolId;
5
6
  export interface AllAccessorDeclarations {
6
7
  firstAccessor: ts.AccessorDeclaration;
7
8
  secondAccessor: ts.AccessorDeclaration | undefined;
@@ -25,16 +26,27 @@ export declare class TransformationContext {
25
26
  readonly diagnostics: ts.Diagnostic[];
26
27
  readonly checker: DiagnosticsProducingTypeChecker;
27
28
  readonly resolver: EmitResolver;
29
+ readonly precedingStatementsStack: lua.Statement[][];
28
30
  readonly options: CompilerOptions;
29
31
  readonly luaTarget: LuaTarget;
30
32
  readonly isModule: boolean;
31
33
  readonly isStrict: boolean;
32
34
  constructor(program: ts.Program, sourceFile: ts.SourceFile, visitorMap: VisitorMap);
33
35
  private currentNodeVisitors;
36
+ private nextTempId;
34
37
  transformNode(node: ts.Node): lua.Node[];
35
38
  superTransformNode(node: ts.Node): lua.Node[];
36
39
  transformExpression(node: ExpressionLikeNode): lua.Expression;
37
40
  superTransformExpression(node: ExpressionLikeNode): lua.Expression;
38
41
  transformStatements(node: StatementLikeNode | readonly StatementLikeNode[]): lua.Statement[];
39
42
  superTransformStatements(node: StatementLikeNode | readonly StatementLikeNode[]): lua.Statement[];
43
+ pushPrecedingStatements(): void;
44
+ popPrecedingStatements(): lua.Statement[];
45
+ addPrecedingStatements(statements: lua.Statement | lua.Statement[]): void;
46
+ prependPrecedingStatements(statements: lua.Statement | lua.Statement[]): void;
47
+ createTempName(prefix?: string): string;
48
+ private getTempNameForLuaExpression;
49
+ createTempNameForLuaExpression(expression: lua.Expression): lua.Identifier;
50
+ private getTempNameForNode;
51
+ createTempNameForNode(node: ts.Node): lua.Identifier;
40
52
  }
@@ -1,12 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TransformationContext = void 0;
3
+ exports.TransformationContext = exports.tempSymbolId = void 0;
4
4
  const ts = require("typescript");
5
5
  const CompilerOptions_1 = require("../../CompilerOptions");
6
6
  const lua = require("../../LuaAST");
7
7
  const utils_1 = require("../../utils");
8
8
  const diagnostics_1 = require("../utils/diagnostics");
9
9
  const lua_ast_1 = require("../utils/lua-ast");
10
+ const safe_names_1 = require("../utils/safe-names");
11
+ exports.tempSymbolId = -1;
10
12
  class TransformationContext {
11
13
  constructor(program, sourceFile, visitorMap) {
12
14
  var _a, _b, _c;
@@ -15,12 +17,14 @@ class TransformationContext {
15
17
  this.visitorMap = visitorMap;
16
18
  this.diagnostics = [];
17
19
  this.checker = this.program.getDiagnosticsProducingTypeChecker();
20
+ this.precedingStatementsStack = [];
18
21
  this.options = this.program.getCompilerOptions();
19
22
  this.luaTarget = (_a = this.options.luaTarget) !== null && _a !== void 0 ? _a : CompilerOptions_1.LuaTarget.Universal;
20
23
  this.isModule = ts.isExternalModule(this.sourceFile);
21
24
  this.isStrict = ((_b = this.options.alwaysStrict) !== null && _b !== void 0 ? _b : this.options.strict) ||
22
25
  (this.isModule && this.options.target !== undefined && this.options.target >= ts.ScriptTarget.ES2015);
23
26
  this.currentNodeVisitors = [];
27
+ this.nextTempId = 0;
24
28
  // Use `getParseTreeNode` to get original SourceFile node, before it was substituted by custom transformers.
25
29
  // It's required because otherwise `getEmitResolver` won't use cached diagnostics, produced in `emitWorker`
26
30
  // and would try to re-analyze the file, which would fail because of replaced nodes.
@@ -67,10 +71,105 @@ class TransformationContext {
67
71
  return result;
68
72
  }
69
73
  transformStatements(node) {
70
- return (0, utils_1.castArray)(node).flatMap(n => this.transformNode(n));
74
+ return (0, utils_1.castArray)(node).flatMap(n => {
75
+ this.pushPrecedingStatements();
76
+ const statements = this.transformNode(n);
77
+ statements.unshift(...this.popPrecedingStatements());
78
+ return statements;
79
+ });
71
80
  }
72
81
  superTransformStatements(node) {
73
- return (0, utils_1.castArray)(node).flatMap(n => this.superTransformNode(n));
82
+ return (0, utils_1.castArray)(node).flatMap(n => {
83
+ this.pushPrecedingStatements();
84
+ const statements = this.superTransformNode(n);
85
+ statements.unshift(...this.popPrecedingStatements());
86
+ return statements;
87
+ });
88
+ }
89
+ pushPrecedingStatements() {
90
+ this.precedingStatementsStack.push([]);
91
+ }
92
+ popPrecedingStatements() {
93
+ const precedingStatements = this.precedingStatementsStack.pop();
94
+ (0, utils_1.assert)(precedingStatements);
95
+ return precedingStatements;
96
+ }
97
+ addPrecedingStatements(statements) {
98
+ const precedingStatements = this.precedingStatementsStack[this.precedingStatementsStack.length - 1];
99
+ (0, utils_1.assert)(precedingStatements);
100
+ if (!Array.isArray(statements)) {
101
+ statements = [statements];
102
+ }
103
+ precedingStatements.push(...statements);
104
+ }
105
+ prependPrecedingStatements(statements) {
106
+ const precedingStatements = this.precedingStatementsStack[this.precedingStatementsStack.length - 1];
107
+ (0, utils_1.assert)(precedingStatements);
108
+ if (!Array.isArray(statements)) {
109
+ statements = [statements];
110
+ }
111
+ precedingStatements.unshift(...statements);
112
+ }
113
+ createTempName(prefix = "temp") {
114
+ prefix = prefix.replace(/^_*/, ""); // Strip leading underscores because createSafeName will add them again
115
+ return (0, safe_names_1.createSafeName)(`${prefix}_${this.nextTempId++}`);
116
+ }
117
+ getTempNameForLuaExpression(expression) {
118
+ if (lua.isStringLiteral(expression)) {
119
+ return expression.value;
120
+ }
121
+ else if (lua.isNumericLiteral(expression)) {
122
+ return `_${expression.value.toString()}`;
123
+ }
124
+ else if (lua.isIdentifier(expression)) {
125
+ return expression.text;
126
+ }
127
+ else if (lua.isCallExpression(expression)) {
128
+ const name = this.getTempNameForLuaExpression(expression.expression);
129
+ if (name) {
130
+ return `${name}_result`;
131
+ }
132
+ }
133
+ else if (lua.isTableIndexExpression(expression)) {
134
+ const tableName = this.getTempNameForLuaExpression(expression.table);
135
+ const indexName = this.getTempNameForLuaExpression(expression.index);
136
+ if (tableName || indexName) {
137
+ return `${tableName !== null && tableName !== void 0 ? tableName : "table"}_${indexName !== null && indexName !== void 0 ? indexName : "index"}`;
138
+ }
139
+ }
140
+ }
141
+ createTempNameForLuaExpression(expression) {
142
+ const name = this.getTempNameForLuaExpression(expression);
143
+ const identifier = lua.createIdentifier(this.createTempName(name), undefined, exports.tempSymbolId);
144
+ lua.setNodePosition(identifier, lua.getOriginalPos(expression));
145
+ return identifier;
146
+ }
147
+ getTempNameForNode(node) {
148
+ if (ts.isStringLiteral(node) || ts.isIdentifier(node) || ts.isMemberName(node)) {
149
+ return node.text;
150
+ }
151
+ else if (ts.isNumericLiteral(node)) {
152
+ return `_${node.text}`;
153
+ }
154
+ else if (ts.isCallExpression(node)) {
155
+ const name = this.getTempNameForNode(node.expression);
156
+ if (name) {
157
+ return `${name}_result`;
158
+ }
159
+ }
160
+ else if (ts.isElementAccessExpression(node) || ts.isPropertyAccessExpression(node)) {
161
+ const tableName = this.getTempNameForNode(node.expression);
162
+ const indexName = ts.isElementAccessExpression(node)
163
+ ? this.getTempNameForNode(node.argumentExpression)
164
+ : node.name.text;
165
+ if (tableName || indexName) {
166
+ return `${tableName !== null && tableName !== void 0 ? tableName : "table"}_${indexName !== null && indexName !== void 0 ? indexName : "index"}`;
167
+ }
168
+ }
169
+ }
170
+ createTempNameForNode(node) {
171
+ const name = this.getTempNameForNode(node);
172
+ return lua.createIdentifier(this.createTempName(name), node, exports.tempSymbolId);
74
173
  }
75
174
  }
76
175
  exports.TransformationContext = TransformationContext;
@@ -34,6 +34,9 @@ export declare const invalidRangeControlVariable: ((node: ts.Node, ...args: any[
34
34
  export declare const invalidMultiIterableWithoutDestructuring: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
35
35
  code: number;
36
36
  };
37
+ export declare const invalidPairsIterableWithoutDestructuring: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
38
+ code: number;
39
+ };
37
40
  export declare const unsupportedAccessorInObjectLiteral: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
38
41
  code: number;
39
42
  };
@@ -73,12 +76,6 @@ export declare const invalidOperatorMappingUse: ((node: ts.Node, ...args: any[])
73
76
  export declare const invalidTableExtensionUse: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
74
77
  code: number;
75
78
  };
76
- export declare const invalidTableDeleteExpression: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
77
- code: number;
78
- };
79
- export declare const invalidTableSetExpression: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
80
- code: number;
81
- };
82
79
  export declare const annotationRemoved: ((node: ts.Node, kind: AnnotationKind) => ts.Diagnostic) & {
83
80
  code: number;
84
81
  };
@@ -91,3 +88,9 @@ export declare const notAllowedOptionalAssignment: ((node: ts.Node, ...args: any
91
88
  export declare const awaitMustBeInAsyncFunction: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
92
89
  code: number;
93
90
  };
91
+ export declare const unsupportedBuiltinOptionalCall: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
92
+ code: number;
93
+ };
94
+ export declare const unsupportedOptionalCompileMembersOnly: ((node: ts.Node, ...args: any[]) => ts.Diagnostic) & {
95
+ code: number;
96
+ };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.awaitMustBeInAsyncFunction = exports.notAllowedOptionalAssignment = exports.annotationDeprecated = exports.annotationRemoved = exports.invalidTableSetExpression = exports.invalidTableDeleteExpression = exports.invalidTableExtensionUse = exports.invalidOperatorMappingUse = exports.invalidMultiReturnAccess = exports.invalidMultiTypeToEmptyPatternOrArrayLiteral = exports.invalidMultiTypeToNonArrayLiteral = exports.invalidMultiFunctionReturnType = exports.invalidMultiFunctionUse = exports.unsupportedVarDeclaration = exports.invalidAmbientIdentifierName = exports.unsupportedProperty = exports.unsupportedForTarget = exports.unsupportedRightShiftOperator = exports.unsupportedAccessorInObjectLiteral = exports.invalidMultiIterableWithoutDestructuring = exports.invalidRangeControlVariable = exports.invalidVarargUse = exports.invalidRangeUse = exports.annotationInvalidArgumentCount = exports.decoratorInvalidContext = exports.unsupportedOverloadAssignment = exports.unsupportedSelfFunctionConversion = exports.unsupportedNoSelfFunctionConversion = exports.forbiddenForIn = exports.unsupportedNodeKind = void 0;
3
+ exports.unsupportedOptionalCompileMembersOnly = exports.unsupportedBuiltinOptionalCall = exports.awaitMustBeInAsyncFunction = exports.notAllowedOptionalAssignment = exports.annotationDeprecated = exports.annotationRemoved = exports.invalidTableExtensionUse = exports.invalidOperatorMappingUse = exports.invalidMultiReturnAccess = exports.invalidMultiTypeToEmptyPatternOrArrayLiteral = exports.invalidMultiTypeToNonArrayLiteral = exports.invalidMultiFunctionReturnType = exports.invalidMultiFunctionUse = exports.unsupportedVarDeclaration = exports.invalidAmbientIdentifierName = exports.unsupportedProperty = exports.unsupportedForTarget = exports.unsupportedRightShiftOperator = exports.unsupportedAccessorInObjectLiteral = exports.invalidPairsIterableWithoutDestructuring = exports.invalidMultiIterableWithoutDestructuring = exports.invalidRangeControlVariable = exports.invalidVarargUse = exports.invalidRangeUse = exports.annotationInvalidArgumentCount = exports.decoratorInvalidContext = exports.unsupportedOverloadAssignment = exports.unsupportedSelfFunctionConversion = exports.unsupportedNoSelfFunctionConversion = exports.forbiddenForIn = exports.unsupportedNodeKind = void 0;
4
4
  const ts = require("typescript");
5
5
  const CompilerOptions_1 = require("../../CompilerOptions");
6
6
  const utils_1 = require("../../utils");
@@ -36,6 +36,7 @@ exports.invalidRangeUse = createErrorDiagnosticFactory("$range can only be used
36
36
  exports.invalidVarargUse = createErrorDiagnosticFactory("$vararg can only be used in a spread element ('...$vararg') in global scope.");
37
37
  exports.invalidRangeControlVariable = createErrorDiagnosticFactory("For loop using $range must declare a single control variable.");
38
38
  exports.invalidMultiIterableWithoutDestructuring = createErrorDiagnosticFactory("LuaIterable with a LuaMultiReturn return value type must be destructured.");
39
+ exports.invalidPairsIterableWithoutDestructuring = createErrorDiagnosticFactory("LuaPairsIterable type must be destructured in a for...of statement.");
39
40
  exports.unsupportedAccessorInObjectLiteral = createErrorDiagnosticFactory("Accessors in object literal are not supported.");
40
41
  exports.unsupportedRightShiftOperator = createErrorDiagnosticFactory("Right shift operator is not supported for target Lua 5.3. Use `>>>` instead.");
41
42
  const getLuaTargetName = (version) => (version === CompilerOptions_1.LuaTarget.LuaJIT ? "LuaJIT" : `Lua ${version}`);
@@ -50,12 +51,12 @@ exports.invalidMultiTypeToEmptyPatternOrArrayLiteral = createErrorDiagnosticFact
50
51
  exports.invalidMultiReturnAccess = createErrorDiagnosticFactory("The LuaMultiReturn type can only be accessed via an element access expression of a numeric type.");
51
52
  exports.invalidOperatorMappingUse = createErrorDiagnosticFactory("This function must always be directly called and cannot be referred to.");
52
53
  exports.invalidTableExtensionUse = createErrorDiagnosticFactory("This function must be called directly and cannot be referred to.");
53
- exports.invalidTableDeleteExpression = createErrorDiagnosticFactory("Table delete extension can only be called as a stand-alone statement. It cannot be used as an expression in another statement.");
54
- exports.invalidTableSetExpression = createErrorDiagnosticFactory("Table set extension can only be called as a stand-alone statement. It cannot be used as an expression in another statement.");
55
54
  exports.annotationRemoved = createErrorDiagnosticFactory((kind) => `'@${kind}' has been removed and will no longer have any effect.` +
56
55
  `See https://typescripttolua.github.io/docs/advanced/compiler-annotations#${kind.toLowerCase()} for more information.`);
57
56
  exports.annotationDeprecated = createWarningDiagnosticFactory((kind) => `'@${kind}' is deprecated and will be removed in a future update. Please update your code before upgrading to the next release, otherwise your project will no longer compile. ` +
58
57
  `See https://typescripttolua.github.io/docs/advanced/compiler-annotations#${kind.toLowerCase()} for more information.`);
59
58
  exports.notAllowedOptionalAssignment = createErrorDiagnosticFactory("The left-hand side of an assignment expression may not be an optional property access.");
60
59
  exports.awaitMustBeInAsyncFunction = createErrorDiagnosticFactory("Await can only be used inside async functions.");
60
+ exports.unsupportedBuiltinOptionalCall = createErrorDiagnosticFactory("Optional calls are not supported for builtin or language extension functions.");
61
+ exports.unsupportedOptionalCompileMembersOnly = createErrorDiagnosticFactory("Optional calls are not supported on enums marked with @compileMembersOnly.");
61
62
  //# sourceMappingURL=diagnostics.js.map
@@ -2,8 +2,8 @@ import * as ts from "typescript";
2
2
  import * as lua from "../../LuaAST";
3
3
  import { TransformationContext } from "../context";
4
4
  export declare function hasDefaultExportModifier(node: ts.Node): boolean;
5
- export declare const createDefaultExportIdentifier: (original: ts.Node) => lua.Identifier;
6
- export declare const createDefaultExportStringLiteral: (original: ts.Node) => lua.StringLiteral;
5
+ export declare function hasExportModifier(node: ts.Node): boolean;
6
+ export declare const createDefaultExportStringLiteral: (original?: ts.Node | undefined) => lua.StringLiteral;
7
7
  export declare function getExportedSymbolDeclaration(symbol: ts.Symbol): ts.Declaration | undefined;
8
8
  export declare function getSymbolFromIdentifier(context: TransformationContext, identifier: lua.Identifier): ts.Symbol | undefined;
9
9
  export declare function getIdentifierExportScope(context: TransformationContext, identifier: lua.Identifier): ts.SourceFile | ts.ModuleDeclaration | undefined;
@@ -14,3 +14,4 @@ export declare function isSymbolExported(context: TransformationContext, symbol:
14
14
  export declare function isSymbolExportedFromScope(context: TransformationContext, symbol: ts.Symbol, scope: ts.SourceFile | ts.ModuleDeclaration): boolean;
15
15
  export declare function addExportToIdentifier(context: TransformationContext, identifier: lua.Identifier): lua.AssignmentLeftHandSideExpression;
16
16
  export declare function createExportedIdentifier(context: TransformationContext, identifier: lua.Identifier, exportScope?: ts.SourceFile | ts.ModuleDeclaration): lua.AssignmentLeftHandSideExpression;
17
+ export declare function createDefaultExportExpression(node: ts.Node): lua.AssignmentLeftHandSideExpression;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createExportedIdentifier = exports.addExportToIdentifier = exports.isSymbolExportedFromScope = exports.isSymbolExported = exports.getDependenciesOfSymbol = exports.getExportedSymbolsFromScope = exports.getSymbolExportScope = exports.getIdentifierExportScope = exports.getSymbolFromIdentifier = exports.getExportedSymbolDeclaration = exports.createDefaultExportStringLiteral = exports.createDefaultExportIdentifier = exports.hasDefaultExportModifier = void 0;
3
+ exports.createDefaultExportExpression = exports.createExportedIdentifier = exports.addExportToIdentifier = exports.isSymbolExportedFromScope = exports.isSymbolExported = exports.getDependenciesOfSymbol = exports.getExportedSymbolsFromScope = exports.getSymbolExportScope = exports.getIdentifierExportScope = exports.getSymbolFromIdentifier = exports.getExportedSymbolDeclaration = exports.createDefaultExportStringLiteral = exports.hasExportModifier = exports.hasDefaultExportModifier = void 0;
4
4
  const ts = require("typescript");
5
5
  const lua = require("../../LuaAST");
6
6
  const namespace_1 = require("../visitors/namespace");
@@ -12,8 +12,11 @@ function hasDefaultExportModifier(node) {
12
12
  return ((_a = node.modifiers) !== null && _a !== void 0 ? _a : []).some(modifier => modifier.kind === ts.SyntaxKind.DefaultKeyword);
13
13
  }
14
14
  exports.hasDefaultExportModifier = hasDefaultExportModifier;
15
- const createDefaultExportIdentifier = (original) => lua.createIdentifier("default", original);
16
- exports.createDefaultExportIdentifier = createDefaultExportIdentifier;
15
+ function hasExportModifier(node) {
16
+ var _a;
17
+ return ((_a = node.modifiers) !== null && _a !== void 0 ? _a : []).some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword);
18
+ }
19
+ exports.hasExportModifier = hasExportModifier;
17
20
  const createDefaultExportStringLiteral = (original) => lua.createStringLiteral("default", original);
18
21
  exports.createDefaultExportStringLiteral = createDefaultExportStringLiteral;
19
22
  function getExportedSymbolDeclaration(symbol) {
@@ -103,4 +106,8 @@ function createExportedIdentifier(context, identifier, exportScope) {
103
106
  return lua.createTableIndexExpression(exportTable, lua.createStringLiteral(identifier.text));
104
107
  }
105
108
  exports.createExportedIdentifier = createExportedIdentifier;
109
+ function createDefaultExportExpression(node) {
110
+ return lua.createTableIndexExpression((0, lua_ast_1.createExportsIdentifier)(), (0, exports.createDefaultExportStringLiteral)(node), node);
111
+ }
112
+ exports.createDefaultExportExpression = createDefaultExportExpression;
106
113
  //# sourceMappingURL=export.js.map
@@ -6,6 +6,7 @@ export declare enum ExtensionKind {
6
6
  RangeFunction = "RangeFunction",
7
7
  VarargConstant = "VarargConstant",
8
8
  IterableType = "IterableType",
9
+ PairsIterableType = "PairsIterableType",
9
10
  AdditionOperatorType = "AdditionOperatorType",
10
11
  AdditionOperatorMethodType = "AdditionOperatorMethodType",
11
12
  SubtractionOperatorType = "SubtractionOperatorType",
@@ -53,4 +54,5 @@ export declare enum ExtensionKind {
53
54
  TableSetMethodType = "TableSetMethodType"
54
55
  }
55
56
  export declare function isExtensionType(type: ts.Type, extensionKind: ExtensionKind): boolean;
57
+ export declare function getExtensionKinds(type: ts.Type): ExtensionKind[];
56
58
  export declare function isExtensionValue(context: TransformationContext, symbol: ts.Symbol, extensionKind: ExtensionKind): boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isExtensionValue = exports.isExtensionType = exports.ExtensionKind = void 0;
3
+ exports.isExtensionValue = exports.getExtensionKinds = exports.isExtensionType = exports.ExtensionKind = void 0;
4
4
  var ExtensionKind;
5
5
  (function (ExtensionKind) {
6
6
  ExtensionKind["MultiFunction"] = "MultiFunction";
@@ -8,6 +8,7 @@ var ExtensionKind;
8
8
  ExtensionKind["RangeFunction"] = "RangeFunction";
9
9
  ExtensionKind["VarargConstant"] = "VarargConstant";
10
10
  ExtensionKind["IterableType"] = "IterableType";
11
+ ExtensionKind["PairsIterableType"] = "PairsIterableType";
11
12
  ExtensionKind["AdditionOperatorType"] = "AdditionOperatorType";
12
13
  ExtensionKind["AdditionOperatorMethodType"] = "AdditionOperatorMethodType";
13
14
  ExtensionKind["SubtractionOperatorType"] = "SubtractionOperatorType";
@@ -65,6 +66,7 @@ const extensionKindToTypeBrand = {
65
66
  [ExtensionKind.RangeFunction]: "__luaRangeFunctionBrand",
66
67
  [ExtensionKind.VarargConstant]: "__luaVarargConstantBrand",
67
68
  [ExtensionKind.IterableType]: "__luaIterableBrand",
69
+ [ExtensionKind.PairsIterableType]: "__luaPairsIterableBrand",
68
70
  [ExtensionKind.AdditionOperatorType]: "__luaAdditionBrand",
69
71
  [ExtensionKind.AdditionOperatorMethodType]: "__luaAdditionMethodBrand",
70
72
  [ExtensionKind.SubtractionOperatorType]: "__luaSubtractionBrand",
@@ -116,6 +118,10 @@ function isExtensionType(type, extensionKind) {
116
118
  return typeBrand !== undefined && type.getProperty(typeBrand) !== undefined;
117
119
  }
118
120
  exports.isExtensionType = isExtensionType;
121
+ function getExtensionKinds(type) {
122
+ return Object.keys(extensionKindToTypeBrand).filter(e => type.getProperty(extensionKindToTypeBrand[e]) !== undefined);
123
+ }
124
+ exports.getExtensionKinds = getExtensionKinds;
119
125
  function isExtensionValue(context, symbol, extensionKind) {
120
126
  var _a;
121
127
  return (symbol.getName() === extensionKindToValueName[extensionKind] &&
@@ -7,7 +7,6 @@ export declare function createSelfIdentifier(tsOriginal?: ts.Node): lua.Identifi
7
7
  export declare function createExportsIdentifier(): lua.Identifier;
8
8
  export declare function addToNumericExpression(expression: lua.Expression, change: number): lua.Expression;
9
9
  export declare function getNumberLiteralValue(expression?: lua.Expression): number | undefined;
10
- export declare function createImmediatelyInvokedFunctionExpression(statements: lua.Statement[], result: lua.Expression | lua.Expression[], tsOriginal?: ts.Node): lua.CallExpression;
11
10
  export declare function createUnpackCall(context: TransformationContext, expression: lua.Expression, tsOriginal?: ts.Node): lua.Expression;
12
11
  export declare function wrapInTable(...expressions: lua.Expression[]): lua.TableExpression;
13
12
  export declare function wrapInToStringForConcat(expression: lua.Expression): lua.Expression;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createNaN = exports.createLocalOrExportedOrGlobalDeclaration = exports.createHoistableVariableDeclarationStatement = exports.wrapInToStringForConcat = exports.wrapInTable = exports.createUnpackCall = exports.createImmediatelyInvokedFunctionExpression = exports.getNumberLiteralValue = exports.addToNumericExpression = exports.createExportsIdentifier = exports.createSelfIdentifier = exports.unwrapVisitorResult = void 0;
3
+ exports.createNaN = exports.createLocalOrExportedOrGlobalDeclaration = exports.createHoistableVariableDeclarationStatement = exports.wrapInToStringForConcat = exports.wrapInTable = exports.createUnpackCall = exports.getNumberLiteralValue = exports.addToNumericExpression = exports.createExportsIdentifier = exports.createSelfIdentifier = exports.unwrapVisitorResult = void 0;
4
4
  const ts = require("typescript");
5
5
  const CompilerOptions_1 = require("../../CompilerOptions");
6
6
  const lua = require("../../LuaAST");
@@ -55,15 +55,6 @@ function getNumberLiteralValue(expression) {
55
55
  return undefined;
56
56
  }
57
57
  exports.getNumberLiteralValue = getNumberLiteralValue;
58
- // Prefer use of transformToImmediatelyInvokedFunctionExpression to maintain correct scope. If you use this directly,
59
- // ensure you push/pop a function scope appropriately to avoid incorrect vararg optimization.
60
- function createImmediatelyInvokedFunctionExpression(statements, result, tsOriginal) {
61
- const body = [...statements, lua.createReturnStatement((0, utils_1.castArray)(result))];
62
- const flags = statements.length === 0 ? lua.FunctionExpressionFlags.Inline : lua.FunctionExpressionFlags.None;
63
- const iife = lua.createFunctionExpression(lua.createBlock(body), undefined, undefined, flags);
64
- return lua.createCallExpression(iife, [], tsOriginal);
65
- }
66
- exports.createImmediatelyInvokedFunctionExpression = createImmediatelyInvokedFunctionExpression;
67
58
  function createUnpackCall(context, expression, tsOriginal) {
68
59
  if (context.luaTarget === CompilerOptions_1.LuaTarget.Universal) {
69
60
  return (0, lualib_1.transformLuaLibFunction)(context, LuaLib_1.LuaLibFeature.Unpack, tsOriginal, expression);
@@ -93,10 +84,7 @@ function createHoistableVariableDeclarationStatement(context, identifier, initia
93
84
  if (identifier.symbolId !== undefined) {
94
85
  const scope = (0, scope_1.peekScope)(context);
95
86
  (0, utils_1.assert)(scope.type !== scope_1.ScopeType.Switch);
96
- if (!scope.variableDeclarations) {
97
- scope.variableDeclarations = [];
98
- }
99
- scope.variableDeclarations.push(declaration);
87
+ (0, scope_1.addScopeVariableDeclaration)(scope, declaration);
100
88
  }
101
89
  return declaration;
102
90
  }
@@ -131,22 +119,25 @@ function createLocalOrExportedOrGlobalDeclaration(context, lhs, rhs, tsOriginal,
131
119
  const scope = (0, scope_1.peekScope)(context);
132
120
  const isTopLevelVariable = scope.type === scope_1.ScopeType.File;
133
121
  if (context.isModule || !isTopLevelVariable) {
134
- if (!isFunctionDeclaration && hasMultipleReferences(scope, lhs)) {
135
- // Split declaration and assignment of identifiers that reference themselves in their declaration
136
- declaration = lua.createVariableDeclarationStatement(lhs, undefined, tsOriginal);
122
+ const isLuaFunctionExpression = rhs && !Array.isArray(rhs) && lua.isFunctionExpression(rhs);
123
+ const isSafeRecursiveFunctionDeclaration = isFunctionDeclaration && isLuaFunctionExpression;
124
+ if (!isSafeRecursiveFunctionDeclaration && hasMultipleReferences(scope, lhs)) {
125
+ // Split declaration and assignment of identifiers that reference themselves in their declaration.
126
+ // Put declaration above preceding statements in case the identifier is referenced in those.
127
+ const precedingDeclaration = lua.createVariableDeclarationStatement(lhs, undefined, tsOriginal);
128
+ context.prependPrecedingStatements(precedingDeclaration);
137
129
  if (rhs) {
138
130
  assignment = lua.createAssignmentStatement(lhs, rhs, tsOriginal);
139
131
  }
132
+ // Remember local variable declarations for hoisting later
133
+ (0, scope_1.addScopeVariableDeclaration)(scope, precedingDeclaration);
140
134
  }
141
135
  else {
142
136
  declaration = lua.createVariableDeclarationStatement(lhs, rhs, tsOriginal);
143
- }
144
- if (!isFunctionDeclaration) {
145
- // Remember local variable declarations for hoisting later
146
- if (!scope.variableDeclarations) {
147
- scope.variableDeclarations = [];
137
+ if (!isFunctionDeclaration) {
138
+ // Remember local variable declarations for hoisting later
139
+ (0, scope_1.addScopeVariableDeclaration)(scope, declaration);
148
140
  }
149
- scope.variableDeclarations.push(declaration);
150
141
  }
151
142
  }
152
143
  else if (rhs) {
@@ -0,0 +1,3 @@
1
+ import * as lua from "../../LuaAST";
2
+ import { TransformationContext } from "../context";
3
+ export declare function transformInPrecedingStatementScope<TReturn extends lua.Statement | lua.Statement[] | lua.Expression | lua.Expression[]>(context: TransformationContext, transformer: () => TReturn): [lua.Statement[], TReturn];
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transformInPrecedingStatementScope = void 0;
4
+ function transformInPrecedingStatementScope(context, transformer) {
5
+ context.pushPrecedingStatements();
6
+ const statementOrStatements = transformer();
7
+ const precedingStatements = context.popPrecedingStatements();
8
+ return [precedingStatements, statementOrStatements];
9
+ }
10
+ exports.transformInPrecedingStatementScope = transformInPrecedingStatementScope;
11
+ //# sourceMappingURL=preceding-statements.js.map