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