forked from TypeScriptToLua/TypeScriptToLua
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconditional.ts
More file actions
96 lines (82 loc) · 3.9 KB
/
Copy pathconditional.ts
File metadata and controls
96 lines (82 loc) · 3.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import * as ts from "typescript";
import * as lua from "../../LuaAST";
import { FunctionVisitor, TransformationContext } from "../context";
import { performHoisting, popScope, pushScope, ScopeType } from "../utils/scope";
import { transformBlockOrStatement } from "./block";
function canBeFalsy(context: TransformationContext, type: ts.Type): boolean {
const strictNullChecks = context.options.strict === true || context.options.strictNullChecks === true;
const falsyFlags =
ts.TypeFlags.Boolean |
ts.TypeFlags.BooleanLiteral |
ts.TypeFlags.Undefined |
ts.TypeFlags.Null |
ts.TypeFlags.Never |
ts.TypeFlags.Void |
ts.TypeFlags.Any;
if (type.flags & falsyFlags) {
return true;
} else if (!strictNullChecks && !type.isLiteral()) {
return true;
} else if (type.isUnion()) {
return type.types.some(subType => canBeFalsy(context, subType));
} else {
return false;
}
}
function wrapInFunctionCall(expression: lua.Expression): lua.FunctionExpression {
const returnStatement = lua.createReturnStatement([expression]);
return lua.createFunctionExpression(
lua.createBlock([returnStatement]),
undefined,
undefined,
lua.FunctionExpressionFlags.Inline
);
}
function transformProtectedConditionalExpression(
context: TransformationContext,
expression: ts.ConditionalExpression
): lua.CallExpression {
const condition = context.transformExpression(expression.condition);
const val1 = context.transformExpression(expression.whenTrue);
const val2 = context.transformExpression(expression.whenFalse);
const val1Function = wrapInFunctionCall(val1);
const val2Function = wrapInFunctionCall(val2);
// (condition and (() => v1) or (() => v2))()
const conditionAnd = lua.createBinaryExpression(condition, val1Function, lua.SyntaxKind.AndOperator);
const orExpression = lua.createBinaryExpression(conditionAnd, val2Function, lua.SyntaxKind.OrOperator);
return lua.createCallExpression(orExpression, [], expression);
}
export const transformConditionalExpression: FunctionVisitor<ts.ConditionalExpression> = (expression, context) => {
if (canBeFalsy(context, context.checker.getTypeAtLocation(expression.whenTrue))) {
return transformProtectedConditionalExpression(context, expression);
}
const condition = context.transformExpression(expression.condition);
const val1 = context.transformExpression(expression.whenTrue);
const val2 = context.transformExpression(expression.whenFalse);
// condition and v1 or v2
const conditionAnd = lua.createBinaryExpression(condition, val1, lua.SyntaxKind.AndOperator);
return lua.createBinaryExpression(conditionAnd, val2, lua.SyntaxKind.OrOperator, expression);
};
export function transformIfStatement(statement: ts.IfStatement, context: TransformationContext): lua.IfStatement {
pushScope(context, ScopeType.Conditional);
const condition = context.transformExpression(statement.expression);
const statements = performHoisting(context, transformBlockOrStatement(context, statement.thenStatement));
popScope(context);
const ifBlock = lua.createBlock(statements);
if (statement.elseStatement) {
if (ts.isIfStatement(statement.elseStatement)) {
const elseStatement = transformIfStatement(statement.elseStatement, context);
return lua.createIfStatement(condition, ifBlock, elseStatement);
} else {
pushScope(context, ScopeType.Conditional);
const elseStatements = performHoisting(
context,
transformBlockOrStatement(context, statement.elseStatement)
);
popScope(context);
const elseBlock = lua.createBlock(elseStatements);
return lua.createIfStatement(condition, ifBlock, elseBlock);
}
}
return lua.createIfStatement(condition, ifBlock);
}