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