X Tutup
Skip to content

Commit d4f4f52

Browse files
ark120202Perryvw
authored andcommitted
Separate transformer run method (#655)
* Separate transformer run method * Address feedback
1 parent 44fdccf commit d4f4f52

File tree

5 files changed

+57
-82
lines changed

5 files changed

+57
-82
lines changed

src/LuaPrinter.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,10 @@ export class LuaPrinter {
3838
[tstl.SyntaxKind.BitwiseNotOperator]: "~",
3939
};
4040

41-
private options: CompilerOptions;
42-
private emitHost: EmitHost;
43-
44-
private currentIndent: string;
45-
41+
private currentIndent = "";
4642
private sourceFile = "";
4743

48-
public constructor(options: CompilerOptions, emitHost: EmitHost) {
49-
this.options = options;
50-
this.emitHost = emitHost;
51-
this.currentIndent = "";
52-
}
44+
public constructor(private options: CompilerOptions, private emitHost: EmitHost) {}
5345

5446
public print(block: tstl.Block, luaLibFeatures?: Set<LuaLibFeature>, sourceFile = ""): [string, string] {
5547
// Add traceback lualib if sourcemap traceback option is enabled

src/LuaTransformer.ts

Lines changed: 45 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -54,85 +54,81 @@ export interface DiagnosticsProducingTypeChecker extends ts.TypeChecker {
5454
}
5555

5656
export class LuaTransformer {
57-
protected isStrict: boolean;
58-
protected luaTarget: LuaTarget;
57+
protected readonly typeValidationCache = new Map<ts.Type, Set<ts.Type>>();
58+
protected currentNamespace?: ts.ModuleDeclaration;
5959

6060
protected checker: DiagnosticsProducingTypeChecker;
6161
protected options: CompilerOptions;
6262

63-
// Resolver is lazy-initialized in transformSourceFile to avoid type-checking all files
64-
protected resolver!: EmitResolver;
65-
66-
protected isModule = false;
67-
protected currentSourceFile?: ts.SourceFile;
68-
69-
protected currentNamespace: ts.ModuleDeclaration | undefined;
70-
protected classStack: ts.ClassLikeDeclaration[] = [];
71-
72-
protected scopeStack: Scope[] = [];
73-
protected genVarCounter = 0;
74-
75-
protected luaLibFeatureSet = new Set<LuaLibFeature>();
76-
77-
protected symbolInfo = new Map<tstl.SymbolId, SymbolInfo>();
78-
protected symbolIds = new Map<ts.Symbol, tstl.SymbolId>();
79-
80-
protected genSymbolIdCounter = 0;
81-
82-
protected readonly typeValidationCache: Map<ts.Type, Set<ts.Type>> = new Map<ts.Type, Set<ts.Type>>();
63+
protected luaTarget: LuaTarget;
64+
protected isStrict: boolean;
8365

8466
public constructor(protected program: ts.Program) {
8567
this.checker = (program as any).getDiagnosticsProducingTypeChecker();
8668
this.options = program.getCompilerOptions();
69+
70+
this.luaTarget = this.options.luaTarget || LuaTarget.LuaJIT;
8771
this.isStrict =
8872
this.options.alwaysStrict !== undefined ||
8973
(this.options.strict !== undefined && this.options.alwaysStrict !== false) ||
9074
(this.isModule && this.options.target !== undefined && this.options.target >= ts.ScriptTarget.ES2015);
9175

92-
this.luaTarget = this.options.luaTarget || LuaTarget.LuaJIT;
93-
9476
this.setupState();
9577
}
9678

97-
protected setupState(): void {
79+
protected genVarCounter!: number;
80+
protected luaLibFeatureSet!: Set<LuaLibFeature>;
81+
82+
protected scopeStack!: Scope[];
83+
protected classStack!: ts.ClassLikeDeclaration[];
84+
85+
protected symbolInfo!: Map<tstl.SymbolId, SymbolInfo>;
86+
protected symbolIds!: Map<ts.Symbol, tstl.SymbolId>;
87+
protected genSymbolIdCounter!: number;
88+
89+
private setupState(): void {
9890
this.genVarCounter = 0;
99-
this.currentSourceFile = undefined;
100-
this.isModule = false;
91+
this.luaLibFeatureSet = new Set<LuaLibFeature>();
92+
10193
this.scopeStack = [];
10294
this.classStack = [];
103-
this.luaLibFeatureSet = new Set<LuaLibFeature>();
104-
this.symbolIds = new Map();
95+
10596
this.symbolInfo = new Map();
97+
this.symbolIds = new Map();
10698
this.genSymbolIdCounter = 1;
10799
}
108100

109-
public transformSourceFile(node: ts.SourceFile): [tstl.Block, Set<LuaLibFeature>] {
110-
this.setupState();
101+
protected currentSourceFile!: ts.SourceFile;
102+
protected isModule!: boolean;
103+
protected resolver!: EmitResolver;
111104

112-
this.currentSourceFile = node;
105+
/** @internal */
106+
public transform(sourceFile: ts.SourceFile): [tstl.Block, Set<LuaLibFeature>] {
107+
this.setupState();
108+
this.currentSourceFile = sourceFile;
109+
this.isModule = tsHelper.isFileModule(sourceFile);
113110

114111
// Use `getParseTreeNode` to get original SourceFile node, before it was substituted by custom transformers.
115112
// It's required because otherwise `getEmitResolver` won't use cached diagnostics, produced in `emitWorker`
116113
// and would try to re-analyze the file, which would fail because of replaced nodes.
117-
const originalSourceFile = ts.getParseTreeNode(node, ts.isSourceFile) || node;
114+
const originalSourceFile = ts.getParseTreeNode(sourceFile, ts.isSourceFile) || sourceFile;
118115
this.resolver = this.checker.getEmitResolver(originalSourceFile);
119116

120-
let statements: tstl.Statement[] = [];
121-
if (node.flags & ts.NodeFlags.JsonFile) {
122-
this.isModule = false;
117+
return [this.transformSourceFile(sourceFile), this.luaLibFeatureSet];
118+
}
123119

124-
const statement = node.statements[0];
120+
public transformSourceFile(sourceFile: ts.SourceFile): tstl.Block {
121+
let statements: tstl.Statement[] = [];
122+
if (sourceFile.flags & ts.NodeFlags.JsonFile) {
123+
const statement = sourceFile.statements[0];
125124
if (!statement || !ts.isExpressionStatement(statement)) {
126-
throw TSTLErrors.InvalidJsonFileContent(node);
125+
throw TSTLErrors.InvalidJsonFileContent(sourceFile);
127126
}
128127

129128
statements.push(tstl.createReturnStatement([this.transformExpression(statement.expression)]));
130129
} else {
131130
this.pushScope(ScopeType.File);
132-
133-
this.isModule = tsHelper.isFileModule(node);
134-
statements = this.performHoisting(this.transformStatements(node.statements));
135-
131+
statements = this.performHoisting(this.transformStatements(sourceFile.statements));
136132
this.popScope();
137133

138134
if (this.isModule) {
@@ -149,7 +145,7 @@ export class LuaTransformer {
149145
}
150146
}
151147

152-
return [tstl.createBlock(statements, node), this.luaLibFeatureSet];
148+
return tstl.createBlock(statements, sourceFile);
153149
}
154150

155151
public transformStatement(node: ts.Statement): StatementVisitResult {
@@ -484,10 +480,6 @@ export class LuaTransformer {
484480

485481
expression = this.transformExternalModuleReference(declaration.moduleReference);
486482
} else {
487-
if (this.currentSourceFile === undefined) {
488-
throw TSTLErrors.MissingSourceFile();
489-
}
490-
491483
const shouldEmit =
492484
this.resolver.isReferencedAliasDeclaration(declaration) ||
493485
(!ts.isExternalModule(this.currentSourceFile) &&
@@ -4974,14 +4966,11 @@ export class LuaTransformer {
49744966
}
49754967

49764968
protected isSymbolExported(symbol: ts.Symbol): boolean {
4977-
if (tsHelper.getExportedSymbolDeclaration(symbol) !== undefined) {
4978-
return true;
4979-
} else if (this.currentSourceFile) {
4969+
return (
4970+
tsHelper.getExportedSymbolDeclaration(symbol) !== undefined ||
49804971
// Symbol may have been exported separately (e.g. 'const foo = "bar"; export { foo }')
4981-
return this.isSymbolExportedFromScope(symbol, this.currentSourceFile);
4982-
} else {
4983-
return false;
4984-
}
4972+
this.isSymbolExportedFromScope(symbol, this.currentSourceFile)
4973+
);
49854974
}
49864975

49874976
protected isSymbolExportedFromScope(symbol: ts.Symbol, scope: ts.SourceFile | ts.ModuleDeclaration): boolean {
@@ -5120,10 +5109,6 @@ export class LuaTransformer {
51205109
return path.resolve(this.options.baseUrl, relativePath);
51215110
}
51225111

5123-
if (this.currentSourceFile === undefined) {
5124-
throw TSTLErrors.MissingSourceFile();
5125-
}
5126-
51275112
return path.resolve(path.dirname(this.currentSourceFile.fileName), relativePath);
51285113
}
51295114

@@ -5194,7 +5179,8 @@ export class LuaTransformer {
51945179
let isFirstDeclaration = true; // var can have multiple declarations for the same variable :/
51955180
if (tsOriginal && ts.isVariableDeclaration(tsOriginal) && tsOriginal.parent) {
51965181
isLetOrConst = (tsOriginal.parent.flags & (ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0;
5197-
isFirstDeclaration = isLetOrConst || tsHelper.isFirstDeclaration(tsOriginal, this.checker);
5182+
isFirstDeclaration =
5183+
isLetOrConst || tsHelper.isFirstDeclaration(tsOriginal, this.checker, this.currentSourceFile);
51985184
}
51995185
if ((this.isModule || this.currentNamespace || insideFunction || isLetOrConst) && isFirstDeclaration) {
52005186
// local
@@ -5560,10 +5546,6 @@ export class LuaTransformer {
55605546
}
55615547

55625548
if (scope.functionDefinitions) {
5563-
if (this.currentSourceFile === undefined) {
5564-
throw TSTLErrors.MissingSourceFile();
5565-
}
5566-
55675549
for (const [functionSymbolId, functionDefinition] of scope.functionDefinitions) {
55685550
if (functionDefinition.definition === undefined) {
55695551
throw TSTLErrors.UndefinedFunctionDefinition(functionSymbolId);

src/TSHelper.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -731,14 +731,12 @@ export function isFalsible(type: ts.Type, strictNullChecks: boolean): boolean {
731731
return false;
732732
}
733733

734-
export function getFirstDeclaration(symbol: ts.Symbol, sourceFile?: ts.SourceFile): ts.Declaration | undefined {
734+
export function getFirstDeclaration(symbol: ts.Symbol, sourceFile: ts.SourceFile): ts.Declaration | undefined {
735735
let declarations = symbol.getDeclarations();
736736
if (!declarations) {
737737
return undefined;
738738
}
739-
if (sourceFile) {
740-
declarations = declarations.filter(d => findFirstNodeAbove(d, ts.isSourceFile) === sourceFile);
741-
}
739+
declarations = declarations.filter(d => findFirstNodeAbove(d, ts.isSourceFile) === sourceFile);
742740
return declarations.length > 0 ? declarations.reduce((p, c) => (p.pos < c.pos ? p : c)) : undefined;
743741
}
744742

@@ -751,12 +749,17 @@ export function getRawLiteral(node: ts.LiteralLikeNode): string {
751749
return text;
752750
}
753751

754-
export function isFirstDeclaration(node: ts.VariableDeclaration, checker: ts.TypeChecker): boolean {
752+
export function isFirstDeclaration(
753+
node: ts.VariableDeclaration,
754+
checker: ts.TypeChecker,
755+
sourceFile: ts.SourceFile
756+
): boolean {
755757
const symbol = checker.getSymbolAtLocation(node.name);
756758
if (!symbol) {
757759
return false;
758760
}
759-
const firstDeclaration = getFirstDeclaration(symbol);
761+
762+
const firstDeclaration = getFirstDeclaration(symbol, sourceFile);
760763
return firstDeclaration === node;
761764
}
762765

src/TSTLErrors.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,6 @@ export const MissingFunctionName = (declaration: ts.FunctionLikeDeclaration) =>
9090
export const MissingMetaExtension = (node: ts.Node) =>
9191
new TranspileError(`@metaExtension requires the extension of the metatable class.`, node);
9292

93-
export const MissingSourceFile = () => new Error("Expected transformer.sourceFile to be set, but it isn't.");
94-
9593
export const UndefinedFunctionDefinition = (functionSymbolId: number) =>
9694
new Error(`Function definition for function symbol ${functionSymbolId} is undefined.`);
9795

src/Transpile.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export function transpile({
8282

8383
const processSourceFile = (sourceFile: ts.SourceFile) => {
8484
try {
85-
const [luaAst, lualibFeatureSet] = transformer.transformSourceFile(sourceFile);
85+
const [luaAst, lualibFeatureSet] = transformer.transform(sourceFile);
8686
if (!options.noEmit && !options.emitDeclarationOnly) {
8787
const [lua, sourceMap] = printer.print(luaAst, lualibFeatureSet, sourceFile.fileName);
8888
updateTranspiledFile(sourceFile.fileName, { luaAst, lua, sourceMap });

0 commit comments

Comments
 (0)
X Tutup