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