Skip to content

Commit c6bbdaa

Browse files
committed
Implemented new export system
1 parent acd394b commit c6bbdaa

File tree

3 files changed

+113
-47
lines changed

3 files changed

+113
-47
lines changed

src/LuaAST.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ export function createDoStatement(statements?: Statement[], parent?: Node, tsOri
189189
// `local test1, test2 = 12, 42` or `local test1, test2`
190190
export interface VariableDeclarationStatement extends Statement {
191191
kind: SyntaxKind.VariableDeclarationStatement;
192-
left: IdentifierOrTableIndexExpression[];
192+
left: Identifier[];
193193
right?: Expression[];
194194
}
195195

@@ -198,7 +198,7 @@ export function isVariableDeclarationStatement(node: Node): node is VariableDecl
198198
}
199199

200200
export function createVariableDeclarationStatement(
201-
left: IdentifierOrTableIndexExpression | IdentifierOrTableIndexExpression[],
201+
left: Identifier | Identifier[],
202202
right?: Expression | Expression[],
203203
parent?: Node,
204204
tsOriginal?: ts.Node): VariableDeclarationStatement {

src/LuaTransformer.ts

Lines changed: 111 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as tstl from "./LuaAST";
77
import {LuaLib, LuaLibFeature} from "./LuaLib";
88
import {ContextType, TSHelper as tsHelper} from "./TSHelper";
99
import {TSTLErrors} from "./TSTLErrors";
10+
import { isArray } from "util";
1011

1112
export type StatementVisitResult = tstl.Statement | tstl.Statement[] | undefined;
1213
export type ExpressionVisitResult = tstl.Expression | undefined;
@@ -758,14 +759,9 @@ export class LuaTransformer {
758759
} else if (this.isModule && (ts.getCombinedModifierFlags(statement) & ts.ModifierFlags.Export)) {
759760
// exports.NS = exports.NS or {}
760761
const namespaceDeclaration = tstl.createAssignmentStatement(
761-
tstl.createTableIndexExpression(
762-
this.transformIdentifier(ts.createIdentifier("exports")),
763-
this.transformIdentifier(statement.name as ts.Identifier)
764-
),
762+
this.createExportedIdentifier(this.transformIdentifier(statement.name as ts.Identifier)),
765763
tstl.createBinaryExpression(
766-
tstl.createTableIndexExpression(
767-
this.transformIdentifier(ts.createIdentifier("exports")),
768-
this.transformIdentifier(statement.name as ts.Identifier)),
764+
this.createExportedIdentifier(this.transformIdentifier(statement.name as ts.Identifier)),
769765
tstl.createTableExpression(),
770766
tstl.SyntaxKind.OrOperator));
771767

@@ -774,9 +770,7 @@ export class LuaTransformer {
774770
// local NS = exports.NS
775771
const localDeclaration = tstl.createVariableDeclarationStatement(
776772
this.transformIdentifier(statement.name as ts.Identifier),
777-
tstl.createTableIndexExpression(
778-
this.transformIdentifier(ts.createIdentifier("exports") as ts.Identifier),
779-
this.transformIdentifier(statement.name as ts.Identifier)));
773+
this.createExportedIdentifier(this.transformIdentifier(statement.name as ts.Identifier)));
780774

781775
result.push(localDeclaration);
782776
} else {
@@ -919,7 +913,8 @@ export class LuaTransformer {
919913
}
920914

921915
public transformVariableDeclaration(statement: ts.VariableDeclaration)
922-
: [tstl.VariableDeclarationStatement] | [tstl.VariableDeclarationStatement, tstl.AssignmentStatement]
916+
: [tstl.AssignmentStatement | tstl.VariableDeclarationStatement]
917+
| [tstl.VariableDeclarationStatement, tstl.AssignmentStatement]
923918
{
924919
if (statement.initializer) {
925920
// Validate assignment
@@ -929,6 +924,7 @@ export class LuaTransformer {
929924
}
930925

931926
if (ts.isIdentifier(statement.name)) {
927+
const isVariableExported = this.isIdentifierExported(statement.name.escapedText);
932928
// Find variable identifier
933929
const identifierName = this.transformIdentifier(statement.name);
934930
if (statement.initializer) {
@@ -937,15 +933,38 @@ export class LuaTransformer {
937933
// Separate declaration and assignment for functions to allow recursion
938934

939935
// local identifierName; identifierName = value;
940-
return [tstl.createVariableDeclarationStatement(identifierName),
941-
tstl.createAssignmentStatement(identifierName, value)];
936+
if (isVariableExported) {
937+
return [tstl.createVariableDeclarationStatement(identifierName),
938+
tstl.createAssignmentStatement(
939+
this.createExportedIdentifier(identifierName),
940+
value),
941+
];
942+
} else {
943+
return [tstl.createVariableDeclarationStatement(identifierName),
944+
tstl.createAssignmentStatement(
945+
identifierName,
946+
value),
947+
];
948+
}
942949
} else {
943950
// local identifierName = value;
944-
return [tstl.createVariableDeclarationStatement(identifierName, value)];
951+
if (isVariableExported) {
952+
return [tstl.createAssignmentStatement(
953+
this.createExportedIdentifier(identifierName), value)];
954+
} else {
955+
return [tstl.createVariableDeclarationStatement(identifierName, value)];
956+
}
945957
}
946958
} else {
947959
// local identifierName = nil;
948-
return [tstl.createVariableDeclarationStatement(identifierName, tstl.createNilLiteral())];
960+
if (isVariableExported) {
961+
return [tstl.createAssignmentStatement(
962+
this.createExportedIdentifier(identifierName), tstl.createNilLiteral())];
963+
} else {
964+
return [tstl.createVariableDeclarationStatement(
965+
identifierName, tstl.createNilLiteral()),
966+
];
967+
}
949968
}
950969
} else if (ts.isArrayBindingPattern(statement.name)) {
951970
// Destructuring type
@@ -956,25 +975,49 @@ export class LuaTransformer {
956975
}
957976

958977
const vars = statement.name.elements.map(e => this.transformArrayBindingElement(e));
978+
const isSomeVariableExported = vars.some(i => this.isIdentifierExported(i.text));
959979

960980
// Don't unpack TupleReturn decorated functions
961981
if (statement.initializer) {
962982
if (tsHelper.isTupleReturnCall(statement.initializer, this.checker)) {
963983
// local vars = initializer;
964-
return [tstl.createVariableDeclarationStatement(
965-
vars,
966-
this.transformExpression(statement.initializer)
967-
)];
984+
if (isSomeVariableExported) {
985+
return [tstl.createAssignmentStatement(
986+
vars.map(i => this.createExportedIdentifier(i)),
987+
this.transformExpression(statement.initializer)
988+
)];
989+
} else {
990+
return [tstl.createVariableDeclarationStatement(
991+
vars,
992+
this.transformExpression(statement.initializer)
993+
)];
994+
}
968995
} else {
969996
// local vars = this.transpileDestructingAssignmentValue(node.initializer);
970997
const initializer = this.createUnpackCall(
971998
this.transformExpression(statement.initializer),
972999
statement.initializer
9731000
);
974-
return [tstl.createVariableDeclarationStatement(vars, initializer)];
1001+
if (isSomeVariableExported) {
1002+
return [
1003+
tstl.createAssignmentStatement(
1004+
vars.map(i => this.createExportedIdentifier(i)),
1005+
initializer),
1006+
];
1007+
} else {
1008+
return [tstl.createVariableDeclarationStatement(vars, initializer)];
1009+
}
9751010
}
9761011
} else {
977-
return [tstl.createVariableDeclarationStatement(vars)];
1012+
if (isSomeVariableExported) {
1013+
return [
1014+
tstl.createAssignmentStatement(
1015+
vars.map(i => this.createExportedIdentifier(i)),
1016+
tstl.createNilLiteral()),
1017+
];
1018+
} else {
1019+
return [tstl.createVariableDeclarationStatement(vars)];
1020+
}
9781021
}
9791022
} else {
9801023
throw TSTLErrors.UnsupportedKind("variable declaration", statement.name.kind, statement);
@@ -1144,7 +1187,9 @@ export class LuaTransformer {
11441187
if (ts.isArrayBindingPattern(initializer.declarations[0].name)) {
11451188
expression = this.createUnpackCall(expression, initializer);
11461189
}
1147-
return tstl.createVariableDeclarationStatement(variableDeclarations[0].left, expression);
1190+
// we can safely assume that for vars are not exported and therefore declarationstatenents
1191+
return tstl.createVariableDeclarationStatement(
1192+
(variableDeclarations[0] as tstl.VariableDeclarationStatement).left, expression);
11481193

11491194
} else {
11501195
// Assignment to existing variable
@@ -1486,7 +1531,7 @@ export class LuaTransformer {
14861531
case ts.SyntaxKind.ElementAccessExpression:
14871532
return this.transformElementAccessExpression(expression as ts.ElementAccessExpression);
14881533
case ts.SyntaxKind.Identifier:
1489-
return this.transformIdentifier(expression as ts.Identifier);
1534+
return this.transformIdentifierExpression(expression as ts.Identifier);
14901535
case ts.SyntaxKind.StringLiteral:
14911536
case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
14921537
return this.transformStringLiteral(expression as ts.StringLiteral);
@@ -2885,31 +2930,58 @@ export class LuaTransformer {
28852930
} else if (ts.isStringLiteral(propertyName)) {
28862931
return this.transformStringLiteral(propertyName);
28872932
} else if (ts.isNumericLiteral(propertyName)) {
2888-
const value = +propertyName.text;
2933+
const value = Number(propertyName.text);
28892934
return tstl.createNumericLiteral(value, undefined, propertyName);
28902935
} else {
28912936
return tstl.createStringLiteral(this.transformIdentifier(propertyName).text);
28922937
}
28932938
}
28942939

2895-
public transformIdentifier(epxression: ts.Identifier, parent?: tstl.Node): tstl.Identifier {
2896-
if (epxression.originalKeywordKind === ts.SyntaxKind.UndefinedKeyword) {
2940+
public transformIdentifier(expression: ts.Identifier): tstl.Identifier {
2941+
if (expression.originalKeywordKind === ts.SyntaxKind.UndefinedKeyword) {
28972942
return tstl.createIdentifier("nil"); // TODO this is a hack that allows use to keep Identifier
28982943
// as return time as changing that would break a lot of stuff.
28992944
// But this should be changed to retun tstl.createNilLiteral()
29002945
// at some point.
29012946
}
2902-
let escapedText = epxression.escapedText as string;
2947+
let escapedText = expression.escapedText as string;
29032948
const underScoreCharCode = "_".charCodeAt(0);
29042949
if (escapedText.length >= 3 && escapedText.charCodeAt(0) === underScoreCharCode &&
29052950
escapedText.charCodeAt(1) === underScoreCharCode && escapedText.charCodeAt(2) === underScoreCharCode) {
29062951
escapedText = escapedText.substr(1);
29072952
}
29082953

29092954
if (this.luaKeywords.has(escapedText)) {
2910-
throw TSTLErrors.KeywordIdentifier(epxression);
2955+
throw TSTLErrors.KeywordIdentifier(expression);
29112956
}
2912-
return tstl.createIdentifier(escapedText, parent, epxression);
2957+
return tstl.createIdentifier(escapedText, undefined, expression);
2958+
}
2959+
2960+
public transformIdentifierExpression(expression: ts.Identifier): tstl.IdentifierOrTableIndexExpression {
2961+
if (this.isIdentifierExported(expression.escapedText)) {
2962+
return this.createExportedIdentifier(this.transformIdentifier(expression));
2963+
}
2964+
return this.transformIdentifier(expression);
2965+
}
2966+
2967+
public isIdentifierExported(identifierName: string | ts.__String): boolean {
2968+
if (!this.isModule) {
2969+
return false;
2970+
}
2971+
const currentScope = this.currentNamespace ? this.currentNamespace : this.currentSourceFile;
2972+
const scopeSymbol = this.checker.getSymbolAtLocation(currentScope)
2973+
? this.checker.getSymbolAtLocation(currentScope)
2974+
: this.checker.getTypeAtLocation(currentScope).getSymbol();
2975+
return scopeSymbol.exports.has(identifierName as ts.__String);
2976+
}
2977+
2978+
public createExportedIdentifier(identifier: tstl.Identifier): tstl.TableIndexExpression {
2979+
const exportTable = this.currentNamespace
2980+
? this.transformIdentifier(this.currentNamespace.name as ts.Identifier)
2981+
: tstl.createIdentifier("exports");
2982+
return tstl.createTableIndexExpression(
2983+
exportTable,
2984+
tstl.createStringLiteral(identifier.text));
29132985
}
29142986

29152987
public escapeString(text: string): string {
@@ -3033,7 +3105,16 @@ export class LuaTransformer {
30333105
|| this.currentNamespace
30343106
|| (tsOriginal && tsHelper.findFirstNodeAbove(tsOriginal, ts.isFunctionLike))
30353107
) {
3036-
statements.push(tstl.createVariableDeclarationStatement(lhs, undefined, parent));
3108+
if (!isArray(lhs)) {
3109+
lhs = [lhs];
3110+
}
3111+
const shouldExport = lhs.some(i => this.isIdentifierExported(i.text));
3112+
if (shouldExport) {
3113+
statements.push(
3114+
tstl.createAssignmentStatement(lhs.map(i => this.createExportedIdentifier(i)), undefined, parent));
3115+
} else {
3116+
statements.push(tstl.createVariableDeclarationStatement(lhs, undefined, parent));
3117+
}
30373118
}
30383119
statements.push(tstl.createAssignmentStatement(lhs, rhs, parent, tsOriginal));
30393120
return statements;

src/TSHelper.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -85,21 +85,6 @@ export class TSHelper {
8585
return false;
8686
}
8787

88-
public static isIdentifierExported(
89-
identifier: ts.Identifier,
90-
scope: ts.ModuleDeclaration | ts.SourceFile,
91-
checker: ts.TypeChecker
92-
): boolean
93-
{
94-
const identifierSymbol = checker.getTypeAtLocation(scope).getSymbol();
95-
if (identifierSymbol.exports)
96-
 {
97-
return identifierSymbol.exports.has(identifier.escapedText);
98-
}
99-
100-
return false;
101-
}
102-
10388
public static isInDestructingAssignment(node: ts.Node): boolean {
10489
return node.parent && ((ts.isVariableDeclaration(node.parent) && ts.isArrayBindingPattern(node.parent.name)) ||
10590
(ts.isBinaryExpression(node.parent) && ts.isArrayLiteralExpression(node.parent.left)));

0 commit comments

Comments
 (0)