typescript-to-lua 1.2.0 → 1.3.3

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 (51) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/LuaLib.d.ts +1 -0
  3. package/dist/LuaLib.js +2 -1
  4. package/dist/LuaPrinter.js +4 -4
  5. package/dist/lualib/Await.lua +7 -3
  6. package/dist/lualib/CloneDescriptor.lua +6 -6
  7. package/dist/lualib/MathSign.lua +8 -0
  8. package/dist/lualib/Promise.lua +10 -2
  9. package/dist/lualib/lualib_bundle.lua +226 -205
  10. package/dist/transformation/builtins/function.js +5 -2
  11. package/dist/transformation/builtins/index.js +9 -7
  12. package/dist/transformation/builtins/math.js +7 -1
  13. package/dist/transformation/utils/diagnostics.d.ts +3 -6
  14. package/dist/transformation/utils/diagnostics.js +2 -3
  15. package/dist/transformation/utils/language-extensions.d.ts +2 -0
  16. package/dist/transformation/utils/language-extensions.js +7 -1
  17. package/dist/transformation/utils/lua-ast.js +5 -5
  18. package/dist/transformation/utils/safe-names.d.ts +4 -2
  19. package/dist/transformation/utils/safe-names.js +11 -5
  20. package/dist/transformation/utils/scope.d.ts +2 -1
  21. package/dist/transformation/utils/scope.js +1 -0
  22. package/dist/transformation/utils/typescript/types.d.ts +3 -1
  23. package/dist/transformation/utils/typescript/types.js +40 -13
  24. package/dist/transformation/visitors/binary-expression/index.js +1 -3
  25. package/dist/transformation/visitors/call.js +7 -40
  26. package/dist/transformation/visitors/class/index.js +1 -1
  27. package/dist/transformation/visitors/class/members/fields.js +12 -8
  28. package/dist/transformation/visitors/conditional.js +2 -23
  29. package/dist/transformation/visitors/errors.js +11 -9
  30. package/dist/transformation/visitors/expression-statement.d.ts +3 -1
  31. package/dist/transformation/visitors/expression-statement.js +21 -19
  32. package/dist/transformation/visitors/function.d.ts +2 -0
  33. package/dist/transformation/visitors/function.js +58 -6
  34. package/dist/transformation/visitors/identifier.js +2 -1
  35. package/dist/transformation/visitors/language-extensions/index.d.ts +4 -0
  36. package/dist/transformation/visitors/language-extensions/index.js +17 -0
  37. package/dist/transformation/visitors/language-extensions/operators.d.ts +1 -1
  38. package/dist/transformation/visitors/language-extensions/operators.js +7 -2
  39. package/dist/transformation/visitors/language-extensions/pairsIterable.d.ts +5 -0
  40. package/dist/transformation/visitors/language-extensions/pairsIterable.js +53 -0
  41. package/dist/transformation/visitors/language-extensions/table.d.ts +1 -8
  42. package/dist/transformation/visitors/language-extensions/table.js +55 -53
  43. package/dist/transformation/visitors/loops/for-of.js +4 -0
  44. package/dist/transformation/visitors/loops/utils.js +6 -1
  45. package/dist/transformation/visitors/namespace.js +1 -1
  46. package/dist/transformation/visitors/spread.js +14 -7
  47. package/dist/transformation/visitors/variable-declaration.js +16 -1
  48. package/dist/transformation/visitors/void.d.ts +1 -4
  49. package/dist/transformation/visitors/void.js +6 -8
  50. package/language-extensions/index.d.ts +11 -1
  51. package/package.json +1 -1
@@ -1,23 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.transformExpressionStatement = void 0;
4
- const ts = require("typescript");
3
+ exports.transformExpressionToStatement = exports.transformExpressionStatement = void 0;
5
4
  const lua = require("../../LuaAST");
5
+ const context_1 = require("../context");
6
6
  const binary_expression_1 = require("./binary-expression");
7
- const table_1 = require("./language-extensions/table");
8
7
  const unary_expression_1 = require("./unary-expression");
