@@ -21,9 +21,11 @@ const containsBreakOrReturn = (statements: ts.Node[]): boolean => {
2121export const transformSwitchStatement : FunctionVisitor < ts . SwitchStatement > = ( statement , context ) => {
2222 const scope = pushScope ( context , ScopeType . Switch ) ;
2323
24- // Give the switch a unique name to prevent nested switches from acting up.
24+ // Give the switch and condition accumulator a unique name to prevent nested switches from acting up.
2525 const switchName = `____switch${ scope . id } ` ;
26+ const conditionName = `____cond${ scope . id } ` ;
2627 const switchVariable = lua . createIdentifier ( switchName ) ;
28+ const conditionVariable = lua . createIdentifier ( conditionName ) ;
2729
2830 // Collect all the expressions into a single expression for use in the default clause
2931 let allExpressions : lua . BinaryExpression ;
@@ -62,11 +64,11 @@ export const transformSwitchStatement: FunctionVisitor<ts.SwitchStatement> = (st
6264 // Fallthrough is handled by accepting the last condition as an additional or clause
6365 // Default is the not of all known case expressions
6466 let previousClause : ts . CaseOrDefaultClause ;
65- let condition : lua . Expression ;
67+ let condition : lua . Expression | undefined ;
6668 statement . caseBlock . clauses . forEach ( clause => {
6769 if ( ! condition || ( previousClause && containsBreakOrReturn ( [ ...previousClause . statements ] ) ) ) {
6870 if ( ts . isDefaultClause ( clause ) ) {
69- condition = lua . createUnaryExpression ( allExpressions , lua . SyntaxKind . NotOperator ) ;
71+ // If the default is first, or followed by a break, we can't fall into it, skip.
7072 } else {
7173 condition = lua . createBinaryExpression (
7274 switchVariable ,
@@ -76,11 +78,7 @@ export const transformSwitchStatement: FunctionVisitor<ts.SwitchStatement> = (st
7678 }
7779 } else {
7880 if ( ts . isDefaultClause ( clause ) ) {
79- condition = lua . createBinaryExpression (
80- condition ,
81- lua . createUnaryExpression ( allExpressions , lua . SyntaxKind . NotOperator ) ,
82- lua . SyntaxKind . OrOperator
83- ) ;
81+ // use the previous condition for the default clause
8482 } else {
8583 condition = lua . createBinaryExpression (
8684 condition ,
@@ -94,14 +92,50 @@ export const transformSwitchStatement: FunctionVisitor<ts.SwitchStatement> = (st
9492 }
9593 }
9694
97- if ( condition && clause . statements . length ) {
95+ if ( clause . statements . length ) {
96+ if ( ! ts . isDefaultClause ( clause ) && condition ) {
97+ statements . push (
98+ lua . createAssignmentStatement (
99+ conditionVariable ,
100+ lua . createBinaryExpression ( conditionVariable , condition , lua . SyntaxKind . OrOperator )
101+ )
102+ ) ;
103+ condition = undefined ;
104+ }
105+
98106 statements . push (
99- lua . createIfStatement ( condition , lua . createBlock ( context . transformStatements ( clause . statements ) ) )
107+ lua . createIfStatement (
108+ conditionVariable ,
109+ lua . createBlock ( context . transformStatements ( clause . statements ) )
110+ )
100111 ) ;
101112 }
102113
103114 previousClause = clause ;
104115 } ) ;
116+
117+ // Amalgamate the default w/ fallthrough clauses and execute if nothing else executed above
118+ const start = clauses . findIndex ( c => ts . isDefaultClause ( c ) ) ;
119+ if ( start >= 0 ) {
120+ const end = statement . caseBlock . clauses
121+ . slice ( start )
122+ . findIndex ( clause => containsBreakOrReturn ( [ ...clause . statements ] ) ) ;
123+ const defaultStatements = statement . caseBlock . clauses
124+ . slice ( start , end >= 0 ? end + start + 1 : undefined )
125+ . reduce < lua . Statement [ ] > (
126+ ( statements , clause ) => [ ...statements , ...context . transformStatements ( clause . statements ) ] ,
127+ [ ]
128+ ) ;
129+
130+ if ( defaultStatements . length ) {
131+ statements . push (
132+ lua . createIfStatement (
133+ lua . createUnaryExpression ( conditionVariable , lua . SyntaxKind . NotOperator ) ,
134+ lua . createBlock ( defaultStatements )
135+ )
136+ ) ;
137+ }
138+ }
105139 }
106140
107141 // Hoist the variable, function, and import statements to the top of the switch
@@ -110,6 +144,7 @@ export const transformSwitchStatement: FunctionVisitor<ts.SwitchStatement> = (st
110144
111145 // Add the switch expression after hoisting
112146 const expression = context . transformExpression ( statement . expression ) ;
147+ statements . unshift ( lua . createVariableDeclarationStatement ( conditionVariable , lua . createBooleanLiteral ( false ) ) ) ;
113148 statements . unshift ( lua . createVariableDeclarationStatement ( switchVariable , expression ) ) ;
114149
115150 // Wrap the statements in a repeat until true statement to facilitate dynamic break/returns
0 commit comments