@@ -24,12 +24,38 @@ impl<'a> AnalyzeContext<'a> {
24
24
diagnostics : & mut dyn DiagnosticHandler ,
25
25
) -> FatalResult {
26
26
for statement in statements. iter_mut ( ) {
27
- if let Some ( ref mut label) = statement. label {
28
- scope. add (
29
- label. define ( self . arena , parent, AnyEntKind :: Label ) ,
30
- diagnostics,
27
+ let parent = if let Some ( ref mut label) = statement. label . tree {
28
+ let ent = self . arena . explicit (
29
+ label. name ( ) ,
30
+ parent,
31
+ if statement. statement . is_loop ( ) {
32
+ AnyEntKind :: LoopLabel
33
+ } else {
34
+ AnyEntKind :: Label
35
+ } ,
36
+ Some ( label. pos ( ) ) ,
31
37
) ;
32
- }
38
+ statement. label . decl = Some ( ent. id ( ) ) ;
39
+ scope. add ( ent, diagnostics) ;
40
+ ent
41
+ } else if statement. statement . can_have_label ( ) {
42
+ // Generate an anonymous label if it is not explicitly defined
43
+ let ent = self . arena . alloc (
44
+ Designator :: Anonymous ( scope. next_anonymous ( ) ) ,
45
+ Some ( parent) ,
46
+ Related :: None ,
47
+ if statement. statement . is_loop ( ) {
48
+ AnyEntKind :: LoopLabel
49
+ } else {
50
+ AnyEntKind :: Label
51
+ } ,
52
+ None ,
53
+ ) ;
54
+ statement. label . decl = Some ( ent. id ( ) ) ;
55
+ ent
56
+ } else {
57
+ parent
58
+ } ;
33
59
34
60
match statement. statement {
35
61
SequentialStatement :: If ( ref mut ifstmt) => {
@@ -153,8 +179,10 @@ impl<'a> AnalyzeContext<'a> {
153
179
loop_label,
154
180
} = & mut exit_stmt. item ;
155
181
156
- if let Some ( ref mut loop_label) = loop_label {
157
- self . check_loop_label ( scope, loop_label, diagnostics) ;
182
+ if let Some ( loop_label) = loop_label {
183
+ self . check_loop_label ( scope, parent, loop_label, diagnostics) ;
184
+ } else if !find_outer_loop ( parent, None ) {
185
+ diagnostics. error ( & exit_stmt. pos , "Exit can only be used inside a loop" )
158
186
}
159
187
160
188
if let Some ( expr) = condition {
@@ -167,8 +195,10 @@ impl<'a> AnalyzeContext<'a> {
167
195
loop_label,
168
196
} = & mut next_stmt. item ;
169
197
170
- if let Some ( ref mut loop_label) = loop_label {
171
- self . check_loop_label ( scope, loop_label, diagnostics) ;
198
+ if let Some ( loop_label) = loop_label {
199
+ self . check_loop_label ( scope, parent, loop_label, diagnostics) ;
200
+ } else if !find_outer_loop ( parent, None ) {
201
+ diagnostics. error ( & next_stmt. pos , "Next can only be used inside a loop" )
172
202
}
173
203
174
204
if let Some ( expr) = condition {
@@ -284,6 +314,7 @@ impl<'a> AnalyzeContext<'a> {
284
314
fn check_loop_label (
285
315
& self ,
286
316
scope : & Scope < ' a > ,
317
+ parent : EntRef < ' a > ,
287
318
label : & mut WithRef < Ident > ,
288
319
diagnostics : & mut dyn DiagnosticHandler ,
289
320
) {
@@ -293,8 +324,14 @@ impl<'a> AnalyzeContext<'a> {
293
324
) {
294
325
Ok ( NamedEntities :: Single ( ent) ) => {
295
326
label. set_unique_reference ( ent) ;
296
- if !matches ! ( ent. kind( ) , AnyEntKind :: Label ) {
297
- // @TODO check that is actually a loop label and that we are inside the loop
327
+ if matches ! ( ent. kind( ) , AnyEntKind :: LoopLabel ) {
328
+ if !find_outer_loop ( parent, Some ( label. item . name ( ) ) ) {
329
+ diagnostics. error (
330
+ & label. item . pos ,
331
+ format ! ( "Cannot be used outside of loop '{}'" , ent. designator( ) ) ,
332
+ ) ;
333
+ }
334
+ } else {
298
335
diagnostics. error (
299
336
& label. item . pos ,
300
337
format ! ( "Expected loop label, got {}" , ent. describe( ) ) ,
@@ -322,19 +359,8 @@ impl<'a> AnalyzeContext<'a> {
322
359
diagnostics : & mut dyn DiagnosticHandler ,
323
360
) -> FatalResult {
324
361
for statement in statements. iter_mut ( ) {
325
- let parent = if statement. statement . can_have_label ( ) {
326
- if let Some ( id) = statement. label . as_ref ( ) . and_then ( |label| label. decl ) {
327
- self . arena . get ( id)
328
- } else {
329
- // Generate an anonymous label if it is not explicitly defined
330
- self . arena . alloc (
331
- Designator :: Anonymous ( scope. next_anonymous ( ) ) ,
332
- Some ( parent) ,
333
- Related :: None ,
334
- AnyEntKind :: Label ,
335
- None ,
336
- )
337
- }
362
+ let parent = if let Some ( id) = statement. label . decl {
363
+ self . arena . get ( id)
338
364
} else {
339
365
parent
340
366
} ;
@@ -352,6 +378,30 @@ enum SequentialRoot<'a> {
352
378
Function ( TypeEnt < ' a > ) ,
353
379
}
354
380
381
+ fn find_outer_loop ( ent : EntRef , label : Option < & Symbol > ) -> bool {
382
+ match ent. kind ( ) {
383
+ AnyEntKind :: LoopLabel => {
384
+ if let Some ( label) = label {
385
+ if matches ! ( ent. designator( ) , Designator :: Identifier ( ident) if ident == label) {
386
+ return true ;
387
+ }
388
+ } else {
389
+ return true ;
390
+ }
391
+ }
392
+ AnyEntKind :: Label => { }
393
+ _ => {
394
+ return false ;
395
+ }
396
+ }
397
+
398
+ if let Some ( parent) = ent. parent {
399
+ find_outer_loop ( parent, label)
400
+ } else {
401
+ false
402
+ }
403
+ }
404
+
355
405
impl < ' a > From < EntRef < ' a > > for SequentialRoot < ' a > {
356
406
fn from ( value : EntRef < ' a > ) -> Self {
357
407
match value. kind ( ) {
@@ -362,7 +412,7 @@ impl<'a> From<EntRef<'a>> for SequentialRoot<'a> {
362
412
SequentialRoot :: Procedure
363
413
}
364
414
}
365
- AnyEntKind :: Label => {
415
+ AnyEntKind :: Label | AnyEntKind :: LoopLabel => {
366
416
if let Some ( parent) = value. parent {
367
417
SequentialRoot :: from ( parent)
368
418
} else {
0 commit comments