9
- const void_1 = require("./void");
10
8
  const transformExpressionStatement = (node, context) => {
11
- const expression = node.expression;
12
- if (ts.isCallExpression(expression) && (0, table_1.isTableDeleteCall)(context, expression)) {
13
- return (0, table_1.transformTableDeleteExpression)(context, expression);
14
- }
15
- if (ts.isCallExpression(expression) && (0, table_1.isTableSetCall)(context, expression)) {
16
- return (0, table_1.transformTableSetExpression)(context, expression);
17
- }
18
- if (ts.isVoidExpression(expression)) {
19
- return (0, void_1.transformVoidExpressionStatement)(expression, context);
20
- }
21
9
  const unaryExpressionResult = (0, unary_expression_1.transformUnaryExpressionStatement)(context, node);
22
10
  if (unaryExpressionResult) {
23
11
  return unaryExpressionResult;
@@ -26,11 +14,25 @@ const transformExpressionStatement = (node, context) => {
26
14
  if (binaryExpressionResult) {
27
15
  return binaryExpressionResult;
28
16
  }
29
- const result = context.transformExpression(expression);
30
- return lua.isCallExpression(result) || lua.isMethodCallExpression(result)
31
- ? lua.createExpressionStatement(result)
32
- : // Assign expression statements to dummy to make sure they're legal Lua
33
- lua.createVariableDeclarationStatement(lua.createAnonymousIdentifier(), result);
17
+ return transformExpressionToStatement(context, node.expression);
34
18
  };
35
19
  exports.transformExpressionStatement = transformExpressionStatement;
20
+ function transformExpressionToStatement(context, expression) {
21
+ const result = context.transformExpression(expression);
22
+ const isTempVariable = lua.isIdentifier(result) && result.symbolId === context_1.tempSymbolId;
23
+ if (isTempVariable) {
24
+ return undefined;
25
+ }
26
+ // "synthetic": no side effects and no original source
27
+ const isSyntheticExpression = (lua.isIdentifier(result) || lua.isLiteral(result)) && result.line === undefined;
28
+ if (isSyntheticExpression) {
29
+ return undefined;
30
+ }
31
+ if (lua.isCallExpression(result) || lua.isMethodCallExpression(result)) {
32
+ return lua.createExpressionStatement(result);
33
+ }
34
+ // Assign expression statements to dummy to make sure they're legal Lua
35
+ return lua.createVariableDeclarationStatement(lua.createAnonymousIdentifier(), result);
36
+ }
37
+ exports.transformExpressionToStatement = transformExpressionToStatement;
36
38
  //# sourceMappingURL=expression-statement.js.map
@@ -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,10 +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");
13
14
  const preceding_statements_1 = require("../utils/preceding-statements");
14
15
  const scope_1 = require("../utils/scope");
16
+ const typescript_1 = require("../utils/typescript");
15
17
  const async_await_1 = require("./async-await");
16
18
  const identifier_1 = require("./identifier");
17
19
  const return_1 = require("./return");
@@ -33,6 +35,39 @@ function isRestParameterReferenced(identifier, scope) {
33
35
  const references = scope.referencedSymbols.get(identifier.symbolId);
34
36
  return references !== undefined && references.length > 0;
35
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;
36
71
  function transformFunctionBodyContent(context, body) {
37
72
  if (!ts.isBlock(body)) {
38
73
  const [precedingStatements, returnStatement] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, return_1.transformExpressionBodyToReturnStatement)(context, body));
@@ -55,7 +90,9 @@ function transformFunctionBodyHeader(context, bodyScope, parameters, spreadIdent
55
90
  headerStatements.push(transformParameterDefaultValueDeclaration(context, identifier, declaration.initializer));
56
91
  }
57
92
  // Binding pattern
58
- bindingPatternDeclarations.push(...(0, 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);
59
96
  }
60
97
  else if (declaration.initializer !== undefined) {
61
98
  // Default parameter
@@ -158,8 +195,9 @@ function transformFunctionLikeDeclaration(node, context) {
158
195
  context.diagnostics.push((0, diagnostics_1.annotationRemoved)(node, annotations_1.AnnotationKind.TupleReturn));
159
196
  }
160
197
  const [functionExpression, functionScope] = transformFunctionToExpression(context, node);
198
+ const isNamedFunctionExpression = ts.isFunctionExpression(node) && node.name;
161
199
  // Handle named function expressions which reference themselves
162
- if (ts.isFunctionExpression(node) && node.name && functionScope.referencedSymbols) {
200
+ if (isNamedFunctionExpression && functionScope.referencedSymbols) {
163
201
  const symbol = context.checker.getSymbolAtLocation(node.name);
164
202
  if (symbol) {
165
203
  // TODO: Not using symbol ids because of https://github.com/microsoft/TypeScript/issues/37131
@@ -167,12 +205,22 @@ function transformFunctionLikeDeclaration(node, context) {
167
205
  // Only handle if the name is actually referenced inside the function
168
206
  if (isReferenced) {
169
207
  const nameIdentifier = (0, identifier_1.transformIdentifier)(context, node.name);
170
- context.addPrecedingStatements(lua.createVariableDeclarationStatement(nameIdentifier, functionExpression));
208
+ if (isFunctionTypeWithProperties(context.checker.getTypeAtLocation(node))) {
209
+ context.addPrecedingStatements([
210
+ lua.createVariableDeclarationStatement(nameIdentifier),
211
+ lua.createAssignmentStatement(nameIdentifier, createCallableTable(functionExpression)),
212
+ ]);
213
+ }
214
+ else {
215
+ context.addPrecedingStatements(lua.createVariableDeclarationStatement(nameIdentifier, functionExpression));
216
+ }
171
217
  return lua.cloneIdentifier(nameIdentifier);
172
218
  }
173
219
  }
174
220
  }
175
- return functionExpression;
221
+ return isNamedFunctionExpression && isFunctionTypeWithProperties(context.checker.getTypeAtLocation(node))
222
+ ? createCallableTable(functionExpression)
223
+ : functionExpression;
176
224
  }
177
225
  exports.transformFunctionLikeDeclaration = transformFunctionLikeDeclaration;
178
226
  const transformFunctionDeclaration = (node, context) => {
@@ -199,7 +247,11 @@ const transformFunctionDeclaration = (node, context) => {
199
247
  const functionInfo = { referencedSymbols: (_a = functionScope.referencedSymbols) !== null && _a !== void 0 ? _a : new Map() };
200
248
  scope.functionDefinitions.set(name.symbolId, functionInfo);
201
249
  }
202
- return (0, lua_ast_1.createLocalOrExportedOrGlobalDeclaration)(context, name, functionExpression, node);
250
+ // Wrap functions with properties into a callable table
251
+ const wrappedFunction = node.name && isFunctionTypeWithProperties(context.checker.getTypeAtLocation(node.name))
252
+ ? createCallableTable(functionExpression)
253
+ : functionExpression;
254
+ return (0, lua_ast_1.createLocalOrExportedOrGlobalDeclaration)(context, name, wrappedFunction, node);
203
255
  };
204
256
  exports.transformFunctionDeclaration = transformFunctionDeclaration;
205
257
  const transformYieldExpression = (expression, context) => {
@@ -5,6 +5,7 @@ const ts = require("typescript");
5
5
  const lua = require("../../LuaAST");
6
6
  const builtins_1 = require("../builtins");
7
7
  const promise_1 = require("../builtins/promise");
8
+ const context_1 = require("../context");
8
9
  const annotations_1 = require("../utils/annotations");
9
10
  const diagnostics_1 = require("../utils/diagnostics");
10
11
  const export_1 = require("../utils/export");
@@ -19,7 +20,7 @@ const vararg_1 = require("./language-extensions/vararg");
19
20
  const optional_chaining_1 = require("./optional-chaining");
20
21
  function transformIdentifier(context, identifier) {
21
22
  if ((0, optional_chaining_1.isOptionalContinuation)(identifier)) {
22
- return lua.createIdentifier(identifier.text);
23
+ return lua.createIdentifier(identifier.text, undefined, context_1.tempSymbolId);
23
24
  }
24
25
  if ((0, multi_1.isMultiFunctionNode)(context, identifier)) {
25
26
  context.diagnostics.push((0, diagnostics_1.invalidMultiFunctionUse)(identifier));
@@ -0,0 +1,4 @@
1
+ import { TransformationContext } from "../../context";
2
+ import * as ts from "typescript";
3
+ import * as lua from "../../../LuaAST";
4
+ export declare function transformLanguageExtensionCallExpression(context: TransformationContext, node: ts.CallExpression, isOptionalCall: boolean): lua.Expression | undefined;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transformLanguageExtensionCallExpression = void 0;
4
+ const operators_1 = require("./operators");
5
+ const table_1 = require("./table");
6
+ function transformLanguageExtensionCallExpression(context, node, isOptionalCall) {
7
+ const operatorMapping = (0, operators_1.transformOperatorMappingExpression)(context, node, isOptionalCall);
8
+ if (operatorMapping) {
9
+ return operatorMapping;
10
+ }
11
+ const tableCall = (0, table_1.transformTableExtensionCall)(context, node, isOptionalCall);
12
+ if (tableCall) {
13
+ return tableCall;
14
+ }
15
+ }
16
+ exports.transformLanguageExtensionCallExpression = transformLanguageExtensionCallExpression;
17
+ //# sourceMappingURL=index.js.map
@@ -2,4 +2,4 @@ import * as ts from "typescript";
2
2
  import * as lua from "../../../LuaAST";
3
3
  import { TransformationContext } from "../../context";
4
4
  export declare function isOperatorMapping(context: TransformationContext, node: ts.CallExpression | ts.Identifier): boolean;
5
- export declare function transformOperatorMappingExpression(context: TransformationContext, node: ts.CallExpression): lua.Expression;
5
+ export declare function transformOperatorMappingExpression(context: TransformationContext, node: ts.CallExpression, isOptionalCall: boolean): lua.Expression | undefined;
@@ -77,9 +77,14 @@ function isOperatorMapping(context, node) {
77
77
  }
78
78
  }
79
79
  exports.isOperatorMapping = isOperatorMapping;
80
- function transformOperatorMappingExpression(context, node) {
80
+ function transformOperatorMappingExpression(context, node, isOptionalCall) {
81
81
  const extensionKind = getOperatorMapExtensionKindForCall(context, node);
82
- (0, utils_1.assert)(extensionKind);
82
+ if (!extensionKind)
83
+ return undefined;
84
+ if (isOptionalCall) {
85
+ context.diagnostics.push((0, diagnostics_1.unsupportedBuiltinOptionalCall)(node));
86
+ return lua.createNilLiteral();
87
+ }
83
88
  const isBefore53 = context.luaTarget === CompilerOptions_1.LuaTarget.Lua51 ||
84
89
  context.luaTarget === CompilerOptions_1.LuaTarget.Lua52 ||
85
90
  context.luaTarget === CompilerOptions_1.LuaTarget.LuaJIT ||
@@ -0,0 +1,5 @@
1
+ import * as ts from "typescript";
2
+ import * as lua from "../../../LuaAST";
3
+ import { TransformationContext } from "../../context";
4
+ export declare function isPairsIterableExpression(context: TransformationContext, expression: ts.Expression): boolean;
5
+ export declare function transformForOfPairsIterableStatement(context: TransformationContext, statement: ts.ForOfStatement, block: lua.Block): lua.Statement;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transformForOfPairsIterableStatement = exports.isPairsIterableExpression = void 0;
4
+ const ts = require("typescript");
5
+ const lua = require("../../../LuaAST");
6
+ const utils_1 = require("../../../utils");
7
+ const diagnostics_1 = require("../../utils/diagnostics");
8
+ const extensions = require("../../utils/language-extensions");
9
+ const utils_2 = require("../loops/utils");
10
+ const variable_declaration_1 = require("../variable-declaration");
11
+ function isPairsIterableType(type) {
12
+ return extensions.isExtensionType(type, extensions.ExtensionKind.PairsIterableType);
13
+ }
14
+ function isPairsIterableExpression(context, expression) {
15
+ const type = context.checker.getTypeAtLocation(expression);
16
+ return isPairsIterableType(type);
17
+ }
18
+ exports.isPairsIterableExpression = isPairsIterableExpression;
19
+ function transformForOfPairsIterableStatement(context, statement, block) {
20
+ const pairsCall = lua.createCallExpression(lua.createIdentifier("pairs"), [
21
+ context.transformExpression(statement.expression),
22
+ ]);
23
+ let identifiers = [];
24
+ if (ts.isVariableDeclarationList(statement.initializer)) {
25
+ // Variables declared in for loop
26
+ // for key, value in iterable do
27
+ const binding = (0, utils_2.getVariableDeclarationBinding)(context, statement.initializer);
28
+ if (ts.isArrayBindingPattern(binding)) {
29
+ identifiers = binding.elements.map(e => (0, variable_declaration_1.transformArrayBindingElement)(context, e));
30
+ }
31
+ else {
32
+ context.diagnostics.push((0, diagnostics_1.invalidPairsIterableWithoutDestructuring)(binding));
33
+ }
34
+ }
35
+ else if (ts.isArrayLiteralExpression(statement.initializer)) {
36
+ // Variables NOT declared in for loop - catch iterator values in temps and assign
37
+ // for ____key, ____value in iterable do
38
+ // key, value = ____key, ____value
39
+ identifiers = statement.initializer.elements.map(e => context.createTempNameForNode(e));
40
+ if (identifiers.length > 0) {
41
+ block.statements.unshift(lua.createAssignmentStatement(statement.initializer.elements.map(e => (0, utils_1.cast)(context.transformExpression(e), lua.isAssignmentLeftHandSideExpression)), identifiers));
42
+ }
43
+ }
44
+ else {
45
+ context.diagnostics.push((0, diagnostics_1.invalidPairsIterableWithoutDestructuring)(statement.initializer));
46
+ }
47
+ if (identifiers.length === 0) {
48
+ identifiers.push(lua.createAnonymousIdentifier());
49
+ }
50
+ return lua.createForInStatement(block, identifiers, [pairsCall], statement);
51
+ }
52
+ exports.transformForOfPairsIterableStatement = transformForOfPairsIterableStatement;
53
+ //# sourceMappingURL=pairsIterable.js.map
@@ -2,12 +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 isTableExtensionIdentifier(context: TransformationContext, node: ts.Identifier): boolean;
5
- export declare function isTableDeleteCall(context: TransformationContext, node: ts.CallExpression): boolean;
6
- export declare function isTableGetCall(context: TransformationContext, node: ts.CallExpression): boolean;
7
- export declare function isTableHasCall(context: TransformationContext, node: ts.CallExpression): boolean;
8
- export declare function isTableSetCall(context: TransformationContext, node: ts.CallExpression): boolean;
9
5
  export declare function isTableNewCall(context: TransformationContext, node: ts.NewExpression): boolean;
10
- export declare function transformTableDeleteExpression(context: TransformationContext, node: ts.CallExpression): lua.Statement;
11
- export declare function transformTableGetExpression(context: TransformationContext, node: ts.CallExpression): lua.Expression;
12
- export declare function transformTableHasExpression(context: TransformationContext, node: ts.CallExpression): lua.Expression;
13
- export declare function transformTableSetExpression(context: TransformationContext, node: ts.CallExpression): lua.Statement;
6
+ export declare function transformTableExtensionCall(context: TransformationContext, node: ts.CallExpression, isOptionalCall: boolean): lua.Expression | undefined;
@@ -1,25 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.transformTableSetExpression = exports.transformTableHasExpression = exports.transformTableGetExpression = exports.transformTableDeleteExpression = exports.isTableNewCall = exports.isTableSetCall = exports.isTableHasCall = exports.isTableGetCall = exports.isTableDeleteCall = exports.isTableExtensionIdentifier = void 0;
3
+ exports.transformTableExtensionCall = exports.isTableNewCall = exports.isTableExtensionIdentifier = void 0;
4
4
  const ts = require("typescript");
5
5
  const lua = require("../../../LuaAST");
6
6
  const extensions = require("../../utils/language-extensions");
7
7
  const typescript_1 = require("../../utils/typescript");
8
- const utils_1 = require("../../../utils");
9
- const tableDeleteExtensions = [
8
+ const expression_list_1 = require("../expression-list");
9
+ const diagnostics_1 = require("../../utils/diagnostics");
10
+ const tableCallExtensions = [
10
11
  extensions.ExtensionKind.TableDeleteType,
11
12
  extensions.ExtensionKind.TableDeleteMethodType,
13
+ extensions.ExtensionKind.TableGetType,
14
+ extensions.ExtensionKind.TableGetMethodType,
15
+ extensions.ExtensionKind.TableHasType,
16
+ extensions.ExtensionKind.TableHasMethodType,
17
+ extensions.ExtensionKind.TableSetType,
18
+ extensions.ExtensionKind.TableSetMethodType,
12
19
  ];
13
- const tableGetExtensions = [extensions.ExtensionKind.TableGetType, extensions.ExtensionKind.TableGetMethodType];
14
- const tableHasExtensions = [extensions.ExtensionKind.TableHasType, extensions.ExtensionKind.TableHasMethodType];
15
- const tableSetExtensions = [extensions.ExtensionKind.TableSetType, extensions.ExtensionKind.TableSetMethodType];
16
- const tableExtensions = [
17
- extensions.ExtensionKind.TableNewType,
18
- ...tableDeleteExtensions,
19
- ...tableGetExtensions,
20
- ...tableHasExtensions,
21
- ...tableSetExtensions,
22
- ];
20
+ const tableExtensions = [extensions.ExtensionKind.TableNewType, ...tableCallExtensions];
23
21
  function getTableExtensionKindForCall(context, node, validExtensions) {
24
22
  const type = (0, typescript_1.getFunctionTypeForCall)(context, node);
25
23
  return type && validExtensions.find(extensionKind => extensions.isExtensionType(type, extensionKind));
@@ -29,79 +27,83 @@ function isTableExtensionIdentifier(context, node) {
29
27
  return tableExtensions.some(extensionKind => extensions.isExtensionType(type, extensionKind));
30
28
  }
31
29
  exports.isTableExtensionIdentifier = isTableExtensionIdentifier;
32
- function isTableDeleteCall(context, node) {
33
- return getTableExtensionKindForCall(context, node, tableDeleteExtensions) !== undefined;
34
- }
35
- exports.isTableDeleteCall = isTableDeleteCall;
36
- function isTableGetCall(context, node) {
37
- return getTableExtensionKindForCall(context, node, tableGetExtensions) !== undefined;
38
- }
39
- exports.isTableGetCall = isTableGetCall;
40
- function isTableHasCall(context, node) {
41
- return getTableExtensionKindForCall(context, node, tableHasExtensions) !== undefined;
42
- }
43
- exports.isTableHasCall = isTableHasCall;
44
- function isTableSetCall(context, node) {
45
- return getTableExtensionKindForCall(context, node, tableSetExtensions) !== undefined;
46
- }
47
- exports.isTableSetCall = isTableSetCall;
48
30
  function isTableNewCall(context, node) {
49
31
  const type = context.checker.getTypeAtLocation(node.expression);
50
32
  return extensions.isExtensionType(type, extensions.ExtensionKind.TableNewType);
51
33
  }
52
34
  exports.isTableNewCall = isTableNewCall;
53
- function transformTableDeleteExpression(context, node) {
54
- const extensionKind = getTableExtensionKindForCall(context, node, tableDeleteExtensions);
55
- (0, utils_1.assert)(extensionKind);
35
+ function transformTableExtensionCall(context, node, isOptionalCall) {
36
+ const extensionType = getTableExtensionKindForCall(context, node, tableCallExtensions);
37
+ if (!extensionType)
38
+ return;
39
+ if (isOptionalCall) {
40
+ context.diagnostics.push((0, diagnostics_1.unsupportedBuiltinOptionalCall)(node));
41
+ return lua.createNilLiteral();
42
+ }
43
+ if (extensionType === extensions.ExtensionKind.TableDeleteType ||
44
+ extensionType === extensions.ExtensionKind.TableDeleteMethodType) {
45
+ return transformTableDeleteExpression(context, node, extensionType);
46
+ }
47
+ if (extensionType === extensions.ExtensionKind.TableGetType ||
48
+ extensionType === extensions.ExtensionKind.TableGetMethodType) {
49
+ return transformTableGetExpression(context, node, extensionType);
50
+ }
51
+ if (extensionType === extensions.ExtensionKind.TableHasType ||
52
+ extensionType === extensions.ExtensionKind.TableHasMethodType) {
53
+ return transformTableHasExpression(context, node, extensionType);
54
+ }
55
+ if (extensionType === extensions.ExtensionKind.TableSetType ||
56
+ extensionType === extensions.ExtensionKind.TableSetMethodType) {
57
+ return transformTableSetExpression(context, node, extensionType);
58
+ }
59
+ }
60
+ exports.transformTableExtensionCall = transformTableExtensionCall;
61
+ function transformTableDeleteExpression(context, node, extensionKind) {
56
62
  const args = node.arguments.slice();
57
- if (args.length === 1 &&
63
+ if (extensionKind === extensions.ExtensionKind.TableDeleteMethodType &&
58
64
  (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression))) {
59
65
  // In case of method (no table argument), push method owner to front of args list
60
66
  args.unshift(node.expression.expression);
61
67
  }
62
68
  // arg0[arg1] = nil
63
- return lua.createAssignmentStatement(lua.createTableIndexExpression(context.transformExpression(args[0]), context.transformExpression(args[1])), lua.createNilLiteral(), node);
69
+ const [table, accessExpression] = (0, expression_list_1.transformExpressionList)(context, args);
70
+ context.addPrecedingStatements(lua.createAssignmentStatement(lua.createTableIndexExpression(table, accessExpression), lua.createNilLiteral(), node));
71
+ return lua.createBooleanLiteral(true);
64
72
  }
65
- exports.transformTableDeleteExpression = transformTableDeleteExpression;
66
- function transformTableGetExpression(context, node) {
67
- const extensionKind = getTableExtensionKindForCall(context, node, tableGetExtensions);
68
- (0, utils_1.assert)(extensionKind);
73
+ function transformTableGetExpression(context, node, extensionKind) {
69
74
  const args = node.arguments.slice();
70
- if (args.length === 1 &&
75
+ if (extensionKind === extensions.ExtensionKind.TableGetMethodType &&
71
76
  (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression))) {
72
77
  // In case of method (no table argument), push method owner to front of args list
73
78
  args.unshift(node.expression.expression);
74
79
  }
80
+ const [table, accessExpression] = (0, expression_list_1.transformExpressionList)(context, args);
75
81
  // arg0[arg1]
76
- return lua.createTableIndexExpression(context.transformExpression(args[0]), context.transformExpression(args[1]), node);
82
+ return lua.createTableIndexExpression(table, accessExpression, node);
77
83
  }
78
- exports.transformTableGetExpression = transformTableGetExpression;
79
- function transformTableHasExpression(context, node) {
80
- const extensionKind = getTableExtensionKindForCall(context, node, tableHasExtensions);
81
- (0, utils_1.assert)(extensionKind);
84
+ function transformTableHasExpression(context, node, extensionKind) {
82
85
  const args = node.arguments.slice();
83
- if (args.length === 1 &&
86
+ if (extensionKind === extensions.ExtensionKind.TableHasMethodType &&
84
87
  (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression))) {
85
88
  // In case of method (no table argument), push method owner to front of args list
86
89
  args.unshift(node.expression.expression);
87
90
  }
88
91
  // arg0[arg1]
89
- const tableIndexExpression = lua.createTableIndexExpression(context.transformExpression(args[0]), context.transformExpression(args[1]));
92
+ const [table, accessExpression] = (0, expression_list_1.transformExpressionList)(context, args);
93
+ const tableIndexExpression = lua.createTableIndexExpression(table, accessExpression);
90
94
  // arg0[arg1] ~= nil
91
95
  return lua.createBinaryExpression(tableIndexExpression, lua.createNilLiteral(), lua.SyntaxKind.InequalityOperator, node);
92
96
  }
93
- exports.transformTableHasExpression = transformTableHasExpression;
94
- function transformTableSetExpression(context, node) {
95
- const extensionKind = getTableExtensionKindForCall(context, node, tableSetExtensions);
96
- (0, utils_1.assert)(extensionKind);
97
+ function transformTableSetExpression(context, node, extensionKind) {
97
98
  const args = node.arguments.slice();
98
- if (args.length === 2 &&
99
+ if (extensionKind === extensions.ExtensionKind.TableSetMethodType &&
99
100
  (ts.isPropertyAccessExpression(node.expression) || ts.isElementAccessExpression(node.expression))) {
100
101
  // In case of method (no table argument), push method owner to front of args list
101
102
  args.unshift(node.expression.expression);
102
103
  }
103
104
  // arg0[arg1] = arg2
104
- return lua.createAssignmentStatement(lua.createTableIndexExpression(context.transformExpression(args[0]), context.transformExpression(args[1])), context.transformExpression(args[2]), node);
105
+ const [table, accessExpression, value] = (0, expression_list_1.transformExpressionList)(context, args);
106
+ context.addPrecedingStatements(lua.createAssignmentStatement(lua.createTableIndexExpression(table, accessExpression), value, node));
107
+ return lua.createNilLiteral();
105
108
  }
106
- exports.transformTableSetExpression = transformTableSetExpression;
107
109
  //# sourceMappingURL=table.js.map
@@ -8,6 +8,7 @@ const diagnostics_1 = require("../../utils/diagnostics");
8
8
  const lualib_1 = require("../../utils/lualib");
9
9
  const typescript_1 = require("../../utils/typescript");
10
10
  const iterable_1 = require("../language-extensions/iterable");
11
+ const pairsIterable_1 = require("../language-extensions/pairsIterable");
11
12
  const range_1 = require("../language-extensions/range");
12
13
  const utils_1 = require("./utils");
13
14
  function transformForOfArrayStatement(context, statement, block) {
@@ -33,6 +34,9 @@ const transformForOfStatement = (node, context) => {
33
34
  else if ((0, iterable_1.isIterableExpression)(context, node.expression)) {
34
35
  return (0, iterable_1.transformForOfIterableStatement)(context, node, body);
35
36
  }
37
+ else if ((0, pairsIterable_1.isPairsIterableExpression)(context, node.expression)) {
38
+ return (0, pairsIterable_1.transformForOfPairsIterableStatement)(context, node, body);
39
+ }
36
40
  else if ((0, annotations_1.isLuaIteratorType)(context, node.expression)) {
37
41
  context.diagnostics.push((0, diagnostics_1.annotationRemoved)(node.expression, annotations_1.AnnotationKind.LuaIterator));
38
42
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.invertCondition = exports.transformForInitializer = exports.getVariableDeclarationBinding = exports.transformLoopBody = void 0;
4
4
  const ts = require("typescript");
5
5
  const lua = require("../../../LuaAST");
6
+ const preceding_statements_1 = require("../../utils/preceding-statements");
6
7
  const scope_1 = require("../../utils/scope");
7
8
  const typescript_1 = require("../../utils/typescript");
8
9
  const assignments_1 = require("../binary-expression/assignments");
@@ -34,14 +35,17 @@ function getVariableDeclarationBinding(context, node) {
34
35
  exports.getVariableDeclarationBinding = getVariableDeclarationBinding;
35
36
  function transformForInitializer(context, initializer, block) {
36
37
  const valueVariable = lua.createIdentifier("____value");
38
+ (0, scope_1.pushScope)(context, scope_1.ScopeType.LoopInitializer);
37
39
  if (ts.isVariableDeclarationList(initializer)) {
38
40
  // Declaration of new variable
39
41
  const binding = getVariableDeclarationBinding(context, initializer);
40
42
  if (ts.isArrayBindingPattern(binding) || ts.isObjectBindingPattern(binding)) {
41
- block.statements.unshift(...(0, variable_declaration_1.transformBindingPattern)(context, binding, valueVariable));
43
+ const [precedingStatements, bindings] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => (0, variable_declaration_1.transformBindingPattern)(context, binding, valueVariable));
44
+ block.statements.unshift(...precedingStatements, ...bindings);
42
45
  }
43
46
  else {
44
47
  // Single variable declared in for loop
48
+ (0, scope_1.popScope)(context);
45
49
  return (0, identifier_1.transformIdentifier)(context, binding);
46
50
  }
47
51
  }
@@ -51,6 +55,7 @@ function transformForInitializer(context, initializer, block) {
51
55
  ? (0, destructuring_assignments_1.transformAssignmentPattern)(context, initializer, valueVariable, false)
52
56
  : (0, assignments_1.transformAssignment)(context, initializer, valueVariable)));
53
57
  }
58
+ (0, scope_1.popScope)(context);
54
59
  return valueVariable;
55
60
  }
56
61
  exports.transformForInitializer = transformForInitializer;
@@ -13,7 +13,7 @@ const symbols_1 = require("../utils/symbols");
13
13
  const identifier_1 = require("./identifier");
14
14
  function createModuleLocalNameIdentifier(context, declaration) {
15
15
  const moduleSymbol = context.checker.getSymbolAtLocation(declaration.name);
16
- if (moduleSymbol !== undefined && (0, safe_names_1.isUnsafeName)(moduleSymbol.name)) {
16
+ if (moduleSymbol !== undefined && (0, safe_names_1.isUnsafeName)(moduleSymbol.name, context.options)) {
17
17
  return lua.createIdentifier((0, safe_names_1.createSafeName)(declaration.name.text), declaration.name, moduleSymbol && (0, symbols_1.getSymbolIdOfSymbol)(context, moduleSymbol), declaration.name.text);
18
18
  }
19
19
  // TODO: Should synthetic name nodes be escaped as well?
@@ -11,9 +11,15 @@ const typescript_1 = require("../utils/typescript");
11
11
  const multi_1 = require("./language-extensions/multi");
12
12
  const diagnostics_1 = require("../utils/diagnostics");
13
13
  const vararg_1 = require("./language-extensions/vararg");
14
+ function skipOuterExpressionParents(node) {
15
+ while (ts.isOuterExpression(node)) {
16
+ node = node.parent;
17
+ }
18
+ return node;
19
+ }
14
20
  function isOptimizedVarArgSpread(context, symbol, identifier) {
15
21
  var _a;
16
- if (!ts.isSpreadElement(identifier.parent)) {
22
+ if (!ts.isSpreadElement(skipOuterExpressionParents(identifier.parent))) {
17
23
  return false;
18
24
  }
19
25
  // Walk up, stopping at any scope types which could stop optimization
@@ -51,19 +57,20 @@ function isOptimizedVarArgSpread(context, symbol, identifier) {
51
57
  exports.isOptimizedVarArgSpread = isOptimizedVarArgSpread;
52
58
  // TODO: Currently it's also used as an array member
53
59
  const transformSpreadElement = (node, context) => {
54
- if (ts.isIdentifier(node.expression)) {
55
- if ((0, annotations_1.isVarargType)(context, node.expression)) {
60
+ const tsInnerExpression = ts.skipOuterExpressions(node.expression);
61
+ if (ts.isIdentifier(tsInnerExpression)) {
62
+ if ((0, annotations_1.isVarargType)(context, tsInnerExpression)) {
56
63
  context.diagnostics.push((0, diagnostics_1.annotationRemoved)(node, annotations_1.AnnotationKind.Vararg));
57
64
  }
58
- const symbol = context.checker.getSymbolAtLocation(node.expression);
59
- if (symbol && isOptimizedVarArgSpread(context, symbol, node.expression)) {
65
+ const symbol = context.checker.getSymbolAtLocation(tsInnerExpression);
66
+ if (symbol && isOptimizedVarArgSpread(context, symbol, tsInnerExpression)) {
60
67
  return lua.createDotsLiteral(node);
61
68
  }
62
69
  }
63
70
  const innerExpression = context.transformExpression(node.expression);
64
- if ((0, multi_1.isMultiReturnCall)(context, node.expression))
71
+ if ((0, multi_1.isMultiReturnCall)(context, tsInnerExpression))
65
72
  return innerExpression;
66
- const type = context.checker.getTypeAtLocation(node.expression);
73
+ const type = context.checker.getTypeAtLocation(node.expression); // not ts-inner expression, in case of casts
67
74
  if ((0, typescript_1.isArrayType)(context, type)) {
68
75
  return (0, lua_ast_1.createUnpackCall)(context, innerExpression, node);
69
76
  }