@@ -24,12 +24,38 @@ impl<'a> AnalyzeContext<'a> {
2424 diagnostics : & mut dyn DiagnosticHandler ,
2525 ) -> FatalResult {
2626 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 ( ) ) ,
3137 ) ;
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+ } ;
3359
3460 match statement. statement {
3561 SequentialStatement :: If ( ref mut ifstmt) => {
@@ -153,8 +179,10 @@ impl<'a> AnalyzeContext<'a> {
153179 loop_label,
154180 } = & mut exit_stmt. item ;
155181
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" )
158186 }
159187
160188 if let Some ( expr) = condition {
@@ -167,8 +195,10 @@ impl<'a> AnalyzeContext<'a> {
167195 loop_label,
168196 } = & mut next_stmt. item ;
169197
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" )
172202 }
173203
174204 if let Some ( expr) = condition {
@@ -284,6 +314,7 @@ impl<'a> AnalyzeContext<'a> {
284314 fn check_loop_label (
285315 & self ,
286316 scope : & Scope < ' a > ,
317+ parent : EntRef < ' a > ,
287318 label : & mut WithRef < Ident > ,
288319 diagnostics : & mut dyn DiagnosticHandler ,
289320 ) {
@@ -293,8 +324,14 @@ impl<'a> AnalyzeContext<'a> {
293324 ) {
294325 Ok ( NamedEntities :: Single ( ent) ) => {
295326 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 {
298335 diagnostics. error (
299336 & label. item . pos ,
300337 format ! ( "Expected loop label, got {}" , ent. describe( ) ) ,
@@ -322,19 +359,8 @@ impl<'a> AnalyzeContext<'a> {
322359 diagnostics : & mut dyn DiagnosticHandler ,
323360 ) -> FatalResult {
324361 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)
338364 } else {
339365 parent
340366 } ;
@@ -352,6 +378,30 @@ enum SequentialRoot<'a> {
352378 Function ( TypeEnt < ' a > ) ,
353379}
354380
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+
355405impl < ' a > From < EntRef < ' a > > for SequentialRoot < ' a > {
356406 fn from ( value : EntRef < ' a > ) -> Self {
357407 match value. kind ( ) {
@@ -362,7 +412,7 @@ impl<'a> From<EntRef<'a>> for SequentialRoot<'a> {
362412 SequentialRoot :: Procedure
363413 }
364414 }
365- AnyEntKind :: Label => {
415+ AnyEntKind :: Label | AnyEntKind :: LoopLabel => {
366416 if let Some ( parent) = value. parent {
367417 SequentialRoot :: from ( parent)
368418 } else {
0 commit comments