@@ -2290,6 +2290,8 @@ export class Compiler extends DiagnosticEmitter {
2290
2290
private compileBlockStatement (
2291
2291
statement : BlockStatement
2292
2292
) : ExpressionRef {
2293
+ if ( statement . label ) return this . compileLabeledBlockStatement ( statement ) ;
2294
+
2293
2295
let statements = statement . statements ;
2294
2296
let outerFlow = this . currentFlow ;
2295
2297
let innerFlow = outerFlow . fork ( ) ;
@@ -2301,6 +2303,30 @@ export class Compiler extends DiagnosticEmitter {
2301
2303
return this . module . flatten ( stmts ) ;
2302
2304
}
2303
2305
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
+
2304
2330
private compileTypeDeclaration ( statement : TypeDeclaration ) : ExpressionRef {
2305
2331
let flow = this . currentFlow ;
2306
2332
let name = statement . name . text ;
@@ -2324,23 +2350,25 @@ export class Compiler extends DiagnosticEmitter {
2324
2350
) : ExpressionRef {
2325
2351
let module = this . module ;
2326
2352
let labelNode = statement . label ;
2353
+ let flow = this . currentFlow ;
2354
+ let breakLabel : string | null = null ;
2327
2355
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 ;
2334
2360
}
2335
- let flow = this . currentFlow ;
2336
- let breakLabel = flow . breakLabel ;
2361
+
2337
2362
if ( breakLabel == null ) {
2338
2363
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 ,
2340
2367
statement . range
2341
2368
) ;
2342
2369
return module . unreachable ( ) ;
2343
2370
}
2371
+
2344
2372
flow . set ( FlowFlags . Breaks ) ;
2345
2373
return module . br ( breakLabel ) ;
2346
2374
}
@@ -2349,25 +2377,27 @@ export class Compiler extends DiagnosticEmitter {
2349
2377
statement : ContinueStatement
2350
2378
) : ExpressionRef {
2351
2379
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 ;
2360
2388
}
2389
+
2361
2390
// Check if 'continue' is allowed here
2362
- let flow = this . currentFlow ;
2363
- let continueLabel = flow . continueLabel ;
2364
2391
if ( continueLabel == null ) {
2365
2392
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 ,
2367
2396
statement . range
2368
2397
) ;
2369
2398
return module . unreachable ( ) ;
2370
2399
}
2400
+
2371
2401
flow . set ( FlowFlags . Continues | FlowFlags . Terminates ) ;
2372
2402
return module . br ( continueLabel ) ;
2373
2403
}
@@ -2409,6 +2439,8 @@ export class Compiler extends DiagnosticEmitter {
2409
2439
let continueLabel = `do-continue|${ label } ` ;
2410
2440
flow . continueLabel = continueLabel ;
2411
2441
let loopLabel = `do-loop|${ label } ` ;
2442
+ let labelNode = statement . label ;
2443
+ if ( labelNode ) flow . addUserLabel ( labelNode . text , breakLabel , continueLabel , labelNode ) ;
2412
2444
this . currentFlow = flow ;
2413
2445
let bodyStmts = new Array < ExpressionRef > ( ) ;
2414
2446
let body = statement . body ;
@@ -2418,6 +2450,7 @@ export class Compiler extends DiagnosticEmitter {
2418
2450
bodyStmts . push ( this . compileStatement ( body ) ) ;
2419
2451
}
2420
2452
flow . popControlFlowLabel ( label ) ;
2453
+ if ( labelNode ) flow . removeUserLabel ( labelNode . text ) ;
2421
2454
2422
2455
let possiblyContinues = flow . isAny ( FlowFlags . Continues | FlowFlags . ConditionallyContinues ) ;
2423
2456
let possiblyBreaks = flow . isAny ( FlowFlags . Breaks | FlowFlags . ConditionallyBreaks ) ;
@@ -2573,6 +2606,8 @@ export class Compiler extends DiagnosticEmitter {
2573
2606
bodyFlow . breakLabel = breakLabel ;
2574
2607
let continueLabel = `for-continue|${ label } ` ;
2575
2608
bodyFlow . continueLabel = continueLabel ;
2609
+ let labelNode = statement . label ;
2610
+ if ( labelNode ) bodyFlow . addUserLabel ( labelNode . text , breakLabel , continueLabel , labelNode ) ;
2576
2611
let loopLabel = `for-loop|${ label } ` ;
2577
2612
this . currentFlow = bodyFlow ;
2578
2613
let bodyStmts = new Array < ExpressionRef > ( ) ;
@@ -2583,6 +2618,7 @@ export class Compiler extends DiagnosticEmitter {
2583
2618
bodyStmts . push ( this . compileStatement ( body ) ) ;
2584
2619
}
2585
2620
bodyFlow . popControlFlowLabel ( label ) ;
2621
+ if ( labelNode ) bodyFlow . removeUserLabel ( labelNode . text ) ;
2586
2622
bodyFlow . breakLabel = null ;
2587
2623
bodyFlow . continueLabel = null ;
2588
2624
@@ -2683,17 +2719,27 @@ export class Compiler extends DiagnosticEmitter {
2683
2719
) ;
2684
2720
let condKind = this . evaluateCondition ( condExprTrueish ) ;
2685
2721
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
+
2686
2732
// Shortcut if the condition is constant
2687
2733
switch ( condKind ) {
2688
2734
case ConditionKind . True : {
2689
- return module . block ( null , [
2735
+ return module . block ( breakLabel , [
2690
2736
module . drop ( condExprTrueish ) ,
2691
2737
this . compileStatement ( ifTrue )
2692
2738
] ) ;
2693
2739
}
2694
2740
case ConditionKind . False : {
2695
2741
return ifFalse
2696
- ? module . block ( null , [
2742
+ ? module . block ( breakLabel , [
2697
2743
module . drop ( condExprTrueish ) ,
2698
2744
this . compileStatement ( ifFalse )
2699
2745
] )
@@ -2703,8 +2749,6 @@ export class Compiler extends DiagnosticEmitter {
2703
2749
2704
2750
// From here on condition is always unknown
2705
2751
2706
- let flow = this . currentFlow ;
2707
-
2708
2752
// Compile ifTrue assuming the condition turned out true
2709
2753
let thenStmts = new Array < ExpressionRef > ( ) ;
2710
2754
let thenFlow = flow . forkThen ( condExpr ) ;
@@ -2717,6 +2761,7 @@ export class Compiler extends DiagnosticEmitter {
2717
2761
this . currentFlow = flow ;
2718
2762
2719
2763
// Compile ifFalse assuming the condition turned out false, if present
2764
+ let expr : ExpressionRef ;
2720
2765
let elseFlow = flow . forkElse ( condExpr ) ;
2721
2766
if ( ifFalse ) {
2722
2767
this . currentFlow = elseFlow ;
@@ -2728,7 +2773,7 @@ export class Compiler extends DiagnosticEmitter {
2728
2773
}
2729
2774
flow . inheritAlternatives ( thenFlow , elseFlow ) ; // terminates if both do
2730
2775
this . currentFlow = flow ;
2731
- return module . if ( condExprTrueish ,
2776
+ expr = module . if ( condExprTrueish ,
2732
2777
module . flatten ( thenStmts ) ,
2733
2778
module . flatten ( elseStmts )
2734
2779
) ;
@@ -2742,10 +2787,15 @@ export class Compiler extends DiagnosticEmitter {
2742
2787
flow . inheritAlternatives ( thenFlow , elseFlow ) ;
2743
2788
}
2744
2789
this . currentFlow = flow ;
2745
- return module . if ( condExprTrueish ,
2790
+ expr = module . if ( condExprTrueish ,
2746
2791
module . flatten ( thenStmts )
2747
2792
) ;
2748
2793
}
2794
+
2795
+ if ( ! labelNode ) return expr ;
2796
+ flow . popControlFlowLabel ( label ) ;
2797
+ flow . removeUserLabel ( labelNode . text ) ;
2798
+ return module . block ( breakLabel , [ expr ] ) ;
2749
2799
}
2750
2800
2751
2801
private compileReturnStatement (
@@ -2802,6 +2852,7 @@ export class Compiler extends DiagnosticEmitter {
2802
2852
) : ExpressionRef {
2803
2853
let module = this . module ;
2804
2854
let cases = statement . cases ;
2855
+ let labelNode = statement . label ;
2805
2856
let numCases = cases . length ;
2806
2857
2807
2858
// Compile the condition (always executes)
@@ -2824,6 +2875,9 @@ export class Compiler extends DiagnosticEmitter {
2824
2875
let breakIndex = 1 ;
2825
2876
let defaultIndex = - 1 ;
2826
2877
let label = outerFlow . pushControlFlowLabel ( ) ;
2878
+ let breakLabel = `break|${ label } ` ;
2879
+ if ( labelNode ) outerFlow . addUserLabel ( labelNode . text , breakLabel , null , labelNode ) ;
2880
+
2827
2881
for ( let i = 0 ; i < numCases ; ++ i ) {
2828
2882
let case_ = cases [ i ] ;
2829
2883
if ( case_ . isDefault ) {
@@ -2843,7 +2897,7 @@ export class Compiler extends DiagnosticEmitter {
2843
2897
// If there is a default case, break to it, otherwise break out of the switch
2844
2898
breaks [ breakIndex ] = module . br ( defaultIndex >= 0
2845
2899
? `case${ defaultIndex } |${ label } `
2846
- : `break| ${ label } `
2900
+ : breakLabel
2847
2901
) ;
2848
2902
2849
2903
// Nest the case blocks in order, to be targeted by the br_if sequence
@@ -2859,7 +2913,6 @@ export class Compiler extends DiagnosticEmitter {
2859
2913
let innerFlow = outerFlow . fork ( /* newBreakContext */ true , /* newContinueContext */ false ) ;
2860
2914
if ( fallThroughFlow ) innerFlow . mergeBranch ( fallThroughFlow ) ;
2861
2915
this . currentFlow = innerFlow ;
2862
- let breakLabel = `break|${ label } ` ;
2863
2916
innerFlow . breakLabel = breakLabel ;
2864
2917
2865
2918
let isLast = i == numCases - 1 ;
@@ -2897,6 +2950,7 @@ export class Compiler extends DiagnosticEmitter {
2897
2950
currentBlock = module . block ( nextLabel , stmts , TypeRef . None ) ; // must be a labeled block
2898
2951
}
2899
2952
outerFlow . popControlFlowLabel ( label ) ;
2953
+ if ( labelNode ) outerFlow . removeUserLabel ( labelNode . text ) ;
2900
2954
2901
2955
// If the switch has a default, we only get past through any breaking flow
2902
2956
if ( defaultIndex >= 0 ) {
@@ -3208,6 +3262,8 @@ export class Compiler extends DiagnosticEmitter {
3208
3262
thenFlow . breakLabel = breakLabel ;
3209
3263
let continueLabel = `while-continue|${ label } ` ;
3210
3264
thenFlow . continueLabel = continueLabel ;
3265
+ let labelNode = statement . label ;
3266
+ if ( labelNode ) thenFlow . addUserLabel ( labelNode . text , breakLabel , continueLabel , labelNode ) ;
3211
3267
this . currentFlow = thenFlow ;
3212
3268
let bodyStmts = new Array < ExpressionRef > ( ) ;
3213
3269
let body = statement . body ;
@@ -3220,6 +3276,7 @@ export class Compiler extends DiagnosticEmitter {
3220
3276
module . br ( continueLabel )
3221
3277
) ;
3222
3278
thenFlow . popControlFlowLabel ( label ) ;
3279
+ if ( labelNode ) thenFlow . removeUserLabel ( labelNode . text ) ;
3223
3280
3224
3281
let possiblyContinues = thenFlow . isAny ( FlowFlags . Continues | FlowFlags . ConditionallyContinues ) ;
3225
3282
let possiblyBreaks = thenFlow . isAny ( FlowFlags . Breaks | FlowFlags . ConditionallyBreaks ) ;
0 commit comments