11import * as ts from "typescript" ;
22import { LuaTarget } from "../../CompilerOptions" ;
33import * as lua from "../../LuaAST" ;
4+ import { assert } from "../../utils" ;
45import { TransformationContext } from "../context" ;
56import { getCurrentNamespace } from "../visitors/namespace" ;
67import { createExportedIdentifier , getIdentifierExportScope } from "./export" ;
78import { findScope , peekScope , ScopeType } from "./scope" ;
8- import { isFirstDeclaration , isFunctionType } from "./typescript" ;
9+ import { isFunctionType } from "./typescript" ;
910
1011export type OneToManyVisitorResult < T extends lua . Node > = T | T [ ] | undefined ;
1112export function unwrapVisitorResult < T extends lua . Node > ( result : OneToManyVisitorResult < T > ) : T [ ] {
@@ -26,22 +27,6 @@ export function createExportsIdentifier(): lua.Identifier {
2627 return lua . createIdentifier ( "____exports" ) ;
2728}
2829
29- export function replaceStatementInParent ( oldNode : lua . Statement , newNode ?: lua . Statement ) : void {
30- if ( ! oldNode . parent ) {
31- throw new Error ( "node has not yet been assigned a parent" ) ;
32- }
33-
34- if ( lua . isBlock ( oldNode . parent ) || lua . isDoStatement ( oldNode . parent ) ) {
35- if ( newNode ) {
36- oldNode . parent . statements . splice ( oldNode . parent . statements . indexOf ( oldNode ) , 1 , newNode ) ;
37- } else {
38- oldNode . parent . statements . splice ( oldNode . parent . statements . indexOf ( oldNode ) , 1 ) ;
39- }
40- } else {
41- throw new Error ( "unexpected parent type" ) ;
42- }
43- }
44-
4530export function createExpressionPlusOne ( expression : lua . Expression ) : lua . Expression {
4631 if ( lua . isNumericLiteral ( expression ) ) {
4732 const newNode = lua . cloneNode ( expression ) ;
@@ -110,12 +95,13 @@ export function createHoistableVariableDeclarationStatement(
11095 context : TransformationContext ,
11196 identifier : lua . Identifier ,
11297 initializer ?: lua . Expression ,
113- tsOriginal ?: ts . Node ,
114- parent ?: lua . Node
98+ tsOriginal ?: ts . Node
11599) : lua . AssignmentStatement | lua . VariableDeclarationStatement {
116- const declaration = lua . createVariableDeclarationStatement ( identifier , initializer , tsOriginal , parent ) ;
100+ const declaration = lua . createVariableDeclarationStatement ( identifier , initializer , tsOriginal ) ;
117101 if ( ! context . options . noHoisting && identifier . symbolId ) {
118102 const scope = peekScope ( context ) ;
103+ assert ( scope . type !== ScopeType . Switch ) ;
104+
119105 if ( ! scope . variableDeclarations ) {
120106 scope . variableDeclarations = [ ] ;
121107 }
@@ -131,13 +117,13 @@ export function createLocalOrExportedOrGlobalDeclaration(
131117 lhs : lua . Identifier | lua . Identifier [ ] ,
132118 rhs ?: lua . Expression | lua . Expression [ ] ,
133119 tsOriginal ?: ts . Node ,
134- parent ?: lua . Node ,
135120 overrideExportScope ?: ts . SourceFile | ts . ModuleDeclaration
136121) : lua . Statement [ ] {
137122 let declaration : lua . VariableDeclarationStatement | undefined ;
138123 let assignment : lua . AssignmentStatement | undefined ;
139124
140- const functionDeclaration = tsOriginal && ts . isFunctionDeclaration ( tsOriginal ) ? tsOriginal : undefined ;
125+ const isVariableDeclaration = tsOriginal !== undefined && ts . isVariableDeclaration ( tsOriginal ) ;
126+ const isFunctionDeclaration = tsOriginal !== undefined && ts . isFunctionDeclaration ( tsOriginal ) ;
141127
142128 const identifiers = Array . isArray ( lhs ) ? lhs : [ lhs ] ;
143129 if ( identifiers . length === 0 ) {
@@ -153,62 +139,51 @@ export function createLocalOrExportedOrGlobalDeclaration(
153139 assignment = lua . createAssignmentStatement (
154140 identifiers . map ( identifier => createExportedIdentifier ( context , identifier , exportScope ) ) ,
155141 rhs ,
156- tsOriginal ,
157- parent
142+ tsOriginal
158143 ) ;
159144 }
160145 } else {
161146 const insideFunction = findScope ( context , ScopeType . Function ) !== undefined ;
162- let isLetOrConst = false ;
163- let isVariableFirstDeclaration = true ; // var can have multiple declarations for the same variable :/
164- if ( tsOriginal && ts . isVariableDeclaration ( tsOriginal ) && tsOriginal . parent ) {
165- isLetOrConst = ( tsOriginal . parent . flags & ( ts . NodeFlags . Let | ts . NodeFlags . Const ) ) !== 0 ;
166- isVariableFirstDeclaration = isLetOrConst || isFirstDeclaration ( context , tsOriginal ) ;
167- }
168147
169- if (
170- ( context . isModule || getCurrentNamespace ( context ) || insideFunction || isLetOrConst ) &&
171- isVariableFirstDeclaration
172- ) {
173- // local
148+ if ( context . isModule || getCurrentNamespace ( context ) || insideFunction || isVariableDeclaration ) {
149+ const scope = peekScope ( context ) ;
150+
174151 const isPossibleWrappedFunction =
175- ! functionDeclaration &&
152+ ! isFunctionDeclaration &&
176153 tsOriginal &&
177154 ts . isVariableDeclaration ( tsOriginal ) &&
178155 tsOriginal . initializer &&
179156 isFunctionType ( context , context . checker . getTypeAtLocation ( tsOriginal . initializer ) ) ;
180- if ( isPossibleWrappedFunction ) {
157+
158+ if ( isPossibleWrappedFunction || scope . type === ScopeType . Switch ) {
181159 // Split declaration and assignment for wrapped function types to allow recursion
182- declaration = lua . createVariableDeclarationStatement ( lhs , undefined , tsOriginal , parent ) ;
183- assignment = lua . createAssignmentStatement ( lhs , rhs , tsOriginal , parent ) ;
160+ declaration = lua . createVariableDeclarationStatement ( lhs , undefined , tsOriginal ) ;
161+ assignment = lua . createAssignmentStatement ( lhs , rhs , tsOriginal ) ;
184162 } else {
185- declaration = lua . createVariableDeclarationStatement ( lhs , rhs , tsOriginal , parent ) ;
163+ declaration = lua . createVariableDeclarationStatement ( lhs , rhs , tsOriginal ) ;
186164 }
187165
188166 if ( ! context . options . noHoisting ) {
189167 // Remember local variable declarations for hoisting later
190- const scope =
191- isLetOrConst || functionDeclaration
192- ? peekScope ( context )
193- : findScope ( context , ScopeType . Function | ScopeType . File ) ;
168+ if ( ! scope . variableDeclarations ) {
169+ scope . variableDeclarations = [ ] ;
170+ }
194171
195- if ( scope ) {
196- if ( ! scope . variableDeclarations ) {
197- scope . variableDeclarations = [ ] ;
198- }
172+ scope . variableDeclarations . push ( declaration ) ;
199173
200- scope . variableDeclarations . push ( declaration ) ;
174+ if ( scope . type === ScopeType . Switch ) {
175+ declaration = undefined ;
201176 }
202177 }
203178 } else if ( rhs ) {
204179 // global
205- assignment = lua . createAssignmentStatement ( lhs , rhs , tsOriginal , parent ) ;
180+ assignment = lua . createAssignmentStatement ( lhs , rhs , tsOriginal ) ;
206181 } else {
207182 return [ ] ;
208183 }
209184 }
210185
211- if ( ! context . options . noHoisting && functionDeclaration ) {
186+ if ( ! context . options . noHoisting && isFunctionDeclaration ) {
212187 // Remember function definitions for hoisting later
213188 const functionSymbolId = ( lhs as lua . Identifier ) . symbolId ;
214189 const scope = peekScope ( context ) ;
0 commit comments