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