1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2008 Jean Privat <jean@pryen.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Manage nested escapable blocks (while, for and closure) and escape statements (break and continue)
22 # Stack escapable blocks
23 class EscapableContext
25 var _stack
: Array[EscapableBlock] = new Array[EscapableBlock]
28 # (all labels, even out of scopes ones)
29 # Used to find duplicates
30 var _labels
: Array[ALabel] = new Array[ALabel]
32 # Push a new escapable block
33 # Display error message if tere is a problem with the label
34 fun push
(block
: EscapableBlock, n_label
: nullable ALabel)
37 if n_label
!= null then
38 var lab
= n_label
.n_id
.to_symbol
40 if n_label
!= nl
and lab
== nl
.n_id
.to_symbol
then
41 visitor
.error
(n_label
, "Syntax error: label {lab} already defined at {nl.location.relative_to(n_label.location)}.")
50 # Return the last stacked block that accepts unlabelled break/continue
51 fun head
: nullable EscapableBlock
53 var i
= _stack
.length
- 1
56 if not (h
isa BreakOnlyEscapableBlock) then return h
62 # Return the block associed to a label
63 # Output an error end return null if the label is not known
64 fun get_by_label
(nl
: ALabel): nullable EscapableBlock
66 var i
= _stack
.length
- 1
67 var block
: nullable EscapableBlock = null
68 var lab
= nl
.n_id
.to_symbol
71 if b
.lab
== lab
then return b
74 visitor
.error
(nl
, "Syntax error: invalid label {lab}.")
78 # Remove the last block (the last stacked)
84 readable var _visitor
: AbsSyntaxVisitor
85 init (v
: AbsSyntaxVisitor)
91 ###############################################################################
93 # A escapable block correspond to a block statement where break and/or continue can by used
94 # 'for' and 'while' use this class
95 # 'do' uses the BreakOnlyEscapableBlock subclass
96 # closures uses the EscapableClosure subclass
98 # The syntax node of the block
99 readable var _node
: ANode
101 # The label of the block (if any)
102 # Set by the push in EscapableContext
103 readable var _lab
: nullable Symbol
105 # Is self a break closure ?
106 fun is_break_block
: Bool do return false
108 # Collected expressions used in breaks.
109 # null if break does not accept values.
110 # break_list is used to store expressions used in break statments and perform type checks latter
111 fun break_list
: nullable Array[AExpr] do return null
113 # The static type required by the continue statement (if any)
114 fun continue_stype
: nullable MMType do return null
122 # specific EscapableBlock where only labelled break can be used
123 class BreakOnlyEscapableBlock
124 special EscapableBlock
125 redef fun is_break_block
: Bool do return true
127 init(node
: ANode) do super
130 # specific EscapableBlock for closures
131 class EscapableClosure
132 special EscapableBlock
133 # The associated closure
134 readable var _closure
: MMClosure
136 redef fun is_break_block
do return _closure
.is_break
138 redef readable var _break_list
: nullable Array[AExpr]
140 redef fun continue_stype
do return _closure
.signature
.return_type
142 init(node
: ANode, closure
: MMClosure, break_list
: nullable Array[AExpr])
146 _break_list
= break_list
150 ###############################################################################
154 # The associated escapable block
155 readable var _escapable
: nullable EscapableBlock
157 # The name of the keyword
158 fun kwname
: String is abstract
160 # Compute, set and return the associated escapable block
161 fun compute_escapable_block
(lctx
: EscapableContext): nullable EscapableBlock
163 var block
: nullable EscapableBlock
166 block
= lctx
.get_by_label
(nl
)
169 if block
== null then
170 lctx
.visitor
.error
(self, "Syntax Error: '{kwname}' statment outside block.")
178 redef class AContinueExpr
180 redef fun kwname
do return "continue"
183 redef class ABreakExpr
185 redef fun kwname
do return "break"