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