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