fbd8a77cc508e2508de06e6b2b1ac6585b0a94dc
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 # Is there no block in the stack?
51 fun is_empty
: Bool do return _stack
.is_empty
53 # Return the current block (the last stacked)
54 fun head
: EscapableBlock
59 # Return the block associed to a label
60 # Output an error end return null if the label is not known
61 fun get_by_label
(nl
: ALabel): nullable EscapableBlock
63 var i
= _stack
.length
- 1
64 var block
: nullable EscapableBlock = null
65 var lab
= nl
.n_id
.to_symbol
68 if b
.lab
== lab
then return b
71 visitor
.error
(nl
, "Syntax error: invalid label {lab}.")
75 # Remove the last block (the last stacked)
81 readable var _visitor
: AbsSyntaxVisitor
82 init (v
: AbsSyntaxVisitor)
88 ###############################################################################
90 # A escapable block correspond to a block statement where break and/or continue can by used
91 # 'for' and 'while' use this class
92 # 'do' uses the BreakOnlyEscapableBlock subclass
93 # closures uses the EscapableClosure subclass
95 # The syntax node of the block
96 readable var _node
: ANode
98 # The label of the block (if any)
99 # Set by the push in EscapableContext
100 readable var _lab
: nullable Symbol
102 # Is self a break closure ?
103 fun is_break_block
: Bool do return false
105 # Collected expressions used in breaks.
106 # null if break does not accept values.
107 # break_list is used to store expressions used in break statments and perform type checks latter
108 fun break_list
: nullable Array[AExpr] do return null
110 # The static type required by the continue statement (if any)
111 fun continue_stype
: nullable MMType do return null
119 # specific EscapableBlock where only break can be used
120 class BreakOnlyEscapableBlock
121 special EscapableBlock
122 redef fun is_break_block
: Bool do return true
124 init(node
: ANode) do super
127 # specific EscapableBlock for closures
128 class EscapableClosure
129 special EscapableBlock
130 # The associated closure
131 readable var _closure
: MMClosure
133 redef fun is_break_block
do return _closure
.is_break
135 redef readable var _break_list
: nullable Array[AExpr]
137 redef fun continue_stype
do return _closure
.signature
.return_type
139 init(node
: ANode, closure
: MMClosure, break_list
: nullable Array[AExpr])
143 _break_list
= break_list
147 ###############################################################################
151 # The associated escapable block
152 readable var _escapable
: nullable EscapableBlock
154 # The name of the keyword
155 fun kwname
: String is abstract
157 # Compute, set and return the associated escapable block
158 fun compute_escapable_block
(lctx
: EscapableContext): nullable EscapableBlock
160 var block
: nullable EscapableBlock
163 block
= lctx
.get_by_label
(nl
)
164 else if lctx
.is_empty
then
165 lctx
.visitor
.error
(self, "Syntax Error: '{kwname}' statment outside block.")
175 redef class AContinueExpr
177 redef fun kwname
do return "continue"
180 redef class ABreakExpr
182 redef fun kwname
do return "break"