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