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