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