nitvm: The interpreter and the vm have each their own specialized frames
[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 ic = get_primitive_class("Int")
205 var instance = new PrimitiveInstance[Int](ic.mclass_type, 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 ic = get_primitive_class("Char")
214 var instance = new PrimitiveInstance[Char](ic.mclass_type, 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 ic = get_primitive_class("Float")
223 var instance = new PrimitiveInstance[Float](ic.mclass_type, 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]](get_primitive_class("NativeArray").get_mtype([elttype]), values)
243 init_instance_primitive(nat)
244 var mtype = get_primitive_class("Array").get_mtype([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 ic = get_primitive_class("NativeString")
272 var instance = new PrimitiveInstance[Buffer](ic.mclass_type, 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 # Return the primitive `MClass` corresponding to the `name` given in parameter
592 # `name` : name of the primitive class
593 fun get_primitive_class(name: String): MClass
594 do
595 return mainmodule.get_primitive_class(name)
596 end
597
598 # This function determines the correct type according to the receiver of the current propdef (self).
599 fun unanchor_type(mtype: MType): MType
600 do
601 return mtype.anchor_to(self.mainmodule, current_receiver_class)
602 end
603
604 # Placebo instance used to mark internal error result when `null` already have a meaning.
605 # TODO: replace with multiple return or something better
606 var error_instance = new MutableInstance(modelbuilder.model.null_type) is lazy
607 end
608
609 # An instance represents a value of the executed program.
610 abstract class Instance
611 # The dynamic type of the instance
612 # ASSERT: not self.mtype.is_anchored
613 var mtype: MType
614
615 # return true if the instance is the true value.
616 # return false if the instance is the true value.
617 # else aborts
618 fun is_true: Bool do abort
619
620 # Return true if `self` IS `o` (using the Nit semantic of is)
621 fun eq_is(o: Instance): Bool do return self.is_same_instance(o)
622
623 # Human readable object identity "Type#number"
624 redef fun to_s do return "{mtype}"
625
626 # Return the integer value if the instance is an integer.
627 # else aborts
628 fun to_i: Int do abort
629
630 # Return the integer value if the instance is a float.
631 # else aborts
632 fun to_f: Float do abort
633
634 # The real value encapsulated if the instance is primitive.
635 # Else aborts.
636 fun val: nullable Object do abort
637 end
638
639 # A instance with attribute (standards objects)
640 class MutableInstance
641 super Instance
642
643 # The values of the attributes
644 var attributes: Map[MAttribute, Instance] = new HashMap[MAttribute, Instance]
645 end
646
647 # Special instance to handle primitives values (int, bool, etc.)
648 # The trick it just to encapsulate the <<real>> value
649 class PrimitiveInstance[E]
650 super Instance
651
652 # The real value encapsulated
653 redef var val: E
654
655 redef fun is_true
656 do
657 if val == true then return true
658 if val == false then return false
659 abort
660 end
661
662 redef fun ==(o)
663 do
664 if not o isa PrimitiveInstance[nullable Object] then return false
665 return self.val == o.val
666 end
667
668 redef fun eq_is(o)
669 do
670 if not o isa PrimitiveInstance[nullable Object] then return false
671 return self.val.is_same_instance(o.val)
672 end
673
674 redef fun to_s do return "{mtype}#{val.object_id}({val or else "null"})"
675
676 redef fun to_i do return val.as(Int)
677
678 redef fun to_f do return val.as(Float)
679 end
680
681 # Information about local variables in a running method
682 abstract class Frame
683 # The current visited node
684 # The node is stored by frame to keep a stack trace
685 var current_node: ANode
686 # The executed property.
687 # A Method in case of a call, an attribute in case of a default initialization.
688 var mpropdef: MPropDef
689 # Arguments of the method (the first is the receiver)
690 var arguments: Array[Instance]
691 # Indicate if the expression has an array comprehension form
692 var comprehension: nullable Array[Instance] = null
693 end
694
695 # Implementation of a Frame with a Hashmap to store local variables
696 class InterpreterFrame
697 super Frame
698
699 # Mapping between a variable and the current value
700 private var map: Map[Variable, Instance] = new HashMap[Variable, Instance]
701 end
702
703 redef class ANode
704 # Aborts the program with a message
705 # `v` is used to know if a colored message is displayed or not
706 fun fatal(v: NaiveInterpreter, message: String)
707 do
708 if v.modelbuilder.toolcontext.opt_no_color.value == true then
709 sys.stderr.write("Runtime error: {message} ({location.file.filename}:{location.line_start})\n")
710 else
711 sys.stderr.write("{location}: Runtime error: {message}\n{location.colored_line("0;31")}\n")
712 sys.stderr.write(v.stack_trace)
713 sys.stderr.write("\n")
714 end
715 exit(1)
716 end
717 end
718
719 redef class APropdef
720 # Execute a `mpropdef` associated with the current node.
721 private fun call(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
722 do
723 fatal(v, "NOT YET IMPLEMENTED method kind {class_name}. {mpropdef}")
724 abort
725 end
726 end
727
728 redef class AMethPropdef
729 super TablesCapable
730
731 redef fun call(v, mpropdef, args)
732 do
733 var f = v.new_frame(self, mpropdef, args)
734 var res = call_commons(v, mpropdef, args, f)
735 v.frames.shift
736 if v.returnmark == f then
737 v.returnmark = null
738 res = v.escapevalue
739 v.escapevalue = null
740 return res
741 end
742 return res
743 end
744
745 private fun call_commons(v: NaiveInterpreter, mpropdef: MMethodDef, arguments: Array[Instance], f: Frame): nullable Instance
746 do
747 v.frames.unshift(f)
748
749 for i in [0..mpropdef.msignature.arity[ do
750 var variable = self.n_signature.n_params[i].variable
751 assert variable != null
752 v.write_variable(variable, arguments[i+1])
753 end
754
755 # Call the implicit super-init
756 var auto_super_inits = self.auto_super_inits
757 if auto_super_inits != null then
758 var args = [arguments.first]
759 for auto_super_init in auto_super_inits do
760 args.clear
761 for i in [0..auto_super_init.msignature.arity+1[ do
762 args.add(arguments[i])
763 end
764 assert auto_super_init.mproperty != mpropdef.mproperty
765 v.callsite(auto_super_init, args)
766 end
767 end
768 if auto_super_call then
769 # standard call-next-method
770 var superpd = mpropdef.lookup_next_definition(v.mainmodule, arguments.first.mtype)
771 v.call(superpd, arguments)
772 end
773
774 if mpropdef.is_intern or mpropdef.is_extern then
775 var res = intern_call(v, mpropdef, arguments)
776 if res != v.error_instance then return res
777 end
778
779 if n_block != null then
780 v.stmt(self.n_block)
781 return null
782 end
783
784 if mpropdef.is_intern then
785 fatal(v, "NOT YET IMPLEMENTED intern {mpropdef}")
786 else if mpropdef.is_extern then
787 fatal(v, "NOT YET IMPLEMENTED extern {mpropdef}")
788 else
789 fatal(v, "NOT YET IMPLEMENTED <wat?> {mpropdef}")
790 end
791 abort
792 end
793
794 # Interprets a intern or a shortcut extern method.
795 # Returns the result for a function, `null` for a procedure, or `error_instance` if the method is unknown.
796 private fun intern_call(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
797 do
798 var pname = mpropdef.mproperty.name
799 var cname = mpropdef.mclassdef.mclass.name
800 if pname == "output" then
801 var recv = args.first
802 recv.val.output
803 return null
804 else if pname == "object_id" then
805 var recv = args.first
806 if recv isa PrimitiveInstance[Object] then
807 return v.int_instance(recv.val.object_id)
808 else
809 return v.int_instance(recv.object_id)
810 end
811 else if pname == "output_class_name" then
812 var recv = args.first
813 print recv.mtype
814 return null
815 else if pname == "native_class_name" then
816 var recv = args.first
817 var txt = recv.mtype.to_s
818 return v.native_string_instance(txt)
819 else if pname == "==" then
820 # == is correctly redefined for instances
821 return v.bool_instance(args[0] == args[1])
822 else if pname == "!=" then
823 return v.bool_instance(args[0] != args[1])
824 else if pname == "is_same_type" then
825 return v.bool_instance(args[0].mtype == args[1].mtype)
826 else if pname == "is_same_instance" then
827 return v.bool_instance(args[0].eq_is(args[1]))
828 else if pname == "exit" then
829 exit(args[1].to_i)
830 abort
831 else if pname == "buffer_mode_full" then
832 return v.int_instance(sys.buffer_mode_full)
833 else if pname == "buffer_mode_line" then
834 return v.int_instance(sys.buffer_mode_line)
835 else if pname == "buffer_mode_none" then
836 return v.int_instance(sys.buffer_mode_none)
837 else if pname == "sys" then
838 return v.mainobj
839 else if cname == "Int" then
840 var recvval = args[0].to_i
841 if pname == "unary -" then
842 return v.int_instance(-args[0].to_i)
843 else if pname == "+" then
844 return v.int_instance(args[0].to_i + args[1].to_i)
845 else if pname == "-" then
846 return v.int_instance(args[0].to_i - args[1].to_i)
847 else if pname == "*" then
848 return v.int_instance(args[0].to_i * args[1].to_i)
849 else if pname == "%" then
850 return v.int_instance(args[0].to_i % args[1].to_i)
851 else if pname == "/" then
852 return v.int_instance(args[0].to_i / args[1].to_i)
853 else if pname == "<" then
854 return v.bool_instance(args[0].to_i < args[1].to_i)
855 else if pname == ">" then
856 return v.bool_instance(args[0].to_i > args[1].to_i)
857 else if pname == "<=" then
858 return v.bool_instance(args[0].to_i <= args[1].to_i)
859 else if pname == ">=" then
860 return v.bool_instance(args[0].to_i >= args[1].to_i)
861 else if pname == "<=>" then
862 return v.int_instance(args[0].to_i <=> args[1].to_i)
863 else if pname == "ascii" then
864 return v.char_instance(args[0].to_i.ascii)
865 else if pname == "to_f" then
866 return v.float_instance(args[0].to_i.to_f)
867 else if pname == "lshift" then
868 return v.int_instance(args[0].to_i.lshift(args[1].to_i))
869 else if pname == "rshift" then
870 return v.int_instance(args[0].to_i.rshift(args[1].to_i))
871 else if pname == "rand" then
872 var res = recvval.rand
873 return v.int_instance(res)
874 else if pname == "bin_and" then
875 return v.int_instance(args[0].to_i.bin_and(args[1].to_i))
876 else if pname == "bin_or" then
877 return v.int_instance(args[0].to_i.bin_or(args[1].to_i))
878 else if pname == "bin_xor" then
879 return v.int_instance(args[0].to_i.bin_xor(args[1].to_i))
880 else if pname == "bin_not" then
881 return v.int_instance(args[0].to_i.bin_not)
882 else if pname == "int_to_s_len" then
883 return v.int_instance(recvval.to_s.length)
884 else if pname == "native_int_to_s" then
885 var s = recvval.to_s
886 var srecv = args[1].val.as(Buffer)
887 srecv.clear
888 srecv.append(s)
889 srecv.add('\0')
890 return null
891 else if pname == "strerror_ext" then
892 return v.native_string_instance(recvval.strerror)
893 end
894 else if cname == "Char" then
895 var recv = args[0].val.as(Char)
896 if pname == "ascii" then
897 return v.int_instance(recv.ascii)
898 else if pname == "successor" then
899 return v.char_instance(recv.successor(args[1].to_i))
900 else if pname == "predecessor" then
901 return v.char_instance(recv.predecessor(args[1].to_i))
902 else if pname == "<" then
903 return v.bool_instance(recv < args[1].val.as(Char))
904 else if pname == ">" then
905 return v.bool_instance(recv > args[1].val.as(Char))
906 else if pname == "<=" then
907 return v.bool_instance(recv <= args[1].val.as(Char))
908 else if pname == ">=" then
909 return v.bool_instance(recv >= args[1].val.as(Char))
910 else if pname == "<=>" then
911 return v.int_instance(recv <=> args[1].val.as(Char))
912 end
913 else if cname == "Float" then
914 var recv = args[0].to_f
915 if pname == "unary -" then
916 return v.float_instance(-recv)
917 else if pname == "+" then
918 return v.float_instance(recv + args[1].to_f)
919 else if pname == "-" then
920 return v.float_instance(recv - args[1].to_f)
921 else if pname == "*" then
922 return v.float_instance(recv * args[1].to_f)
923 else if pname == "/" then
924 return v.float_instance(recv / args[1].to_f)
925 else if pname == "<" then
926 return v.bool_instance(recv < args[1].to_f)
927 else if pname == ">" then
928 return v.bool_instance(recv > args[1].to_f)
929 else if pname == "<=" then
930 return v.bool_instance(recv <= args[1].to_f)
931 else if pname == ">=" then
932 return v.bool_instance(recv >= args[1].to_f)
933 else if pname == "to_i" then
934 return v.int_instance(recv.to_i)
935 else if pname == "cos" then
936 return v.float_instance(args[0].to_f.cos)
937 else if pname == "sin" then
938 return v.float_instance(args[0].to_f.sin)
939 else if pname == "tan" then
940 return v.float_instance(args[0].to_f.tan)
941 else if pname == "acos" then
942 return v.float_instance(args[0].to_f.acos)
943 else if pname == "asin" then
944 return v.float_instance(args[0].to_f.asin)
945 else if pname == "atan" then
946 return v.float_instance(args[0].to_f.atan)
947 else if pname == "sqrt" then
948 return v.float_instance(args[0].to_f.sqrt)
949 else if pname == "exp" then
950 return v.float_instance(args[0].to_f.exp)
951 else if pname == "log" then
952 return v.float_instance(args[0].to_f.log)
953 else if pname == "pow" then
954 return v.float_instance(args[0].to_f.pow(args[1].to_f))
955 else if pname == "rand" then
956 return v.float_instance(args[0].to_f.rand)
957 else if pname == "abs" then
958 return v.float_instance(args[0].to_f.abs)
959 else if pname == "hypot_with" then
960 return v.float_instance(args[0].to_f.hypot_with(args[1].to_f))
961 else if pname == "is_nan" then
962 return v.bool_instance(args[0].to_f.is_nan)
963 else if pname == "is_inf_extern" then
964 return v.bool_instance(args[0].to_f.is_inf != 0)
965 else if pname == "round" then
966 return v.float_instance(args[0].to_f.round)
967 end
968 else if cname == "NativeString" then
969 if pname == "new" then
970 return v.native_string_instance("!" * args[1].to_i)
971 end
972 var recvval = args.first.val.as(Buffer)
973 if pname == "[]" then
974 var arg1 = args[1].to_i
975 if arg1 >= recvval.length or arg1 < 0 then
976 debug("Illegal access on {recvval} for element {arg1}/{recvval.length}")
977 end
978 return v.char_instance(recvval.chars[arg1])
979 else if pname == "[]=" then
980 var arg1 = args[1].to_i
981 if arg1 >= recvval.length or arg1 < 0 then
982 debug("Illegal access on {recvval} for element {arg1}/{recvval.length}")
983 end
984 recvval.chars[arg1] = args[2].val.as(Char)
985 return null
986 else if pname == "copy_to" then
987 # sig= copy_to(dest: NativeString, length: Int, from: Int, to: Int)
988 var destval = args[1].val.as(FlatBuffer)
989 var lenval = args[2].to_i
990 var fromval = args[3].to_i
991 var toval = args[4].to_i
992 if fromval < 0 then
993 debug("Illegal access on {recvval} for element {fromval}/{recvval.length}")
994 end
995 if fromval + lenval > recvval.length then
996 debug("Illegal access on {recvval} for element {fromval}+{lenval}/{recvval.length}")
997 end
998 if toval < 0 then
999 debug("Illegal access on {destval} for element {toval}/{destval.length}")
1000 end
1001 if toval + lenval > destval.length then
1002 debug("Illegal access on {destval} for element {toval}+{lenval}/{destval.length}")
1003 end
1004 recvval.as(FlatBuffer).copy(fromval, lenval, destval, toval)
1005 return null
1006 else if pname == "atoi" then
1007 return v.int_instance(recvval.to_i)
1008 else if pname == "file_exists" then
1009 return v.bool_instance(recvval.to_s.file_exists)
1010 else if pname == "file_mkdir" then
1011 recvval.to_s.mkdir
1012 return null
1013 else if pname == "file_chdir" then
1014 recvval.to_s.chdir
1015 return null
1016 else if pname == "file_realpath" then
1017 return v.native_string_instance(recvval.to_s.realpath)
1018 else if pname == "get_environ" then
1019 var txt = recvval.to_s.environ
1020 return v.native_string_instance(txt)
1021 else if pname == "system" then
1022 var res = sys.system(recvval.to_s)
1023 return v.int_instance(res)
1024 else if pname == "atof" then
1025 return v.float_instance(recvval.to_f)
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.get_primitive_class("String").mclass_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 == "calloc_array" then
1108 var recvtype = args.first.mtype.as(MClassType)
1109 var mtype: MType
1110 mtype = recvtype.supertype_to(v.mainmodule, recvtype, v.get_primitive_class("ArrayCapable"))
1111 mtype = mtype.arguments.first
1112 var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
1113 var instance = new PrimitiveInstance[Array[Instance]](v.get_primitive_class("NativeArray").get_mtype([mtype]), val)
1114 v.init_instance_primitive(instance)
1115 return instance
1116 else if pname == "native_argc" then
1117 return v.int_instance(v.arguments.length)
1118 else if pname == "native_argv" then
1119 var txt = v.arguments[args[1].to_i]
1120 return v.native_string_instance(txt)
1121 else if pname == "native_argc" then
1122 return v.int_instance(v.arguments.length)
1123 else if pname == "native_argv" then
1124 var txt = v.arguments[args[1].to_i]
1125 return v.native_string_instance(txt)
1126 else if pname == "get_time" then
1127 return v.int_instance(get_time)
1128 else if pname == "srand" then
1129 srand
1130 return null
1131 else if pname == "srand_from" then
1132 srand_from(args[1].to_i)
1133 return null
1134 else if pname == "atan2" then
1135 return v.float_instance(atan2(args[1].to_f, args[2].to_f))
1136 else if pname == "pi" then
1137 return v.float_instance(pi)
1138 else if pname == "lexer_goto" then
1139 return v.int_instance(lexer_goto(args[1].to_i, args[2].to_i))
1140 else if pname == "lexer_accept" then
1141 return v.int_instance(lexer_accept(args[1].to_i))
1142 else if pname == "parser_goto" then
1143 return v.int_instance(parser_goto(args[1].to_i, args[2].to_i))
1144 else if pname == "parser_action" then
1145 return v.int_instance(parser_action(args[1].to_i, args[2].to_i))
1146 else if pname == "file_getcwd" then
1147 return v.native_string_instance(getcwd)
1148 else if pname == "errno" then
1149 return v.int_instance(sys.errno)
1150 else if pname == "address_is_null" then
1151 var recv = args[0]
1152 if recv isa PrimitiveInstance[PrimitiveNativeFile] then
1153 return v.bool_instance(recv.val.address_is_null)
1154 end
1155 return v.false_instance
1156 end
1157 return v.error_instance
1158 end
1159 end
1160
1161 redef class AAttrPropdef
1162 redef fun call(v, mpropdef, args)
1163 do
1164 var recv = args.first
1165 assert recv isa MutableInstance
1166 var attr = self.mpropdef.mproperty
1167 if mpropdef == mreadpropdef then
1168 assert args.length == 1
1169 if not is_lazy or v.isset_attribute(attr, recv) then return v.read_attribute(attr, recv)
1170 var f = v.new_frame(self, mpropdef, args)
1171 return evaluate_expr(v, recv, f)
1172 else if mpropdef == mwritepropdef then
1173 assert args.length == 2
1174 v.write_attribute(attr, recv, args[1])
1175 return null
1176 else
1177 abort
1178 end
1179 end
1180
1181 # Evaluate and set the default value of the attribute in `recv`
1182 private fun init_expr(v: NaiveInterpreter, recv: Instance)
1183 do
1184 if is_lazy then return
1185 if has_value then
1186 var f = v.new_frame(self, mpropdef.as(not null), [recv])
1187 evaluate_expr(v, recv, f)
1188 return
1189 end
1190 var mpropdef = self.mpropdef
1191 if mpropdef == null then return
1192 var mtype = mpropdef.static_mtype.as(not null)
1193 mtype = mtype.anchor_to(v.mainmodule, recv.mtype.as(MClassType))
1194 if mtype isa MNullableType then
1195 v.write_attribute(self.mpropdef.mproperty, recv, v.null_instance)
1196 end
1197 end
1198
1199 private fun evaluate_expr(v: NaiveInterpreter, recv: Instance, f: Frame): Instance
1200 do
1201 assert recv isa MutableInstance
1202 v.frames.unshift(f)
1203
1204 var val
1205
1206 var nexpr = self.n_expr
1207 var nblock = self.n_block
1208 if nexpr != null then
1209 val = v.expr(nexpr)
1210 else if nblock != null then
1211 v.stmt(nblock)
1212 assert v.returnmark == f
1213 val = v.escapevalue
1214 v.returnmark = null
1215 v.escapevalue = null
1216 else
1217 abort
1218 end
1219 assert val != null
1220
1221 v.frames.shift
1222 assert not v.is_escaping
1223 v.write_attribute(self.mpropdef.mproperty, recv, val)
1224 return val
1225 end
1226 end
1227
1228 redef class AClassdef
1229 # Execute an implicit `mpropdef` associated with the current node.
1230 private fun call(v: NaiveInterpreter, mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
1231 do
1232 if mpropdef.mproperty.is_root_init then
1233 assert args.length == 1
1234 if not mpropdef.is_intro then
1235 # standard call-next-method
1236 var superpd = mpropdef.lookup_next_definition(v.mainmodule, args.first.mtype)
1237 v.call(superpd, args)
1238 end
1239 return null
1240 else
1241 abort
1242 end
1243 end
1244 end
1245
1246 redef class AExpr
1247 # Evaluate the node as a possible expression.
1248 # Return a possible value
1249 # NOTE: Do not call this method directly, but use `v.expr`
1250 # This method is here to be implemented by subclasses.
1251 protected fun expr(v: NaiveInterpreter): nullable Instance
1252 do
1253 fatal(v, "NOT YET IMPLEMENTED expr {class_name}")
1254 abort
1255 end
1256
1257 # Evaluate the node as a statement.
1258 # NOTE: Do not call this method directly, but use `v.stmt`
1259 # This method is here to be implemented by subclasses (no need to return something).
1260 protected fun stmt(v: NaiveInterpreter)
1261 do
1262 expr(v)
1263 end
1264
1265 end
1266
1267 redef class ABlockExpr
1268 redef fun expr(v)
1269 do
1270 var last = self.n_expr.last
1271 for e in self.n_expr do
1272 if e == last then break
1273 v.stmt(e)
1274 if v.is_escaping then return null
1275 end
1276 return last.expr(v)
1277 end
1278
1279 redef fun stmt(v)
1280 do
1281 for e in self.n_expr do
1282 v.stmt(e)
1283 if v.is_escaping then return
1284 end
1285 end
1286 end
1287
1288 redef class AVardeclExpr
1289 redef fun stmt(v)
1290 do
1291 var ne = self.n_expr
1292 if ne != null then
1293 var i = v.expr(ne)
1294 if i == null then return
1295 v.write_variable(self.variable.as(not null), i)
1296 end
1297 end
1298 end
1299
1300 redef class AVarExpr
1301 redef fun expr(v)
1302 do
1303 return v.read_variable(self.variable.as(not null))
1304 end
1305 end
1306
1307 redef class AVarAssignExpr
1308 redef fun expr(v)
1309 do
1310 var i = v.expr(self.n_value)
1311 if i == null then return null
1312 v.write_variable(self.variable.as(not null), i)
1313 return i
1314 end
1315 end
1316
1317 redef class AVarReassignExpr
1318 redef fun stmt(v)
1319 do
1320 var variable = self.variable.as(not null)
1321 var vari = v.read_variable(variable)
1322 var value = v.expr(self.n_value)
1323 if value == null then return
1324 var res = v.callsite(reassign_callsite, [vari, value])
1325 assert res != null
1326 v.write_variable(variable, res)
1327 end
1328 end
1329
1330 redef class ASelfExpr
1331 redef fun expr(v)
1332 do
1333 return v.frame.arguments.first
1334 end
1335 end
1336
1337 redef class AEscapeExpr
1338 redef fun stmt(v)
1339 do
1340 var ne = self.n_expr
1341 if ne != null then
1342 var i = v.expr(ne)
1343 if i == null then return
1344 v.escapevalue = i
1345 end
1346 v.escapemark = self.escapemark
1347 end
1348 end
1349
1350 redef class AReturnExpr
1351 redef fun stmt(v)
1352 do
1353 var ne = self.n_expr
1354 if ne != null then
1355 var i = v.expr(ne)
1356 if i == null then return
1357 v.escapevalue = i
1358 end
1359 v.returnmark = v.frame
1360 end
1361 end
1362
1363 redef class AAbortExpr
1364 redef fun stmt(v)
1365 do
1366 fatal(v, "Aborted")
1367 exit(1)
1368 end
1369 end
1370
1371 redef class AIfExpr
1372 redef fun expr(v)
1373 do
1374 var cond = v.expr(self.n_expr)
1375 if cond == null then return null
1376 if cond.is_true then
1377 return v.expr(self.n_then.as(not null))
1378 else
1379 return v.expr(self.n_else.as(not null))
1380 end
1381 end
1382
1383 redef fun stmt(v)
1384 do
1385 var cond = v.expr(self.n_expr)
1386 if cond == null then return
1387 if cond.is_true then
1388 v.stmt(self.n_then)
1389 else
1390 v.stmt(self.n_else)
1391 end
1392 end
1393 end
1394
1395 redef class AIfexprExpr
1396 redef fun expr(v)
1397 do
1398 var cond = v.expr(self.n_expr)
1399 if cond == null then return null
1400 if cond.is_true then
1401 return v.expr(self.n_then)
1402 else
1403 return v.expr(self.n_else)
1404 end
1405 end
1406 end
1407
1408 redef class ADoExpr
1409 redef fun stmt(v)
1410 do
1411 v.stmt(self.n_block)
1412 v.is_escape(self.break_mark) # Clear the break (if any)
1413 end
1414 end
1415
1416 redef class AWhileExpr
1417 redef fun stmt(v)
1418 do
1419 loop
1420 var cond = v.expr(self.n_expr)
1421 if cond == null then return
1422 if not cond.is_true then return
1423 v.stmt(self.n_block)
1424 if v.is_escape(self.break_mark) then return
1425 v.is_escape(self.continue_mark) # Clear the break
1426 if v.is_escaping then return
1427 end
1428 end
1429 end
1430
1431 redef class ALoopExpr
1432 redef fun stmt(v)
1433 do
1434 loop
1435 v.stmt(self.n_block)
1436 if v.is_escape(self.break_mark) then return
1437 v.is_escape(self.continue_mark) # Clear the break
1438 if v.is_escaping then return
1439 end
1440 end
1441 end
1442
1443 redef class AForExpr
1444 redef fun stmt(v)
1445 do
1446 var col = v.expr(self.n_expr)
1447 if col == null then return
1448 if col.mtype isa MNullType then fatal(v, "Receiver is null")
1449
1450 #self.debug("col {col}")
1451 var iter = v.callsite(method_iterator, [col]).as(not null)
1452 #self.debug("iter {iter}")
1453 loop
1454 var isok = v.callsite(method_is_ok, [iter]).as(not null)
1455 if not isok.is_true then break
1456 if self.variables.length == 1 then
1457 var item = v.callsite(method_item, [iter]).as(not null)
1458 #self.debug("item {item}")
1459 v.write_variable(self.variables.first, item)
1460 else if self.variables.length == 2 then
1461 var key = v.callsite(method_key, [iter]).as(not null)
1462 v.write_variable(self.variables[0], key)
1463 var item = v.callsite(method_item, [iter]).as(not null)
1464 v.write_variable(self.variables[1], item)
1465 else
1466 abort
1467 end
1468 v.stmt(self.n_block)
1469 if v.is_escape(self.break_mark) then break
1470 v.is_escape(self.continue_mark) # Clear the break
1471 if v.is_escaping then break
1472 v.callsite(method_next, [iter])
1473 end
1474 var method_finish = self.method_finish
1475 if method_finish != null then
1476 v.callsite(method_finish, [iter])
1477 end
1478 end
1479 end
1480
1481 redef class AAssertExpr
1482 redef fun stmt(v)
1483 do
1484 var cond = v.expr(self.n_expr)
1485 if cond == null then return
1486 if not cond.is_true then
1487 v.stmt(self.n_else)
1488 if v.is_escaping then return
1489 var nid = self.n_id
1490 if nid != null then
1491 fatal(v, "Assert '{nid.text}' failed")
1492 else
1493 fatal(v, "Assert failed")
1494 end
1495 exit(1)
1496 end
1497 end
1498 end
1499
1500 redef class AOrExpr
1501 redef fun expr(v)
1502 do
1503 var cond = v.expr(self.n_expr)
1504 if cond == null then return null
1505 if cond.is_true then return cond
1506 return v.expr(self.n_expr2)
1507 end
1508 end
1509
1510 redef class AImpliesExpr
1511 redef fun expr(v)
1512 do
1513 var cond = v.expr(self.n_expr)
1514 if cond == null then return null
1515 if not cond.is_true then return v.true_instance
1516 return v.expr(self.n_expr2)
1517 end
1518 end
1519
1520 redef class AAndExpr
1521 redef fun expr(v)
1522 do
1523 var cond = v.expr(self.n_expr)
1524 if cond == null then return null
1525 if not cond.is_true then return cond
1526 return v.expr(self.n_expr2)
1527 end
1528 end
1529
1530 redef class ANotExpr
1531 redef fun expr(v)
1532 do
1533 var cond = v.expr(self.n_expr)
1534 if cond == null then return null
1535 return v.bool_instance(not cond.is_true)
1536 end
1537 end
1538
1539 redef class AOrElseExpr
1540 redef fun expr(v)
1541 do
1542 var i = v.expr(self.n_expr)
1543 if i == null then return null
1544 if i != v.null_instance then return i
1545 return v.expr(self.n_expr2)
1546 end
1547 end
1548
1549 redef class AIntExpr
1550 redef fun expr(v)
1551 do
1552 return v.int_instance(self.value.as(not null))
1553 end
1554 end
1555
1556 redef class AFloatExpr
1557 redef fun expr(v)
1558 do
1559 return v.float_instance(self.value.as(not null))
1560 end
1561 end
1562
1563 redef class ACharExpr
1564 redef fun expr(v)
1565 do
1566 return v.char_instance(self.value.as(not null))
1567 end
1568 end
1569
1570 redef class AArrayExpr
1571 redef fun expr(v)
1572 do
1573 var val = new Array[Instance]
1574 var old_comprehension = v.frame.comprehension
1575 v.frame.comprehension = val
1576 for nexpr in self.n_exprs do
1577 if nexpr isa AForExpr then
1578 v.stmt(nexpr)
1579 else
1580 var i = v.expr(nexpr)
1581 if i == null then return null
1582 val.add(i)
1583 end
1584 end
1585 v.frame.comprehension = old_comprehension
1586 var mtype = v.unanchor_type(self.mtype.as(not null)).as(MClassType)
1587 var elttype = mtype.arguments.first
1588 return v.array_instance(val, elttype)
1589 end
1590 end
1591
1592 redef class AStringFormExpr
1593 redef fun expr(v)
1594 do
1595 var txt = self.value.as(not null)
1596 return v.string_instance(txt)
1597 end
1598 end
1599
1600 redef class ASuperstringExpr
1601 redef fun expr(v)
1602 do
1603 var array = new Array[Instance]
1604 for nexpr in n_exprs do
1605 var i = v.expr(nexpr)
1606 if i == null then return null
1607 array.add(i)
1608 end
1609 var i = v.array_instance(array, v.get_primitive_class("Object").mclass_type)
1610 var res = v.send(v.force_get_primitive_method("to_s", i.mtype), [i])
1611 assert res != null
1612 return res
1613 end
1614 end
1615
1616 redef class ACrangeExpr
1617 redef fun expr(v)
1618 do
1619 var e1 = v.expr(self.n_expr)
1620 if e1 == null then return null
1621 var e2 = v.expr(self.n_expr2)
1622 if e2 == null then return null
1623 var mtype = v.unanchor_type(self.mtype.as(not null))
1624 var res = new MutableInstance(mtype)
1625 v.init_instance(res)
1626 v.callsite(init_callsite, [res, e1, e2])
1627 return res
1628 end
1629 end
1630
1631 redef class AOrangeExpr
1632 redef fun expr(v)
1633 do
1634 var e1 = v.expr(self.n_expr)
1635 if e1 == null then return null
1636 var e2 = v.expr(self.n_expr2)
1637 if e2 == null then return null
1638 var mtype = v.unanchor_type(self.mtype.as(not null))
1639 var res = new MutableInstance(mtype)
1640 v.init_instance(res)
1641 v.callsite(init_callsite, [res, e1, e2])
1642 return res
1643 end
1644 end
1645
1646 redef class ATrueExpr
1647 redef fun expr(v)
1648 do
1649 return v.bool_instance(true)
1650 end
1651 end
1652
1653 redef class AFalseExpr
1654 redef fun expr(v)
1655 do
1656 return v.bool_instance(false)
1657 end
1658 end
1659
1660 redef class ANullExpr
1661 redef fun expr(v)
1662 do
1663 return v.null_instance
1664 end
1665 end
1666
1667 redef class AIsaExpr
1668 redef fun expr(v)
1669 do
1670 var i = v.expr(self.n_expr)
1671 if i == null then return null
1672 var mtype = v.unanchor_type(self.cast_type.as(not null))
1673 return v.bool_instance(v.is_subtype(i.mtype, mtype))
1674 end
1675 end
1676
1677 redef class AAsCastExpr
1678 redef fun expr(v)
1679 do
1680 var i = v.expr(self.n_expr)
1681 if i == null then return null
1682 var mtype = self.mtype.as(not null)
1683 var amtype = v.unanchor_type(mtype)
1684 if not v.is_subtype(i.mtype, amtype) then
1685 fatal(v, "Cast failed. Expected `{amtype}`, got `{i.mtype}`")
1686 end
1687 return i
1688 end
1689 end
1690
1691 redef class AAsNotnullExpr
1692 redef fun expr(v)
1693 do
1694 var i = v.expr(self.n_expr)
1695 if i == null then return null
1696 if i.mtype isa MNullType then
1697 fatal(v, "Cast failed")
1698 end
1699 return i
1700 end
1701 end
1702
1703 redef class AParExpr
1704 redef fun expr(v)
1705 do
1706 return v.expr(self.n_expr)
1707 end
1708 end
1709
1710 redef class AOnceExpr
1711 redef fun expr(v)
1712 do
1713 if v.onces.has_key(self) then
1714 return v.onces[self]
1715 else
1716 var res = v.expr(self.n_expr)
1717 if res == null then return null
1718 v.onces[self] = res
1719 return res
1720 end
1721 end
1722 end
1723
1724 redef class ASendExpr
1725 redef fun expr(v)
1726 do
1727 var recv = v.expr(self.n_expr)
1728 if recv == null then return null
1729 var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
1730 if args == null then return null
1731
1732 var res = v.callsite(callsite, args)
1733 return res
1734 end
1735 end
1736
1737 redef class ASendReassignFormExpr
1738 redef fun stmt(v)
1739 do
1740 var recv = v.expr(self.n_expr)
1741 if recv == null then return
1742 var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
1743 if args == null then return
1744 var value = v.expr(self.n_value)
1745 if value == null then return
1746
1747 var read = v.callsite(callsite, args)
1748 assert read != null
1749
1750 var write = v.callsite(reassign_callsite, [read, value])
1751 assert write != null
1752
1753 args.add(write)
1754
1755 v.callsite(write_callsite, args)
1756 end
1757 end
1758
1759 redef class ASuperExpr
1760 redef fun expr(v)
1761 do
1762 var recv = v.frame.arguments.first
1763
1764 var callsite = self.callsite
1765 if callsite != null then
1766 var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
1767 if args == null then return null
1768 # Add additional arguments for the super init call
1769 if args.length == 1 then
1770 for i in [0..callsite.msignature.arity[ do
1771 args.add(v.frame.arguments[i+1])
1772 end
1773 end
1774 # Super init call
1775 var res = v.callsite(callsite, args)
1776 return res
1777 end
1778
1779 # standard call-next-method
1780 var mpropdef = self.mpropdef
1781 mpropdef = mpropdef.lookup_next_definition(v.mainmodule, recv.mtype)
1782
1783 var args = v.varargize(mpropdef, recv, self.n_args.n_exprs)
1784 if args == null then return null
1785
1786 if args.length == 1 then
1787 args = v.frame.arguments
1788 end
1789 var res = v.call(mpropdef, args)
1790 return res
1791 end
1792 end
1793
1794 redef class ANewExpr
1795 redef fun expr(v)
1796 do
1797 var mtype = v.unanchor_type(self.recvtype.as(not null))
1798 var recv: Instance = new MutableInstance(mtype)
1799 v.init_instance(recv)
1800 var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
1801 if args == null then return null
1802 var res2 = v.callsite(callsite, args)
1803 if res2 != null then
1804 #self.debug("got {res2} from {mproperty}. drop {recv}")
1805 return res2
1806 end
1807 return recv
1808 end
1809 end
1810
1811 redef class AAttrExpr
1812 redef fun expr(v)
1813 do
1814 var recv = v.expr(self.n_expr)
1815 if recv == null then return null
1816 if recv.mtype isa MNullType then fatal(v, "Receiver is null")
1817 var mproperty = self.mproperty.as(not null)
1818 return v.read_attribute(mproperty, recv)
1819 end
1820 end
1821
1822 redef class AAttrAssignExpr
1823 redef fun stmt(v)
1824 do
1825 var recv = v.expr(self.n_expr)
1826 if recv == null then return
1827 if recv.mtype isa MNullType then fatal(v, "Receiver is null")
1828 var i = v.expr(self.n_value)
1829 if i == null then return
1830 var mproperty = self.mproperty.as(not null)
1831 v.write_attribute(mproperty, recv, i)
1832 end
1833 end
1834
1835 redef class AAttrReassignExpr
1836 redef fun stmt(v)
1837 do
1838 var recv = v.expr(self.n_expr)
1839 if recv == null then return
1840 if recv.mtype isa MNullType then fatal(v, "Receiver is null")
1841 var value = v.expr(self.n_value)
1842 if value == null then return
1843 var mproperty = self.mproperty.as(not null)
1844 var attr = v.read_attribute(mproperty, recv)
1845 var res = v.callsite(reassign_callsite, [attr, value])
1846 assert res != null
1847 v.write_attribute(mproperty, recv, res)
1848 end
1849 end
1850
1851 redef class AIssetAttrExpr
1852 redef fun expr(v)
1853 do
1854 var recv = v.expr(self.n_expr)
1855 if recv == null then return null
1856 if recv.mtype isa MNullType then fatal(v, "Receiver is null")
1857 var mproperty = self.mproperty.as(not null)
1858 return v.bool_instance(v.isset_attribute(mproperty, recv))
1859 end
1860 end
1861
1862 redef class ADebugTypeExpr
1863 redef fun stmt(v)
1864 do
1865 # do nothing
1866 end
1867 end