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