tests: recognize a nonstart #alt as a #!alt
[nit.git] / src / naive_interpreter.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012 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 # Interpretation of a Nit program directly on the AST
18 module naive_interpreter
19
20 import literal
21 import typing
22 import auto_super_init
23
24 redef class ModelBuilder
25 # Execute the program from the entry point (Sys::main) of the `mainmodule'
26 # `arguments' are the command-line arguments in order
27 # REQUIRE that:
28 # 1. the AST is fully loaded.
29 # 2. the model is fully built.
30 # 3. the instructions are fully analysed.
31 fun run_naive_interpreter(mainmodule: MModule, arguments: Array[String])
32 do
33 var time0 = get_time
34 self.toolcontext.info("*** START INTERPRETING ***", 1)
35
36 var interpreter = new NaiveInterpreter(self, mainmodule, arguments)
37 var sys_type = mainmodule.sys_type
38 if sys_type == null then return # no class Sys
39 var mainobj = new Instance(sys_type)
40 interpreter.mainobj = mainobj
41 interpreter.init_instance(mainobj)
42 var initprop = mainmodule.try_get_primitive_method("init", sys_type)
43 if initprop != null then
44 interpreter.send(initprop, [mainobj])
45 end
46 interpreter.check_init_instance(mainobj)
47 var mainprop = mainmodule.try_get_primitive_method("main", sys_type)
48 if mainprop != null then
49 interpreter.send(mainprop, [mainobj])
50 end
51
52 var time1 = get_time
53 self.toolcontext.info("*** END INTERPRETING: {time1-time0} ***", 2)
54 end
55 end
56
57 # The visitor that interprets the Nit Program by walking on the AST
58 private class NaiveInterpreter
59 # The modelbuilder that know the AST and its associations with the model
60 var modelbuilder: ModelBuilder
61
62 # The main moduleof the program (used to lookup methoda
63 var mainmodule: MModule
64
65 # The command line arguments of the interpreted program
66 # arguments.first is the program name
67 # arguments[1] is the first argument
68 var arguments: Array[String]
69
70 var mainobj: nullable Instance
71
72 init(modelbuilder: ModelBuilder, mainmodule: MModule, arguments: Array[String])
73 do
74 self.modelbuilder = modelbuilder
75 self.mainmodule = mainmodule
76 self.arguments = arguments
77 self.true_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, true)
78 self.false_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, false)
79 self.null_instance = new Instance(mainmodule.model.null_type)
80 end
81
82 # Subtype test in the context of the mainmodule
83 fun is_subtype(sub, sup: MType): Bool
84 do
85 return sub.is_subtype(self.mainmodule, self.frame.arguments.first.mtype.as(MClassType), sup)
86 end
87
88 # Is a return executed?
89 # Set this mark to skip the evaluation until the end of the specified method frame
90 var returnmark: nullable Frame = null
91
92 # Is a break executed?
93 # Set this mark to skip the evaluation until a labeled statement catch it with `is_break'
94 var breakmark: nullable EscapeMark = null
95
96 # Is a continue executed?
97 # Set this mark to skip the evaluation until a labeled statement catch it with `is_continue'
98 var continuemark: nullable EscapeMark = null
99
100 # Is a return or a break or a continue executed?
101 # Use this function to know if you must skip the evaluation of statements
102 fun is_escaping: Bool do return returnmark != null or breakmark != null or continuemark != null
103
104 # The value associated with the current return/break/continue, if any.
105 # Set the value when you set a escapemark.
106 # Read the value when you catch a mark or reach the end of a method
107 var escapevalue: nullable Instance = null
108
109 # If there is a break and is associated with `escapemark', then return true an clear the mark.
110 # If there is no break or if `escapemark' is null then return false.
111 # Use this function to catch a potential break.
112 fun is_break(escapemark: nullable EscapeMark): Bool
113 do
114 if escapemark != null and self.breakmark == escapemark then
115 self.breakmark = null
116 return true
117 else
118 return false
119 end
120 end
121
122 # If there is a continue and is associated with `escapemark', then return true an clear the mark.
123 # If there is no continue or if `escapemark' is null then return false.
124 # Use this function to catch a potential continue.
125 fun is_continue(escapemark: nullable EscapeMark): Bool
126 do
127 if escapemark != null and self.continuemark == escapemark then
128 self.continuemark = null
129 return true
130 else
131 return false
132 end
133 end
134
135 # Evaluate `n' as an expression in the current context.
136 # Return the value of the expression.
137 # If `n' cannot be evaluated, then aborts.
138 fun expr(n: AExpr): nullable Instance
139 do
140 var old = self.frame.current_node
141 self.frame.current_node = n
142 #n.debug("IN Execute expr")
143 var i = n.expr(self)
144 if i == null and not self.is_escaping then
145 n.debug("inconsitance: no value and not escaping.")
146 end
147 #n.debug("OUT Execute expr: value is {i}")
148 #if not is_subtype(i.mtype, n.mtype.as(not null)) then n.debug("Expected {n.mtype.as(not null)} got {i}")
149 self.frame.current_node = old
150 return i
151 end
152
153 # Evaluate `n' as a statement in the current context.
154 # Do nothing if `n' is sull.
155 # If `n' cannot be evaluated, then aborts.
156 fun stmt(n: nullable AExpr)
157 do
158 if n != null then
159 var old = self.frame.current_node
160 self.frame.current_node = n
161 #n.debug("Execute stmt")
162 n.stmt(self)
163 self.frame.current_node = old
164 end
165 end
166
167 # Map used to store values of nodes that must be evaluated once in the system (AOnceExpr)
168 var onces: Map[ANode, Instance] = new HashMap[ANode, Instance]
169
170 # Return the boolean instance associated with `val'.
171 fun bool_instance(val: Bool): Instance
172 do
173 if val then return self.true_instance else return self.false_instance
174 end
175
176 # Return the integer instance associated with `val'.
177 fun int_instance(val: Int): Instance
178 do
179 var ic = self.mainmodule.get_primitive_class("Int")
180 return new PrimitiveInstance[Int](ic.mclass_type, val)
181 end
182
183 # Return the char instance associated with `val'.
184 fun char_instance(val: Char): Instance
185 do
186 var ic = self.mainmodule.get_primitive_class("Char")
187 return new PrimitiveInstance[Char](ic.mclass_type, val)
188 end
189
190 # Return the float instance associated with `val'.
191 fun float_instance(val: Float): Instance
192 do
193 var ic = self.mainmodule.get_primitive_class("Float")
194 return new PrimitiveInstance[Float](ic.mclass_type, val)
195 end
196
197 # The unique intance of the `true' value.
198 var true_instance: Instance
199
200 # The unique intance of the `false' value.
201 var false_instance: Instance
202
203 # The unique intance of the `null' value.
204 var null_instance: Instance
205
206 # Return a new array made of `values'.
207 # The dynamic type of the result is Array[elttype].
208 fun array_instance(values: Array[Instance], elttype: MType): Instance
209 do
210 assert not elttype.need_anchor
211 var nat = new PrimitiveInstance[Array[Instance]](self.mainmodule.get_primitive_class("NativeArray").get_mtype([elttype]), values)
212 var mtype = self.mainmodule.get_primitive_class("Array").get_mtype([elttype])
213 var res = new Instance(mtype)
214 self.init_instance(res)
215 self.send(self.mainmodule.force_get_primitive_method("with_native", mtype), [res, nat, self.int_instance(values.length)])
216 self.check_init_instance(res)
217 return res
218 end
219
220 # Return a new native string initialized with `txt'
221 fun native_string_instance(txt: String): Instance
222 do
223 var val = new Buffer.from(txt)
224 val.add('\0')
225 var ic = self.mainmodule.get_primitive_class("NativeString")
226 return new PrimitiveInstance[Buffer](ic.mclass_type, val)
227 end
228
229 # The current frame used to store local variables of the current method executed
230 fun frame: Frame do return frames.first
231
232 # The stack of all frames. The first one is the current one.
233 var frames: List[Frame] = new List[Frame]
234
235 # Return a stack stace. One line per function
236 fun stack_trace: String
237 do
238 var b = new Buffer
239 b.append(",---- Stack trace -- - - -\n")
240 for f in frames do
241 b.append("| {f.mpropdef} ({f.current_node.location})\n")
242 end
243 b.append("`------------------- - - -")
244 return b.to_s
245 end
246
247 # Exit the program with a message
248 fun fatal(message: String)
249 do
250 if frames.is_empty then
251 print message
252 else
253 self.frame.current_node.fatal(self, message)
254 end
255 exit(1)
256 end
257
258 # Execute `mpropdef' for a `args' (where args[0] is the receiver).
259 # Return a falue if `mpropdef' is a function, or null if it is a procedure.
260 # The call is direct/static. There is no message-seding/late-bindng.
261 fun call(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
262 do
263 var vararg_rank = mpropdef.msignature.vararg_rank
264 if vararg_rank >= 0 then
265 assert args.length >= mpropdef.msignature.arity + 1 # because of self
266 var rawargs = args
267 args = new Array[Instance]
268
269 args.add(rawargs.first) # recv
270
271 for i in [0..vararg_rank[ do
272 args.add(rawargs[i+1])
273 end
274
275 var vararg_lastrank = vararg_rank + rawargs.length-1-mpropdef.msignature.arity
276 var vararg = new Array[Instance]
277 for i in [vararg_rank..vararg_lastrank] do
278 vararg.add(rawargs[i+1])
279 end
280 # FIXME: its it to late to determine the vararg type, this should have been done during a previous analysis
281 var elttype = mpropdef.msignature.mparameters[vararg_rank].mtype.anchor_to(self.mainmodule, args.first.mtype.as(MClassType))
282 args.add(self.array_instance(vararg, elttype))
283
284 for i in [vararg_lastrank+1..rawargs.length-1[ do
285 args.add(rawargs[i+1])
286 end
287 end
288 #assert args.length == mpropdef.msignature.arity + 1 # because of self
289
290 # Look for the AST node that implements the property
291 var mproperty = mpropdef.mproperty
292 if self.modelbuilder.mpropdef2npropdef.has_key(mpropdef) then
293 var npropdef = self.modelbuilder.mpropdef2npropdef[mpropdef]
294 return npropdef.call(self, mpropdef, args)
295 else if mproperty.name == "init" then
296 var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef]
297 return nclassdef.call(self, mpropdef, args)
298 else
299 fatal("Fatal Error: method {mpropdef} not found in the AST")
300 abort
301 end
302 end
303
304 fun call_closure(closure: ClosureInstance, args: Array[Instance]): nullable Instance
305 do
306 var nclosuredef = closure.nclosuredef
307 var f = closure.frame
308 for i in [0..closure.nclosuredef.mclosure.mtype.as(MSignature).arity[ do
309 var variable = nclosuredef.variables[i]
310 f.map[variable] = args[i]
311 end
312
313 self.frames.unshift(f)
314
315 self.stmt(nclosuredef.n_expr)
316
317 self.frames.shift
318
319 if self.is_continue(nclosuredef.escapemark) then
320 var res = self.escapevalue
321 self.escapevalue = null
322 return res
323 end
324 return null
325 end
326
327 # Execute `mproperty' for a `args' (where args[0] is the receiver).
328 # Return a falue if `mproperty' is a function, or null if it is a procedure.
329 # The call is polimotphic. There is a message-seding/late-bindng according to te receiver (args[0]).
330 fun send(mproperty: MMethod, args: Array[Instance]): nullable Instance
331 do
332 var recv = args.first
333 var mtype = recv.mtype
334 if mtype isa MNullType then
335 if mproperty.name == "==" then
336 return self.bool_instance(args[0] == args[1])
337 else if mproperty.name == "!=" then
338 return self.bool_instance(args[0] != args[1])
339 end
340 #fatal("Reciever is null. {mproperty}. {args.join(" ")} {self.frame.current_node.class_name}")
341 fatal("Reciever is null")
342 abort
343 end
344 var propdefs = mproperty.lookup_definitions(self.mainmodule, mtype)
345 if propdefs.length > 1 then
346 fatal("NOT YET IMPLEMETED ERROR: Property conflict: {propdefs.join(", ")}")
347 abort
348 end
349 assert propdefs.length == 1 else
350 fatal("Fatal Error: No property '{mproperty}' for '{recv}'")
351 abort
352 end
353 var propdef = propdefs.first
354 return self.call(propdef, args)
355 end
356
357 # Read the attribute `mproperty' of an instance `recv' and return its value.
358 # If the attribute in not yet initialized, then aborts with an error message.
359 fun read_attribute(mproperty: MAttribute, recv: Instance): Instance
360 do
361 if not recv.attributes.has_key(mproperty) then
362 fatal("Uninitialized attribute {mproperty.name}")
363 abort
364 end
365 return recv.attributes[mproperty]
366 end
367
368 # Fill the initial values of the newly created instance `recv'.
369 # `recv.mtype' is used to know what must be filled.
370 fun init_instance(recv: Instance)
371 do
372 for cd in recv.mtype.collect_mclassdefs(self.mainmodule)
373 do
374 var n = self.modelbuilder.mclassdef2nclassdef[cd]
375 for npropdef in n.n_propdefs do
376 if npropdef isa AAttrPropdef then
377 npropdef.init_expr(self, recv)
378 end
379 end
380 end
381 end
382
383 # Check that non nullable attributes of `recv' are correctly initialized.
384 # This function is used as the last instruction of a new
385 # FIXME: this will work better once there is nullable types
386 fun check_init_instance(recv: Instance)
387 do
388 for cd in recv.mtype.collect_mclassdefs(self.mainmodule)
389 do
390 var n = self.modelbuilder.mclassdef2nclassdef[cd]
391 for npropdef in n.n_propdefs do
392 if npropdef isa AAttrPropdef and npropdef.n_expr == null then
393 # Force read to check the initialization
394 self.read_attribute(npropdef.mpropdef.mproperty, recv)
395 end
396 end
397 end
398 end
399
400 # This function determine the correct type according the reciever of the current definition (self).
401 fun unanchor_type(mtype: MType): MType
402 do
403 return mtype.anchor_to(self.mainmodule, self.frame.arguments.first.mtype.as(MClassType))
404 end
405 end
406
407 # An instance represents a value of the executed program.
408 class Instance
409 # The dynamic type of the instance
410 # ASSERT: not self.mtype.is_anchored
411 var mtype: MType
412
413 # The values of the attributes
414 var attributes: Map[MAttribute, Instance] = new HashMap[MAttribute, Instance]
415
416 # return true if the instance is the true value.
417 # return false if the instance is the true value.
418 # else aborts
419 fun is_true: Bool do abort
420
421 # Return true if `self' IS `o' (using the Nit semantic of is)
422 fun eq_is(o: Instance): Bool do return self is o
423
424 # Human readable object identity "Type#number"
425 redef fun to_s do return "{mtype}#{object_id}"
426
427 # Return the integer valur is the instance is an integer.
428 # else aborts
429 fun to_i: Int do abort
430
431 # The real value encapsulated if the instance is primitive.
432 # Else aborts.
433 fun val: Object do abort
434 end
435
436 # Special instance to handle primitives values (int, bool, etc.)
437 # The trick it just to encapsulate the <<real>> value
438 class PrimitiveInstance[E: Object]
439 super Instance
440
441 # The real value encapsulated
442 redef var val: E
443
444 init(mtype: MType, val: E)
445 do
446 super(mtype)
447 self.val = val
448 end
449
450 redef fun is_true
451 do
452 if val == true then return true
453 if val == false then return false
454 abort
455 end
456
457 redef fun ==(o)
458 do
459 if not o isa PrimitiveInstance[Object] then return false
460 return self.val == o.val
461 end
462
463 redef fun eq_is(o)
464 do
465 if not o isa PrimitiveInstance[Object] then return false
466 return self.val is o.val
467 end
468
469 redef fun to_s do return "{mtype}#{val.object_id}({val})"
470
471 redef fun to_i do return val.as(Int)
472 end
473
474 private class ClosureInstance
475 super Instance
476
477 var frame: Frame
478
479 var nclosuredef: AClosureDef
480
481 init(mtype: MType, frame: Frame, nclosuredef: AClosureDef)
482 do
483 super(mtype)
484 self.frame = frame
485 self.nclosuredef = nclosuredef
486 end
487 end
488
489 # Information about local variables in a running method
490 private class Frame
491 # The current visited node
492 # The node is stored by frame to keep a stack trace
493 var current_node: ANode
494 # The executed property.
495 # A Method in case of a call, an attribute in case of a default initialization.
496 var mpropdef: MPropDef
497 # Arguments of the method (the first is te receiver
498 var arguments: Array[Instance]
499 # Mapping betwen a variable an the current value
500 var map: Map[Variable, Instance] = new HashMap[Variable, Instance]
501 end
502
503 redef class ANode
504 # Aborts the program with a message
505 # `v' is used to know if a colored message is displayed or not
506 private fun fatal(v: NaiveInterpreter, message: String)
507 do
508 if v.modelbuilder.toolcontext.opt_no_color.value == true then
509 print("{message} ({location.file.filename}:{location.line_start})")
510 else
511 print("{location}: {message}\n{location.colored_line("0;31")}")
512 print(v.stack_trace)
513 end
514 exit(1)
515 end
516 end
517
518 redef class APropdef
519 # Execute a `mpropdef' associated with the current node.
520 private fun call(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
521 do
522 fatal(v, "Unimplemented {mpropdef}")
523 abort
524 end
525 end
526
527 redef class AConcreteMethPropdef
528 redef fun call(v, mpropdef, args)
529 do
530 var f = new Frame(self, self.mpropdef.as(not null), args)
531 for i in [0..mpropdef.msignature.arity[ do
532 var variable = self.n_signature.n_params[i].variable
533 assert variable != null
534 f.map[variable] = args[i+1]
535 end
536 for i in [0..mpropdef.msignature.mclosures.length[ do
537 var c = mpropdef.msignature.mclosures[i]
538 var variable = self.n_signature.n_closure_decls[i].variable
539 assert variable != null
540 f.map[variable] = args[i + 1 + mpropdef.msignature.arity]
541 end
542
543 v.frames.unshift(f)
544
545 # Call the implicit super-init
546 var auto_super_inits = self.auto_super_inits
547 if auto_super_inits != null then
548 var selfarg = [args.first]
549 for auto_super_init in auto_super_inits do
550 if auto_super_init.intro.msignature.arity == 0 then
551 v.send(auto_super_init, selfarg)
552 else
553 v.send(auto_super_init, args)
554 end
555 end
556 end
557
558 v.stmt(self.n_block)
559 v.frames.shift
560 if v.returnmark == f then
561 v.returnmark = null
562 var res = v.escapevalue
563 v.escapevalue = null
564 return res
565 end
566 return null
567 end
568 end
569
570 redef class AInternMethPropdef
571 redef fun call(v, mpropdef, args)
572 do
573 var pname = mpropdef.mproperty.name
574 var cname = mpropdef.mclassdef.mclass.name
575 if pname == "output" then
576 var recv = args.first
577 recv.val.output
578 return null
579 else if pname == "object_id" then
580 var recv = args.first
581 if recv isa PrimitiveInstance[Object] then
582 return v.int_instance(recv.val.object_id)
583 else
584 return v.int_instance(recv.object_id)
585 end
586 else if pname == "output_class_name" then
587 var recv = args.first
588 print recv.mtype.as(MClassType).mclass
589 return null
590 else if pname == "native_class_name" then
591 var recv = args.first
592 var txt = recv.mtype.as(MClassType).mclass.to_s
593 return v.native_string_instance(txt)
594 else if pname == "==" then
595 # == is correclt redefined for instances
596 return v.bool_instance(args[0] == args[1])
597 else if pname == "!=" then
598 return v.bool_instance(args[0] != args[1])
599 else if pname == "is_same_type" then
600 return v.bool_instance(args[0].mtype == args[1].mtype)
601 else if pname == "exit" then
602 exit(args[1].to_i)
603 abort
604 else if pname == "sys" then
605 return v.mainobj
606 else if cname == "Int" then
607 if pname == "unary -" then
608 return v.int_instance(-args[0].to_i)
609 else if pname == "succ" then
610 return v.int_instance(args[0].to_i + 1)
611 else if pname == "prec" then
612 return v.int_instance(args[0].to_i - 1)
613 else if pname == "+" then
614 return v.int_instance(args[0].to_i + args[1].to_i)
615 else if pname == "-" then
616 return v.int_instance(args[0].to_i - args[1].to_i)
617 else if pname == "*" then
618 return v.int_instance(args[0].to_i * args[1].to_i)
619 else if pname == "%" then
620 return v.int_instance(args[0].to_i % args[1].to_i)
621 else if pname == "/" then
622 return v.int_instance(args[0].to_i / args[1].to_i)
623 else if pname == "<" then
624 return v.bool_instance(args[0].to_i < args[1].to_i)
625 else if pname == ">" then
626 return v.bool_instance(args[0].to_i > args[1].to_i)
627 else if pname == "<=" then
628 return v.bool_instance(args[0].to_i <= args[1].to_i)
629 else if pname == ">=" then
630 return v.bool_instance(args[0].to_i >= args[1].to_i)
631 else if pname == "<=>" then
632 return v.int_instance(args[0].to_i <=> args[1].to_i)
633 else if pname == "ascii" then
634 return v.char_instance(args[0].to_i.ascii)
635 else if pname == "to_f" then
636 return v.float_instance(args[0].to_i.to_f)
637 else if pname == "lshift" then
638 return v.int_instance(args[0].to_i.lshift(args[1].to_i))
639 else if pname == "rshift" then
640 return v.int_instance(args[0].to_i.rshift(args[1].to_i))
641 end
642 else if cname == "Char" then
643 var recv = args[0].val.as(Char)
644 if pname == "ascii" then
645 return v.int_instance(recv.ascii)
646 else if pname == "succ" then
647 return v.char_instance(recv.succ)
648 else if pname == "prec" then
649 return v.char_instance(recv.prec)
650 else if pname == "<" then
651 return v.bool_instance(recv < args[1].val.as(Char))
652 else if pname == ">" then
653 return v.bool_instance(recv > args[1].val.as(Char))
654 else if pname == "<=" then
655 return v.bool_instance(recv <= args[1].val.as(Char))
656 else if pname == ">=" then
657 return v.bool_instance(recv >= args[1].val.as(Char))
658 else if pname == "<=>" then
659 return v.int_instance(recv <=> args[1].val.as(Char))
660 end
661 else if cname == "Float" then
662 if pname == "+" then
663 return v.float_instance(args[0].val.as(Float) + args[1].val.as(Float))
664 else if pname == "-" then
665 return v.float_instance(args[0].val.as(Float) - args[1].val.as(Float))
666 else if pname == "*" then
667 return v.float_instance(args[0].val.as(Float) * args[1].val.as(Float))
668 else if pname == "/" then
669 return v.float_instance(args[0].val.as(Float) / args[1].val.as(Float))
670 else if pname == "to_i" then
671 return v.int_instance(args[0].val.as(Float).to_i)
672 end
673 else if cname == "NativeString" then
674 var recvval = args.first.val.as(Buffer)
675 if pname == "[]" then
676 var arg1 = args[1].to_i
677 if arg1 >= recvval.length or arg1 < 0 then
678 debug("Illegal access on {recvval} for element {arg1}/{recvval.length}")
679 end
680 return v.char_instance(recvval[arg1])
681 else if pname == "[]=" then
682 var arg1 = args[1].to_i
683 if arg1 >= recvval.length or arg1 < 0 then
684 debug("Illegal access on {recvval} for element {arg1}/{recvval.length}")
685 end
686 recvval[arg1] = args[2].val.as(Char)
687 return null
688 else if pname == "copy_to" then
689 # sig= copy_to(dest: NativeString, length: Int, from: Int, to: Int)
690 var destval = args[1].val.as(Buffer)
691 var lenval = args[2].to_i
692 var fromval = args[3].to_i
693 var toval = args[4].to_i
694 if fromval < 0 then
695 debug("Illegal access on {recvval} for element {fromval}/{recvval.length}")
696 end
697 if fromval + lenval >= recvval.length then
698 debug("Illegal access on {recvval} for element {fromval}+{lenval}/{recvval.length}")
699 end
700 if toval < 0 then
701 debug("Illegal access on {destval} for element {toval}/{destval.length}")
702 end
703 if toval + lenval >= destval.length then
704 debug("Illegal access on {destval} for element {toval}+{lenval}/{destval.length}")
705 end
706 recvval.copy(fromval, lenval, destval, toval)
707 return null
708 else if pname == "atoi" then
709 return v.int_instance(recvval.to_i)
710 end
711 else if pname == "calloc_string" then
712 return v.native_string_instance("!" * args[1].to_i)
713 else if cname == "NativeArray" then
714 var recvval = args.first.val.as(Array[Instance])
715 if pname == "[]" then
716 if args[1].to_i >= recvval.length or args[1].to_i < 0 then
717 debug("Illegal access on {recvval} for element {args[1].to_i}/{recvval.length}")
718 end
719 return recvval[args[1].to_i]
720 else if pname == "[]=" then
721 recvval[args[1].to_i] = args[2]
722 return null
723 else if pname == "copy_to" then
724 recvval.copy(0, args[2].to_i, args[1].val.as(Array[Instance]), 0)
725 return null
726 end
727 else if pname == "calloc_array" then
728 var recvtype = args.first.mtype.as(MClassType)
729 var mtype: MType = recvtype.supertype_to(v.mainmodule, recvtype, v.mainmodule.get_primitive_class("ArrayCapable"))
730 mtype = mtype.as(MGenericType).arguments.first
731 var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
732 return new PrimitiveInstance[Array[Instance]](v.mainmodule.get_primitive_class("NativeArray").get_mtype([mtype]), val)
733 end
734 fatal(v, "Unimplemented intern {mpropdef}")
735 abort
736 end
737 end
738
739 redef class AbstractArray[E]
740 fun copy(start: Int, len: Int, dest: AbstractArray[E], new_start: Int)
741 do
742 self.copy_to(start, len, dest, new_start)
743 end
744 end
745
746 redef class AExternInitPropdef
747 redef fun call(v, mpropdef, args)
748 do
749 var pname = mpropdef.mproperty.name
750 var cname = mpropdef.mclassdef.mclass.name
751 if pname == "native_stdout" then
752 return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, stdout)
753 else if pname == "native_stdin" then
754 return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, stdin)
755 else if pname == "native_stderr" then
756 return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, stderr)
757 else if pname == "io_open_read" then
758 var a1 = args[1].val.as(Buffer)
759 return new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, new IFStream.open(a1.to_s))
760 else if pname == "io_open_write" then
761 var a1 = args[1].val.as(Buffer)
762 return new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, new OFStream.open(a1.to_s))
763 end
764 fatal(v, "Unimplemented extern init {mpropdef}")
765 abort
766 end
767 end
768
769 redef class AExternMethPropdef
770 super TablesCapable
771 redef fun call(v, mpropdef, args)
772 do
773 var pname = mpropdef.mproperty.name
774 var cname = mpropdef.mclassdef.mclass.name
775 if cname == "Int" then
776 var recvval = args.first.val.as(Int)
777 if pname == "rand" then
778 var res = recvval.rand
779 return v.int_instance(res)
780 end
781 else if cname == "NativeFile" then
782 var recvval = args.first.val
783 if pname == "io_write" then
784 var a1 = args[1].val.as(Buffer)
785 recvval.as(OStream).write(a1.substring(0, args[2].to_i))
786 return args[2]
787 else if pname == "io_read" then
788 var str = recvval.as(IStream).read(args[2].to_i)
789 var a1 = args[1].val.as(Buffer)
790 new Buffer.from(str).copy(0, str.length, a1, 0)
791 return v.int_instance(str.length)
792 else if pname == "io_close" then
793 recvval.as(IOS).close
794 return v.int_instance(0)
795 end
796 else if cname == "NativeString" then
797 var recvval = args.first.val.as(Buffer)
798 if pname == "file_exists" then
799 return v.bool_instance(recvval.to_s.file_exists)
800 else if pname == "file_mkdir" then
801 recvval.to_s.mkdir
802 return null
803 else if pname == "get_environ" then
804 var txt = recvval.to_s.environ
805 return v.native_string_instance(txt)
806 else if pname == "system" then
807 var res = sys.system(recvval.to_s)
808 return v.int_instance(res)
809 end
810 else if pname == "native_argc" then
811 return v.int_instance(v.arguments.length)
812 else if pname == "native_argv" then
813 var txt = v.arguments[args[1].to_i]
814 return v.native_string_instance(txt)
815 else if pname == "get_time" then
816 return v.int_instance(get_time)
817 else if pname == "lexer_goto" then
818 return v.int_instance(lexer_goto(args[1].to_i, args[2].to_i))
819 else if pname == "lexer_accept" then
820 return v.int_instance(lexer_accept(args[1].to_i))
821 else if pname == "parser_goto" then
822 return v.int_instance(parser_goto(args[1].to_i, args[2].to_i))
823 else if pname == "parser_action" then
824 return v.int_instance(parser_action(args[1].to_i, args[2].to_i))
825 end
826 fatal(v, "Unimplemented extern {mpropdef}")
827 abort
828 end
829 end
830
831 redef class AAttrPropdef
832 redef fun call(v, mpropdef, args)
833 do
834 var attr = self.mpropdef.mproperty
835 if args.length == 1 then
836 return v.read_attribute(attr, args.first)
837 else
838 assert args.length == 2
839 args.first.attributes[attr] = args[1]
840 return null
841 end
842 end
843
844 # Evaluate and set the default value of the attribute in `recv'
845 private fun init_expr(v: NaiveInterpreter, recv: Instance)
846 do
847 var nexpr = self.n_expr
848 if nexpr != null then
849 var f = new Frame(self, self.mpropdef.as(not null), [recv])
850 v.frames.unshift(f)
851 var val = v.expr(nexpr)
852 assert val != null
853 v.frames.shift
854 assert not v.is_escaping
855 recv.attributes[self.mpropdef.mproperty] = val
856 return
857 end
858 var mtype = self.mpropdef.static_mtype.as(not null)
859 # TODO The needinit info is statically computed, move it to modelbuilder or whatever
860 mtype = mtype.resolve_for(self.mpropdef.mclassdef.bound_mtype, self.mpropdef.mclassdef.bound_mtype, self.mpropdef.mclassdef.mmodule, true)
861 if mtype isa MNullableType then
862 recv.attributes[self.mpropdef.mproperty] = v.null_instance
863 end
864 end
865 end
866
867 redef class AClassdef
868 # Execute an implicit `mpropdef' associated with the current node.
869 private fun call(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
870 do
871 var super_inits = self.super_inits
872 if super_inits != null then
873 assert args.length == 1
874 for su in super_inits do
875 v.send(su, args)
876 end
877 return null
878 end
879 var recv = args.first
880 var i = 1
881 # Collect undefined attributes
882 for npropdef in self.n_propdefs do
883 if npropdef isa AAttrPropdef and npropdef.n_expr == null then
884 recv.attributes[npropdef.mpropdef.mproperty] = args[i]
885 i += 1
886 end
887 end
888 return null
889 end
890 end
891
892 redef class AExpr
893 # Evaluate the node as a possible expression.
894 # Return a possible value
895 # NOTE: Do not call this method directly, but use `v.expr'
896 # This method is here to be implemented by subclasses.
897 private fun expr(v: NaiveInterpreter): nullable Instance
898 do
899 fatal(v, "Unimplemented expr {class_name}")
900 abort
901 end
902
903 # Evaluate the node as a statement.
904 # NOTE: Do not call this method directly, but use `v.stmt'
905 # This method is here to be implemented by subclasses (no need to return something).
906 private fun stmt(v: NaiveInterpreter)
907 do
908 expr(v)
909 end
910
911 end
912
913 redef class ABlockExpr
914 redef fun stmt(v)
915 do
916 for e in self.n_expr do
917 v.stmt(e)
918 if v.is_escaping then return
919 end
920 end
921 end
922
923 redef class AVardeclExpr
924 redef fun stmt(v)
925 do
926 var ne = self.n_expr
927 if ne != null then
928 var i = v.expr(ne)
929 if i == null then return
930 v.frame.map[self.variable.as(not null)] = i
931 end
932 end
933 end
934
935 redef class AVarExpr
936 redef fun expr(v)
937 do
938 return v.frame.map[self.variable.as(not null)]
939 end
940 end
941
942 redef class AVarAssignExpr
943 redef fun stmt(v)
944 do
945 var i = v.expr(self.n_value)
946 if i == null then return
947 v.frame.map[self.variable.as(not null)] = i
948 end
949 end
950
951 redef class AVarReassignExpr
952 redef fun stmt(v)
953 do
954 var vari = v.frame.map[self.variable.as(not null)]
955 var value = v.expr(self.n_value)
956 if value == null then return
957 var res = v.send(reassign_property.mproperty, [vari, value])
958 assert res != null
959 v.frame.map[self.variable.as(not null)] = res
960 end
961 end
962
963 redef class ASelfExpr
964 redef fun expr(v)
965 do
966 return v.frame.arguments.first
967 end
968 end
969
970 redef class AContinueExpr
971 redef fun stmt(v)
972 do
973 var ne = self.n_expr
974 if ne != null then
975 var i = v.expr(ne)
976 if i == null then return
977 v.escapevalue = i
978 end
979 v.continuemark = self.escapemark
980 end
981 end
982
983 redef class ABreakExpr
984 redef fun stmt(v)
985 do
986 var ne = self.n_expr
987 if ne != null then
988 var i = v.expr(ne)
989 if i == null then return
990 v.escapevalue = i
991 end
992 v.breakmark = self.escapemark
993 end
994 end
995
996 redef class AReturnExpr
997 redef fun stmt(v)
998 do
999 var ne = self.n_expr
1000 if ne != null then
1001 var i = v.expr(ne)
1002 if i == null then return
1003 v.escapevalue = i
1004 end
1005 v.returnmark = v.frame
1006 end
1007 end
1008
1009 redef class AAbortExpr
1010 redef fun stmt(v)
1011 do
1012 fatal(v, "Aborted")
1013 exit(1)
1014 end
1015 end
1016
1017 redef class AIfExpr
1018 redef fun stmt(v)
1019 do
1020 var cond = v.expr(self.n_expr)
1021 if cond == null then return
1022 if cond.is_true then
1023 v.stmt(self.n_then)
1024 else
1025 v.stmt(self.n_else)
1026 end
1027 end
1028 end
1029
1030 redef class AIfexprExpr
1031 redef fun expr(v)
1032 do
1033 var cond = v.expr(self.n_expr)
1034 if cond == null then return null
1035 if cond.is_true then
1036 return v.expr(self.n_then)
1037 else
1038 return v.expr(self.n_else)
1039 end
1040 end
1041 end
1042
1043 redef class ADoExpr
1044 redef fun stmt(v)
1045 do
1046 v.stmt(self.n_block)
1047 v.is_break(self.escapemark) # Clear the break (if any)
1048 end
1049 end
1050
1051 redef class AWhileExpr
1052 redef fun stmt(v)
1053 do
1054 loop
1055 var cond = v.expr(self.n_expr)
1056 if cond == null then return
1057 if not cond.is_true then return
1058 v.stmt(self.n_block)
1059 if v.is_break(self.escapemark) then return
1060 v.is_continue(self.escapemark) # Clear the break
1061 if v.is_escaping then return
1062 end
1063 end
1064 end
1065
1066 redef class ALoopExpr
1067 redef fun stmt(v)
1068 do
1069 loop
1070 v.stmt(self.n_block)
1071 if v.is_break(self.escapemark) then return
1072 v.is_continue(self.escapemark) # Clear the break
1073 if v.is_escaping then return
1074 end
1075 end
1076 end
1077
1078 redef class AForExpr
1079 redef fun stmt(v)
1080 do
1081 var col = v.expr(self.n_expr)
1082 if col == null then return
1083 #self.debug("col {col}")
1084 var iter = v.send(v.mainmodule.force_get_primitive_method("iterator", col.mtype), [col]).as(not null)
1085 #self.debug("iter {iter}")
1086 loop
1087 var isok = v.send(v.mainmodule.force_get_primitive_method("is_ok", iter.mtype), [iter]).as(not null)
1088 if not isok.is_true then return
1089 if self.variables.length == 1 then
1090 var item = v.send(v.mainmodule.force_get_primitive_method("item", iter.mtype), [iter]).as(not null)
1091 #self.debug("item {item}")
1092 v.frame.map[self.variables.first] = item
1093 else if self.variables.length == 2 then
1094 var key = v.send(v.mainmodule.force_get_primitive_method("key", iter.mtype), [iter]).as(not null)
1095 v.frame.map[self.variables[0]] = key
1096 var item = v.send(v.mainmodule.force_get_primitive_method("item", iter.mtype), [iter]).as(not null)
1097 v.frame.map[self.variables[1]] = item
1098 else
1099 abort
1100 end
1101 v.stmt(self.n_block)
1102 if v.is_break(self.escapemark) then return
1103 v.is_continue(self.escapemark) # Clear the break
1104 if v.is_escaping then return
1105 v.send(v.mainmodule.force_get_primitive_method("next", iter.mtype), [iter])
1106 end
1107 end
1108 end
1109
1110 redef class AAssertExpr
1111 redef fun stmt(v)
1112 do
1113 var cond = v.expr(self.n_expr)
1114 if cond == null then return
1115 if not cond.is_true then
1116 v.stmt(self.n_else)
1117 if v.is_escaping then return
1118 var nid = self.n_id
1119 if nid != null then
1120 fatal(v, "Assert '{nid.text}' failed")
1121 else
1122 fatal(v, "Assert failed")
1123 end
1124 exit(1)
1125 end
1126 end
1127 end
1128
1129 redef class AOrExpr
1130 redef fun expr(v)
1131 do
1132 var cond = v.expr(self.n_expr)
1133 if cond == null then return null
1134 if cond.is_true then return cond
1135 return v.expr(self.n_expr2)
1136 end
1137 end
1138
1139 redef class AAndExpr
1140 redef fun expr(v)
1141 do
1142 var cond = v.expr(self.n_expr)
1143 if cond == null then return null
1144 if not cond.is_true then return cond
1145 return v.expr(self.n_expr2)
1146 end
1147 end
1148
1149 redef class ANotExpr
1150 redef fun expr(v)
1151 do
1152 var cond = v.expr(self.n_expr)
1153 if cond == null then return null
1154 return v.bool_instance(not cond.is_true)
1155 end
1156 end
1157
1158 redef class AOrElseExpr
1159 redef fun expr(v)
1160 do
1161 var i = v.expr(self.n_expr)
1162 if i == null then return null
1163 if i != v.null_instance then return i
1164 return v.expr(self.n_expr2)
1165 end
1166 end
1167
1168 redef class AEeExpr
1169 redef fun expr(v)
1170 do
1171 var i = v.expr(self.n_expr)
1172 if i == null then return null
1173 var i2 = v.expr(self.n_expr2)
1174 if i2 == null then return null
1175 return v.bool_instance(i.eq_is(i2))
1176 end
1177 end
1178
1179 redef class AIntExpr
1180 redef fun expr(v)
1181 do
1182 return v.int_instance(self.value.as(not null))
1183 end
1184 end
1185
1186 redef class AFloatExpr
1187 redef fun expr(v)
1188 do
1189 return v.float_instance(self.value.as(not null))
1190 end
1191 end
1192
1193 redef class ACharExpr
1194 redef fun expr(v)
1195 do
1196 return v.char_instance(self.value.as(not null))
1197 end
1198 end
1199
1200 redef class AArrayExpr
1201 redef fun expr(v)
1202 do
1203 var val = new Array[Instance]
1204 for nexpr in self.n_exprs.n_exprs do
1205 var i = v.expr(nexpr)
1206 if i == null then return null
1207 val.add(i)
1208 end
1209 var mtype = v.unanchor_type(self.mtype.as(not null)).as(MGenericType)
1210 var elttype = mtype.arguments.first
1211 return v.array_instance(val, elttype)
1212 end
1213 end
1214
1215 redef class AStringFormExpr
1216 redef fun expr(v)
1217 do
1218 var txt = self.value.as(not null)
1219 var nat = v.native_string_instance(txt)
1220 var res = new Instance(v.mainmodule.get_primitive_class("String").mclass_type)
1221 v.init_instance(res)
1222 v.send(v.mainmodule.force_get_primitive_method("from_cstring", res.mtype), [res, nat])
1223 v.check_init_instance(res)
1224 return res
1225 end
1226 end
1227
1228 redef class ASuperstringExpr
1229 redef fun expr(v)
1230 do
1231 var array = new Array[Instance]
1232 for nexpr in n_exprs do
1233 var i = v.expr(nexpr)
1234 if i == null then return null
1235 array.add(i)
1236 end
1237 var i = v.array_instance(array, v.mainmodule.get_primitive_class("Object").mclass_type)
1238 var res = v.send(v.mainmodule.force_get_primitive_method("to_s", i.mtype), [i])
1239 assert res != null
1240 return res
1241 end
1242 end
1243
1244 redef class ACrangeExpr
1245 redef fun expr(v)
1246 do
1247 var e1 = v.expr(self.n_expr)
1248 if e1 == null then return null
1249 var e2 = v.expr(self.n_expr2)
1250 if e2 == null then return null
1251 var mtype = v.unanchor_type(self.mtype.as(not null))
1252 var res = new Instance(mtype)
1253 v.init_instance(res)
1254 v.send(v.mainmodule.force_get_primitive_method("init", mtype), [res, e1, e2])
1255 v.check_init_instance(res)
1256 return res
1257 end
1258 end
1259
1260 redef class AOrangeExpr
1261 redef fun expr(v)
1262 do
1263 var e1 = v.expr(self.n_expr)
1264 if e1 == null then return null
1265 var e2 = v.expr(self.n_expr2)
1266 if e2 == null then return null
1267 var mtype = v.unanchor_type(self.mtype.as(not null))
1268 var res = new Instance(mtype)
1269 v.init_instance(res)
1270 v.send(v.mainmodule.force_get_primitive_method("without_last", mtype), [res, e1, e2])
1271 v.check_init_instance(res)
1272 return res
1273 end
1274 end
1275
1276 redef class ATrueExpr
1277 redef fun expr(v)
1278 do
1279 return v.bool_instance(true)
1280 end
1281 end
1282
1283 redef class AFalseExpr
1284 redef fun expr(v)
1285 do
1286 return v.bool_instance(false)
1287 end
1288 end
1289
1290 redef class ANullExpr
1291 redef fun expr(v)
1292 do
1293 return v.null_instance
1294 end
1295 end
1296
1297 redef class AIsaExpr
1298 redef fun expr(v)
1299 do
1300 var i = v.expr(self.n_expr)
1301 if i == null then return null
1302 var mtype = v.unanchor_type(self.cast_type.as(not null))
1303 return v.bool_instance(v.is_subtype(i.mtype, mtype))
1304 end
1305 end
1306
1307 redef class AAsCastExpr
1308 redef fun expr(v)
1309 do
1310 var i = v.expr(self.n_expr)
1311 if i == null then return null
1312 var mtype = v.unanchor_type(self.mtype.as(not null))
1313 if not v.is_subtype(i.mtype, mtype) then
1314 #fatal(v, "Cast failed expected {mtype}, got {i}")
1315 fatal(v, "Cast failed")
1316 end
1317 return i
1318 end
1319 end
1320
1321 redef class AAsNotnullExpr
1322 redef fun expr(v)
1323 do
1324 var i = v.expr(self.n_expr)
1325 if i == null then return null
1326 var mtype = v.unanchor_type(self.mtype.as(not null))
1327 if i.mtype isa MNullType then
1328 fatal(v, "Cast failed")
1329 end
1330 return i
1331 end
1332 end
1333
1334 redef class AParExpr
1335 redef fun expr(v)
1336 do
1337 return v.expr(self.n_expr)
1338 end
1339 end
1340
1341 redef class AOnceExpr
1342 redef fun expr(v)
1343 do
1344 if v.onces.has_key(self) then
1345 return v.onces[self]
1346 else
1347 var res = v.expr(self.n_expr)
1348 if res == null then return null
1349 v.onces[self] = res
1350 return res
1351 end
1352 end
1353 end
1354
1355 redef class ASendExpr
1356 redef fun expr(v)
1357 do
1358 var recv = v.expr(self.n_expr)
1359 if recv == null then return null
1360 var args = [recv]
1361 for a in compute_raw_arguments do
1362 var i = v.expr(a)
1363 if i == null then return null
1364 args.add(i)
1365 end
1366 for c in self.n_closure_defs do
1367 var mtype = c.mclosure.mtype
1368 var instance = new ClosureInstance(mtype, v.frame, c)
1369 args.add(instance)
1370 end
1371 var mproperty = self.mproperty.as(not null)
1372
1373 var res = v.send(mproperty, args)
1374 if v.is_break(self.escapemark) then
1375 res = v.escapevalue
1376 v.escapevalue = null
1377 end
1378 return res
1379 end
1380 end
1381
1382 redef class ASendReassignFormExpr
1383 redef fun stmt(v)
1384 do
1385 var recv = v.expr(self.n_expr)
1386 if recv == null then return
1387 var args = [recv]
1388 for a in compute_raw_arguments do
1389 var i = v.expr(a)
1390 if i == null then return
1391 args.add(i)
1392 end
1393 var value = v.expr(self.n_value)
1394 if value == null then return
1395
1396 var mproperty = self.mproperty.as(not null)
1397 var read = v.send(mproperty, args)
1398 assert read != null
1399
1400 var write = v.send(self.reassign_property.mproperty, [read, value])
1401 assert write != null
1402
1403 args.add(write)
1404
1405 v.send(self.write_mproperty.as(not null), args)
1406 end
1407 end
1408
1409 redef class ASuperExpr
1410 redef fun expr(v)
1411 do
1412 var recv = v.frame.arguments.first
1413 var args = [recv]
1414 for a in self.n_args.n_exprs do
1415 var i = v.expr(a)
1416 if i == null then return null
1417 args.add(i)
1418 end
1419 if args.length == 1 then
1420 args = v.frame.arguments
1421 end
1422
1423 var mproperty = self.mproperty
1424 if mproperty != null then
1425 if mproperty.intro.msignature.arity == 0 then
1426 args = [recv]
1427 end
1428 # Super init call
1429 var res = v.send(mproperty, args)
1430 return res
1431 end
1432
1433 # stantard call-next-method
1434 var mpropdef = v.frame.mpropdef
1435 # FIXME: we do not want an ugly static call!
1436 var mpropdefs = mpropdef.mproperty.lookup_super_definitions(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
1437 if mpropdefs.length != 1 then
1438 debug("MPRODFEFS for super {mpropdef} for {recv}: {mpropdefs.join(", ")}")
1439 end
1440 mpropdef = mpropdefs.first
1441 assert mpropdef isa MMethodDef
1442 var res = v.call(mpropdef, args)
1443 return res
1444 end
1445 end
1446
1447 redef class ANewExpr
1448 redef fun expr(v)
1449 do
1450 var mtype = v.unanchor_type(self.mtype.as(not null))
1451 var recv = new Instance(mtype)
1452 v.init_instance(recv)
1453 var args = [recv]
1454 for a in self.n_args.n_exprs do
1455 var i = v.expr(a)
1456 if i == null then return null
1457 args.add(i)
1458 end
1459 var mproperty = self.mproperty.as(not null)
1460 var res2 = v.send(mproperty, args)
1461 if res2 != null then
1462 #self.debug("got {res2} from {mproperty}. drop {recv}")
1463 return res2
1464 end
1465 v.check_init_instance(recv)
1466 return recv
1467 end
1468 end
1469
1470 redef class AAttrExpr
1471 redef fun expr(v)
1472 do
1473 var recv = v.expr(self.n_expr)
1474 if recv == null then return null
1475 var mproperty = self.mproperty.as(not null)
1476 return v.read_attribute(mproperty, recv)
1477 end
1478 end
1479
1480 redef class AAttrAssignExpr
1481 redef fun stmt(v)
1482 do
1483 var recv = v.expr(self.n_expr)
1484 if recv == null then return
1485 var i = v.expr(self.n_value)
1486 if i == null then return
1487 var mproperty = self.mproperty.as(not null)
1488 recv.attributes[mproperty] = i
1489 end
1490 end
1491
1492 redef class AAttrReassignExpr
1493 redef fun stmt(v)
1494 do
1495 var recv = v.expr(self.n_expr)
1496 if recv == null then return
1497 var value = v.expr(self.n_value)
1498 if value == null then return
1499 var mproperty = self.mproperty.as(not null)
1500 var attr = v.read_attribute(mproperty, recv)
1501 var res = v.send(reassign_property.mproperty, [attr, value])
1502 assert res != null
1503 recv.attributes[mproperty] = res
1504 end
1505 end
1506
1507 redef class AIssetAttrExpr
1508 redef fun expr(v)
1509 do
1510 var recv = v.expr(self.n_expr)
1511 if recv == null then return null
1512 var mproperty = self.mproperty.as(not null)
1513 return v.bool_instance(recv.attributes.has_key(mproperty))
1514 end
1515 end
1516
1517 redef class AClosureCallExpr
1518 redef fun expr(v)
1519 do
1520 var args = new Array[Instance]
1521 for a in self.n_args.n_exprs do
1522 var i = v.expr(a)
1523 if i == null then return null
1524 args.add(i)
1525 end
1526 var i = v.frame.map[self.variable.as(not null)]
1527 assert i isa ClosureInstance
1528 var res = v.call_closure(i, args)
1529 return res
1530 end
1531 end
1532
1533 redef class ADebugTypeExpr
1534 redef fun stmt(v)
1535 do
1536 # do nothing
1537 end
1538 end