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