syntax: New escape block management
[nit.git] / src / syntax / escape.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2008 Jean Privat <jean@pryen.org>
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # Manage nested escapable blocks (while, for and closure) and escape statements (break and continue)
18 package escape
19
20 import syntax_base
21
22 # Stack escapable blocks
23 class EscapableContext
24 # Stack of blocks
25 attr _stack: Array[EscapableBlock] = new Array[EscapableBlock]
26
27 # Push a new escapable block
28 meth push(block: EscapableBlock)
29 do
30 _stack.push(block)
31 end
32
33 # Is there no block in the stack?
34 meth is_empty: Bool do return _stack.is_empty
35
36 # Return the current block (the last stacked)
37 meth head: EscapableBlock
38 do
39 return _stack.last
40 end
41
42 # Remove the last block (the last stacked)
43 meth pop
44 do
45 var n = _stack.pop
46 end
47
48 readable attr _visitor: AbsSyntaxVisitor
49 init (v: AbsSyntaxVisitor)
50 do
51 _visitor = v
52 end
53 end
54
55 ###############################################################################
56
57 # A escapable block correspond to a block statement where break and/or continue can by used
58 # For and while use this class. closures uses the EscapableClosure subclass.
59 class EscapableBlock
60 # The syntax node of the block
61 readable attr _node: PNode = null
62
63 # Is self a break closure ?
64 meth is_break_block: Bool do return false
65
66 # Collected expressions used in breaks.
67 # null if break does not accept values.
68 # break_list is used to store expressions used in break statments and perform type checks latter
69 meth break_list: Array[PExpr] do return null
70
71 # The static type required by the continue statement (if any)
72 meth continue_stype: MMType do return null
73
74 init(node: PNode)
75 do
76 _node = node
77 end
78 end
79
80 # specific EscapableBlock for closures
81 class EscapableClosure
82 special EscapableBlock
83 # The associated closure
84 readable attr _closure: MMClosure
85
86 redef meth is_break_block do return _closure.is_break
87
88 redef readable attr _break_list: Array[PExpr]
89
90 redef meth continue_stype do return _closure.signature.return_type
91
92 init(node: PNode, closure: MMClosure, break_list: Array[PExpr])
93 do
94 super(node)
95 _closure = closure
96 _break_list = break_list
97 end
98 end
99
100 ###############################################################################
101
102 class AEscapeExpr
103 special PNode
104 # The associated escapable block
105 readable attr _escapable_block: EscapableBlock
106
107 # The name of the keyword
108 meth kwname: String is abstract
109
110 # Compute, set and return the _abelable_node value
111 meth compute_escapable_block(lctx: EscapableContext): EscapableBlock
112 do
113 var block: EscapableBlock
114 if lctx.is_empty then
115 lctx.visitor.error(self, "Syntax Error: '{kwname}' statment outside block.")
116 return null
117 end
118 block = lctx.head
119 _escapable_block = block
120 return block
121 end
122 end
123
124 redef class AContinueExpr
125 special AEscapeExpr
126 redef meth kwname do return "continue"
127 end
128
129 redef class ABreakExpr
130 special AEscapeExpr
131 redef meth kwname do return "break"
132 end
133