typescript-to-lua 1.2.0 → 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.
- package/CHANGELOG.md +12 -0
- package/dist/LuaLib.js +1 -1
- package/dist/LuaPrinter.js +4 -4
- package/dist/lualib/Await.lua +7 -3
- package/dist/lualib/CloneDescriptor.lua +6 -6
- package/dist/lualib/Promise.lua +10 -2
- package/dist/lualib/lualib_bundle.lua +217 -205
- package/dist/transformation/builtins/function.js +5 -2
- package/dist/transformation/builtins/index.js +2 -2
- package/dist/transformation/utils/diagnostics.d.ts +3 -0
- package/dist/transformation/utils/diagnostics.js +2 -1
- package/dist/transformation/utils/language-extensions.d.ts +2 -0
- package/dist/transformation/utils/language-extensions.js +7 -1
- package/dist/transformation/utils/lua-ast.js +5 -5
- package/dist/transformation/utils/safe-names.d.ts +4 -2
- package/dist/transformation/utils/safe-names.js +11 -5
- package/dist/transformation/utils/scope.d.ts +2 -1
- package/dist/transformation/utils/scope.js +1 -0
- package/dist/transformation/utils/typescript/types.d.ts +3 -1
- package/dist/transformation/utils/typescript/types.js +40 -13
- package/dist/transformation/visitors/binary-expression/index.js +1 -3
- package/dist/transformation/visitors/call.js +1 -1
- package/dist/transformation/visitors/class/index.js +1 -1
- package/dist/transformation/visitors/conditional.js +2 -23
- package/dist/transformation/visitors/errors.js +11 -9
- package/dist/transformation/visitors/function.d.ts +2 -0
- package/dist/transformation/visitors/function.js +53 -4
- package/dist/transformation/visitors/language-extensions/pairsIterable.d.ts +5 -0
- package/dist/transformation/visitors/language-extensions/pairsIterable.js +53 -0
- package/dist/transformation/visitors/loops/for-of.js +4 -0
- package/dist/transformation/visitors/loops/utils.js +6 -1
- package/dist/transformation/visitors/namespace.js +1 -1
- package/dist/transformation/visitors/spread.js +14 -7
- package/dist/transformation/visitors/variable-declaration.js +10 -1
- package/language-extensions/index.d.ts +11 -1
- package/package.json +1 -1
|
@@ -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] &&
|
|
@@ -119,7 +119,9 @@ function createLocalOrExportedOrGlobalDeclaration(context, lhs, rhs, tsOriginal,
|
|
|
119
119
|
const scope = (0, scope_1.peekScope)(context);
|
|
120
120
|
const isTopLevelVariable = scope.type === scope_1.ScopeType.File;
|
|
121
121
|
if (context.isModule || !isTopLevelVariable) {
|
|
122
|
-
|
|
122
|
+
const isLuaFunctionExpression = rhs && !Array.isArray(rhs) && lua.isFunctionExpression(rhs);
|
|
123
|
+
const isSafeRecursiveFunctionDeclaration = isFunctionDeclaration && isLuaFunctionExpression;
|
|
124
|
+
if (!isSafeRecursiveFunctionDeclaration && hasMultipleReferences(scope, lhs)) {
|
|
123
125
|
// Split declaration and assignment of identifiers that reference themselves in their declaration.
|
|
124
126
|
// Put declaration above preceding statements in case the identifier is referenced in those.
|
|
125
127
|
const precedingDeclaration = lua.createVariableDeclarationStatement(lhs, undefined, tsOriginal);
|
|
@@ -127,10 +129,8 @@ function createLocalOrExportedOrGlobalDeclaration(context, lhs, rhs, tsOriginal,
|
|
|
127
129
|
if (rhs) {
|
|
128
130
|
assignment = lua.createAssignmentStatement(lhs, rhs, tsOriginal);
|
|
129
131
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
(0, scope_1.addScopeVariableDeclaration)(scope, precedingDeclaration);
|
|
133
|
-
}
|
|
132
|
+
// Remember local variable declarations for hoisting later
|
|
133
|
+
(0, scope_1.addScopeVariableDeclaration)(scope, precedingDeclaration);
|
|
134
134
|
}
|
|
135
135
|
else {
|
|
136
136
|
declaration = lua.createVariableDeclarationStatement(lhs, rhs, tsOriginal);
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as ts from "typescript";
|
|
2
|
+
import { CompilerOptions } from "../..";
|
|
2
3
|
import { TransformationContext } from "../context";
|
|
3
|
-
export declare const
|
|
4
|
+
export declare const shouldAllowUnicode: (options: CompilerOptions) => boolean;
|
|
5
|
+
export declare const isValidLuaIdentifier: (name: string, options: CompilerOptions) => boolean;
|
|
4
6
|
export declare const luaKeywords: ReadonlySet<string>;
|
|
5
|
-
export declare const isUnsafeName: (name: string) => boolean;
|
|
7
|
+
export declare const isUnsafeName: (name: string, options: CompilerOptions) => boolean;
|
|
6
8
|
export declare function hasUnsafeSymbolName(context: TransformationContext, symbol: ts.Symbol, tsOriginal: ts.Identifier): boolean;
|
|
7
9
|
export declare function hasUnsafeIdentifierName(context: TransformationContext, identifier: ts.Identifier, checkSymbol?: boolean): boolean;
|
|
8
10
|
export declare const createSafeName: (name: string) => string;
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createSafeName = exports.hasUnsafeIdentifierName = exports.hasUnsafeSymbolName = exports.isUnsafeName = exports.luaKeywords = exports.isValidLuaIdentifier = void 0;
|
|
3
|
+
exports.createSafeName = exports.hasUnsafeIdentifierName = exports.hasUnsafeSymbolName = exports.isUnsafeName = exports.luaKeywords = exports.isValidLuaIdentifier = exports.shouldAllowUnicode = void 0;
|
|
4
|
+
const __1 = require("../..");
|
|
4
5
|
const diagnostics_1 = require("./diagnostics");
|
|
5
6
|
const export_1 = require("./export");
|
|
6
7
|
const typescript_1 = require("./typescript");
|
|
7
|
-
const
|
|
8
|
+
const shouldAllowUnicode = (options) => options.luaTarget === __1.LuaTarget.LuaJIT;
|
|
9
|
+
exports.shouldAllowUnicode = shouldAllowUnicode;
|
|
10
|
+
const isValidLuaIdentifier = (name, options) => !exports.luaKeywords.has(name) &&
|
|
11
|
+
((0, exports.shouldAllowUnicode)(options)
|
|
12
|
+
? /^[a-zA-Z_\u007F-\uFFFD][a-zA-Z0-9_\u007F-\uFFFD]*$/
|
|
13
|
+
: /^[a-zA-Z_][a-zA-Z0-9_]*$/).test(name);
|
|
8
14
|
exports.isValidLuaIdentifier = isValidLuaIdentifier;
|
|
9
15
|
exports.luaKeywords = new Set([
|
|
10
16
|
"and",
|
|
@@ -51,10 +57,10 @@ const luaBuiltins = new Set([
|
|
|
51
57
|
"type",
|
|
52
58
|
"unpack",
|
|
53
59
|
]);
|
|
54
|
-
const isUnsafeName = (name) => !(0, exports.isValidLuaIdentifier)(name) || luaBuiltins.has(name);
|
|
60
|
+
const isUnsafeName = (name, options) => !(0, exports.isValidLuaIdentifier)(name, options) || luaBuiltins.has(name);
|
|
55
61
|
exports.isUnsafeName = isUnsafeName;
|
|
56
62
|
function checkName(context, name, node) {
|
|
57
|
-
const isInvalid = !(0, exports.isValidLuaIdentifier)(name);
|
|
63
|
+
const isInvalid = !(0, exports.isValidLuaIdentifier)(name, context.options);
|
|
58
64
|
if (isInvalid) {
|
|
59
65
|
// Empty identifier is a TypeScript error
|
|
60
66
|
if (name !== "") {
|
|
@@ -71,7 +77,7 @@ function hasUnsafeSymbolName(context, symbol, tsOriginal) {
|
|
|
71
77
|
return true;
|
|
72
78
|
}
|
|
73
79
|
// only unsafe when non-ambient and not exported
|
|
74
|
-
return (0, exports.isUnsafeName)(symbol.name) && !isAmbient && !(0, export_1.isSymbolExported)(context, symbol);
|
|
80
|
+
return (0, exports.isUnsafeName)(symbol.name, context.options) && !isAmbient && !(0, export_1.isSymbolExported)(context, symbol);
|
|
75
81
|
}
|
|
76
82
|
exports.hasUnsafeSymbolName = hasUnsafeSymbolName;
|
|
77
83
|
function hasUnsafeIdentifierName(context, identifier, checkSymbol = true) {
|
|
@@ -16,6 +16,7 @@ var ScopeType;
|
|
|
16
16
|
ScopeType[ScopeType["Block"] = 32] = "Block";
|
|
17
17
|
ScopeType[ScopeType["Try"] = 64] = "Try";
|
|
18
18
|
ScopeType[ScopeType["Catch"] = 128] = "Catch";
|
|
19
|
+
ScopeType[ScopeType["LoopInitializer"] = 256] = "LoopInitializer";
|
|
19
20
|
})(ScopeType = exports.ScopeType || (exports.ScopeType = {}));
|
|
20
21
|
const scopeStacks = new WeakMap();
|
|
21
22
|
function getScopeStack(context) {
|
|
@@ -10,4 +10,6 @@ export declare function isNumberType(context: TransformationContext, type: ts.Ty
|
|
|
10
10
|
*/
|
|
11
11
|
export declare function forTypeOrAnySupertype(context: TransformationContext, type: ts.Type, predicate: (type: ts.Type) => boolean): boolean;
|
|
12
12
|
export declare function isArrayType(context: TransformationContext, type: ts.Type): boolean;
|
|
13
|
-
export declare function isFunctionType(
|
|
13
|
+
export declare function isFunctionType(type: ts.Type): boolean;
|
|
14
|
+
export declare function canBeFalsy(context: TransformationContext, type: ts.Type): boolean;
|
|
15
|
+
export declare function canBeFalsyWhenNotNull(context: TransformationContext, type: ts.Type): boolean;
|
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isFunctionType = exports.isArrayType = exports.forTypeOrAnySupertype = exports.isNumberType = exports.isStringType = exports.typeCanSatisfy = exports.typeAlwaysSatisfies = exports.isTypeWithFlags = void 0;
|
|
3
|
+
exports.canBeFalsyWhenNotNull = exports.canBeFalsy = exports.isFunctionType = exports.isArrayType = exports.forTypeOrAnySupertype = exports.isNumberType = exports.isStringType = exports.typeCanSatisfy = exports.typeAlwaysSatisfies = exports.isTypeWithFlags = void 0;
|
|
4
4
|
const ts = require("typescript");
|
|
5
5
|
function isTypeWithFlags(context, type, flags) {
|
|
6
|
-
const predicate = (type) =>
|
|
7
|
-
if (type.symbol) {
|
|
8
|
-
const baseConstraint = context.checker.getBaseConstraintOfType(type);
|
|
9
|
-
if (baseConstraint && baseConstraint !== type) {
|
|
10
|
-
return isTypeWithFlags(context, baseConstraint, flags);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
return (type.flags & flags) !== 0;
|
|
14
|
-
};
|
|
6
|
+
const predicate = (type) => (type.flags & flags) !== 0;
|
|
15
7
|
return typeAlwaysSatisfies(context, type, predicate);
|
|
16
8
|
}
|
|
17
9
|
exports.isTypeWithFlags = isTypeWithFlags;
|
|
18
10
|
function typeAlwaysSatisfies(context, type, predicate) {
|
|
11
|
+
const baseConstraint = context.checker.getBaseConstraintOfType(type);
|
|
12
|
+
if (baseConstraint) {
|
|
13
|
+
type = baseConstraint;
|
|
14
|
+
}
|
|
19
15
|
if (predicate(type)) {
|
|
20
16
|
return true;
|
|
21
17
|
}
|
|
@@ -29,6 +25,15 @@ function typeAlwaysSatisfies(context, type, predicate) {
|
|
|
29
25
|
}
|
|
30
26
|
exports.typeAlwaysSatisfies = typeAlwaysSatisfies;
|
|
31
27
|
function typeCanSatisfy(context, type, predicate) {
|
|
28
|
+
const baseConstraint = context.checker.getBaseConstraintOfType(type);
|
|
29
|
+
if (!baseConstraint) {
|
|
30
|
+
// type parameter with no constraint can be anything, assume it might satisfy predicate
|
|
31
|
+
if (type.isTypeParameter())
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
type = baseConstraint;
|
|
36
|
+
}
|
|
32
37
|
if (predicate(type)) {
|
|
33
38
|
return true;
|
|
34
39
|
}
|
|
@@ -84,9 +89,31 @@ function isArrayType(context, type) {
|
|
|
84
89
|
return forTypeOrAnySupertype(context, type, t => isExplicitArrayType(context, t));
|
|
85
90
|
}
|
|
86
91
|
exports.isArrayType = isArrayType;
|
|
87
|
-
function isFunctionType(
|
|
88
|
-
|
|
89
|
-
return typeNode !== undefined && ts.isFunctionTypeNode(typeNode);
|
|
92
|
+
function isFunctionType(type) {
|
|
93
|
+
return type.getCallSignatures().length > 0;
|
|
90
94
|
}
|
|
91
95
|
exports.isFunctionType = isFunctionType;
|
|
96
|
+
function canBeFalsy(context, type) {
|
|
97
|
+
const strictNullChecks = context.options.strict === true || context.options.strictNullChecks === true;
|
|
98
|
+
const falsyFlags = ts.TypeFlags.Boolean |
|
|
99
|
+
ts.TypeFlags.BooleanLiteral |
|
|
100
|
+
ts.TypeFlags.Never |
|
|
101
|
+
ts.TypeFlags.Void |
|
|
102
|
+
ts.TypeFlags.Unknown |
|
|
103
|
+
ts.TypeFlags.Any |
|
|
104
|
+
ts.TypeFlags.Undefined |
|
|
105
|
+
ts.TypeFlags.Null;
|
|
106
|
+
return typeCanSatisfy(context, type, type => (type.flags & falsyFlags) !== 0 || (!strictNullChecks && !type.isLiteral()));
|
|
107
|
+
}
|
|
108
|
+
exports.canBeFalsy = canBeFalsy;
|
|
109
|
+
function canBeFalsyWhenNotNull(context, type) {
|
|
110
|
+
const falsyFlags = ts.TypeFlags.Boolean |
|
|
111
|
+
ts.TypeFlags.BooleanLiteral |
|
|
112
|
+
ts.TypeFlags.Never |
|
|
113
|
+
ts.TypeFlags.Void |
|
|
114
|
+
ts.TypeFlags.Unknown |
|
|
115
|
+
ts.TypeFlags.Any;
|
|
116
|
+
return typeCanSatisfy(context, type, type => (type.flags & falsyFlags) !== 0);
|
|
117
|
+
}
|
|
118
|
+
exports.canBeFalsyWhenNotNull = canBeFalsyWhenNotNull;
|
|
92
119
|
//# sourceMappingURL=types.js.map
|
|
@@ -167,9 +167,7 @@ exports.transformBinaryExpressionStatement = transformBinaryExpressionStatement;
|
|
|
167
167
|
function transformNullishCoalescingOperationNoPrecedingStatements(context, node, transformedLeft, transformedRight) {
|
|
168
168
|
const lhsType = context.checker.getTypeAtLocation(node.left);
|
|
169
169
|
// Check if we can take a shortcut to 'lhs or rhs' if the left-hand side cannot be 'false'.
|
|
170
|
-
|
|
171
|
-
(type.flags & ts.TypeFlags.BooleanLiteral & ts.TypeFlags.PossiblyFalsy) !== 0;
|
|
172
|
-
if ((0, typescript_1.typeCanSatisfy)(context, lhsType, typeCanBeFalse)) {
|
|
170
|
+
if ((0, typescript_1.canBeFalsyWhenNotNull)(context, lhsType)) {
|
|
173
171
|
// reuse logic from case with preceding statements
|
|
174
172
|
const [precedingStatements, result] = createShortCircuitBinaryExpressionPrecedingStatements(context, transformedLeft, transformedRight, [], ts.SyntaxKind.QuestionQuestionToken, node);
|
|
175
173
|
context.addPrecedingStatements(precedingStatements);
|
|
@@ -86,7 +86,7 @@ function transformContextualCallExpression(context, node, args, signature) {
|
|
|
86
86
|
let [argPrecedingStatements, transformedArguments] = (0, preceding_statements_1.transformInPrecedingStatementScope)(context, () => transformArguments(context, args, signature));
|
|
87
87
|
if (ts.isPropertyAccessExpression(left) &&
|
|
88
88
|
ts.isIdentifier(left.name) &&
|
|
89
|
-
(0, safe_names_1.isValidLuaIdentifier)(left.name.text) &&
|
|
89
|
+
(0, safe_names_1.isValidLuaIdentifier)(left.name.text, context.options) &&
|
|
90
90
|
argPrecedingStatements.length === 0) {
|
|
91
91
|
// table:name()
|
|
92
92
|
const table = context.transformExpression(left.expression);
|
|
@@ -70,7 +70,7 @@ function transformClassLikeDeclaration(classDeclaration, context, nameOverride)
|
|
|
70
70
|
const instanceFields = properties.filter(prop => !(0, utils_2.isStaticNode)(prop));
|
|
71
71
|
const result = [];
|
|
72
72
|
let localClassName;
|
|
73
|
-
if ((0, safe_names_1.isUnsafeName)(className.text)) {
|
|
73
|
+
if ((0, safe_names_1.isUnsafeName)(className.text, context.options)) {
|
|
74
74
|
localClassName = lua.createIdentifier((0, safe_names_1.createSafeName)(className.text), undefined, className.symbolId, className.text);
|
|
75
75
|
lua.setNodePosition(localClassName, className);
|
|
76
76
|
}
|
|
@@ -6,28 +6,7 @@ const lua = require("../../LuaAST");
|
|
|
6
6
|
const preceding_statements_1 = require("../utils/preceding-statements");
|
|
7
7
|
const scope_1 = require("../utils/scope");
|
|
8
8
|
const block_1 = require("./block");
|
|
9
|
-
|
|
10
|
-
const strictNullChecks = context.options.strict === true || context.options.strictNullChecks === true;
|
|
11
|
-
const falsyFlags = ts.TypeFlags.Boolean |
|
|
12
|
-
ts.TypeFlags.BooleanLiteral |
|
|
13
|
-
ts.TypeFlags.Undefined |
|
|
14
|
-
ts.TypeFlags.Null |
|
|
15
|
-
ts.TypeFlags.Never |
|
|
16
|
-
ts.TypeFlags.Void |
|
|
17
|
-
ts.TypeFlags.Any;
|
|
18
|
-
if (type.flags & falsyFlags) {
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
else if (!strictNullChecks && !type.isLiteral()) {
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
else if (type.isUnion()) {
|
|
25
|
-
return type.types.some(subType => canBeFalsy(context, subType));
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
9
|
+
const typescript_1 = require("../utils/typescript");
|
|
31
10
|
function transformProtectedConditionalExpression(context, expression) {
|
|
32
11
|
const tempVar = context.createTempNameForNode(expression.condition);
|
|
33
12
|
const condition = context.transformExpression(expression.condition);
|
|
@@ -42,7 +21,7 @@ function transformProtectedConditionalExpression(context, expression) {
|
|
|
42
21
|
return lua.cloneIdentifier(tempVar);
|
|
43
22
|
}
|
|
44
23
|
const transformConditionalExpression = (expression, context) => {
|
|
45
|
-
if (canBeFalsy(context, context.checker.getTypeAtLocation(expression.whenTrue))) {
|
|
24
|
+
if ((0, typescript_1.canBeFalsy)(context, context.checker.getTypeAtLocation(expression.whenTrue))) {
|
|
46
25
|
return transformProtectedConditionalExpression(context, expression);
|
|
47
26
|
}
|
|
48
27
|
const condition = context.transformExpression(expression.condition);
|
|
@@ -12,6 +12,7 @@ const identifier_1 = require("./identifier");
|
|
|
12
12
|
const multi_1 = require("./language-extensions/multi");
|
|
13
13
|
const return_1 = require("./return");
|
|
14
14
|
const transformTryStatement = (statement, context) => {
|
|
15
|
+
var _a;
|
|
15
16
|
const [tryBlock, tryScope] = (0, block_1.transformScopeBlock)(context, statement.tryBlock, scope_1.ScopeType.Try);
|
|
16
17
|
if (context.options.luaTarget === __1.LuaTarget.Lua51 && (0, typescript_1.isInAsyncFunction)(statement)) {
|
|
17
18
|
context.diagnostics.push((0, diagnostics_1.unsupportedForTarget)(statement, "try/catch inside async functions", __1.LuaTarget.Lua51));
|
|
@@ -34,24 +35,25 @@ const transformTryStatement = (statement, context) => {
|
|
|
34
35
|
const catchParameter = statement.catchClause.variableDeclaration
|
|
35
36
|
? (0, identifier_1.transformIdentifier)(context, statement.catchClause.variableDeclaration.name)
|
|
36
37
|
: undefined;
|
|
37
|
-
const
|
|
38
|
+
const catchFunction = lua.createFunctionExpression(catchBlock, catchParameter ? [lua.cloneIdentifier(catchParameter)] : []);
|
|
38
39
|
const catchIdentifier = lua.createIdentifier("____catch");
|
|
39
|
-
const catchFunction = lua.createFunctionExpression(catchBlock, catchParameters());
|
|
40
40
|
result.push(lua.createVariableDeclarationStatement(catchIdentifier, catchFunction));
|
|
41
|
+
const hasReturn = (_a = tryScope.functionReturned) !== null && _a !== void 0 ? _a : catchScope.functionReturned;
|
|
41
42
|
const tryReturnIdentifiers = [tryResultIdentifier]; // ____try
|
|
42
|
-
if (
|
|
43
|
-
tryReturnIdentifiers.push(returnedIdentifier); // ____returned
|
|
44
|
-
if (
|
|
43
|
+
if (hasReturn || statement.catchClause.variableDeclaration) {
|
|
44
|
+
tryReturnIdentifiers.push(returnedIdentifier); // ____returned
|
|
45
|
+
if (hasReturn) {
|
|
45
46
|
tryReturnIdentifiers.push(returnValueIdentifier); // ____returnValue
|
|
46
47
|
returnCondition = lua.cloneIdentifier(returnedIdentifier);
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
result.push(lua.createVariableDeclarationStatement(tryReturnIdentifiers, tryCall));
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
51
|
+
const catchCall = lua.createCallExpression(catchIdentifier, statement.catchClause.variableDeclaration ? [lua.cloneIdentifier(returnedIdentifier)] : []);
|
|
52
|
+
const catchCallStatement = hasReturn
|
|
53
|
+
? lua.createAssignmentStatement([lua.cloneIdentifier(returnedIdentifier), lua.cloneIdentifier(returnValueIdentifier)], catchCall)
|
|
54
|
+
: lua.createExpressionStatement(catchCall);
|
|
53
55
|
const notTryCondition = lua.createUnaryExpression(tryResultIdentifier, lua.SyntaxKind.NotOperator);
|
|
54
|
-
result.push(lua.createIfStatement(notTryCondition, lua.createBlock([
|
|
56
|
+
result.push(lua.createIfStatement(notTryCondition, lua.createBlock([catchCallStatement])));
|
|
55
57
|
}
|
|
56
58
|
else if (tryScope.functionReturned) {
|
|
57
59
|
// try with return, but no catch
|
|
@@ -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
|
-
|
|
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
|
|
@@ -167,7 +204,15 @@ function transformFunctionLikeDeclaration(node, context) {
|
|
|
167
204
|
// Only handle if the name is actually referenced inside the function
|
|
168
205
|
if (isReferenced) {
|
|
169
206
|
const nameIdentifier = (0, identifier_1.transformIdentifier)(context, node.name);
|
|
170
|
-
context.
|
|
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
|
+
}
|
|
171
216
|
return lua.cloneIdentifier(nameIdentifier);
|
|
172
217
|
}
|
|
173
218
|
}
|
|
@@ -199,7 +244,11 @@ const transformFunctionDeclaration = (node, context) => {
|
|
|
199
244
|
const functionInfo = { referencedSymbols: (_a = functionScope.referencedSymbols) !== null && _a !== void 0 ? _a : new Map() };
|
|
200
245
|
scope.functionDefinitions.set(name.symbolId, functionInfo);
|
|
201
246
|
}
|
|
202
|
-
|
|
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);
|
|
203
252
|
};
|
|
204
253
|
exports.transformFunctionDeclaration = transformFunctionDeclaration;
|
|
205
254
|
const transformYieldExpression = (expression, context) => {
|
|
@@ -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
|
|
@@ -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
|
-
|
|
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
|
-
|
|
55
|
-
|
|
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(
|
|
59
|
-
if (symbol && isOptimizedVarArgSpread(context, symbol,
|
|
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,
|
|
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
|
}
|