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