forked from TypeScriptToLua/TypeScriptToLua
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontext.ts
More file actions
114 lines (91 loc) · 5.07 KB
/
context.ts
File metadata and controls
114 lines (91 loc) · 5.07 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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import * as ts from "typescript";
import { CompilerOptions, LuaTarget } from "../../CompilerOptions";
import * as lua from "../../LuaAST";
import { castArray } from "../../utils";
import { unsupportedNodeKind } from "../utils/diagnostics";
import { unwrapVisitorResult } from "../utils/lua-ast";
import { ExpressionLikeNode, ObjectVisitor, StatementLikeNode, VisitorMap } from "./visitors";
export interface AllAccessorDeclarations {
firstAccessor: ts.AccessorDeclaration;
secondAccessor: ts.AccessorDeclaration | undefined;
getAccessor: ts.GetAccessorDeclaration | undefined;
setAccessor: ts.SetAccessorDeclaration | undefined;
}
export interface EmitResolver {
isValueAliasDeclaration(node: ts.Node): boolean;
isReferencedAliasDeclaration(node: ts.Node, checkChildren?: boolean): boolean;
isTopLevelValueImportEqualsWithEntityName(node: ts.ImportEqualsDeclaration): boolean;
moduleExportsSomeValue(moduleReferenceExpression: ts.Expression): boolean;
getAllAccessorDeclarations(declaration: ts.AccessorDeclaration): AllAccessorDeclarations;
}
export interface DiagnosticsProducingTypeChecker extends ts.TypeChecker {
getEmitResolver(sourceFile?: ts.SourceFile, cancellationToken?: ts.CancellationToken): EmitResolver;
}
export class TransformationContext {
public readonly diagnostics: ts.Diagnostic[] = [];
public readonly checker: DiagnosticsProducingTypeChecker = (this
.program as any).getDiagnosticsProducingTypeChecker();
public readonly resolver: EmitResolver;
public readonly options: CompilerOptions = this.program.getCompilerOptions();
public readonly luaTarget = this.options.luaTarget ?? LuaTarget.Universal;
public readonly isModule = ts.isExternalModule(this.sourceFile);
public readonly isStrict =
(this.options.alwaysStrict ?? this.options.strict) ||
(this.isModule && this.options.target !== undefined && this.options.target >= ts.ScriptTarget.ES2015);
constructor(public program: ts.Program, public sourceFile: ts.SourceFile, private visitorMap: VisitorMap) {
// Use `getParseTreeNode` to get original SourceFile node, before it was substituted by custom transformers.
// It's required because otherwise `getEmitResolver` won't use cached diagnostics, produced in `emitWorker`
// and would try to re-analyze the file, which would fail because of replaced nodes.
const originalSourceFile = ts.getParseTreeNode(sourceFile, ts.isSourceFile) ?? sourceFile;
this.resolver = this.checker.getEmitResolver(originalSourceFile);
}
private currentNodeVisitors: Array<ObjectVisitor<ts.Node>> = [];
public transformNode(node: ts.Node): lua.Node[];
/** @internal */
// eslint-disable-next-line @typescript-eslint/unified-signatures
public transformNode(node: ts.Node, isExpression?: boolean): lua.Node[];
public transformNode(node: ts.Node, isExpression?: boolean): lua.Node[] {
// TODO: Move to visitors?
if (node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.DeclareKeyword)) {
return [];
}
const nodeVisitors = this.visitorMap.get(node.kind);
if (!nodeVisitors || nodeVisitors.length === 0) {
this.diagnostics.push(unsupportedNodeKind(node, node.kind));
return isExpression ? [lua.createNilLiteral()] : [];
}
const previousNodeVisitors = this.currentNodeVisitors;
this.currentNodeVisitors = [...nodeVisitors];
const visitor = this.currentNodeVisitors.pop()!;
const result = unwrapVisitorResult(visitor.transform(node, this));
this.currentNodeVisitors = previousNodeVisitors;
return result;
}
public superTransformNode(node: ts.Node): lua.Node[] {
if (this.currentNodeVisitors.length === 0) {
throw new Error(`There is no super transform for ${ts.SyntaxKind[node.kind]} visitor`);
}
const visitor = this.currentNodeVisitors.pop()!;
return unwrapVisitorResult(visitor.transform(node, this));
}
public transformExpression(node: ExpressionLikeNode): lua.Expression {
const [result] = this.transformNode(node, true);
if (result === undefined) {
throw new Error(`Expression visitor for node type ${ts.SyntaxKind[node.kind]} did not return any result.`);
}
return result as lua.Expression;
}
public superTransformExpression(node: ExpressionLikeNode): lua.Expression {
const [result] = this.superTransformNode(node);
if (result === undefined) {
throw new Error(`Expression visitor for node type ${ts.SyntaxKind[node.kind]} did not return any result.`);
}
return result as lua.Expression;
}
public transformStatements(node: StatementLikeNode | readonly StatementLikeNode[]): lua.Statement[] {
return castArray(node).flatMap(n => this.transformNode(n) as lua.Statement[]);
}
public superTransformStatements(node: StatementLikeNode | readonly StatementLikeNode[]): lua.Statement[] {
return castArray(node).flatMap(n => this.superTransformNode(n) as lua.Statement[]);
}
}