engines: move compilation of `abstract` method to MMethodDef
[nit.git] / src / interpreter / 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 semantize
22 private import parser::tables
23 import mixin
24 import primitive_types
25
26 redef class ToolContext
27 # --discover-call-trace
28 var opt_discover_call_trace = new OptionBool("Trace calls of the first invocation of a method", "--discover-call-trace")
29
30 redef init
31 do
32 super
33 self.option_context.add_option(self.opt_discover_call_trace)
34 end
35 end
36
37 redef class ModelBuilder
38 # Execute the program from the entry point (`Sys::main`) of the `mainmodule`
39 # `arguments` are the command-line arguments in order
40 # REQUIRE that:
41 # 1. the AST is fully loaded.
42 # 2. the model is fully built.
43 # 3. the instructions are fully analysed.
44 fun run_naive_interpreter(mainmodule: MModule, arguments: Array[String])
45 do
46 var time0 = get_time
47 self.toolcontext.info("*** START INTERPRETING ***", 1)
48
49 var interpreter = new NaiveInterpreter(self, mainmodule, arguments)
50 interpreter.start(mainmodule)
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 class NaiveInterpreter
59 # The modelbuilder that know the AST and its associations with the model
60 var modelbuilder: ModelBuilder
61
62 # The main module of the program (used to lookup method)
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 # The main Sys instance
71 var mainobj: nullable Instance is noinit
72
73 init
74 do
75 if mainmodule.model.get_mclasses_by_name("Bool") != null then
76 self.true_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, true)
77 init_instance_primitive(self.true_instance)
78 self.false_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, false)
79 init_instance_primitive(self.false_instance)
80 end
81 self.null_instance = new PrimitiveInstance[nullable Object](mainmodule.model.null_type, null)
82 end
83
84 # Starts the interpreter on the main module of a program
85 fun start(mainmodule: MModule) do
86 var interpreter = self
87 var sys_type = mainmodule.sys_type
88 if sys_type == null then return # no class Sys
89 var mainobj = new MutableInstance(sys_type)
90 interpreter.mainobj = mainobj
91 interpreter.init_instance(mainobj)
92 var initprop = mainmodule.try_get_primitive_method("init", sys_type.mclass)
93 if initprop != null then
94 interpreter.send(initprop, [mainobj])
95 end
96 var mainprop = mainmodule.try_get_primitive_method("run", sys_type.mclass) or else
97 mainmodule.try_get_primitive_method("main", sys_type.mclass)
98 if mainprop != null then
99 interpreter.send(mainprop, [mainobj])
100 end
101 end
102
103 # Subtype test in the context of the mainmodule
104 fun is_subtype(sub, sup: MType): Bool
105 do
106 return sub.is_subtype(self.mainmodule, current_receiver_class, sup)
107 end
108
109 # Get a primitive method in the context of the main module
110 fun force_get_primitive_method(name: String, recv: MType): MMethod
111 do
112 assert recv isa MClassType
113 return self.modelbuilder.force_get_primitive_method(current_node, name, recv.mclass, self.mainmodule)
114 end
115
116 # Is a return executed?
117 # Set this mark to skip the evaluation until the end of the specified method frame
118 var returnmark: nullable Frame = null
119
120 # Is a break or a continue executed?
121 # Set this mark to skip the evaluation until a labeled statement catch it with `is_escape`
122 var escapemark: nullable EscapeMark = null
123
124 # Is a return or a break or a continue executed?
125 # Use this function to know if you must skip the evaluation of statements
126 fun is_escaping: Bool do return returnmark != null or escapemark != null
127
128 # The value associated with the current return/break/continue, if any.
129 # Set the value when you set a escapemark.
130 # Read the value when you catch a mark or reach the end of a method
131 var escapevalue: nullable Instance = null
132
133 # If there is a break/continue and is associated with `escapemark`, then return true and clear the mark.
134 # If there is no break/continue or if `escapemark` is null then return false.
135 # Use this function to catch a potential break/continue.
136 fun is_escape(escapemark: nullable EscapeMark): Bool
137 do
138 if escapemark != null and self.escapemark == escapemark then
139 self.escapemark = null
140 return true
141 else
142 return false
143 end
144 end
145
146 # Evaluate `n` as an expression in the current context.
147 # Return the value of the expression.
148 # If `n` cannot be evaluated, then aborts.
149 fun expr(n: AExpr): nullable Instance
150 do
151 var frame = self.frame
152 var old = frame.current_node
153 frame.current_node = n
154 #n.debug("IN Execute expr")
155 var i = n.expr(self)
156 if i == null and not self.is_escaping then
157 n.debug("inconsitance: no value and not escaping.")
158 end
159 var implicit_cast_to = n.implicit_cast_to
160 if implicit_cast_to != null then
161 var mtype = self.unanchor_type(implicit_cast_to)
162 if not self.is_subtype(i.mtype, mtype) then n.fatal(self, "Cast failed. Expected `{implicit_cast_to}`, got `{i.mtype}`")
163 end
164
165 #n.debug("OUT Execute expr: value is {i}")
166 #if not is_subtype(i.mtype, n.mtype.as(not null)) then n.debug("Expected {n.mtype.as(not null)} got {i}")
167 frame.current_node = old
168 return i
169 end
170
171 # Evaluate `n` as a statement in the current context.
172 # Do nothing if `n` is null.
173 # If `n` cannot be evaluated, then aborts.
174 fun stmt(n: nullable AExpr)
175 do
176 if n == null then return
177
178 if n.comprehension != null then
179 var comprehension = frame.comprehension.as(not null)
180 var i = expr(n)
181 if i != null then comprehension.add(i)
182 return
183 end
184
185 var frame = self.frame
186 var old = frame.current_node
187 frame.current_node = n
188 n.stmt(self)
189 frame.current_node = old
190 end
191
192 # Map used to store values of nodes that must be evaluated once in the system (`AOnceExpr`)
193 var onces: Map[ANode, Instance] = new HashMap[ANode, Instance]
194
195 # Return the boolean instance associated with `val`.
196 fun bool_instance(val: Bool): Instance
197 do
198 if val then return self.true_instance else return self.false_instance
199 end
200
201 # Return the integer instance associated with `val`.
202 fun int_instance(val: Int): Instance
203 do
204 var ic = get_primitive_class("Int")
205 var instance = new PrimitiveInstance[Int](ic.mclass_type, val)
206 init_instance_primitive(instance)
207 return instance
208 end
209
210 # Return the char instance associated with `val`.
211 fun char_instance(val: Char): Instance
212 do
213 var ic = get_primitive_class("Char")
214 var instance = new PrimitiveInstance[Char](ic.mclass_type, val)
215 init_instance_primitive(instance)
216 return instance
217 end
218
219 # Return the float instance associated with `val`.
220 fun float_instance(val: Float): Instance
221 do
222 var ic = get_primitive_class("Float")
223 var instance = new PrimitiveInstance[Float](ic.mclass_type, val)
224 init_instance_primitive(instance)
225 return instance
226 end
227
228 # The unique instance of the `true` value.
229 var true_instance: Instance is noinit
230
231 # The unique instance of the `false` value.
232 var false_instance: Instance is noinit
233
234 # The unique instance of the `null` value.
235 var null_instance: Instance is noinit
236
237 # Return a new array made of `values`.
238 # The dynamic type of the result is Array[elttype].
239 fun array_instance(values: Array[Instance], elttype: MType): Instance
240 do
241 assert not elttype.need_anchor
242 var nat = new PrimitiveInstance[Array[Instance]](get_primitive_class("NativeArray").get_mtype([elttype]), values)
243 init_instance_primitive(nat)
244 var mtype = get_primitive_class("Array").get_mtype([elttype])
245 var res = new MutableInstance(mtype)
246 self.init_instance(res)
247 self.send(self.force_get_primitive_method("with_native", mtype), [res, nat, self.int_instance(values.length)])
248 return res
249 end
250
251 # Return a instance associated to a primitive class
252 # Current primitive classes are `Int`, `Bool`, and `String`
253 fun value_instance(object: Object): Instance
254 do
255 if object isa Int then
256 return int_instance(object)
257 else if object isa Bool then
258 return bool_instance(object)
259 else if object isa String then
260 return string_instance(object)
261 else
262 abort
263 end
264 end
265
266 # Return a new native string initialized with `txt`
267 fun native_string_instance(txt: String): Instance
268 do
269 var val = new FlatBuffer.from(txt)
270 val.add('\0')
271 var ic = get_primitive_class("NativeString")
272 var instance = new PrimitiveInstance[Buffer](ic.mclass_type, val)
273 init_instance_primitive(instance)
274 return instance
275 end
276
277 # Return a new String instance for `txt`
278 fun string_instance(txt: String): Instance
279 do
280 var nat = native_string_instance(txt)
281 var res = self.send(self.force_get_primitive_method("to_s_with_length", nat.mtype), [nat, self.int_instance(txt.length)])
282 assert res != null
283 return res
284 end
285
286 # The current frame used to store local variables of the current method executed
287 fun frame: Frame do return frames.first
288
289 # The stack of all frames. The first one is the current one.
290 var frames = new List[Frame]
291
292 # Return a stack trace. One line per function
293 fun stack_trace: String
294 do
295 var b = new FlatBuffer
296 b.append(",---- Stack trace -- - - -\n")
297 for f in frames do
298 b.append("| {f.mpropdef} ({f.current_node.location})\n")
299 end
300 b.append("`------------------- - - -")
301 return b.to_s
302 end
303
304 # The current node, used to print errors, debug and stack-traces
305 fun current_node: nullable ANode
306 do
307 if frames.is_empty then return null
308 return frames.first.current_node
309 end
310
311 # The dynamic type of the current `self`
312 fun current_receiver_class: MClassType
313 do
314 return frames.first.arguments.first.mtype.as(MClassType)
315 end
316
317 # Exit the program with a message
318 fun fatal(message: String)
319 do
320 var node = current_node
321 if node == null then
322 print message
323 else
324 node.fatal(self, message)
325 end
326 exit(1)
327 end
328
329 # Debug on the current node
330 fun debug(message: String)
331 do
332 var node = current_node
333 if node == null then
334 print message
335 else
336 node.debug(message)
337 end
338 end
339
340 # Retrieve the value of the variable in the current frame
341 fun read_variable(v: Variable): Instance
342 do
343 var f = frames.first
344 return f.map[v]
345 end
346
347 # Assign the value of the variable in the current frame
348 fun write_variable(v: Variable, value: Instance)
349 do
350 var f = frames.first
351 f.map[v] = value
352 end
353
354 # Store known methods, used to trace methods as they are reached
355 var discover_call_trace: Set[MMethodDef] = new HashSet[MMethodDef]
356
357 # Evaluate `args` as expressions in the call of `mpropdef` on `recv`.
358 # This method is used to manage varargs in signatures and returns the real array
359 # of instances to use in the call.
360 # Return `null` if one of the evaluation of the arguments return null.
361 fun varargize(mpropdef: MMethodDef, recv: Instance, args: SequenceRead[AExpr]): nullable Array[Instance]
362 do
363 var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
364 var res = new Array[Instance]
365 res.add(recv)
366
367 if args.is_empty then return res
368
369 var vararg_rank = msignature.vararg_rank
370 var vararg_len = args.length - msignature.arity
371 if vararg_len < 0 then vararg_len = 0
372
373 for i in [0..msignature.arity[ do
374 if i == vararg_rank then
375 var ne = args[i]
376 if ne isa AVarargExpr then
377 var e = self.expr(ne.n_expr)
378 if e == null then return null
379 res.add(e)
380 continue
381 end
382 var vararg = new Array[Instance]
383 for j in [vararg_rank..vararg_rank+vararg_len] do
384 var e = self.expr(args[j])
385 if e == null then return null
386 vararg.add(e)
387 end
388 var elttype = msignature.mparameters[vararg_rank].mtype.anchor_to(self.mainmodule, recv.mtype.as(MClassType))
389 res.add(self.array_instance(vararg, elttype))
390 else
391 var j = i
392 if i > vararg_rank then j += vararg_len
393 var e = self.expr(args[j])
394 if e == null then return null
395 res.add(e)
396 end
397 end
398 return res
399 end
400
401 # Execute `mpropdef` for a `args` (where `args[0]` is the receiver).
402 # Return a value if `mpropdef` is a function, or null if it is a procedure.
403 # The call is direct/static. There is no message-sending/late-binding.
404 fun call(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
405 do
406 if self.modelbuilder.toolcontext.opt_discover_call_trace.value and not self.discover_call_trace.has(mpropdef) then
407 self.discover_call_trace.add mpropdef
408 self.debug("Discovered {mpropdef}")
409 end
410 assert args.length == mpropdef.msignature.arity + 1 else debug("Invalid arity for {mpropdef}. {args.length} arguments given.")
411
412 # Look for the AST node that implements the property
413 var val = mpropdef.constant_value
414
415 var node = modelbuilder.mpropdef2node(mpropdef)
416 if mpropdef.is_abstract then
417 if node != null then
418 self.frames.unshift new Frame(node, mpropdef, args)
419 end
420 fatal("Abstract method `{mpropdef.mproperty.name}` called on `{args.first.mtype}`")
421 abort
422 end
423
424 if node isa APropdef then
425 self.parameter_check(node, mpropdef, args)
426 return node.call(self, mpropdef, args)
427 else if node isa AClassdef then
428 self.parameter_check(node, mpropdef, args)
429 return node.call(self, mpropdef, args)
430 else if node != null then
431 fatal("Fatal Error: method {mpropdef} associated to unexpected AST node {node.location}")
432 abort
433 else if val != null then
434 return value_instance(val)
435 else
436 fatal("Fatal Error: method {mpropdef} not found in the AST")
437 abort
438 end
439 end
440
441 # Execute type checks of covariant parameters
442 fun parameter_check(node: ANode, mpropdef: MMethodDef, args: Array[Instance])
443 do
444 var msignature = mpropdef.msignature
445 for i in [0..msignature.arity[ do
446 # skip test for vararg since the array is instantiated with the correct polymorphic type
447 if msignature.vararg_rank == i then continue
448
449 # skip if the cast is not required
450 var origmtype = mpropdef.mproperty.intro.msignature.mparameters[i].mtype
451 if not origmtype.need_anchor then continue
452
453 #print "{mpropdef}: {mpropdef.mproperty.intro.msignature.mparameters[i]}"
454
455 # get the parameter type
456 var mtype = msignature.mparameters[i].mtype
457 var anchor = args.first.mtype.as(MClassType)
458 var amtype = mtype.anchor_to(self.mainmodule, anchor)
459 if not args[i+1].mtype.is_subtype(self.mainmodule, anchor, amtype) then
460 node.fatal(self, "Cast failed. Expected `{mtype}`, got `{args[i+1].mtype}`")
461 end
462 end
463 end
464
465 # Common code for runtime injected calls and normal calls
466 fun send_commons(mproperty: MMethod, args: Array[Instance], mtype: MType): nullable Instance
467 do
468 if mtype isa MNullType then
469 if mproperty.name == "==" or mproperty.name == "is_same_instance" then
470 return self.bool_instance(args[0] == args[1])
471 else if mproperty.name == "!=" then
472 return self.bool_instance(args[0] != args[1])
473 end
474 #fatal("Receiver is null. {mproperty}. {args.join(" ")} {self.frame.current_node.class_name}")
475 fatal("Receiver is null")
476 end
477 return null
478 end
479
480 # Execute a full `callsite` for given `args`
481 # Use this method, instead of `send` to execute and control the additional behavior of the call-sites
482 fun callsite(callsite: nullable CallSite, arguments: Array[Instance]): nullable Instance
483 do
484 var initializers = callsite.mpropdef.initializers
485 if not initializers.is_empty then
486 var recv = arguments.first
487 var i = 1
488 for p in initializers do
489 if p isa MMethod then
490 var args = [recv]
491 for x in p.intro.msignature.mparameters do
492 args.add arguments[i]
493 i += 1
494 end
495 self.send(p, args)
496 else if p isa MAttribute then
497 assert recv isa MutableInstance
498 write_attribute(p, recv, arguments[i])
499 i += 1
500 else abort
501 end
502 assert i == arguments.length
503
504 return send(callsite.mproperty, [recv])
505 end
506 return send(callsite.mproperty, arguments)
507 end
508
509 # Execute `mproperty` for a `args` (where `args[0]` is the receiver).
510 # Return a value if `mproperty` is a function, or null if it is a procedure.
511 # The call is polymorphic. There is a message-sending/late-binding according to the receiver (args[0]).
512 fun send(mproperty: MMethod, args: Array[Instance]): nullable Instance
513 do
514 var recv = args.first
515 var mtype = recv.mtype
516 var ret = send_commons(mproperty, args, mtype)
517 if ret != null then return ret
518 var propdef = mproperty.lookup_first_definition(self.mainmodule, mtype)
519 return self.call(propdef, args)
520 end
521
522 # Read the attribute `mproperty` of an instance `recv` and return its value.
523 # If the attribute in not yet initialized, then aborts with an error message.
524 fun read_attribute(mproperty: MAttribute, recv: Instance): Instance
525 do
526 assert recv isa MutableInstance
527 if not recv.attributes.has_key(mproperty) then
528 fatal("Uninitialized attribute {mproperty.name}")
529 abort
530 end
531 return recv.attributes[mproperty]
532 end
533
534 # Replace in `recv` the value of the attribute `mproperty` by `value`
535 fun write_attribute(mproperty: MAttribute, recv: Instance, value: Instance)
536 do
537 assert recv isa MutableInstance
538 recv.attributes[mproperty] = value
539 end
540
541 # Is the attribute `mproperty` initialized the instance `recv`?
542 fun isset_attribute(mproperty: MAttribute, recv: Instance): Bool
543 do
544 assert recv isa MutableInstance
545 return recv.attributes.has_key(mproperty)
546 end
547
548 # Collect attributes of a type in the order of their init
549 fun collect_attr_propdef(mtype: MType): Array[AAttrPropdef]
550 do
551 var cache = self.collect_attr_propdef_cache
552 if cache.has_key(mtype) then return cache[mtype]
553
554 var res = new Array[AAttrPropdef]
555 var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
556 self.mainmodule.linearize_mclassdefs(cds)
557 for cd in cds do
558 res.add_all(modelbuilder.collect_attr_propdef(cd))
559 end
560
561 cache[mtype] = res
562 return res
563 end
564
565 private var collect_attr_propdef_cache = new HashMap[MType, Array[AAttrPropdef]]
566
567 # Fill the initial values of the newly created instance `recv`.
568 # `recv.mtype` is used to know what must be filled.
569 fun init_instance(recv: Instance)
570 do
571 for npropdef in collect_attr_propdef(recv.mtype) do
572 npropdef.init_expr(self, recv)
573 end
574 end
575
576 # A hook to initialize a `PrimitiveInstance`
577 fun init_instance_primitive(recv: Instance) do end
578
579 # Return the primitive `MClass` corresponding to the `name` given in parameter
580 # `name` : name of the primitive class
581 fun get_primitive_class(name: String): MClass
582 do
583 return mainmodule.get_primitive_class(name)
584 end
585
586 # This function determines the correct type according to the receiver of the current propdef (self).
587 fun unanchor_type(mtype: MType): MType
588 do
589 return mtype.anchor_to(self.mainmodule, current_receiver_class)
590 end
591
592 # Placebo instance used to mark internal error result when `null` already have a meaning.
593 # TODO: replace with multiple return or something better
594 var error_instance = new MutableInstance(modelbuilder.model.null_type) is lazy
595 end
596
597 # An instance represents a value of the executed program.
598 abstract class Instance
599 # The dynamic type of the instance
600 # ASSERT: not self.mtype.is_anchored
601 var mtype: MType
602
603 # return true if the instance is the true value.
604 # return false if the instance is the true value.
605 # else aborts
606 fun is_true: Bool do abort
607
608 # Return true if `self` IS `o` (using the Nit semantic of is)
609 fun eq_is(o: Instance): Bool do return self.is_same_instance(o)
610
611 # Human readable object identity "Type#number"
612 redef fun to_s do return "{mtype}"
613
614 # Return the integer value if the instance is an integer.
615 # else aborts
616 fun to_i: Int do abort
617
618 # Return the integer value if the instance is a float.
619 # else aborts
620 fun to_f: Float do abort
621
622 # The real value encapsulated if the instance is primitive.
623 # Else aborts.
624 fun val: nullable Object do abort
625 end
626
627 # A instance with attribute (standards objects)
628 class MutableInstance
629 super Instance
630
631 # The values of the attributes
632 var attributes: Map[MAttribute, Instance] = new HashMap[MAttribute, Instance]
633 end
634
635 # Special instance to handle primitives values (int, bool, etc.)
636 # The trick it just to encapsulate the <<real>> value
637 class PrimitiveInstance[E]
638 super Instance
639
640 # The real value encapsulated
641 redef var val: E
642
643 redef fun is_true
644 do
645 if val == true then return true
646 if val == false then return false
647 abort
648 end
649
650 redef fun ==(o)
651 do
652 if not o isa PrimitiveInstance[nullable Object] then return false
653 return self.val == o.val
654 end
655
656 redef fun eq_is(o)
657 do
658 if not o isa PrimitiveInstance[nullable Object] then return false
659 return self.val.is_same_instance(o.val)
660 end
661
662 redef fun to_s do return "{mtype}#{val.object_id}({val or else "null"})"
663
664 redef fun to_i do return val.as(Int)
665
666 redef fun to_f do return val.as(Float)
667 end
668
669 # Information about local variables in a running method
670 class Frame
671 # The current visited node
672 # The node is stored by frame to keep a stack trace
673 var current_node: ANode
674 # The executed property.
675 # A Method in case of a call, an attribute in case of a default initialization.
676 var mpropdef: MPropDef
677 # Arguments of the method (the first is the receiver)
678 var arguments: Array[Instance]
679 # Mapping between a variable and the current value
680 private var map: Map[Variable, Instance] = new HashMap[Variable, Instance]
681 var comprehension: nullable Array[Instance] = null
682 end
683
684 redef class ANode
685 # Aborts the program with a message
686 # `v` is used to know if a colored message is displayed or not
687 fun fatal(v: NaiveInterpreter, message: String)
688 do
689 if v.modelbuilder.toolcontext.opt_no_color.value == true then
690 sys.stderr.write("Runtime error: {message} ({location.file.filename}:{location.line_start})\n")
691 else
692 sys.stderr.write("{location}: Runtime error: {message}\n{location.colored_line("0;31")}\n")
693 sys.stderr.write(v.stack_trace)
694 sys.stderr.write("\n")
695 end
696 exit(1)
697 end
698 end
699
700 redef class APropdef
701 # Execute a `mpropdef` associated with the current node.
702 private fun call(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
703 do
704 fatal(v, "NOT YET IMPLEMENTED method kind {class_name}. {mpropdef}")
705 abort
706 end
707 end
708
709 redef class AMethPropdef
710 super TablesCapable
711
712 redef fun call(v, mpropdef, args)
713 do
714 var f = new Frame(self, self.mpropdef.as(not null), args)
715 var res = call_commons(v, mpropdef, args, f)
716 v.frames.shift
717 if v.returnmark == f then
718 v.returnmark = null
719 res = v.escapevalue
720 v.escapevalue = null
721 return res
722 end
723 return res
724 end
725
726 private fun call_commons(v: NaiveInterpreter, mpropdef: MMethodDef, arguments: Array[Instance], f: Frame): nullable Instance
727 do
728 v.frames.unshift(f)
729
730 for i in [0..mpropdef.msignature.arity[ do
731 var variable = self.n_signature.n_params[i].variable
732 assert variable != null
733 v.write_variable(variable, arguments[i+1])
734 end
735
736 # Call the implicit super-init
737 var auto_super_inits = self.auto_super_inits
738 if auto_super_inits != null then
739 var args = [arguments.first]
740 for auto_super_init in auto_super_inits do
741 args.clear
742 for i in [0..auto_super_init.msignature.arity+1[ do
743 args.add(arguments[i])
744 end
745 assert auto_super_init.mproperty != mpropdef.mproperty
746 v.callsite(auto_super_init, args)
747 end
748 end
749 if auto_super_call then
750 # standard call-next-method
751 var superpd = mpropdef.lookup_next_definition(v.mainmodule, arguments.first.mtype)
752 v.call(superpd, arguments)
753 end
754
755 if mpropdef.is_intern or mpropdef.is_extern then
756 var res = intern_call(v, mpropdef, arguments)
757 if res != v.error_instance then return res
758 end
759
760 if n_block != null then
761 v.stmt(self.n_block)
762 return null
763 end
764
765 if mpropdef.is_intern then
766 fatal(v, "NOT YET IMPLEMENTED intern {mpropdef}")
767 else if mpropdef.is_extern then
768 fatal(v, "NOT YET IMPLEMENTED extern {mpropdef}")
769 else
770 fatal(v, "NOT YET IMPLEMENTED <wat?> {mpropdef}")
771 end
772 abort
773 end
774
775 # Interprets a intern or a shortcut extern method.
776 # Returns the result for a function, `null` for a procedure, or `error_instance` if the method is unknown.
777 private fun intern_call(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
778 do
779 var pname = mpropdef.mproperty.name
780 var cname = mpropdef.mclassdef.mclass.name
781 if pname == "output" then
782 var recv = args.first
783 recv.val.output
784 return null
785 else if pname == "object_id" then
786 var recv = args.first
787 if recv isa PrimitiveInstance[Object] then
788 return v.int_instance(recv.val.object_id)
789 else
790 return v.int_instance(recv.object_id)
791 end
792 else if pname == "output_class_name" then
793 var recv = args.first
794 print recv.mtype
795 return null
796 else if pname == "native_class_name" then
797 var recv = args.first
798 var txt = recv.mtype.to_s
799 return v.native_string_instance(txt)
800 else if pname == "==" then
801 # == is correctly redefined for instances
802 return v.bool_instance(args[0] == args[1])
803 else if pname == "!=" then
804 return v.bool_instance(args[0] != args[1])
805 else if pname == "is_same_type" then
806 return v.bool_instance(args[0].mtype == args[1].mtype)
807 else if pname == "is_same_instance" then
808 return v.bool_instance(args[0].eq_is(args[1]))
809 else if pname == "exit" then
810 exit(args[1].to_i)
811 abort
812 else if pname == "buffer_mode_full" then
813 return v.int_instance(sys.buffer_mode_full)
814 else if pname == "buffer_mode_line" then
815 return v.int_instance(sys.buffer_mode_line)
816 else if pname == "buffer_mode_none" then
817 return v.int_instance(sys.buffer_mode_none)
818 else if pname == "sys" then
819 return v.mainobj
820 else if cname == "Int" then
821 var recvval = args[0].to_i
822 if pname == "unary -" then
823 return v.int_instance(-args[0].to_i)
824 else if pname == "+" then
825 return v.int_instance(args[0].to_i + args[1].to_i)
826 else if pname == "-" then
827 return v.int_instance(args[0].to_i - args[1].to_i)
828 else if pname == "*" then
829 return v.int_instance(args[0].to_i * args[1].to_i)
830 else if pname == "%" then
831 return v.int_instance(args[0].to_i % args[1].to_i)
832 else if pname == "/" then
833 return v.int_instance(args[0].to_i / args[1].to_i)
834 else if pname == "<" then
835 return v.bool_instance(args[0].to_i < args[1].to_i)
836 else if pname == ">" then
837 return v.bool_instance(args[0].to_i > args[1].to_i)
838 else if pname == "<=" then
839 return v.bool_instance(args[0].to_i <= args[1].to_i)
840 else if pname == ">=" then
841 return v.bool_instance(args[0].to_i >= args[1].to_i)
842 else if pname == "<=>" then
843 return v.int_instance(args[0].to_i <=> args[1].to_i)
844 else if pname == "ascii" then
845 return v.char_instance(args[0].to_i.ascii)
846 else if pname == "to_f" then
847 return v.float_instance(args[0].to_i.to_f)
848 else if pname == "lshift" then
849 return v.int_instance(args[0].to_i.lshift(args[1].to_i))
850 else if pname == "rshift" then
851 return v.int_instance(args[0].to_i.rshift(args[1].to_i))
852 else if pname == "rand" then
853 var res = recvval.rand
854 return v.int_instance(res)
855 else if pname == "bin_and" then
856 return v.int_instance(args[0].to_i.bin_and(args[1].to_i))
857 else if pname == "bin_or" then
858 return v.int_instance(args[0].to_i.bin_or(args[1].to_i))
859 else if pname == "bin_xor" then
860 return v.int_instance(args[0].to_i.bin_xor(args[1].to_i))
861 else if pname == "bin_not" then
862 return v.int_instance(args[0].to_i.bin_not)
863 else if pname == "int_to_s_len" then
864 return v.int_instance(recvval.to_s.length)
865 else if pname == "native_int_to_s" then
866 var s = recvval.to_s
867 var srecv = args[1].val.as(Buffer)
868 srecv.clear
869 srecv.append(s)
870 srecv.add('\0')
871 return null
872 else if pname == "strerror_ext" then
873 return v.native_string_instance(recvval.strerror)
874 end
875 else if cname == "Char" then
876 var recv = args[0].val.as(Char)
877 if pname == "ascii" then
878 return v.int_instance(recv.ascii)
879 else if pname == "successor" then
880 return v.char_instance(recv.successor(args[1].to_i))
881 else if pname == "predecessor" then
882 return v.char_instance(recv.predecessor(args[1].to_i))
883 else if pname == "<" then
884 return v.bool_instance(recv < args[1].val.as(Char))
885 else if pname == ">" then
886 return v.bool_instance(recv > args[1].val.as(Char))
887 else if pname == "<=" then
888 return v.bool_instance(recv <= args[1].val.as(Char))
889 else if pname == ">=" then
890 return v.bool_instance(recv >= args[1].val.as(Char))
891 else if pname == "<=>" then
892 return v.int_instance(recv <=> args[1].val.as(Char))
893 end
894 else if cname == "Float" then
895 var recv = args[0].to_f
896 if pname == "unary -" then
897 return v.float_instance(-recv)
898 else if pname == "+" then
899 return v.float_instance(recv + args[1].to_f)
900 else if pname == "-" then
901 return v.float_instance(recv - args[1].to_f)
902 else if pname == "*" then
903 return v.float_instance(recv * args[1].to_f)
904 else if pname == "/" then
905 return v.float_instance(recv / args[1].to_f)
906 else if pname == "<" then
907 return v.bool_instance(recv < args[1].to_f)
908 else if pname == ">" then
909 return v.bool_instance(recv > args[1].to_f)
910 else if pname == "<=" then
911 return v.bool_instance(recv <= args[1].to_f)
912 else if pname == ">=" then
913 return v.bool_instance(recv >= args[1].to_f)
914 else if pname == "to_i" then
915 return v.int_instance(recv.to_i)
916 else if pname == "cos" then
917 return v.float_instance(args[0].to_f.cos)
918 else if pname == "sin" then
919 return v.float_instance(args[0].to_f.sin)
920 else if pname == "tan" then
921 return v.float_instance(args[0].to_f.tan)
922 else if pname == "acos" then
923 return v.float_instance(args[0].to_f.acos)
924 else if pname == "asin" then
925 return v.float_instance(args[0].to_f.asin)
926 else if pname == "atan" then
927 return v.float_instance(args[0].to_f.atan)
928 else if pname == "sqrt" then
929 return v.float_instance(args[0].to_f.sqrt)
930 else if pname == "exp" then
931 return v.float_instance(args[0].to_f.exp)
932 else if pname == "log" then
933 return v.float_instance(args[0].to_f.log)
934 else if pname == "pow" then
935 return v.float_instance(args[0].to_f.pow(args[1].to_f))
936 else if pname == "rand" then
937 return v.float_instance(args[0].to_f.rand)
938 else if pname == "abs" then
939 return v.float_instance(args[0].to_f.abs)
940 else if pname == "hypot_with" then
941 return v.float_instance(args[0].to_f.hypot_with(args[1].to_f))
942 else if pname == "is_nan" then
943 return v.bool_instance(args[0].to_f.is_nan)
944 else if pname == "is_inf_extern" then
945 return v.bool_instance(args[0].to_f.is_inf != 0)
946 else if pname == "round" then
947 return v.float_instance(args[0].to_f.round)
948 end
949 else if cname == "NativeString" then
950 if pname == "new" then
951 return v.native_string_instance("!" * args[1].to_i)
952 end
953 var recvval = args.first.val.as(Buffer)
954 if pname == "[]" then
955 var arg1 = args[1].to_i
956 if arg1 >= recvval.length or arg1 < 0 then
957 debug("Illegal access on {recvval} for element {arg1}/{recvval.length}")
958 end
959 return v.char_instance(recvval.chars[arg1])
960 else if pname == "[]=" then
961 var arg1 = args[1].to_i
962 if arg1 >= recvval.length or arg1 < 0 then
963 debug("Illegal access on {recvval} for element {arg1}/{recvval.length}")
964 end
965 recvval.chars[arg1] = args[2].val.as(Char)
966 return null
967 else if pname == "copy_to" then
968 # sig= copy_to(dest: NativeString, length: Int, from: Int, to: Int)
969 var destval = args[1].val.as(FlatBuffer)
970 var lenval = args[2].to_i
971 var fromval = args[3].to_i
972 var toval = args[4].to_i
973 if fromval < 0 then
974 debug("Illegal access on {recvval} for element {fromval}/{recvval.length}")
975 end
976 if fromval + lenval > recvval.length then
977 debug("Illegal access on {recvval} for element {fromval}+{lenval}/{recvval.length}")
978 end
979 if toval < 0 then
980 debug("Illegal access on {destval} for element {toval}/{destval.length}")
981 end
982 if toval + lenval > destval.length then
983 debug("Illegal access on {destval} for element {toval}+{lenval}/{destval.length}")
984 end
985 recvval.as(FlatBuffer).copy(fromval, lenval, destval, toval)
986 return null
987 else if pname == "atoi" then
988 return v.int_instance(recvval.to_i)
989 else if pname == "file_exists" then
990 return v.bool_instance(recvval.to_s.file_exists)
991 else if pname == "file_mkdir" then
992 recvval.to_s.mkdir
993 return null
994 else if pname == "file_chdir" then
995 recvval.to_s.chdir
996 return null
997 else if pname == "file_realpath" then
998 return v.native_string_instance(recvval.to_s.realpath)
999 else if pname == "get_environ" then
1000 var txt = recvval.to_s.environ
1001 return v.native_string_instance(txt)
1002 else if pname == "system" then
1003 var res = sys.system(recvval.to_s)
1004 return v.int_instance(res)
1005 else if pname == "atof" then
1006 return v.float_instance(recvval.to_f)
1007 end
1008 else if cname == "String" then
1009 var cs = v.send(v.force_get_primitive_method("to_cstring", args.first.mtype), [args.first])
1010 var str = cs.val.to_s
1011 if pname == "files" then
1012 var res = new Array[Instance]
1013 for f in str.files do res.add v.string_instance(f)
1014 return v.array_instance(res, v.get_primitive_class("String").mclass_type)
1015 end
1016 else if pname == "calloc_string" then
1017 return v.native_string_instance("!" * args[1].to_i)
1018 else if cname == "NativeArray" then
1019 if pname == "new" then
1020 var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
1021 var instance = new PrimitiveInstance[Array[Instance]](args[0].mtype, val)
1022 v.init_instance_primitive(instance)
1023 return instance
1024 end
1025 var recvval = args.first.val.as(Array[Instance])
1026 if pname == "[]" then
1027 if args[1].to_i >= recvval.length or args[1].to_i < 0 then
1028 debug("Illegal access on {recvval} for element {args[1].to_i}/{recvval.length}")
1029 end
1030 return recvval[args[1].to_i]
1031 else if pname == "[]=" then
1032 recvval[args[1].to_i] = args[2]
1033 return null
1034 else if pname == "length" then
1035 return v.int_instance(recvval.length)
1036 else if pname == "copy_to" then
1037 recvval.copy_to(0, args[2].to_i, args[1].val.as(Array[Instance]), 0)
1038 return null
1039 end
1040 else if cname == "NativeFile" then
1041 if pname == "native_stdout" then
1042 var inst = new PrimitiveNativeFile.native_stdout
1043 var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst)
1044 v.init_instance_primitive(instance)
1045 return instance
1046 else if pname == "native_stdin" then
1047 var inst = new PrimitiveNativeFile.native_stdin
1048 var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst)
1049 v.init_instance_primitive(instance)
1050 return instance
1051 else if pname == "native_stderr" then
1052 var inst = new PrimitiveNativeFile.native_stderr
1053 var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst)
1054 v.init_instance_primitive(instance)
1055 return instance
1056 else if pname == "io_open_read" then
1057 var a1 = args[1].val.as(Buffer)
1058 var inst = new PrimitiveNativeFile.io_open_read(a1.to_s)
1059 var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst)
1060 v.init_instance_primitive(instance)
1061 return instance
1062 else if pname == "io_open_write" then
1063 var a1 = args[1].val.as(Buffer)
1064 var inst = new PrimitiveNativeFile.io_open_write(a1.to_s)
1065 var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst)
1066 v.init_instance_primitive(instance)
1067 return instance
1068 end
1069 var recvval = args.first.val
1070 if pname == "io_write" then
1071 var a1 = args[1].val.as(Buffer)
1072 return v.int_instance(recvval.as(PrimitiveNativeFile).io_write(a1.to_cstring, args[2].to_i))
1073 else if pname == "io_read" then
1074 var a1 = args[1].val.as(Buffer)
1075 var ns = new NativeString(a1.length)
1076 var len = recvval.as(PrimitiveNativeFile).io_read(ns, args[2].to_i)
1077 a1.clear
1078 a1.append(ns.to_s_with_length(len))
1079 return v.int_instance(len)
1080 else if pname == "flush" then
1081 recvval.as(PrimitiveNativeFile).flush
1082 return null
1083 else if pname == "io_close" then
1084 return v.int_instance(recvval.as(PrimitiveNativeFile).io_close)
1085 else if pname == "set_buffering_type" then
1086 return v.int_instance(recvval.as(PrimitiveNativeFile).set_buffering_type(args[1].to_i, args[2].to_i))
1087 end
1088 else if pname == "calloc_array" then
1089 var recvtype = args.first.mtype.as(MClassType)
1090 var mtype: MType
1091 mtype = recvtype.supertype_to(v.mainmodule, recvtype, v.get_primitive_class("ArrayCapable"))
1092 mtype = mtype.arguments.first
1093 var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
1094 var instance = new PrimitiveInstance[Array[Instance]](v.get_primitive_class("NativeArray").get_mtype([mtype]), val)
1095 v.init_instance_primitive(instance)
1096 return instance
1097 else if pname == "native_argc" then
1098 return v.int_instance(v.arguments.length)
1099 else if pname == "native_argv" then
1100 var txt = v.arguments[args[1].to_i]
1101 return v.native_string_instance(txt)
1102 else if pname == "native_argc" then
1103 return v.int_instance(v.arguments.length)
1104 else if pname == "native_argv" then
1105 var txt = v.arguments[args[1].to_i]
1106 return v.native_string_instance(txt)
1107 else if pname == "get_time" then
1108 return v.int_instance(get_time)
1109 else if pname == "srand" then
1110 srand
1111 return null
1112 else if pname == "srand_from" then
1113 srand_from(args[1].to_i)
1114 return null
1115 else if pname == "atan2" then
1116 return v.float_instance(atan2(args[1].to_f, args[2].to_f))
1117 else if pname == "pi" then
1118 return v.float_instance(pi)
1119 else if pname == "lexer_goto" then
1120 return v.int_instance(lexer_goto(args[1].to_i, args[2].to_i))
1121 else if pname == "lexer_accept" then
1122 return v.int_instance(lexer_accept(args[1].to_i))
1123 else if pname == "parser_goto" then
1124 return v.int_instance(parser_goto(args[1].to_i, args[2].to_i))
1125 else if pname == "parser_action" then
1126 return v.int_instance(parser_action(args[1].to_i, args[2].to_i))
1127 else if pname == "file_getcwd" then
1128 return v.native_string_instance(getcwd)
1129 else if pname == "errno" then
1130 return v.int_instance(sys.errno)
1131 else if pname == "address_is_null" then
1132 var recv = args[0]
1133 if recv isa PrimitiveInstance[PrimitiveNativeFile] then
1134 return v.bool_instance(recv.val.address_is_null)
1135 end
1136 return v.false_instance
1137 end
1138 return v.error_instance
1139 end
1140 end
1141
1142 redef class AAttrPropdef
1143 redef fun call(v, mpropdef, args)
1144 do
1145 var recv = args.first
1146 assert recv isa MutableInstance
1147 var attr = self.mpropdef.mproperty
1148 if mpropdef == mreadpropdef then
1149 assert args.length == 1
1150 if not is_lazy or v.isset_attribute(attr, recv) then return v.read_attribute(attr, recv)
1151 return evaluate_expr(v, recv)
1152 else if mpropdef == mwritepropdef then
1153 assert args.length == 2
1154 v.write_attribute(attr, recv, args[1])
1155 return null
1156 else
1157 abort
1158 end
1159 end
1160
1161 # Evaluate and set the default value of the attribute in `recv`
1162 private fun init_expr(v: NaiveInterpreter, recv: Instance)
1163 do
1164 if is_lazy then return
1165 if has_value then
1166 evaluate_expr(v, recv)
1167 return
1168 end
1169 var mtype = self.mpropdef.static_mtype.as(not null)
1170 mtype = mtype.anchor_to(v.mainmodule, recv.mtype.as(MClassType))
1171 if mtype isa MNullableType then
1172 v.write_attribute(self.mpropdef.mproperty, recv, v.null_instance)
1173 end
1174 end
1175
1176 private fun evaluate_expr(v: NaiveInterpreter, recv: Instance): Instance
1177 do
1178 assert recv isa MutableInstance
1179 var f = new Frame(self, self.mpropdef.as(not null), [recv])
1180 v.frames.unshift(f)
1181
1182 var val
1183
1184 var nexpr = self.n_expr
1185 var nblock = self.n_block
1186 if nexpr != null then
1187 val = v.expr(nexpr)
1188 else if nblock != null then
1189 v.stmt(nblock)
1190 assert v.returnmark == f
1191 val = v.escapevalue
1192 v.returnmark = null
1193 v.escapevalue = null
1194 else
1195 abort
1196 end
1197 assert val != null
1198
1199 v.frames.shift
1200 assert not v.is_escaping
1201 v.write_attribute(self.mpropdef.mproperty, recv, val)
1202 return val
1203 end
1204 end
1205
1206 redef class AClassdef
1207 # Execute an implicit `mpropdef` associated with the current node.
1208 private fun call(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
1209 do
1210 if mpropdef.mproperty.is_root_init then
1211 assert args.length == 1
1212 if not mpropdef.is_intro then
1213 # standard call-next-method
1214 var superpd = mpropdef.lookup_next_definition(v.mainmodule, args.first.mtype)
1215 v.call(superpd, args)
1216 end
1217 return null
1218 else
1219 abort
1220 end
1221 end
1222 end
1223
1224 redef class AExpr
1225 # Evaluate the node as a possible expression.
1226 # Return a possible value
1227 # NOTE: Do not call this method directly, but use `v.expr`
1228 # This method is here to be implemented by subclasses.
1229 protected fun expr(v: NaiveInterpreter): nullable Instance
1230 do
1231 fatal(v, "NOT YET IMPLEMENTED expr {class_name}")
1232 abort
1233 end
1234
1235 # Evaluate the node as a statement.
1236 # NOTE: Do not call this method directly, but use `v.stmt`
1237 # This method is here to be implemented by subclasses (no need to return something).
1238 protected fun stmt(v: NaiveInterpreter)
1239 do
1240 expr(v)
1241 end
1242
1243 end
1244
1245 redef class ABlockExpr
1246 redef fun expr(v)
1247 do
1248 var last = self.n_expr.last
1249 for e in self.n_expr do
1250 if e == last then break
1251 v.stmt(e)
1252 if v.is_escaping then return null
1253 end
1254 return last.expr(v)
1255 end
1256
1257 redef fun stmt(v)
1258 do
1259 for e in self.n_expr do
1260 v.stmt(e)
1261 if v.is_escaping then return
1262 end
1263 end
1264 end
1265
1266 redef class AVardeclExpr
1267 redef fun stmt(v)
1268 do
1269 var ne = self.n_expr
1270 if ne != null then
1271 var i = v.expr(ne)
1272 if i == null then return
1273 v.write_variable(self.variable.as(not null), i)
1274 end
1275 end
1276 end
1277
1278 redef class AVarExpr
1279 redef fun expr(v)
1280 do
1281 return v.read_variable(self.variable.as(not null))
1282 end
1283 end
1284
1285 redef class AVarAssignExpr
1286 redef fun expr(v)
1287 do
1288 var i = v.expr(self.n_value)
1289 if i == null then return null
1290 v.write_variable(self.variable.as(not null), i)
1291 return i
1292 end
1293 end
1294
1295 redef class AVarReassignExpr
1296 redef fun stmt(v)
1297 do
1298 var variable = self.variable.as(not null)
1299 var vari = v.read_variable(variable)
1300 var value = v.expr(self.n_value)
1301 if value == null then return
1302 var res = v.callsite(reassign_callsite, [vari, value])
1303 assert res != null
1304 v.write_variable(variable, res)
1305 end
1306 end
1307
1308 redef class ASelfExpr
1309 redef fun expr(v)
1310 do
1311 return v.frame.arguments.first
1312 end
1313 end
1314
1315 redef class AEscapeExpr
1316 redef fun stmt(v)
1317 do
1318 var ne = self.n_expr
1319 if ne != null then
1320 var i = v.expr(ne)
1321 if i == null then return
1322 v.escapevalue = i
1323 end
1324 v.escapemark = self.escapemark
1325 end
1326 end
1327
1328 redef class AReturnExpr
1329 redef fun stmt(v)
1330 do
1331 var ne = self.n_expr
1332 if ne != null then
1333 var i = v.expr(ne)
1334 if i == null then return
1335 v.escapevalue = i
1336 end
1337 v.returnmark = v.frame
1338 end
1339 end
1340
1341 redef class AAbortExpr
1342 redef fun stmt(v)
1343 do
1344 fatal(v, "Aborted")
1345 exit(1)
1346 end
1347 end
1348
1349 redef class AIfExpr
1350 redef fun expr(v)
1351 do
1352 var cond = v.expr(self.n_expr)
1353 if cond == null then return null
1354 if cond.is_true then
1355 return v.expr(self.n_then.as(not null))
1356 else
1357 return v.expr(self.n_else.as(not null))
1358 end
1359 end
1360
1361 redef fun stmt(v)
1362 do
1363 var cond = v.expr(self.n_expr)
1364 if cond == null then return
1365 if cond.is_true then
1366 v.stmt(self.n_then)
1367 else
1368 v.stmt(self.n_else)
1369 end
1370 end
1371 end
1372
1373 redef class AIfexprExpr
1374 redef fun expr(v)
1375 do
1376 var cond = v.expr(self.n_expr)
1377 if cond == null then return null
1378 if cond.is_true then
1379 return v.expr(self.n_then)
1380 else
1381 return v.expr(self.n_else)
1382 end
1383 end
1384 end
1385
1386 redef class ADoExpr
1387 redef fun stmt(v)
1388 do
1389 v.stmt(self.n_block)
1390 v.is_escape(self.break_mark) # Clear the break (if any)
1391 end
1392 end
1393
1394 redef class AWhileExpr
1395 redef fun stmt(v)
1396 do
1397 loop
1398 var cond = v.expr(self.n_expr)
1399 if cond == null then return
1400 if not cond.is_true then return
1401 v.stmt(self.n_block)
1402 if v.is_escape(self.break_mark) then return
1403 v.is_escape(self.continue_mark) # Clear the break
1404 if v.is_escaping then return
1405 end
1406 end
1407 end
1408
1409 redef class ALoopExpr
1410 redef fun stmt(v)
1411 do
1412 loop
1413 v.stmt(self.n_block)
1414 if v.is_escape(self.break_mark) then return
1415 v.is_escape(self.continue_mark) # Clear the break
1416 if v.is_escaping then return
1417 end
1418 end
1419 end
1420
1421 redef class AForExpr
1422 redef fun stmt(v)
1423 do
1424 var col = v.expr(self.n_expr)
1425 if col == null then return
1426 if col.mtype isa MNullType then fatal(v, "Receiver is null")
1427
1428 #self.debug("col {col}")
1429 var iter = v.callsite(method_iterator, [col]).as(not null)
1430 #self.debug("iter {iter}")
1431 loop
1432 var isok = v.callsite(method_is_ok, [iter]).as(not null)
1433 if not isok.is_true then break
1434 if self.variables.length == 1 then
1435 var item = v.callsite(method_item, [iter]).as(not null)
1436 #self.debug("item {item}")
1437 v.write_variable(self.variables.first, item)
1438 else if self.variables.length == 2 then
1439 var key = v.callsite(method_key, [iter]).as(not null)
1440 v.write_variable(self.variables[0], key)
1441 var item = v.callsite(method_item, [iter]).as(not null)
1442 v.write_variable(self.variables[1], item)
1443 else
1444 abort
1445 end
1446 v.stmt(self.n_block)
1447 if v.is_escape(self.break_mark) then break
1448 v.is_escape(self.continue_mark) # Clear the break
1449 if v.is_escaping then break
1450 v.callsite(method_next, [iter])
1451 end
1452 var method_finish = self.method_finish
1453 if method_finish != null then
1454 v.callsite(method_finish, [iter])
1455 end
1456 end
1457 end
1458
1459 redef class AAssertExpr
1460 redef fun stmt(v)
1461 do
1462 var cond = v.expr(self.n_expr)
1463 if cond == null then return
1464 if not cond.is_true then
1465 v.stmt(self.n_else)
1466 if v.is_escaping then return
1467 var nid = self.n_id
1468 if nid != null then
1469 fatal(v, "Assert '{nid.text}' failed")
1470 else
1471 fatal(v, "Assert failed")
1472 end
1473 exit(1)
1474 end
1475 end
1476 end
1477
1478 redef class AOrExpr
1479 redef fun expr(v)
1480 do
1481 var cond = v.expr(self.n_expr)
1482 if cond == null then return null
1483 if cond.is_true then return cond
1484 return v.expr(self.n_expr2)
1485 end
1486 end
1487
1488 redef class AImpliesExpr
1489 redef fun expr(v)
1490 do
1491 var cond = v.expr(self.n_expr)
1492 if cond == null then return null
1493 if not cond.is_true then return v.true_instance
1494 return v.expr(self.n_expr2)
1495 end
1496 end
1497
1498 redef class AAndExpr
1499 redef fun expr(v)
1500 do
1501 var cond = v.expr(self.n_expr)
1502 if cond == null then return null
1503 if not cond.is_true then return cond
1504 return v.expr(self.n_expr2)
1505 end
1506 end
1507
1508 redef class ANotExpr
1509 redef fun expr(v)
1510 do
1511 var cond = v.expr(self.n_expr)
1512 if cond == null then return null
1513 return v.bool_instance(not cond.is_true)
1514 end
1515 end
1516
1517 redef class AOrElseExpr
1518 redef fun expr(v)
1519 do
1520 var i = v.expr(self.n_expr)
1521 if i == null then return null
1522 if i != v.null_instance then return i
1523 return v.expr(self.n_expr2)
1524 end
1525 end
1526
1527 redef class AIntExpr
1528 redef fun expr(v)
1529 do
1530 return v.int_instance(self.value.as(not null))
1531 end
1532 end
1533
1534 redef class AFloatExpr
1535 redef fun expr(v)
1536 do
1537 return v.float_instance(self.value.as(not null))
1538 end
1539 end
1540
1541 redef class ACharExpr
1542 redef fun expr(v)
1543 do
1544 return v.char_instance(self.value.as(not null))
1545 end
1546 end
1547
1548 redef class AArrayExpr
1549 redef fun expr(v)
1550 do
1551 var val = new Array[Instance]
1552 var old_comprehension = v.frame.comprehension
1553 v.frame.comprehension = val
1554 for nexpr in self.n_exprs do
1555 if nexpr isa AForExpr then
1556 v.stmt(nexpr)
1557 else
1558 var i = v.expr(nexpr)
1559 if i == null then return null
1560 val.add(i)
1561 end
1562 end
1563 v.frame.comprehension = old_comprehension
1564 var mtype = v.unanchor_type(self.mtype.as(not null)).as(MClassType)
1565 var elttype = mtype.arguments.first
1566 return v.array_instance(val, elttype)
1567 end
1568 end
1569
1570 redef class AStringFormExpr
1571 redef fun expr(v)
1572 do
1573 var txt = self.value.as(not null)
1574 return v.string_instance(txt)
1575 end
1576 end
1577
1578 redef class ASuperstringExpr
1579 redef fun expr(v)
1580 do
1581 var array = new Array[Instance]
1582 for nexpr in n_exprs do
1583 var i = v.expr(nexpr)
1584 if i == null then return null
1585 array.add(i)
1586 end
1587 var i = v.array_instance(array, v.get_primitive_class("Object").mclass_type)
1588 var res = v.send(v.force_get_primitive_method("to_s", i.mtype), [i])
1589 assert res != null
1590 return res
1591 end
1592 end
1593
1594 redef class ACrangeExpr
1595 redef fun expr(v)
1596 do
1597 var e1 = v.expr(self.n_expr)
1598 if e1 == null then return null
1599 var e2 = v.expr(self.n_expr2)
1600 if e2 == null then return null
1601 var mtype = v.unanchor_type(self.mtype.as(not null))
1602 var res = new MutableInstance(mtype)
1603 v.init_instance(res)
1604 v.callsite(init_callsite, [res, e1, e2])
1605 return res
1606 end
1607 end
1608
1609 redef class AOrangeExpr
1610 redef fun expr(v)
1611 do
1612 var e1 = v.expr(self.n_expr)
1613 if e1 == null then return null
1614 var e2 = v.expr(self.n_expr2)
1615 if e2 == null then return null
1616 var mtype = v.unanchor_type(self.mtype.as(not null))
1617 var res = new MutableInstance(mtype)
1618 v.init_instance(res)
1619 v.callsite(init_callsite, [res, e1, e2])
1620 return res
1621 end
1622 end
1623
1624 redef class ATrueExpr
1625 redef fun expr(v)
1626 do
1627 return v.bool_instance(true)
1628 end
1629 end
1630
1631 redef class AFalseExpr
1632 redef fun expr(v)
1633 do
1634 return v.bool_instance(false)
1635 end
1636 end
1637
1638 redef class ANullExpr
1639 redef fun expr(v)
1640 do
1641 return v.null_instance
1642 end
1643 end
1644
1645 redef class AIsaExpr
1646 redef fun expr(v)
1647 do
1648 var i = v.expr(self.n_expr)
1649 if i == null then return null
1650 var mtype = v.unanchor_type(self.cast_type.as(not null))
1651 return v.bool_instance(v.is_subtype(i.mtype, mtype))
1652 end
1653 end
1654
1655 redef class AAsCastExpr
1656 redef fun expr(v)
1657 do
1658 var i = v.expr(self.n_expr)
1659 if i == null then return null
1660 var mtype = self.mtype.as(not null)
1661 var amtype = v.unanchor_type(mtype)
1662 if not v.is_subtype(i.mtype, amtype) then
1663 fatal(v, "Cast failed. Expected `{amtype}`, got `{i.mtype}`")
1664 end
1665 return i
1666 end
1667 end
1668
1669 redef class AAsNotnullExpr
1670 redef fun expr(v)
1671 do
1672 var i = v.expr(self.n_expr)
1673 if i == null then return null
1674 if i.mtype isa MNullType then
1675 fatal(v, "Cast failed")
1676 end
1677 return i
1678 end
1679 end
1680
1681 redef class AParExpr
1682 redef fun expr(v)
1683 do
1684 return v.expr(self.n_expr)
1685 end
1686 end
1687
1688 redef class AOnceExpr
1689 redef fun expr(v)
1690 do
1691 if v.onces.has_key(self) then
1692 return v.onces[self]
1693 else
1694 var res = v.expr(self.n_expr)
1695 if res == null then return null
1696 v.onces[self] = res
1697 return res
1698 end
1699 end
1700 end
1701
1702 redef class ASendExpr
1703 redef fun expr(v)
1704 do
1705 var recv = v.expr(self.n_expr)
1706 if recv == null then return null
1707 var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
1708 if args == null then return null
1709
1710 var res = v.callsite(callsite, args)
1711 return res
1712 end
1713 end
1714
1715 redef class ASendReassignFormExpr
1716 redef fun stmt(v)
1717 do
1718 var recv = v.expr(self.n_expr)
1719 if recv == null then return
1720 var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
1721 if args == null then return
1722 var value = v.expr(self.n_value)
1723 if value == null then return
1724
1725 var read = v.callsite(callsite, args)
1726 assert read != null
1727
1728 var write = v.callsite(reassign_callsite, [read, value])
1729 assert write != null
1730
1731 args.add(write)
1732
1733 v.callsite(write_callsite, args)
1734 end
1735 end
1736
1737 redef class ASuperExpr
1738 redef fun expr(v)
1739 do
1740 var recv = v.frame.arguments.first
1741
1742 var callsite = self.callsite
1743 if callsite != null then
1744 var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
1745 if args == null then return null
1746 # Add additional arguments for the super init call
1747 if args.length == 1 then
1748 for i in [0..callsite.msignature.arity[ do
1749 args.add(v.frame.arguments[i+1])
1750 end
1751 end
1752 # Super init call
1753 var res = v.callsite(callsite, args)
1754 return res
1755 end
1756
1757 # standard call-next-method
1758 var mpropdef = self.mpropdef
1759 mpropdef = mpropdef.lookup_next_definition(v.mainmodule, recv.mtype)
1760
1761 var args = v.varargize(mpropdef, recv, self.n_args.n_exprs)
1762 if args == null then return null
1763
1764 if args.length == 1 then
1765 args = v.frame.arguments
1766 end
1767 var res = v.call(mpropdef, args)
1768 return res
1769 end
1770 end
1771
1772 redef class ANewExpr
1773 redef fun expr(v)
1774 do
1775 var mtype = v.unanchor_type(self.recvtype.as(not null))
1776 var recv: Instance = new MutableInstance(mtype)
1777 v.init_instance(recv)
1778 var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
1779 if args == null then return null
1780 var res2 = v.callsite(callsite, args)
1781 if res2 != null then
1782 #self.debug("got {res2} from {mproperty}. drop {recv}")
1783 return res2
1784 end
1785 return recv
1786 end
1787 end
1788
1789 redef class AAttrExpr
1790 redef fun expr(v)
1791 do
1792 var recv = v.expr(self.n_expr)
1793 if recv == null then return null
1794 if recv.mtype isa MNullType then fatal(v, "Receiver is null")
1795 var mproperty = self.mproperty.as(not null)
1796 return v.read_attribute(mproperty, recv)
1797 end
1798 end
1799
1800 redef class AAttrAssignExpr
1801 redef fun stmt(v)
1802 do
1803 var recv = v.expr(self.n_expr)
1804 if recv == null then return
1805 if recv.mtype isa MNullType then fatal(v, "Receiver is null")
1806 var i = v.expr(self.n_value)
1807 if i == null then return
1808 var mproperty = self.mproperty.as(not null)
1809 v.write_attribute(mproperty, recv, i)
1810 end
1811 end
1812
1813 redef class AAttrReassignExpr
1814 redef fun stmt(v)
1815 do
1816 var recv = v.expr(self.n_expr)
1817 if recv == null then return
1818 if recv.mtype isa MNullType then fatal(v, "Receiver is null")
1819 var value = v.expr(self.n_value)
1820 if value == null then return
1821 var mproperty = self.mproperty.as(not null)
1822 var attr = v.read_attribute(mproperty, recv)
1823 var res = v.callsite(reassign_callsite, [attr, value])
1824 assert res != null
1825 v.write_attribute(mproperty, recv, res)
1826 end
1827 end
1828
1829 redef class AIssetAttrExpr
1830 redef fun expr(v)
1831 do
1832 var recv = v.expr(self.n_expr)
1833 if recv == null then return null
1834 if recv.mtype isa MNullType then fatal(v, "Receiver is null")
1835 var mproperty = self.mproperty.as(not null)
1836 return v.bool_instance(v.isset_attribute(mproperty, recv))
1837 end
1838 end
1839
1840 redef class ADebugTypeExpr
1841 redef fun stmt(v)
1842 do
1843 # do nothing
1844 end
1845 end