interpreter&vm: handle multi-iterator
[nit.git] / src / vm / variables_numbering.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2015 Julien Pagès <julien.pages@lirmm.fr>
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 # Handle all numbering operations related to local variables in the Nit virtual machine
18 module variables_numbering
19
20 import virtual_machine
21
22 redef class VirtualMachine
23
24 # The frames of the VirtualMachine are specialized
25 redef type FRAME: VmFrame
26
27 # Number the variables in `n`.
28 # Do nothing if `n` is null
29 fun numbering(n: nullable AExpr, position: Int): Int
30 do
31 if n == null then return position
32
33 var pos = n.numbering(self, position)
34 return pos
35 end
36
37 # Redef to add the numbering of variables and arguments
38 redef fun new_frame(node, mpropdef, args)
39 do
40 var f = new VmFrame(node, mpropdef, args)
41
42 # If this Frame is for a method or an attribute block then number variables into the body of the method
43 if node isa APropdef then
44 # Compile the code (number its local variables)
45 if not node.is_compiled then node.compile(self)
46
47 # Create an empty environment
48 f.variables = new Array[Instance].filled_with(initialization_value, node.environment_size)
49 end
50
51 # Putting self at the beginning of the environment
52 f.variables[0] = args[0]
53 return f
54 end
55
56 # Read a `Variable` from a frame by using its position
57 redef fun read_variable(v: Variable): Instance
58 do
59 return frame.variables[v.position]
60 end
61
62 # Assign the value of the `Variable` in an environment
63 redef fun write_variable(v: Variable, value: Instance)
64 do
65 frame.variables[v.position] = value
66 end
67 end
68
69 redef class Variable
70 # The position in the environment
71 var position: Int is writable
72 end
73
74 # Implementation of a Frame with numbered variables
75 class VmFrame
76 super Frame
77
78 # Contains the value of Variables (which are numbered)
79 var variables: Array[Instance] = new Array[Instance]
80 end
81
82 redef class AExpr
83 # Give a position to each variable declared in the node.
84 # NOTE: Do not call this method directly, but use `v.numbering`
85 # This method is here to be implemented by subclasses.
86 # *`v` The current instance of the virtual machine
87 # *`position` The first available position in the environment a variable can have
88 # Return the next available position a variable can have
89 public fun numbering(v: VirtualMachine, position: Int): Int
90 do
91 return position
92 end
93 end
94
95 redef class APropdef
96 # Indicite if this propdef was compile
97 var is_compiled: Bool = false
98
99 # Indicate if the variables numbering has been done
100 private var is_numbering: Bool = false
101
102 # The size of the environment to create to call this method
103 private var environment_size: Int = 0
104
105 # Compile this propdef
106 # *`vm` The running instance of `VirtualMachine`
107 fun compile(vm: VirtualMachine)
108 do
109 # Number the variables
110 if not is_numbering then numbering_variables(vm)
111
112 is_compiled = true
113 end
114
115 # Numbering the variable inside the propdef
116 fun numbering_variables(vm: VirtualMachine) is abstract
117 end
118
119 redef class AMethPropdef
120 # Assign a position in the environment to each local variable
121 # *`vm` The current VirtualMachine
122 redef fun numbering_variables(vm: VirtualMachine)
123 do
124 # The position in the environment
125 var position = 0
126
127 # The `self` variable has the first position
128 if self.selfvariable != null then
129 self.selfvariable.position = position
130 position += 1
131 end
132
133 # Number the parameters
134 for i in [0..mpropdef.msignature.arity[ do
135 var variable = self.n_signature.n_params[i].variable
136 variable.as(not null).position = position
137 position += 1
138 end
139
140 # Recursively go into the AST nodes to number all local variables
141 if n_block != null then
142 position = vm.numbering(self.n_block, position)
143 end
144
145 is_numbering = true
146
147 # The size of the environment to create to execute a call to this method
148 environment_size = position
149 end
150 end
151
152 redef class AAttrPropdef
153 # Assign a position in the environment to each local variable
154 # *`vm` The current VirtualMachine
155 redef fun numbering_variables(vm: VirtualMachine)
156 do
157 # The position in the environment
158 var position = 0
159
160 # The `self` variable has the first position
161 if self.selfvariable != null then
162 self.selfvariable.position = position
163 position += 1
164 end
165
166 # Recursively go into the AST nodes to number all local variables
167 if n_block != null then
168 position = vm.numbering(self.n_block, position)
169 end
170
171 is_numbering = true
172
173 # The size of the environment to create to execute a call to this method
174 environment_size = position
175 end
176 end
177
178 redef class AVardeclExpr
179 redef fun numbering(v, position)
180 do
181 # Attribute a position to this variable
182 self.variable.as(not null).position = position
183 position += 1
184
185 # Recursively continue to numbering the variables
186 position = v.numbering(self.n_expr, position)
187
188 # `position` is the next available position in the environment
189 return position
190 end
191 end
192
193 redef class ABlockExpr
194 redef fun numbering(v, position)
195 do
196 for e in self.n_expr do
197 position = v.numbering(e, position)
198 end
199 return position
200 end
201 end
202
203 redef class AIfExpr
204 redef fun numbering(v, position)
205 do
206 # Attribute numbers separetely for the two branches
207 var pos = v.numbering(self.n_then, position)
208 var pos1 = v.numbering(self.n_else, position)
209
210 if pos > pos1 then
211 return pos
212 else
213 return pos1
214 end
215 end
216 end
217
218 redef class AIfexprExpr
219 redef fun numbering(v, position)
220 do
221 # Attribute numbers separetely for the two branches
222 var pos = v.numbering(self.n_then, position)
223 var pos1 = v.numbering(self.n_else, position)
224
225 if pos > pos1 then
226 return pos
227 else
228 return pos1
229 end
230 end
231 end
232
233 redef class ADoExpr
234 redef fun numbering(v, position)
235 do
236 return v.numbering(self.n_block, position)
237 end
238 end
239
240 redef class AWhileExpr
241 redef fun numbering(v, position)
242 do
243 return v.numbering(self.n_block, position)
244 end
245 end
246
247 redef class ALoopExpr
248 redef fun numbering(v, position)
249 do
250 return v.numbering(self.n_block, position)
251 end
252 end
253
254 redef class AForExpr
255 redef fun numbering(v, position)
256 do
257 for g in n_groups do
258 # Give a position to each variable declared in the header of the for
259 if g.variables.length == 1 then
260 g.variables.first.position = position
261 g.variables[0].position = position
262 position += 1
263 else if g.variables.length == 2 then
264 g.variables[0].position = position
265 position += 1
266 g.variables[1].position = position
267 position += 1
268 end
269 position = v.numbering(self.n_block, position)
270 end
271 return position
272 end
273 end
274
275 redef class AArrayExpr
276 redef fun numbering(v, position)
277 do
278 for nexpr in self.n_exprs do
279 position = v.numbering(nexpr, position)
280 end
281 return position
282 end
283 end