@@ -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
@@ -2683,17 +2719,27 @@ export class Compiler extends DiagnosticEmitter {
26832719 ) ;
26842720 let condKind = this . evaluateCondition ( condExprTrueish ) ;
26852721
2722+ let flow = this . currentFlow ;
2723+ let label = - 1 ;
2724+ let labelNode = statement . label ;
2725+ let breakLabel : string | null = null ;
2726+ if ( labelNode ) {
2727+ label = flow . pushControlFlowLabel ( ) ;
2728+ breakLabel = `if-break|${ label } ` ;
2729+ flow . addUserLabel ( labelNode . text , breakLabel , null , labelNode ) ;
2730+ }
2731+
26862732 // Shortcut if the condition is constant
26872733 switch ( condKind ) {
26882734 case ConditionKind . True : {
2689- return module . block ( null , [
2735+ return module . block ( breakLabel , [
26902736 module . drop ( condExprTrueish ) ,
26912737 this . compileStatement ( ifTrue )
26922738 ] ) ;
26932739 }
26942740 case ConditionKind . False : {
26952741 return ifFalse
2696- ? module . block ( null , [
2742+ ? module . block ( breakLabel , [
26972743 module . drop ( condExprTrueish ) ,
26982744 this . compileStatement ( ifFalse )
26992745 ] )
@@ -2703,8 +2749,6 @@ export class Compiler extends DiagnosticEmitter {
27032749
27042750 // From here on condition is always unknown
27052751
2706- let flow = this . currentFlow ;
2707-
27082752 // Compile ifTrue assuming the condition turned out true
27092753 let thenStmts = new Array < ExpressionRef > ( ) ;
27102754 let thenFlow = flow . forkThen ( condExpr ) ;
@@ -2717,6 +2761,7 @@ export class Compiler extends DiagnosticEmitter {
27172761 this . currentFlow = flow ;
27182762
27192763 // Compile ifFalse assuming the condition turned out false, if present
2764+ let expr : ExpressionRef ;
27202765 let elseFlow = flow . forkElse ( condExpr ) ;
27212766 if ( ifFalse ) {
27222767 this . currentFlow = elseFlow ;
@@ -2728,7 +2773,7 @@ export class Compiler extends DiagnosticEmitter {
27282773 }
27292774 flow . inheritAlternatives ( thenFlow , elseFlow ) ; // terminates if both do
27302775 this . currentFlow = flow ;
2731- return module . if ( condExprTrueish ,
2776+ expr = module . if ( condExprTrueish ,
27322777 module . flatten ( thenStmts ) ,
27332778 module . flatten ( elseStmts )
27342779 ) ;
@@ -2742,10 +2787,15 @@ export class Compiler extends DiagnosticEmitter {
27422787 flow . inheritAlternatives ( thenFlow , elseFlow ) ;
27432788 }
27442789 this . currentFlow = flow ;
2745- return module . if ( condExprTrueish ,
2790+ expr = module . if ( condExprTrueish ,
27462791 module . flatten ( thenStmts )
27472792 ) ;
27482793 }
2794+
2795+ if ( ! labelNode ) return expr ;
2796+ flow . popControlFlowLabel ( label ) ;
2797+ flow . removeUserLabel ( labelNode . text ) ;
2798+ return module . block ( breakLabel , [ expr ] ) ;
27492799 }
27502800
27512801 private compileReturnStatement (
@@ -2802,6 +2852,7 @@ export class Compiler extends DiagnosticEmitter {
28022852 ) : ExpressionRef {
28032853 let module = this . module ;
28042854 let cases = statement . cases ;
2855+ let labelNode = statement . label ;
28052856 let numCases = cases . length ;
28062857
28072858 // Compile the condition (always executes)
@@ -2824,6 +2875,9 @@ export class Compiler extends DiagnosticEmitter {
28242875 let breakIndex = 1 ;
28252876 let defaultIndex = - 1 ;
28262877 let label = outerFlow . pushControlFlowLabel ( ) ;
2878+ let breakLabel = `break|${ label } ` ;
2879+ if ( labelNode ) outerFlow . addUserLabel ( labelNode . text , breakLabel , null , labelNode ) ;
2880+
28272881 for ( let i = 0 ; i < numCases ; ++ i ) {
28282882 let case_ = cases [ i ] ;
28292883 if ( case_ . isDefault ) {
@@ -2843,7 +2897,7 @@ export class Compiler extends DiagnosticEmitter {
28432897 // If there is a default case, break to it, otherwise break out of the switch
28442898 breaks [ breakIndex ] = module . br ( defaultIndex >= 0
28452899 ? `case${ defaultIndex } |${ label } `
2846- : `break| ${ label } `
2900+ : breakLabel
28472901 ) ;
28482902
28492903 // Nest the case blocks in order, to be targeted by the br_if sequence
@@ -2859,7 +2913,6 @@ export class Compiler extends DiagnosticEmitter {
28592913 let innerFlow = outerFlow . fork ( /* newBreakContext */ true , /* newContinueContext */ false ) ;
28602914 if ( fallThroughFlow ) innerFlow . mergeBranch ( fallThroughFlow ) ;
28612915 this . currentFlow = innerFlow ;
2862- let breakLabel = `break|${ label } ` ;
28632916 innerFlow . breakLabel = breakLabel ;
28642917
28652918 let isLast = i == numCases - 1 ;
@@ -2897,6 +2950,7 @@ export class Compiler extends DiagnosticEmitter {
28972950 currentBlock = module . block ( nextLabel , stmts , TypeRef . None ) ; // must be a labeled block
28982951 }
28992952 outerFlow . popControlFlowLabel ( label ) ;
2953+ if ( labelNode ) outerFlow . removeUserLabel ( labelNode . text ) ;
29002954
29012955 // If the switch has a default, we only get past through any breaking flow
29022956 if ( defaultIndex >= 0 ) {
@@ -3208,6 +3262,8 @@ export class Compiler extends DiagnosticEmitter {
32083262 thenFlow . breakLabel = breakLabel ;
32093263 let continueLabel = `while-continue|${ label } ` ;
32103264 thenFlow . continueLabel = continueLabel ;
3265+ let labelNode = statement . label ;
3266+ if ( labelNode ) thenFlow . addUserLabel ( labelNode . text , breakLabel , continueLabel , labelNode ) ;
32113267 this . currentFlow = thenFlow ;
32123268 let bodyStmts = new Array < ExpressionRef > ( ) ;
32133269 let body = statement . body ;
@@ -3220,6 +3276,7 @@ export class Compiler extends DiagnosticEmitter {
32203276 module . br ( continueLabel )
32213277 ) ;
32223278 thenFlow . popControlFlowLabel ( label ) ;
3279+ if ( labelNode ) thenFlow . removeUserLabel ( labelNode . text ) ;
32233280
32243281 let possiblyContinues = thenFlow . isAny ( FlowFlags . Continues | FlowFlags . ConditionallyContinues ) ;
32253282 let possiblyBreaks = thenFlow . isAny ( FlowFlags . Breaks | FlowFlags . ConditionallyBreaks ) ;
0 commit comments