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