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