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