@@ -2290,6 +2290,8 @@ export class Compiler extends DiagnosticEmitter {
22902290 private compileBlockStatement (
22912291 statement : BlockStatement
22922292 ) : ExpressionRef {
2293+ if ( statement . label ) return this . compileLabeledBlockStatement ( statement ) ;
2294+
22932295 let statements = statement . statements ;
22942296 let outerFlow = this . currentFlow ;
22952297 let innerFlow = outerFlow . fork ( ) ;
@@ -2301,6 +2303,30 @@ export class Compiler extends DiagnosticEmitter {
23012303 return this . module . flatten ( stmts ) ;
23022304 }
23032305
2306+ private compileLabeledBlockStatement (
2307+ statement : BlockStatement
2308+ ) : ExpressionRef {
2309+ let statements = statement . statements ;
2310+ let outerFlow = this . currentFlow ;
2311+ let innerFlow = outerFlow . fork ( ) ;
2312+
2313+ let labelNode = assert ( statement . label ) ;
2314+ let label = innerFlow . pushControlFlowLabel ( ) ;
2315+ let breakLabel = `block-break|${ label } ` ;
2316+ innerFlow . addUserLabel ( labelNode . text , breakLabel , null , labelNode ) ;
2317+ this . currentFlow = innerFlow ;
2318+
2319+ let stmts = this . compileStatements ( statements ) ;
2320+ innerFlow . popControlFlowLabel ( label ) ;
2321+ innerFlow . removeUserLabel ( labelNode . text ) ;
2322+
2323+ outerFlow . inherit ( innerFlow ) ;
2324+ this . currentFlow = outerFlow ;
2325+ return innerFlow . isAny ( FlowFlags . Breaks | FlowFlags . ConditionallyBreaks )
2326+ ? this . module . block ( breakLabel , stmts )
2327+ : this . module . flatten ( stmts ) ;
2328+ }
2329+
23042330 private compileTypeDeclaration ( statement : TypeDeclaration ) : ExpressionRef {
23052331 let flow = this . currentFlow ;
23062332 let name = statement . name . text ;
@@ -2324,23 +2350,25 @@ export class Compiler extends DiagnosticEmitter {
23242350 ) : ExpressionRef {
23252351 let module = this . module ;
23262352 let labelNode = statement . label ;
2353+ let flow = this . currentFlow ;
2354+ let breakLabel : string | null = null ;
23272355 if ( labelNode ) {
2328- this . error (
2329- DiagnosticCode . Not_implemented_0 ,
2330- labelNode . range ,
2331- "Break label"
2332- ) ;
2333- return module . unreachable ( ) ;
2356+ const userLabel = flow . getUserLabel ( labelNode . text ) ;
2357+ if ( userLabel ) breakLabel = userLabel . breakLabel ;
2358+ } else {
2359+ breakLabel = flow . breakLabel ;
23342360 }
2335- let flow = this . currentFlow ;
2336- let breakLabel = flow . breakLabel ;
2361+
23372362 if ( breakLabel == null ) {
23382363 this . error (
2339- DiagnosticCode . A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement ,
2364+ labelNode
2365+ ? DiagnosticCode . A_break_statement_can_only_jump_to_a_label_of_an_enclosing_statement
2366+ : DiagnosticCode . A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement ,
23402367 statement . range
23412368 ) ;
23422369 return module . unreachable ( ) ;
23432370 }
2371+
23442372 flow . set ( FlowFlags . Breaks ) ;
23452373 return module . br ( breakLabel ) ;
23462374 }
@@ -2349,25 +2377,27 @@ export class Compiler extends DiagnosticEmitter {
23492377 statement : ContinueStatement
23502378 ) : ExpressionRef {
23512379 let module = this . module ;
2352- let label = statement . label ;
2353- if ( label ) {
2354- this . error (
2355- DiagnosticCode . Not_implemented_0 ,
2356- label . range ,
2357- "Continue label"
2358- ) ;
2359- return module . unreachable ( ) ;
2380+ let labelNode = statement . label ;
2381+ let flow = this . currentFlow ;
2382+ let continueLabel : string | null = null ;
2383+ if ( labelNode ) {
2384+ const userLabel = flow . getUserLabel ( labelNode . text ) ;
2385+ if ( userLabel ) continueLabel = userLabel . continueLabel ;
2386+ } else {
2387+ continueLabel = flow . continueLabel ;
23602388 }
2389+
23612390 // Check if 'continue' is allowed here
2362- let flow = this . currentFlow ;
2363- let continueLabel = flow . continueLabel ;
23642391 if ( continueLabel == null ) {
23652392 this . error (
2366- DiagnosticCode . A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement ,
2393+ labelNode
2394+ ? DiagnosticCode . A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement
2395+ : DiagnosticCode . A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement ,
23672396 statement . range
23682397 ) ;
23692398 return module . unreachable ( ) ;
23702399 }
2400+
23712401 flow . set ( FlowFlags . Continues | FlowFlags . Terminates ) ;
23722402 return module . br ( continueLabel ) ;
23732403 }
@@ -2409,6 +2439,8 @@ export class Compiler extends DiagnosticEmitter {
24092439 let continueLabel = `do-continue|${ label } ` ;
24102440 flow . continueLabel = continueLabel ;
24112441 let loopLabel = `do-loop|${ label } ` ;
2442+ let labelNode = statement . label ;
2443+ if ( labelNode ) flow . addUserLabel ( labelNode . text , breakLabel , continueLabel , labelNode ) ;
24122444 this . currentFlow = flow ;
24132445 let bodyStmts = new Array < ExpressionRef > ( ) ;
24142446 let body = statement . body ;
@@ -2418,6 +2450,7 @@ export class Compiler extends DiagnosticEmitter {
24182450 bodyStmts . push ( this . compileStatement ( body ) ) ;
24192451 }
24202452 flow . popControlFlowLabel ( label ) ;
2453+ if ( labelNode ) flow . removeUserLabel ( labelNode . text ) ;
24212454
24222455 let possiblyContinues = flow . isAny ( FlowFlags . Continues | FlowFlags . ConditionallyContinues ) ;
24232456 let possiblyBreaks = flow . isAny ( FlowFlags . Breaks | FlowFlags . ConditionallyBreaks ) ;
@@ -2573,6 +2606,8 @@ export class Compiler extends DiagnosticEmitter {
25732606 bodyFlow . breakLabel = breakLabel ;
25742607 let continueLabel = `for-continue|${ label } ` ;
25752608 bodyFlow . continueLabel = continueLabel ;
2609+ let labelNode = statement . label ;
2610+ if ( labelNode ) bodyFlow . addUserLabel ( labelNode . text , breakLabel , continueLabel , labelNode ) ;
25762611 let loopLabel = `for-loop|${ label } ` ;
25772612 this . currentFlow = bodyFlow ;
25782613 let bodyStmts = new Array < ExpressionRef > ( ) ;
@@ -2583,6 +2618,7 @@ export class Compiler extends DiagnosticEmitter {
25832618 bodyStmts . push ( this . compileStatement ( body ) ) ;
25842619 }
25852620 bodyFlow . popControlFlowLabel ( label ) ;
2621+ if ( labelNode ) bodyFlow . removeUserLabel ( labelNode . text ) ;
25862622 bodyFlow . breakLabel = null ;
25872623 bodyFlow . continueLabel = null ;
25882624
@@ -2802,6 +2838,7 @@ export class Compiler extends DiagnosticEmitter {
28022838 ) : ExpressionRef {
28032839 let module = this . module ;
28042840 let cases = statement . cases ;
2841+ let labelNode = statement . label ;
28052842 let numCases = cases . length ;
28062843
28072844 // Compile the condition (always executes)
@@ -2824,6 +2861,9 @@ export class Compiler extends DiagnosticEmitter {
28242861 let breakIndex = 1 ;
28252862 let defaultIndex = - 1 ;
28262863 let label = outerFlow . pushControlFlowLabel ( ) ;
2864+ let breakLabel = `break|${ label } ` ;
2865+ if ( labelNode ) outerFlow . addUserLabel ( labelNode . text , breakLabel , null , labelNode ) ;
2866+
28272867 for ( let i = 0 ; i < numCases ; ++ i ) {
28282868 let case_ = cases [ i ] ;
28292869 if ( case_ . isDefault ) {
@@ -2843,7 +2883,7 @@ export class Compiler extends DiagnosticEmitter {
28432883 // If there is a default case, break to it, otherwise break out of the switch
28442884 breaks [ breakIndex ] = module . br ( defaultIndex >= 0
28452885 ? `case${ defaultIndex } |${ label } `
2846- : `break| ${ label } `
2886+ : breakLabel
28472887 ) ;
28482888
28492889 // Nest the case blocks in order, to be targeted by the br_if sequence
@@ -2859,7 +2899,6 @@ export class Compiler extends DiagnosticEmitter {
28592899 let innerFlow = outerFlow . fork ( /* newBreakContext */ true , /* newContinueContext */ false ) ;
28602900 if ( fallThroughFlow ) innerFlow . mergeBranch ( fallThroughFlow ) ;
28612901 this . currentFlow = innerFlow ;
2862- let breakLabel = `break|${ label } ` ;
28632902 innerFlow . breakLabel = breakLabel ;
28642903
28652904 let isLast = i == numCases - 1 ;
@@ -2897,6 +2936,7 @@ export class Compiler extends DiagnosticEmitter {
28972936 currentBlock = module . block ( nextLabel , stmts , TypeRef . None ) ; // must be a labeled block
28982937 }
28992938 outerFlow . popControlFlowLabel ( label ) ;
2939+ if ( labelNode ) outerFlow . removeUserLabel ( labelNode . text ) ;
29002940
29012941 // If the switch has a default, we only get past through any breaking flow
29022942 if ( defaultIndex >= 0 ) {
@@ -3208,6 +3248,8 @@ export class Compiler extends DiagnosticEmitter {
32083248 thenFlow . breakLabel = breakLabel ;
32093249 let continueLabel = `while-continue|${ label } ` ;
32103250 thenFlow . continueLabel = continueLabel ;
3251+ let labelNode = statement . label ;
3252+ if ( labelNode ) thenFlow . addUserLabel ( labelNode . text , breakLabel , continueLabel , labelNode ) ;
32113253 this . currentFlow = thenFlow ;
32123254 let bodyStmts = new Array < ExpressionRef > ( ) ;
32133255 let body = statement . body ;
@@ -3220,6 +3262,7 @@ export class Compiler extends DiagnosticEmitter {
32203262 module . br ( continueLabel )
32213263 ) ;
32223264 thenFlow . popControlFlowLabel ( label ) ;
3265+ if ( labelNode ) thenFlow . removeUserLabel ( labelNode . text ) ;
32233266
32243267 let possiblyContinues = thenFlow . isAny ( FlowFlags . Continues | FlowFlags . ConditionallyContinues ) ;
32253268 let possiblyBreaks = thenFlow . isAny ( FlowFlags . Breaks | FlowFlags . ConditionallyBreaks ) ;
0 commit comments