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