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