1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012 Jean Privat <jean@pryen.org>
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 # Interpretation of a Nit program directly on the AST
18 module naive_interpreter
22 private import parser
::tables
24 private import model
::serialize_model
25 private import frontend
::explain_assert_api
27 redef class ToolContext
28 # --discover-call-trace
29 var opt_discover_call_trace
= new OptionBool("Trace calls of the first invocation of methods", "--discover-call-trace")
34 self.option_context
.add_option
(self.opt_discover_call_trace
)
38 redef class ModelBuilder
39 # Execute the program from the entry point (`Sys::main`) of the `mainmodule`
40 # `arguments` are the command-line arguments in order
42 # 1. the AST is fully loaded.
43 # 2. the model is fully built.
44 # 3. the instructions are fully analysed.
45 fun run_naive_interpreter
(mainmodule
: MModule, arguments
: Array[String])
48 self.toolcontext
.info
("*** START INTERPRETING ***", 1)
50 var interpreter
= new NaiveInterpreter(self, mainmodule
, arguments
)
51 interpreter
.start
(mainmodule
)
54 self.toolcontext
.info
("*** END INTERPRETING: {time1-time0} ***", 2)
58 # The visitor that interprets the Nit Program by walking on the AST
59 class NaiveInterpreter
60 # The modelbuilder that know the AST and its associations with the model
61 var modelbuilder
: ModelBuilder
63 # The main module of the program (used to lookup method)
64 var mainmodule
: MModule is writable
66 # The command line arguments of the interpreted program
67 # arguments.first is the program name
68 # arguments[1] is the first argument
69 var arguments
: Array[String]
71 # The main Sys instance
72 var mainobj
: nullable Instance is noinit
74 # Name of all supported functional names
75 var routine_types
: Set[String] = new HashSet[String]
79 if mainmodule
.model
.get_mclasses_by_name
("Bool") != null then
80 self.true_instance
= new PrimitiveInstance[Bool](mainmodule
.bool_type
, true)
81 init_instance_primitive
(self.true_instance
)
82 self.false_instance
= new PrimitiveInstance[Bool](mainmodule
.bool_type
, false)
83 init_instance_primitive
(self.false_instance
)
85 self.null_instance
= new PrimitiveInstance[nullable Object](mainmodule
.model
.null_type
, null)
87 routine_types
.add
("RoutineRef")
88 for name
in ["Proc", "Fun", "ProcRef", "FunRef"] do
89 # 20 is a magic number = upper limit of the arity of each functional class.
90 # i.e. Proc0, Proc1, ... Proc19
92 routine_types
.add
("{name}{i}")
97 # Starts the interpreter on the main module of a program
98 fun start
(mainmodule
: MModule) do
99 var interpreter
= self
100 var sys_type
= mainmodule
.sys_type
101 if sys_type
== null then return # no class Sys
102 var mainobj
= new MutableInstance(sys_type
)
103 interpreter
.mainobj
= mainobj
104 interpreter
.init_instance
(mainobj
)
105 var initprop
= mainmodule
.try_get_primitive_method
("init", sys_type
.mclass
)
106 if initprop
!= null then
107 interpreter
.send
(initprop
, [mainobj
])
109 var mainprop
= mainmodule
.try_get_primitive_method
("run", sys_type
.mclass
) or else
110 mainmodule
.try_get_primitive_method
("main", sys_type
.mclass
)
111 if mainprop
!= null then
112 interpreter
.send
(mainprop
, [mainobj
])
116 # Subtype test in the context of the mainmodule
117 fun is_subtype
(sub
, sup
: MType): Bool
119 return sub
.is_subtype
(self.mainmodule
, current_receiver_class
, sup
)
122 # Get a primitive method in the context of the main module
123 fun force_get_primitive_method
(name
: String, recv
: MType): MMethod
125 assert recv
isa MClassType
126 return self.modelbuilder
.force_get_primitive_method
(current_node
, name
, recv
.mclass
, self.mainmodule
)
129 # Is a return, a break or a continue executed?
130 # Set this mark to skip the evaluation until a labeled statement catch it with `is_escape`
131 var escapemark
: nullable EscapeMark = null
133 # The count of `catch` blocs that have been encountered and can catch an abort
134 var catch_count
= 0 is writable
136 # The last error thrown on abort/runtime error where catch_count > 0
137 var last_error
: nullable FatalError = null
139 # Is a return or a break or a continue executed?
140 # Use this function to know if you must skip the evaluation of statements
141 fun is_escaping
: Bool do return escapemark
!= null
143 # The value associated with the current return/break/continue, if any.
144 # Set the value when you set a escapemark.
145 # Read the value when you catch a mark or reach the end of a method
146 var escapevalue
: nullable Instance = null
148 # If there is a break/continue and is associated with `escapemark`, then return true and clear the mark.
149 # If there is no break/continue or if `escapemark` is null then return false.
150 # Use this function to catch a potential break/continue.
151 fun is_escape
(escapemark
: nullable EscapeMark): Bool
153 if escapemark
!= null and self.escapemark
== escapemark
then
154 self.escapemark
= null
161 # Evaluate `n` as an expression in the current context.
162 # Return the value of the expression.
163 # If `n` cannot be evaluated, then aborts.
164 fun expr
(n
: AExpr): nullable Instance
166 var frame
= self.frame
167 var old
= frame
.current_node
168 frame
.current_node
= n
169 #n.debug("IN Execute expr")
171 if i
== null and not self.is_escaping
then
172 n
.debug
("inconsitance: no value and not escaping.")
174 var implicit_cast_to
= n
.implicit_cast_to
175 if i
!= null and implicit_cast_to
!= null then
176 var mtype
= self.unanchor_type
(implicit_cast_to
)
177 if not self.is_subtype
(i
.mtype
, mtype
) then n
.fatal
(self, "Cast failed. Expected `{implicit_cast_to}`, got `{i.mtype}`")
180 #n.debug("OUT Execute expr: value is {i}")
181 #if not is_subtype(i.mtype, n.mtype.as(not null)) then n.debug("Expected {n.mtype.as(not null)} got {i}")
182 frame
.current_node
= old
186 # Evaluate `n` as a statement in the current context.
187 # Do nothing if `n` is null.
188 # If `n` cannot be evaluated, then aborts.
189 fun stmt
(n
: nullable AExpr)
191 if n
== null then return
193 if n
.comprehension
!= null then
194 var comprehension
= frame
.comprehension
.as(not null)
196 if i
!= null then comprehension
.add
(i
)
200 var frame
= self.frame
201 var old
= frame
.current_node
202 frame
.current_node
= n
204 frame
.current_node
= old
207 # Map used to store values of nodes that must be evaluated once in the system (`AOnceExpr`)
208 var onces
: Map[ANode, Instance] = new HashMap[ANode, Instance]
210 # Return the boolean instance associated with `val`.
211 fun bool_instance
(val
: Bool): Instance
213 if val
then return self.true_instance
else return self.false_instance
216 # Return the integer instance associated with `val`.
217 fun int_instance
(val
: Int): Instance
219 var t
= mainmodule
.int_type
220 var instance
= new PrimitiveInstance[Int](t
, val
)
221 init_instance_primitive
(instance
)
225 # Return the byte instance associated with `val`.
226 fun byte_instance
(val
: Byte): Instance
228 var t
= mainmodule
.byte_type
229 var instance
= new PrimitiveInstance[Byte](t
, val
)
230 init_instance_primitive
(instance
)
234 # Return the int8 instance associated with `val`.
235 fun int8_instance
(val
: Int8): Instance
237 var t
= mainmodule
.int8_type
238 var instance
= new PrimitiveInstance[Int8](t
, val
)
239 init_instance_primitive
(instance
)
243 # Return the int16 instance associated with `val`.
244 fun int16_instance
(val
: Int16): Instance
246 var t
= mainmodule
.int16_type
247 var instance
= new PrimitiveInstance[Int16](t
, val
)
248 init_instance_primitive
(instance
)
252 # Return the uint16 instance associated with `val`.
253 fun uint16_instance
(val
: UInt16): Instance
255 var t
= mainmodule
.uint16_type
256 var instance
= new PrimitiveInstance[UInt16](t
, val
)
257 init_instance_primitive
(instance
)
261 # Return the int32 instance associated with `val`.
262 fun int32_instance
(val
: Int32): Instance
264 var t
= mainmodule
.int32_type
265 var instance
= new PrimitiveInstance[Int32](t
, val
)
266 init_instance_primitive
(instance
)
270 # Return the uint32 instance associated with `val`.
271 fun uint32_instance
(val
: UInt32): Instance
273 var t
= mainmodule
.uint32_type
274 var instance
= new PrimitiveInstance[UInt32](t
, val
)
275 init_instance_primitive
(instance
)
279 # Return the char instance associated with `val`.
280 fun char_instance
(val
: Char): Instance
282 var t
= mainmodule
.char_type
283 var instance
= new PrimitiveInstance[Char](t
, val
)
284 init_instance_primitive
(instance
)
288 # Return the float instance associated with `val`.
289 fun float_instance
(val
: Float): Instance
291 var t
= mainmodule
.float_type
292 var instance
= new PrimitiveInstance[Float](t
, val
)
293 init_instance_primitive
(instance
)
297 # The unique instance of the `true` value.
298 var true_instance
: Instance is noinit
300 # The unique instance of the `false` value.
301 var false_instance
: Instance is noinit
303 # The unique instance of the `null` value.
304 var null_instance
: Instance is noinit
306 # Return a new array made of `values`.
307 # The dynamic type of the result is Array[elttype].
308 fun array_instance
(values
: Array[Instance], elttype
: MType): Instance
310 assert not elttype
.need_anchor
311 var nat
= new PrimitiveInstance[Array[Instance]](mainmodule
.native_array_type
(elttype
), values
)
312 init_instance_primitive
(nat
)
313 var mtype
= mainmodule
.array_type
(elttype
)
314 var res
= new MutableInstance(mtype
)
315 self.init_instance
(res
)
316 self.send
(self.force_get_primitive_method
("with_native", mtype
), [res
, nat
, self.int_instance
(values
.length
)])
320 # Return a instance associated to a primitive class
321 # Current primitive classes are `Int`, `Bool`, and `String`
322 fun value_instance
(object
: Object): Instance
324 if object
isa Int then
325 return int_instance
(object
)
326 else if object
isa Bool then
327 return bool_instance
(object
)
328 else if object
isa String then
329 return string_instance
(object
)
335 # Return a new C string initialized with `txt`
336 fun c_string_instance
(txt
: String): Instance
338 var instance
= c_string_instance_len
(txt
.byte_length
+1)
339 var val
= instance
.val
340 val
[txt
.byte_length
] = 0
341 txt
.to_cstring
.copy_to
(val
, txt
.byte_length
, 0, 0)
346 # Return a new C string initialized with `txt`
347 fun c_string_instance_from_ns
(txt
: CString, len
: Int): Instance
349 var instance
= c_string_instance_len
(len
)
350 var val
= instance
.val
351 txt
.copy_to
(val
, len
, 0, 0)
356 # Return a new C string instance sharing the same data space as `txt`
357 fun c_string_instance_fast_cstr
(txt
: CString, from
: Int): Instance
359 var ncstr
= txt
.fast_cstring
(from
)
360 var t
= mainmodule
.c_string_type
362 var instance
= new PrimitiveInstance[CString](t
, ncstr
)
363 init_instance_primitive
(instance
)
368 # Return a new C string initialized of `length`
369 fun c_string_instance_len
(length
: Int): PrimitiveInstance[CString]
371 var val
= new CString(length
)
373 var t
= mainmodule
.c_string_type
374 var instance
= new PrimitiveInstance[CString](t
, val
)
375 init_instance_primitive
(instance
)
379 # Return a new String instance for `txt`
380 fun string_instance
(txt
: String): Instance
382 var nat
= c_string_instance
(txt
)
383 var res
= self.send
(self.force_get_primitive_method
("to_s_unsafe", nat
.mtype
), [nat
, self.int_instance
(txt
.byte_length
), self.int_instance
(txt
.length
), self.false_instance
, self.false_instance
])
388 # The virtual type of the frames used in the execution engine
391 # The current frame used to store local variables of the current method executed
392 fun frame
: FRAME do return frames
.first
394 # The stack of all frames. The first one is the current one.
395 var frames
= new List[FRAME]
397 # Return a stack trace. One line per function
398 fun stack_trace
: String
400 var b
= new FlatBuffer
401 b
.append
(",---- Stack trace -- - - -\n")
403 b
.append
("| {f.mpropdef} ({f.current_node.location})\n")
405 b
.append
("`------------------- - - -")
409 # The current node, used to print errors, debug and stack-traces
410 fun current_node
: nullable ANode
412 if frames
.is_empty
then return null
413 return frames
.first
.current_node
416 # The dynamic type of the current `self`
417 fun current_receiver_class
: MClassType
419 return frames
.first
.arguments
.first
.mtype
.as(MClassType)
422 # Initialize the environment for a call and return a new Frame
423 # *`node` The AST node
424 # *`mpropdef` The corresponding mpropdef
425 # *`args` Arguments of the call
426 fun new_frame
(node
: ANode, mpropdef
: MPropDef, args
: Array[Instance]): FRAME
428 return new InterpreterFrame(node
, mpropdef
, args
)
431 # Exit the program with a message
432 fun fatal
(message
: String)
434 var node
= current_node
438 node
.fatal
(self, message
)
443 # Debug on the current node
444 fun debug
(message
: String)
446 var node
= current_node
454 # Retrieve the value of the variable in the current frame
455 fun read_variable
(v
: Variable): Instance
457 var f
= frames
.first
.as(InterpreterFrame)
461 # Assign the value of the variable in the current frame
462 fun write_variable
(v
: Variable, value
: Instance)
464 var f
= frames
.first
.as(InterpreterFrame)
468 # Store known methods, used to trace methods as they are reached
469 var discover_call_trace
: Set[MMethodDef] = new HashSet[MMethodDef]
471 # Consumes an iterator of expressions and tries to map each element to
472 # its corresponding Instance.
474 # If any AExprs doesn't resolve to an Instance, then it returns null.
475 # Otherwise return an array of instances
476 fun aexprs_to_instances
(aexprs
: Iterator[AExpr]): nullable Array[Instance]
478 var accumulator
= new Array[Instance]
479 for aexpr
in aexprs
do
480 var instance
= expr
(aexpr
)
481 if instance
== null then return null
482 accumulator
.push
(instance
)
487 # Evaluate `args` as expressions in the call of `mpropdef` on `recv`.
488 # This method is used to manage varargs in signatures and returns the real array
489 # of instances to use in the call.
490 # Return `null` if one of the evaluation of the arguments return null.
491 fun varargize
(mpropdef
: MMethodDef, map
: nullable SignatureMap, recv
: Instance, args
: SequenceRead[AExpr]): nullable Array[Instance]
493 var msignature
= mpropdef
.msignature
.as(not null)
494 var res
= new Array[Instance]
497 if msignature
.arity
== 0 then return res
500 assert args
.length
== msignature
.arity
else debug
("Expected {msignature.arity} args, got {args.length}")
501 var rest_args
= aexprs_to_instances
(args
.iterator
)
502 if rest_args
== null then return null
503 res
.append
(rest_args
)
507 # Eval in order of arguments, not parameters
508 var exprs
= aexprs_to_instances
(args
.iterator
)
509 if exprs
== null then return null
511 # Fill `res` with the result of the evaluation according to the mapping
512 for i
in [0..msignature
.arity
[ do
513 var param
= msignature
.mparameters
[i
]
514 var j
= map
.map
.get_or_null
(i
)
517 res
.add
(null_instance
)
520 if param
.is_vararg
and args
[i
].vararg_decl
> 0 then
521 var vararg
= exprs
.sub
(j
, args
[i
].vararg_decl
)
522 var elttype
= param
.mtype
.anchor_to
(self.mainmodule
, recv
.mtype
.as(MClassType))
523 var arg
= self.array_instance
(vararg
, elttype
)
532 # Execute `mpropdef` for a `args` (where `args[0]` is the receiver).
533 # Return a value if `mpropdef` is a function, or null if it is a procedure.
534 # The call is direct/static. There is no message-sending/late-binding.
535 fun call
(mpropdef
: MMethodDef, args
: Array[Instance]): nullable Instance
537 if self.modelbuilder
.toolcontext
.opt_discover_call_trace
.value
and not self.discover_call_trace
.has
(mpropdef
) then
538 self.discover_call_trace
.add mpropdef
539 self.debug
("Discovered {mpropdef}")
541 assert args
.length
== mpropdef
.msignature
.arity
+ 1 else debug
("Invalid arity for {mpropdef}. {args.length} arguments given.")
543 # Look for the AST node that implements the property
544 var val
= mpropdef
.constant_value
546 var node
= modelbuilder
.mpropdef2node
(mpropdef
)
547 if mpropdef
.is_abstract
then
549 self.frames
.unshift new_frame
(node
, mpropdef
, args
)
551 fatal
("Abstract method `{mpropdef.mproperty.name}` called on `{args.first.mtype}`")
555 if node
isa APropdef then
556 self.parameter_check
(node
, mpropdef
, args
)
557 return node
.call
(self, mpropdef
, args
)
558 else if node
isa AClassdef then
559 self.parameter_check
(node
, mpropdef
, args
)
560 return node
.call
(self, mpropdef
, args
)
561 else if node
!= null then
562 fatal
("Fatal Error: method {mpropdef} associated to unexpected AST node {node.location}")
564 else if val
!= null then
565 return value_instance
(val
)
567 fatal
("Fatal Error: method {mpropdef} not found in the AST")
572 # Execute type checks of covariant parameters
573 fun parameter_check
(node
: ANode, mpropdef
: MMethodDef, args
: Array[Instance])
575 var msignature
= mpropdef
.msignature
.as(not null)
576 for i
in [0..msignature
.arity
[ do
577 var mp
= msignature
.mparameters
[i
]
579 # skip test for vararg since the array is instantiated with the correct polymorphic type
580 if mp
.is_vararg
then continue
582 # skip if the cast is not required
583 var origmtype
= mpropdef
.mproperty
.intro
.msignature
.mparameters
[i
].mtype
584 if not origmtype
.need_anchor
then continue
586 #print "{mpropdef}: {mpropdef.mproperty.intro.msignature.mparameters[i]}"
588 # get the parameter type
590 var anchor
= args
.first
.mtype
.as(MClassType)
591 var amtype
= mtype
.anchor_to
(self.mainmodule
, anchor
)
592 if not args
[i
+1].mtype
.is_subtype
(self.mainmodule
, anchor
, amtype
) then
593 node
.fatal
(self, "Cast failed. Expected `{mtype}`, got `{args[i+1].mtype}`")
598 # Common code for runtime injected calls and normal calls
599 fun send_commons
(mproperty
: MMethod, args
: Array[Instance], mtype
: MType): nullable Instance
601 if mtype
isa MNullType then
602 if mproperty
.name
== "==" or mproperty
.name
== "is_same_instance" then
603 return self.bool_instance
(args
[0] == args
[1])
604 else if mproperty
.name
== "!=" then
605 return self.bool_instance
(args
[0] != args
[1])
607 #fatal("Receiver is null. {mproperty}. {args.join(" ")} {self.frame.current_node.class_name}")
608 fatal
("Receiver is null")
613 # Execute a full `callsite` for given `args`
614 # Use this method, instead of `send` to execute and control the additional behavior of the call-sites
615 fun callsite
(callsite
: nullable CallSite, arguments
: Array[Instance]): nullable Instance
617 if callsite
== null then return null
618 return send
(callsite
.mproperty
, arguments
)
621 # Execute `mproperty` for a `args` (where `args[0]` is the receiver).
622 # Return a value if `mproperty` is a function, or null if it is a procedure.
623 # The call is polymorphic. There is a message-sending/late-binding according to the receiver (args[0]).
624 fun send
(mproperty
: MMethod, args
: Array[Instance]): nullable Instance
626 var recv
= args
.first
627 var mtype
= recv
.mtype
628 var ret
= send_commons
(mproperty
, args
, mtype
)
629 if ret
!= null then return ret
630 var propdef
= mproperty
.lookup_first_definition
(self.mainmodule
, mtype
)
631 return self.call
(propdef
, args
)
634 # Read the attribute `mproperty` of an instance `recv` and return its value.
635 # If the attribute in not yet initialized, then aborts with an error message.
636 fun read_attribute
(mproperty
: MAttribute, recv
: Instance): Instance
638 assert recv
isa MutableInstance
639 if not recv
.attributes
.has_key
(mproperty
) then
640 fatal
("Uninitialized attribute {mproperty.name}")
643 return recv
.attributes
[mproperty
]
646 # Replace in `recv` the value of the attribute `mproperty` by `value`
647 fun write_attribute
(mproperty
: MAttribute, recv
: Instance, value
: Instance)
649 assert recv
isa MutableInstance
650 recv
.attributes
[mproperty
] = value
653 # Is the attribute `mproperty` initialized the instance `recv`?
654 fun isset_attribute
(mproperty
: MAttribute, recv
: Instance): Bool
656 assert recv
isa MutableInstance
657 return recv
.attributes
.has_key
(mproperty
)
660 # Collect attributes of a type in the order of their init
661 fun collect_attr_propdef
(mtype
: MType): Array[AAttrPropdef]
663 var cache
= self.collect_attr_propdef_cache
664 if cache
.has_key
(mtype
) then return cache
[mtype
]
666 var res
= new Array[AAttrPropdef]
667 var cds
= mtype
.collect_mclassdefs
(self.mainmodule
).to_a
668 self.mainmodule
.linearize_mclassdefs
(cds
)
670 res
.add_all
(modelbuilder
.collect_attr_propdef
(cd
))
677 private var collect_attr_propdef_cache
= new HashMap[MType, Array[AAttrPropdef]]
679 # Fill the initial values of the newly created instance `recv`.
680 # `recv.mtype` is used to know what must be filled.
681 fun init_instance
(recv
: Instance)
683 for npropdef
in collect_attr_propdef
(recv
.mtype
) do
684 npropdef
.init_expr
(self, recv
)
688 # A hook to initialize a `PrimitiveInstance`
689 fun init_instance_primitive
(recv
: Instance) do end
691 # This function determines the correct type according to the receiver of the current propdef (self).
692 fun unanchor_type
(mtype
: MType): MType
694 return mtype
.anchor_to
(self.mainmodule
, current_receiver_class
)
697 # Placebo instance used to mark internal error result when `null` already have a meaning.
698 # TODO: replace with multiple return or something better
699 var error_instance
= new MutableInstance(modelbuilder
.model
.null_type
) is lazy
707 # The problematic node, if any
708 var node
: nullable ANode
711 # An instance represents a value of the executed program.
712 abstract class Instance
713 # The dynamic type of the instance
714 # ASSERT: not self.mtype.is_anchored
717 # Return `true` if the instance is the `true` value.
719 # Return `false` if the instance is the `false` value.
720 # Abort if the instance is not a boolean value.
721 fun is_true
: Bool do abort
723 # Return `true` if the instance is null.
724 # Return `false` otherwise.
725 fun is_null
: Bool do return mtype
isa MNullType
727 # Return true if `self` IS `o` (using the Nit semantic of is)
728 fun eq_is
(o
: Instance): Bool do return self.is_same_instance
(o
)
730 # Human readable object identity "Type#number"
731 redef fun to_s
do return "{mtype}"
733 # Return the integer value if the instance is an integer.
735 fun to_i
: Int do abort
737 # Return the integer value if the instance is a float.
739 fun to_f
: Float do abort
741 # Return the integer value if the instance is a byte.
743 fun to_b
: Byte do abort
745 # Return the integer value if the instance is a int8.
747 fun to_i8
: Int8 do abort
749 # Return the integer value if the instance is a int16.
751 fun to_i16
: Int16 do abort
753 # Return the integer value if the instance is a uint16.
755 fun to_u16
: UInt16 do abort
757 # Return the integer value if the instance is a int32.
759 fun to_i32
: Int32 do abort
761 # Return the integer value if the instance is a uint32.
763 fun to_u32
: UInt32 do abort
765 # The real value encapsulated if the instance is primitive.
767 fun val
: nullable Object do abort
770 # A instance with attribute (standards objects)
771 class MutableInstance
774 # The values of the attributes
775 var attributes
: Map[MAttribute, Instance] = new HashMap[MAttribute, Instance]
778 # An instance with the original receiver and callsite (for function reference)
779 class CallrefInstance
782 # The original receiver
786 # var f = &a.toto # `a` is the original receiver
790 # The original callsite
794 # var f = &a.toto # `toto` is the original callsite
796 var callsite
: CallSite
799 # Special instance to handle primitives values (int, bool, etc.)
800 # The trick is just to encapsulate the “real” value.
801 class PrimitiveInstance[E
]
804 # The real value encapsulated
809 if val
== true then return true
810 if val
== false then return false
816 if not o
isa PrimitiveInstance[nullable Object] then return false
817 return self.val
== o
.val
822 if not o
isa PrimitiveInstance[nullable Object] then return false
823 return self.val
.is_same_instance
(o
.val
)
826 redef fun to_s
do return "{mtype}#{val.object_id}({val or else "null"})"
828 redef fun to_i
do return val
.as(Int)
830 redef fun to_f
do return val
.as(Float)
832 redef fun to_b
do return val
.as(Byte)
834 redef fun to_i8
do return val
.as(Int8)
836 redef fun to_i16
do return val
.as(Int16)
838 redef fun to_u16
do return val
.as(UInt16)
840 redef fun to_i32
do return val
.as(Int32)
842 redef fun to_u32
do return val
.as(UInt32)
845 # Information about local variables in a running method
847 # The current visited node
848 # The node is stored by frame to keep a stack trace
849 var current_node
: ANode
850 # The executed property.
851 # A Method in case of a call, an attribute in case of a default initialization.
852 var mpropdef
: MPropDef
853 # Arguments of the method (the first is the receiver)
854 var arguments
: Array[Instance]
855 # Indicate if the expression has an array comprehension form
856 var comprehension
: nullable Array[Instance] = null
859 # Implementation of a Frame with a Hashmap to store local variables
860 class InterpreterFrame
863 # Mapping between a variable and the current value
864 var map
: Map[Variable, Instance] = new HashMap[Variable, Instance]
868 # Aborts the program with a message
869 # `v` is used to know if a colored message is displayed or not
870 fun fatal
(v
: NaiveInterpreter, message
: String)
872 # Abort if there is a `catch` block
873 if v
.catch_count
> 0 then
874 v
.last_error
= new FatalError(message
, self)
878 if v
.modelbuilder
.toolcontext
.opt_no_color
.value
then
879 sys
.stderr
.write
("Runtime error: {message} ({location.file.filename}:{location.line_start})\n")
881 sys
.stderr
.write
("{location}: Runtime error: {message}\n{location.colored_line("0;31")}\n")
882 sys
.stderr
.write
(v
.stack_trace
)
883 sys
.stderr
.write
("\n")
890 # Execute a `mpropdef` associated with the current node.
891 private fun call
(v
: NaiveInterpreter, mpropdef
: MMethodDef, args
: Array[Instance]): nullable Instance
893 fatal
(v
, "NOT YET IMPLEMENTED method kind {class_name}. {mpropdef}")
898 redef class AMethPropdef
901 redef fun call
(v
, mpropdef
, args
)
903 var f
= v
.new_frame
(self, mpropdef
, args
)
904 var res
= call_commons
(v
, mpropdef
, args
, f
)
906 if v
.is_escape
(self.return_mark
) then
913 # Execution of the body of the method
915 # It handle the common special cases: super, intern, extern
916 fun call_commons
(v
: NaiveInterpreter, mpropdef
: MMethodDef, arguments
: Array[Instance], f
: Frame): nullable Instance
920 for i
in [0..mpropdef
.msignature
.arity
[ do
921 var variable
= self.n_signature
.n_params
[i
].variable
922 assert variable
!= null
923 v
.write_variable
(variable
, arguments
[i
+1])
926 # Call the implicit super-init
927 var auto_super_inits
= self.auto_super_inits
928 if auto_super_inits
!= null then
929 var args
= [arguments
.first
]
930 for auto_super_init
in auto_super_inits
do
932 for i
in [0..auto_super_init
.msignature
.arity
+1[ do
933 args
.add
(arguments
[i
])
935 assert auto_super_init
.mproperty
!= mpropdef
.mproperty
936 v
.callsite
(auto_super_init
, args
)
939 if auto_super_call
then
940 # standard call-next-method
941 var superpd
= mpropdef
.lookup_next_definition
(v
.mainmodule
, arguments
.first
.mtype
)
942 v
.call
(superpd
, arguments
)
946 if mpropdef
.is_intern
or mpropdef
.is_extern
then
947 var res
= intern_call
(v
, mpropdef
, arguments
)
948 if res
!= v
.error_instance
then return res
951 if mpropdef
.is_extern
then
952 var res
= call_extern
(v
, mpropdef
, arguments
, f
)
953 if res
!= v
.error_instance
then return res
956 if n_block
!= null then
961 # Fail if nothing succeed
962 if mpropdef
.is_intern
then
963 fatal
(v
, "NOT YET IMPLEMENTED intern {mpropdef}")
964 else if mpropdef
.is_extern
then
965 fatal
(v
, "NOT YET IMPLEMENTED extern {mpropdef}")
967 fatal
(v
, "NOT YET IMPLEMENTED <wat?> {mpropdef}")
972 # Call this extern method
973 protected fun call_extern
(v
: NaiveInterpreter, mpropdef
: MMethodDef, arguments
: Array[Instance], f
: Frame): nullable Instance
975 return v
.error_instance
978 # Interprets a intern or a shortcut extern method.
979 # Returns the result for a function, `null` for a procedure, or `error_instance` if the method is unknown.
980 private fun intern_call
(v
: NaiveInterpreter, mpropdef
: MMethodDef, args
: Array[Instance]): nullable Instance
982 var pname
= mpropdef
.mproperty
.name
983 var cname
= mpropdef
.mclassdef
.mclass
.name
985 if pname
== "call" and v
.routine_types
.has
(cname
) then
986 var routine
= args
.shift
987 assert routine
isa CallrefInstance
988 # Swap the receiver position with the original recv of the call form.
989 args
.unshift routine
.recv
990 var res
= v
.callsite
(routine
.callsite
, args
)
991 # recover the old args state
997 if pname
== "output" then
998 var recv
= args
.first
1001 else if pname
== "object_id" then
1002 var recv
= args
.first
1003 if recv
isa PrimitiveInstance[Object] then
1004 return v
.int_instance
(recv
.val
.object_id
)
1006 return v
.int_instance
(recv
.object_id
)
1008 else if pname
== "output_class_name" then
1009 var recv
= args
.first
1012 else if pname
== "native_class_name" then
1013 var recv
= args
.first
1014 var txt
= recv
.mtype
.to_s
1015 return v
.c_string_instance
(txt
)
1016 else if pname
== "==" then
1017 # == is correctly redefined for instances
1018 return v
.bool_instance
(args
[0] == args
[1])
1019 else if pname
== "!=" then
1020 return v
.bool_instance
(args
[0] != args
[1])
1021 else if pname
== "is_same_type" then
1022 return v
.bool_instance
(args
[0].mtype
== args
[1].mtype
)
1023 else if pname
== "is_same_instance" then
1024 return v
.bool_instance
(args
[0].eq_is
(args
[1]))
1025 else if pname
== "class_inheritance_metamodel_json" then
1026 return v
.c_string_instance
(v
.mainmodule
.flatten_mclass_hierarchy
.to_thin_json
)
1027 else if pname
== "exit" then
1030 else if pname
== "buffer_mode_full" then
1031 return v
.int_instance
(sys
.buffer_mode_full
)
1032 else if pname
== "buffer_mode_line" then
1033 return v
.int_instance
(sys
.buffer_mode_line
)
1034 else if pname
== "buffer_mode_none" then
1035 return v
.int_instance
(sys
.buffer_mode_none
)
1036 else if pname
== "sys" then
1038 else if cname
== "Int" then
1039 var recvval
= args
[0].to_i
1040 if pname
== "unary -" then
1041 return v
.int_instance
(-recvval
)
1042 else if pname
== "unary +" then
1044 else if pname
== "+" then
1045 return v
.int_instance
(recvval
+ args
[1].to_i
)
1046 else if pname
== "-" then
1047 return v
.int_instance
(recvval
- args
[1].to_i
)
1048 else if pname
== "*" then
1049 return v
.int_instance
(recvval
* args
[1].to_i
)
1050 else if pname
== "%" then
1051 return v
.int_instance
(recvval
% args
[1].to_i
)
1052 else if pname
== "/" then
1053 return v
.int_instance
(recvval
/ args
[1].to_i
)
1054 else if pname
== "<" then
1055 return v
.bool_instance
(recvval
< args
[1].to_i
)
1056 else if pname
== ">" then
1057 return v
.bool_instance
(recvval
> args
[1].to_i
)
1058 else if pname
== "<=" then
1059 return v
.bool_instance
(recvval
<= args
[1].to_i
)
1060 else if pname
== ">=" then
1061 return v
.bool_instance
(recvval
>= args
[1].to_i
)
1062 else if pname
== "<=>" then
1063 return v
.int_instance
(recvval
<=> args
[1].to_i
)
1064 else if pname
== "&" then
1065 return v
.int_instance
(recvval
& args
[1].to_i
)
1066 else if pname
== "|" then
1067 return v
.int_instance
(recvval
| args
[1].to_i
)
1068 else if pname
== "to_f" then
1069 return v
.float_instance
(recvval
.to_f
)
1070 else if pname
== "to_b" then
1071 return v
.byte_instance
(recvval
.to_b
)
1072 else if pname
== "<<" then
1073 return v
.int_instance
(recvval
<< args
[1].to_i
)
1074 else if pname
== ">>" then
1075 return v
.int_instance
(recvval
>> args
[1].to_i
)
1076 else if pname
== "to_i8" then
1077 return v
.int8_instance
(recvval
.to_i8
)
1078 else if pname
== "to_i16" then
1079 return v
.int16_instance
(recvval
.to_i16
)
1080 else if pname
== "to_u16" then
1081 return v
.uint16_instance
(recvval
.to_u16
)
1082 else if pname
== "to_i32" then
1083 return v
.int32_instance
(recvval
.to_i32
)
1084 else if pname
== "to_u32" then
1085 return v
.uint32_instance
(recvval
.to_u32
)
1087 else if cname
== "Byte" then
1088 var recvval
= args
[0].to_b
1089 if pname
== "unary -" then
1090 return v
.byte_instance
(-recvval
)
1091 else if pname
== "unary +" then
1093 else if pname
== "+" then
1094 return v
.byte_instance
(recvval
+ args
[1].to_b
)
1095 else if pname
== "-" then
1096 return v
.byte_instance
(recvval
- args
[1].to_b
)
1097 else if pname
== "*" then
1098 return v
.byte_instance
(recvval
* args
[1].to_b
)
1099 else if pname
== "%" then
1100 return v
.byte_instance
(recvval
% args
[1].to_b
)
1101 else if pname
== "/" then
1102 return v
.byte_instance
(recvval
/ args
[1].to_b
)
1103 else if pname
== "<" then
1104 return v
.bool_instance
(recvval
< args
[1].to_b
)
1105 else if pname
== ">" then
1106 return v
.bool_instance
(recvval
> args
[1].to_b
)
1107 else if pname
== "<=" then
1108 return v
.bool_instance
(recvval
<= args
[1].to_b
)
1109 else if pname
== ">=" then
1110 return v
.bool_instance
(recvval
>= args
[1].to_b
)
1111 else if pname
== "<=>" then
1112 return v
.int_instance
(recvval
<=> args
[1].to_b
)
1113 else if pname
== "&" then
1114 return v
.byte_instance
(recvval
& args
[1].to_b
)
1115 else if pname
== "|" then
1116 return v
.byte_instance
(recvval
| args
[1].to_b
)
1117 else if pname
== "to_f" then
1118 return v
.float_instance
(recvval
.to_f
)
1119 else if pname
== "to_i" then
1120 return v
.int_instance
(recvval
.to_i
)
1121 else if pname
== "<<" then
1122 return v
.byte_instance
(recvval
<< args
[1].to_i
)
1123 else if pname
== ">>" then
1124 return v
.byte_instance
(recvval
>> args
[1].to_i
)
1125 else if pname
== "to_i8" then
1126 return v
.int8_instance
(recvval
.to_i8
)
1127 else if pname
== "to_i16" then
1128 return v
.int16_instance
(recvval
.to_i16
)
1129 else if pname
== "to_u16" then
1130 return v
.uint16_instance
(recvval
.to_u16
)
1131 else if pname
== "to_i32" then
1132 return v
.int32_instance
(recvval
.to_i32
)
1133 else if pname
== "to_u32" then
1134 return v
.uint32_instance
(recvval
.to_u32
)
1135 else if pname
== "byte_to_s_len" then
1136 return v
.int_instance
(recvval
.to_s
.length
)
1138 else if cname
== "Char" then
1139 var recv
= args
[0].val
.as(Char)
1140 if pname
== "successor" then
1141 return v
.char_instance
(recv
.successor
(args
[1].to_i
))
1142 else if pname
== "predecessor" then
1143 return v
.char_instance
(recv
.predecessor
(args
[1].to_i
))
1144 else if pname
== "<" then
1145 return v
.bool_instance
(recv
< args
[1].val
.as(Char))
1146 else if pname
== ">" then
1147 return v
.bool_instance
(recv
> args
[1].val
.as(Char))
1148 else if pname
== "<=" then
1149 return v
.bool_instance
(recv
<= args
[1].val
.as(Char))
1150 else if pname
== ">=" then
1151 return v
.bool_instance
(recv
>= args
[1].val
.as(Char))
1152 else if pname
== "<=>" then
1153 return v
.int_instance
(recv
<=> args
[1].val
.as(Char))
1155 else if cname
== "Float" then
1156 var recv
= args
[0].to_f
1157 if pname
== "unary -" then
1158 return v
.float_instance
(-recv
)
1159 else if pname
== "unary +" then
1161 else if pname
== "+" then
1162 return v
.float_instance
(recv
+ args
[1].to_f
)
1163 else if pname
== "-" then
1164 return v
.float_instance
(recv
- args
[1].to_f
)
1165 else if pname
== "*" then
1166 return v
.float_instance
(recv
* args
[1].to_f
)
1167 else if pname
== "/" then
1168 return v
.float_instance
(recv
/ args
[1].to_f
)
1169 else if pname
== "<" then
1170 return v
.bool_instance
(recv
< args
[1].to_f
)
1171 else if pname
== ">" then
1172 return v
.bool_instance
(recv
> args
[1].to_f
)
1173 else if pname
== "<=" then
1174 return v
.bool_instance
(recv
<= args
[1].to_f
)
1175 else if pname
== ">=" then
1176 return v
.bool_instance
(recv
>= args
[1].to_f
)
1177 else if pname
== "to_i" then
1178 return v
.int_instance
(recv
.to_i
)
1179 else if pname
== "to_b" then
1180 return v
.byte_instance
(recv
.to_b
)
1181 else if pname
== "to_i8" then
1182 return v
.int8_instance
(recv
.to_i8
)
1183 else if pname
== "to_i16" then
1184 return v
.int16_instance
(recv
.to_i16
)
1185 else if pname
== "to_u16" then
1186 return v
.uint16_instance
(recv
.to_u16
)
1187 else if pname
== "to_i32" then
1188 return v
.int32_instance
(recv
.to_i32
)
1189 else if pname
== "to_u32" then
1190 return v
.uint32_instance
(recv
.to_u32
)
1191 else if pname
== "cos" then
1192 return v
.float_instance
(args
[0].to_f
.cos
)
1193 else if pname
== "sin" then
1194 return v
.float_instance
(args
[0].to_f
.sin
)
1195 else if pname
== "tan" then
1196 return v
.float_instance
(args
[0].to_f
.tan
)
1197 else if pname
== "acos" then
1198 return v
.float_instance
(args
[0].to_f
.acos
)
1199 else if pname
== "asin" then
1200 return v
.float_instance
(args
[0].to_f
.asin
)
1201 else if pname
== "atan" then
1202 return v
.float_instance
(args
[0].to_f
.atan
)
1203 else if pname
== "sqrt" then
1204 return v
.float_instance
(args
[0].to_f
.sqrt
)
1205 else if pname
== "exp" then
1206 return v
.float_instance
(args
[0].to_f
.exp
)
1207 else if pname
== "log" then
1208 return v
.float_instance
(args
[0].to_f
.log
)
1209 else if pname
== "pow" then
1210 return v
.float_instance
(args
[0].to_f
.pow
(args
[1].to_f
))
1211 else if pname
== "abs" then
1212 return v
.float_instance
(args
[0].to_f
.abs
)
1213 else if pname
== "hypot_with" then
1214 return v
.float_instance
(args
[0].to_f
.hypot_with
(args
[1].to_f
))
1215 else if pname
== "is_nan" then
1216 return v
.bool_instance
(args
[0].to_f
.is_nan
)
1217 else if pname
== "is_inf_extern" then
1218 return v
.bool_instance
(args
[0].to_f
.is_inf
!= 0)
1219 else if pname
== "round" then
1220 return v
.float_instance
(args
[0].to_f
.round
)
1222 else if cname
== "CString" then
1223 if pname
== "new" then
1224 return v
.c_string_instance_len
(args
[1].to_i
)
1226 var recvval
= args
.first
.val
.as(CString)
1227 if pname
== "[]" then
1228 var arg1
= args
[1].to_i
1229 return v
.int_instance
(recvval
[arg1
])
1230 else if pname
== "[]=" then
1231 var arg1
= args
[1].to_i
1232 recvval
[arg1
] = args
[2].val
.as(Int)
1234 else if pname
== "copy_to" then
1235 # sig= copy_to(dest: CString, length: Int, from: Int, to: Int)
1236 var destval
= args
[1].val
.as(CString)
1237 var lenval
= args
[2].to_i
1238 var fromval
= args
[3].to_i
1239 var toval
= args
[4].to_i
1240 recvval
.copy_to
(destval
, lenval
, fromval
, toval
)
1242 else if pname
== "atoi" then
1243 return v
.int_instance
(recvval
.atoi
)
1244 else if pname
== "fast_cstring" then
1245 return v
.c_string_instance_fast_cstr
(args
[0].val
.as(CString), args
[1].to_i
)
1246 else if pname
== "fetch_4_chars" then
1247 return v
.uint32_instance
(args
[0].val
.as(CString).fetch_4_chars
(args
[1].to_i
))
1248 else if pname
== "fetch_4_hchars" then
1249 return v
.uint32_instance
(args
[0].val
.as(CString).fetch_4_hchars
(args
[1].to_i
))
1250 else if pname
== "utf8_length" then
1251 return v
.int_instance
(args
[0].val
.as(CString).utf8_length
(args
[1].to_i
, args
[2].to_i
))
1253 else if cname
== "NativeArray" then
1254 if pname
== "new" then
1255 var val
= new Array[Instance].filled_with
(v
.null_instance
, args
[1].to_i
)
1256 var instance
= new PrimitiveInstance[Array[Instance]](args
[0].mtype
, val
)
1257 v
.init_instance_primitive
(instance
)
1260 var recvval
= args
.first
.val
.as(Array[Instance])
1261 if pname
== "[]" then
1262 return recvval
[args
[1].to_i
]
1263 else if pname
== "[]=" then
1264 recvval
[args
[1].to_i
] = args
[2]
1266 else if pname
== "length" then
1267 return v
.int_instance
(recvval
.length
)
1268 else if pname
== "copy_to" then
1269 recvval
.copy_to
(0, args
[2].to_i
, args
[1].val
.as(Array[Instance]), 0)
1272 else if cname
== "Int8" then
1273 var recvval
= args
[0].to_i8
1274 if pname
== "unary -" then
1275 return v
.int8_instance
(-recvval
)
1276 else if pname
== "unary +" then
1278 else if pname
== "+" then
1279 return v
.int8_instance
(recvval
+ args
[1].to_i8
)
1280 else if pname
== "-" then
1281 return v
.int8_instance
(recvval
- args
[1].to_i8
)
1282 else if pname
== "*" then
1283 return v
.int8_instance
(recvval
* args
[1].to_i8
)
1284 else if pname
== "%" then
1285 return v
.int8_instance
(recvval
% args
[1].to_i8
)
1286 else if pname
== "/" then
1287 return v
.int8_instance
(recvval
/ args
[1].to_i8
)
1288 else if pname
== "<" then
1289 return v
.bool_instance
(recvval
< args
[1].to_i8
)
1290 else if pname
== ">" then
1291 return v
.bool_instance
(recvval
> args
[1].to_i8
)
1292 else if pname
== "<=" then
1293 return v
.bool_instance
(recvval
<= args
[1].to_i8
)
1294 else if pname
== ">=" then
1295 return v
.bool_instance
(recvval
>= args
[1].to_i8
)
1296 else if pname
== "<=>" then
1297 return v
.int_instance
(recvval
<=> args
[1].to_i8
)
1298 else if pname
== "to_f" then
1299 return v
.float_instance
(recvval
.to_f
)
1300 else if pname
== "to_i" then
1301 return v
.int_instance
(recvval
.to_i
)
1302 else if pname
== "to_b" then
1303 return v
.byte_instance
(recvval
.to_b
)
1304 else if pname
== "to_i16" then
1305 return v
.int16_instance
(recvval
.to_i16
)
1306 else if pname
== "to_u16" then
1307 return v
.uint16_instance
(recvval
.to_u16
)
1308 else if pname
== "to_i32" then
1309 return v
.int32_instance
(recvval
.to_i32
)
1310 else if pname
== "to_u32" then
1311 return v
.uint32_instance
(recvval
.to_u32
)
1312 else if pname
== "<<" then
1313 return v
.int8_instance
(recvval
<< (args
[1].to_i
))
1314 else if pname
== ">>" then
1315 return v
.int8_instance
(recvval
>> (args
[1].to_i
))
1316 else if pname
== "&" then
1317 return v
.int8_instance
(recvval
& args
[1].to_i8
)
1318 else if pname
== "|" then
1319 return v
.int8_instance
(recvval
| args
[1].to_i8
)
1320 else if pname
== "^" then
1321 return v
.int8_instance
(recvval ^ args
[1].to_i8
)
1322 else if pname
== "unary ~" then
1323 return v
.int8_instance
(~recvval
)
1325 else if cname
== "Int16" then
1326 var recvval
= args
[0].to_i16
1327 if pname
== "unary -" then
1328 return v
.int16_instance
(-recvval
)
1329 else if pname
== "unary +" then
1331 else if pname
== "+" then
1332 return v
.int16_instance
(recvval
+ args
[1].to_i16
)
1333 else if pname
== "-" then
1334 return v
.int16_instance
(recvval
- args
[1].to_i16
)
1335 else if pname
== "*" then
1336 return v
.int16_instance
(recvval
* args
[1].to_i16
)
1337 else if pname
== "%" then
1338 return v
.int16_instance
(recvval
% args
[1].to_i16
)
1339 else if pname
== "/" then
1340 return v
.int16_instance
(recvval
/ args
[1].to_i16
)
1341 else if pname
== "<" then
1342 return v
.bool_instance
(recvval
< args
[1].to_i16
)
1343 else if pname
== ">" then
1344 return v
.bool_instance
(recvval
> args
[1].to_i16
)
1345 else if pname
== "<=" then
1346 return v
.bool_instance
(recvval
<= args
[1].to_i16
)
1347 else if pname
== ">=" then
1348 return v
.bool_instance
(recvval
>= args
[1].to_i16
)
1349 else if pname
== "<=>" then
1350 return v
.int_instance
(recvval
<=> args
[1].to_i16
)
1351 else if pname
== "to_f" then
1352 return v
.float_instance
(recvval
.to_f
)
1353 else if pname
== "to_i" then
1354 return v
.int_instance
(recvval
.to_i
)
1355 else if pname
== "to_b" then
1356 return v
.byte_instance
(recvval
.to_b
)
1357 else if pname
== "to_i8" then
1358 return v
.int8_instance
(recvval
.to_i8
)
1359 else if pname
== "to_u16" then
1360 return v
.uint16_instance
(recvval
.to_u16
)
1361 else if pname
== "to_i32" then
1362 return v
.int32_instance
(recvval
.to_i32
)
1363 else if pname
== "to_u32" then
1364 return v
.uint32_instance
(recvval
.to_u32
)
1365 else if pname
== "<<" then
1366 return v
.int16_instance
(recvval
<< (args
[1].to_i
))
1367 else if pname
== ">>" then
1368 return v
.int16_instance
(recvval
>> (args
[1].to_i
))
1369 else if pname
== "&" then
1370 return v
.int16_instance
(recvval
& args
[1].to_i16
)
1371 else if pname
== "|" then
1372 return v
.int16_instance
(recvval
| args
[1].to_i16
)
1373 else if pname
== "^" then
1374 return v
.int16_instance
(recvval ^ args
[1].to_i16
)
1375 else if pname
== "unary ~" then
1376 return v
.int16_instance
(~recvval
)
1378 else if cname
== "UInt16" then
1379 var recvval
= args
[0].to_u16
1380 if pname
== "unary -" then
1381 return v
.uint16_instance
(-recvval
)
1382 else if pname
== "unary +" then
1384 else if pname
== "+" then
1385 return v
.uint16_instance
(recvval
+ args
[1].to_u16
)
1386 else if pname
== "-" then
1387 return v
.uint16_instance
(recvval
- args
[1].to_u16
)
1388 else if pname
== "*" then
1389 return v
.uint16_instance
(recvval
* args
[1].to_u16
)
1390 else if pname
== "%" then
1391 return v
.uint16_instance
(recvval
% args
[1].to_u16
)
1392 else if pname
== "/" then
1393 return v
.uint16_instance
(recvval
/ args
[1].to_u16
)
1394 else if pname
== "<" then
1395 return v
.bool_instance
(recvval
< args
[1].to_u16
)
1396 else if pname
== ">" then
1397 return v
.bool_instance
(recvval
> args
[1].to_u16
)
1398 else if pname
== "<=" then
1399 return v
.bool_instance
(recvval
<= args
[1].to_u16
)
1400 else if pname
== ">=" then
1401 return v
.bool_instance
(recvval
>= args
[1].to_u16
)
1402 else if pname
== "<=>" then
1403 return v
.int_instance
(recvval
<=> args
[1].to_u16
)
1404 else if pname
== "to_f" then
1405 return v
.float_instance
(recvval
.to_f
)
1406 else if pname
== "to_i" then
1407 return v
.int_instance
(recvval
.to_i
)
1408 else if pname
== "to_b" then
1409 return v
.byte_instance
(recvval
.to_b
)
1410 else if pname
== "to_i8" then
1411 return v
.int8_instance
(recvval
.to_i8
)
1412 else if pname
== "to_i16" then
1413 return v
.int16_instance
(recvval
.to_i16
)
1414 else if pname
== "to_i32" then
1415 return v
.int32_instance
(recvval
.to_i32
)
1416 else if pname
== "to_u32" then
1417 return v
.uint32_instance
(recvval
.to_u32
)
1418 else if pname
== "<<" then
1419 return v
.uint16_instance
(recvval
<< (args
[1].to_i
))
1420 else if pname
== ">>" then
1421 return v
.uint16_instance
(recvval
>> (args
[1].to_i
))
1422 else if pname
== "&" then
1423 return v
.uint16_instance
(recvval
& args
[1].to_u16
)
1424 else if pname
== "|" then
1425 return v
.uint16_instance
(recvval
| args
[1].to_u16
)
1426 else if pname
== "^" then
1427 return v
.uint16_instance
(recvval ^ args
[1].to_u16
)
1428 else if pname
== "unary ~" then
1429 return v
.uint16_instance
(~recvval
)
1431 else if cname
== "Int32" then
1432 var recvval
= args
[0].to_i32
1433 if pname
== "unary -" then
1434 return v
.int32_instance
(-recvval
)
1435 else if pname
== "unary +" then
1437 else if pname
== "+" then
1438 return v
.int32_instance
(recvval
+ args
[1].to_i32
)
1439 else if pname
== "-" then
1440 return v
.int32_instance
(recvval
- args
[1].to_i32
)
1441 else if pname
== "*" then
1442 return v
.int32_instance
(recvval
* args
[1].to_i32
)
1443 else if pname
== "%" then
1444 return v
.int32_instance
(recvval
% args
[1].to_i32
)
1445 else if pname
== "/" then
1446 return v
.int32_instance
(recvval
/ args
[1].to_i32
)
1447 else if pname
== "<" then
1448 return v
.bool_instance
(recvval
< args
[1].to_i32
)
1449 else if pname
== ">" then
1450 return v
.bool_instance
(recvval
> args
[1].to_i32
)
1451 else if pname
== "<=" then
1452 return v
.bool_instance
(recvval
<= args
[1].to_i32
)
1453 else if pname
== ">=" then
1454 return v
.bool_instance
(recvval
>= args
[1].to_i32
)
1455 else if pname
== "<=>" then
1456 return v
.int_instance
(recvval
<=> args
[1].to_i32
)
1457 else if pname
== "to_f" then
1458 return v
.float_instance
(recvval
.to_f
)
1459 else if pname
== "to_i" then
1460 return v
.int_instance
(recvval
.to_i
)
1461 else if pname
== "to_b" then
1462 return v
.byte_instance
(recvval
.to_b
)
1463 else if pname
== "to_i8" then
1464 return v
.int8_instance
(recvval
.to_i8
)
1465 else if pname
== "to_i16" then
1466 return v
.int16_instance
(recvval
.to_i16
)
1467 else if pname
== "to_u16" then
1468 return v
.uint16_instance
(recvval
.to_u16
)
1469 else if pname
== "to_u32" then
1470 return v
.uint32_instance
(recvval
.to_u32
)
1471 else if pname
== "<<" then
1472 return v
.int32_instance
(recvval
<< (args
[1].to_i
))
1473 else if pname
== ">>" then
1474 return v
.int32_instance
(recvval
>> (args
[1].to_i
))
1475 else if pname
== "&" then
1476 return v
.int32_instance
(recvval
& args
[1].to_i32
)
1477 else if pname
== "|" then
1478 return v
.int32_instance
(recvval
| args
[1].to_i32
)
1479 else if pname
== "^" then
1480 return v
.int32_instance
(recvval ^ args
[1].to_i32
)
1481 else if pname
== "unary ~" then
1482 return v
.int32_instance
(~recvval
)
1484 else if cname
== "UInt32" then
1485 var recvval
= args
[0].to_u32
1486 if pname
== "unary -" then
1487 return v
.uint32_instance
(-recvval
)
1488 else if pname
== "unary +" then
1490 else if pname
== "+" then
1491 return v
.uint32_instance
(recvval
+ args
[1].to_u32
)
1492 else if pname
== "-" then
1493 return v
.uint32_instance
(recvval
- args
[1].to_u32
)
1494 else if pname
== "*" then
1495 return v
.uint32_instance
(recvval
* args
[1].to_u32
)
1496 else if pname
== "%" then
1497 return v
.uint32_instance
(recvval
% args
[1].to_u32
)
1498 else if pname
== "/" then
1499 return v
.uint32_instance
(recvval
/ args
[1].to_u32
)
1500 else if pname
== "<" then
1501 return v
.bool_instance
(recvval
< args
[1].to_u32
)
1502 else if pname
== ">" then
1503 return v
.bool_instance
(recvval
> args
[1].to_u32
)
1504 else if pname
== "<=" then
1505 return v
.bool_instance
(recvval
<= args
[1].to_u32
)
1506 else if pname
== ">=" then
1507 return v
.bool_instance
(recvval
>= args
[1].to_u32
)
1508 else if pname
== "<=>" then
1509 return v
.int_instance
(recvval
<=> args
[1].to_u32
)
1510 else if pname
== "to_f" then
1511 return v
.float_instance
(recvval
.to_f
)
1512 else if pname
== "to_i" then
1513 return v
.int_instance
(recvval
.to_i
)
1514 else if pname
== "to_b" then
1515 return v
.byte_instance
(recvval
.to_b
)
1516 else if pname
== "to_i8" then
1517 return v
.int8_instance
(recvval
.to_i8
)
1518 else if pname
== "to_i16" then
1519 return v
.int16_instance
(recvval
.to_i16
)
1520 else if pname
== "to_u16" then
1521 return v
.uint16_instance
(recvval
.to_u16
)
1522 else if pname
== "to_i32" then
1523 return v
.int32_instance
(recvval
.to_i32
)
1524 else if pname
== "<<" then
1525 return v
.uint32_instance
(recvval
<< (args
[1].to_i
))
1526 else if pname
== ">>" then
1527 return v
.uint32_instance
(recvval
>> (args
[1].to_i
))
1528 else if pname
== "&" then
1529 return v
.uint32_instance
(recvval
& args
[1].to_u32
)
1530 else if pname
== "|" then
1531 return v
.uint32_instance
(recvval
| args
[1].to_u32
)
1532 else if pname
== "^" then
1533 return v
.uint32_instance
(recvval ^ args
[1].to_u32
)
1534 else if pname
== "unary ~" then
1535 return v
.uint32_instance
(~recvval
)
1537 else if pname
== "native_argc" then
1538 return v
.int_instance
(v
.arguments
.length
)
1539 else if pname
== "native_argv" then
1540 var txt
= v
.arguments
[args
[1].to_i
]
1541 return v
.c_string_instance
(txt
)
1542 else if pname
== "lexer_goto" then
1543 return v
.int_instance
(lexer_goto
(args
[1].to_i
, args
[2].to_i
))
1544 else if pname
== "lexer_accept" then
1545 return v
.int_instance
(lexer_accept
(args
[1].to_i
))
1546 else if pname
== "parser_goto" then
1547 return v
.int_instance
(parser_goto
(args
[1].to_i
, args
[2].to_i
))
1548 else if pname
== "parser_action" then
1549 return v
.int_instance
(parser_action
(args
[1].to_i
, args
[2].to_i
))
1551 return v
.error_instance
1555 redef class AAttrPropdef
1556 redef fun call
(v
, mpropdef
, args
)
1558 var recv
= args
.first
1559 assert recv
isa MutableInstance
1560 var attr
= self.mpropdef
.mproperty
1561 if mpropdef
== mreadpropdef
then
1562 assert args
.length
== 1
1563 if not is_lazy
or v
.isset_attribute
(attr
, recv
) then return v
.read_attribute
(attr
, recv
)
1564 var f
= v
.new_frame
(self, mpropdef
, args
)
1565 return evaluate_expr
(v
, recv
, f
)
1566 else if mpropdef
== mwritepropdef
then
1567 assert args
.length
== 2
1569 if is_optional
and arg
.is_null
then
1570 var f
= v
.new_frame
(self, mpropdef
, args
)
1571 arg
= evaluate_expr
(v
, recv
, f
)
1573 v
.write_attribute
(attr
, recv
, arg
)
1580 # Evaluate and set the default value of the attribute in `recv`
1581 private fun init_expr
(v
: NaiveInterpreter, recv
: Instance)
1583 if is_lazy
or is_optional
then return
1585 var f
= v
.new_frame
(self, mreadpropdef
.as(not null), [recv
])
1586 evaluate_expr
(v
, recv
, f
)
1589 var mpropdef
= self.mpropdef
1590 if mpropdef
== null then return
1591 var mtype
= self.mtype
.as(not null)
1592 mtype
= mtype
.anchor_to
(v
.mainmodule
, recv
.mtype
.as(MClassType))
1593 if mtype
isa MNullableType then
1594 v
.write_attribute
(self.mpropdef
.mproperty
, recv
, v
.null_instance
)
1598 private fun evaluate_expr
(v
: NaiveInterpreter, recv
: Instance, f
: Frame): Instance
1600 assert recv
isa MutableInstance
1605 var nexpr
= self.n_expr
1606 var nblock
= self.n_block
1607 if nexpr
!= null then
1609 else if nblock
!= null then
1611 assert v
.escapemark
== return_mark
1620 assert not v
.is_escaping
1621 v
.write_attribute
(self.mpropdef
.mproperty
, recv
, val
)
1626 redef class AClassdef
1627 # Execute an implicit `mpropdef` associated with the current node.
1628 private fun call
(v
: NaiveInterpreter, mpropdef
: MMethodDef, arguments
: Array[Instance]): nullable Instance
1630 if mpropdef
.mproperty
.is_root_init
then
1631 assert arguments
.length
== 1
1632 if not mpropdef
.is_intro
then
1633 # standard call-next-method
1634 var superpd
= mpropdef
.lookup_next_definition
(v
.mainmodule
, arguments
.first
.mtype
)
1635 v
.call
(superpd
, arguments
)
1638 else if mclassdef
.default_init
== mpropdef
then
1639 var recv
= arguments
.first
1640 var initializers
= mpropdef
.initializers
1642 if not initializers
.is_empty
and not mpropdef
.is_old_style_init
then
1644 for p
in initializers
do
1645 if p
isa MMethod then
1647 for x
in p
.intro
.msignature
.mparameters
do
1648 args
.add arguments
[i
]
1652 if p
.intro
.is_calling_init
then no_init
= true
1653 else if p
isa MAttribute then
1654 assert recv
isa MutableInstance
1655 v
.write_attribute
(p
, recv
, arguments
[i
])
1659 assert i
== arguments
.length
1661 if not no_init
then v
.send
(mclass
.the_root_init_mmethod
.as(not null), [recv
])
1670 # Evaluate the node as a possible expression.
1671 # Return a possible value
1672 # NOTE: Do not call this method directly, but use `v.expr`
1673 # This method is here to be implemented by subclasses.
1674 protected fun expr
(v
: NaiveInterpreter): nullable Instance
1676 fatal
(v
, "NOT YET IMPLEMENTED expr {class_name}")
1680 # Evaluate the node as a statement.
1681 # NOTE: Do not call this method directly, but use `v.stmt`
1682 # This method is here to be implemented by subclasses (no need to return something).
1683 protected fun stmt
(v
: NaiveInterpreter)
1690 redef class ABlockExpr
1693 var last
= self.n_expr
.last
1694 for e
in self.n_expr
do
1695 if e
== last
then break
1697 if v
.is_escaping
then return null
1704 for e
in self.n_expr
do
1706 if v
.is_escaping
then return
1711 redef class AVardeclExpr
1714 var ne
= self.n_expr
1717 if i
== null then return null
1718 v
.write_variable
(self.variable
.as(not null), i
)
1725 redef class AVarExpr
1728 return v
.read_variable
(self.variable
.as(not null))
1732 redef class AVarAssignExpr
1735 var i
= v
.expr
(self.n_value
)
1736 if i
== null then return null
1737 v
.write_variable
(self.variable
.as(not null), i
)
1742 redef class AVarReassignExpr
1745 var variable
= self.variable
.as(not null)
1746 var vari
= v
.read_variable
(variable
)
1747 var value
= v
.expr
(self.n_value
)
1748 if value
== null then return
1749 var res
= v
.callsite
(reassign_callsite
, [vari
, value
])
1751 v
.write_variable
(variable
, res
)
1755 redef class ASelfExpr
1758 return v
.frame
.arguments
.first
1762 redef class AImplicitSelfExpr
1765 if not is_sys
then return super
1770 redef class AEscapeExpr
1773 var ne
= self.n_expr
1776 if i
== null then return
1779 v
.escapevalue
= null
1781 v
.escapemark
= self.escapemark
1785 redef class AAbortExpr
1796 var cond
= v
.expr
(self.n_expr
)
1797 if cond
== null then return null
1798 if cond
.is_true
then
1799 return v
.expr
(self.n_then
.as(not null))
1801 return v
.expr
(self.n_else
.as(not null))
1807 var cond
= v
.expr
(self.n_expr
)
1808 if cond
== null then return
1809 if cond
.is_true
then
1817 redef class AIfexprExpr
1820 var cond
= v
.expr
(self.n_expr
)
1821 if cond
== null then return null
1822 if cond
.is_true
then
1823 return v
.expr
(self.n_then
)
1825 return v
.expr
(self.n_else
)
1833 # If this bloc has a catch, handle it with a do ... catch ... end
1834 if self.n_catch
!= null then
1838 v
.stmt
(self.n_block
)
1839 v
.is_escape
(self.break_mark
) # Clear the break (if any)
1842 # Restore the current frame if needed
1843 while v
.frame
!= frame
do v
.frames
.shift
1845 v
.stmt
(self.n_catch
)
1848 v
.stmt
(self.n_block
)
1849 v
.is_escape
(self.break_mark
)
1854 redef class AWhileExpr
1858 var cond
= v
.expr
(self.n_expr
)
1859 if cond
== null then return
1860 if not cond
.is_true
then return
1861 v
.stmt
(self.n_block
)
1862 if v
.is_escape
(self.break_mark
) then return
1863 v
.is_escape
(self.continue_mark
) # Clear the break
1864 if v
.is_escaping
then return
1869 redef class ALoopExpr
1873 v
.stmt
(self.n_block
)
1874 if v
.is_escape
(self.break_mark
) then return
1875 v
.is_escape
(self.continue_mark
) # Clear the break
1876 if v
.is_escaping
then return
1881 redef class AForExpr
1884 var iters
= new Array[Instance]
1886 for g
in n_groups
do
1887 var col
= v
.expr
(g
.n_expr
)
1888 if col
== null then return
1889 if col
.is_null
then fatal
(v
, "Receiver is null")
1891 var iter
= v
.callsite
(g
.method_iterator
, [col
]).as(not null)
1896 for g
in n_groups
, iter
in iters
do
1897 var isok
= v
.callsite
(g
.method_is_ok
, [iter
]).as(not null)
1898 if not isok
.is_true
then break label
1899 if g
.variables
.length
== 1 then
1900 var item
= v
.callsite
(g
.method_item
, [iter
]).as(not null)
1901 #self.debug("item {item}")
1902 v
.write_variable
(g
.variables
.first
, item
)
1903 else if g
.variables
.length
== 2 then
1904 var key
= v
.callsite
(g
.method_key
, [iter
]).as(not null)
1905 v
.write_variable
(g
.variables
[0], key
)
1906 var item
= v
.callsite
(g
.method_item
, [iter
]).as(not null)
1907 v
.write_variable
(g
.variables
[1], item
)
1912 v
.stmt
(self.n_block
)
1913 if v
.is_escape
(self.break_mark
) then break
1914 v
.is_escape
(self.continue_mark
) # Clear the break
1915 if v
.is_escaping
then break
1916 for g
in n_groups
, iter
in iters
do
1917 v
.callsite
(g
.method_next
, [iter
])
1920 for g
in n_groups
, iter
in iters
do
1921 var method_finish
= g
.method_finish
1922 if method_finish
!= null then
1923 v
.callsite
(method_finish
, [iter
])
1929 redef class AWithExpr
1932 var expr
= v
.expr
(self.n_expr
)
1933 if expr
== null then return
1935 v
.callsite
(method_start
, [expr
])
1936 v
.stmt
(self.n_block
)
1937 v
.is_escape
(self.break_mark
) # Clear the break
1939 # Execute the finally without an escape
1940 var old_mark
= v
.escapemark
1942 v
.callsite
(method_finish
, [expr
])
1943 # Restore the escape unless another escape was provided
1944 if v
.escapemark
== null then v
.escapemark
= old_mark
1948 redef class AAssertExpr
1951 var cond
= v
.expr
(self.n_expr
)
1952 if cond
== null then return
1953 if not cond
.is_true
then
1955 if v
.is_escaping
then return
1957 # Explain assert if it fails
1958 var explain_assert_str
= explain_assert_str
1959 if explain_assert_str
!= null then
1960 var i
= v
.expr
(explain_assert_str
)
1961 if i
isa MutableInstance then
1962 var res
= v
.send
(v
.force_get_primitive_method
("to_cstring", i
.mtype
), [i
])
1966 print_error
"Runtime assert: {val.to_s}"
1974 fatal
(v
, "Assert '{nid.text}' failed")
1976 fatal
(v
, "Assert failed")
1986 var cond
= v
.expr
(self.n_expr
)
1987 if cond
== null then return null
1988 if cond
.is_true
then return cond
1989 return v
.expr
(self.n_expr2
)
1993 redef class AImpliesExpr
1996 var cond
= v
.expr
(self.n_expr
)
1997 if cond
== null then return null
1998 if not cond
.is_true
then return v
.true_instance
1999 return v
.expr
(self.n_expr2
)
2003 redef class AAndExpr
2006 var cond
= v
.expr
(self.n_expr
)
2007 if cond
== null then return null
2008 if not cond
.is_true
then return cond
2009 return v
.expr
(self.n_expr2
)
2013 redef class ANotExpr
2016 var cond
= v
.expr
(self.n_expr
)
2017 if cond
== null then return null
2018 return v
.bool_instance
(not cond
.is_true
)
2022 redef class AOrElseExpr
2025 var i
= v
.expr
(self.n_expr
)
2026 if i
== null then return null
2027 if i
!= v
.null_instance
then return i
2028 return v
.expr
(self.n_expr2
)
2032 redef class AIntegerExpr
2035 if value
isa Int then return v
.int_instance
(value
.as(Int))
2036 if value
isa Byte then return v
.byte_instance
(value
.as(Byte))
2037 if value
isa Int8 then return v
.int8_instance
(value
.as(Int8))
2038 if value
isa Int16 then return v
.int16_instance
(value
.as(Int16))
2039 if value
isa UInt16 then return v
.uint16_instance
(value
.as(UInt16))
2040 if value
isa Int32 then return v
.int32_instance
(value
.as(Int32))
2041 if value
isa UInt32 then return v
.uint32_instance
(value
.as(UInt32))
2046 redef class AFloatExpr
2049 return v
.float_instance
(self.value
.as(not null))
2053 redef class ACharExpr
2056 if is_code_point
then
2057 return v
.int_instance
(self.value
.as(not null).code_point
)
2059 return v
.char_instance
(self.value
.as(not null))
2063 redef class AArrayExpr
2066 var val
= new Array[Instance]
2067 var old_comprehension
= v
.frame
.comprehension
2068 v
.frame
.comprehension
= val
2069 for nexpr
in self.n_exprs
do
2070 if nexpr
isa AForExpr then
2073 var i
= v
.expr
(nexpr
)
2074 if i
== null then return null
2078 v
.frame
.comprehension
= old_comprehension
2079 var mtype
= v
.unanchor_type
(self.mtype
.as(not null)).as(MClassType)
2080 var elttype
= mtype
.arguments
.first
2081 return v
.array_instance
(val
, elttype
)
2085 redef class AugmentedStringFormExpr
2086 # Factorize the making of a `Regex` object from a literal prefixed string
2087 fun make_re
(v
: NaiveInterpreter, rs
: Instance): nullable Instance do
2090 var res
= v
.callsite
(tore
, [rs
])
2092 print
"Cannot call property `to_re` on {self}"
2095 for j
in suffix
.chars
do
2097 var prop
= ignore_case
2099 v
.callsite
(prop
, [res
, v
.bool_instance
(true)])
2105 v
.callsite
(prop
, [res
, v
.bool_instance
(true)])
2111 v
.callsite
(prop
, [res
, v
.bool_instance
(false)])
2114 # Should not happen, this needs to be updated
2115 # along with the addition of new suffixes
2122 redef class AStringFormExpr
2123 redef fun expr
(v
) do return v
.string_instance
(value
)
2126 redef class AStringExpr
2127 redef fun expr
(v
) do
2128 var s
= v
.string_instance
(value
)
2129 if is_string
then return s
2130 if is_bytestring
then
2131 var ns
= v
.c_string_instance_from_ns
(bytes
.items
, bytes
.length
)
2132 var ln
= v
.int_instance
(bytes
.length
)
2133 var prop
= to_bytes_with_copy
2135 var res
= v
.callsite
(prop
, [ns
, ln
])
2137 print
"Cannot call property `to_bytes` on {self}"
2142 var res
= make_re
(v
, s
)
2146 print
"Unimplemented prefix or suffix for {self}"
2153 redef class ASuperstringExpr
2156 var array
= new Array[Instance]
2157 for nexpr
in n_exprs
do
2158 var i
= v
.expr
(nexpr
)
2159 if i
== null then return null
2162 var i
= v
.array_instance
(array
, v
.mainmodule
.object_type
)
2163 var res
= v
.send
(v
.force_get_primitive_method
("plain_to_s", i
.mtype
), [i
])
2165 if is_re
then res
= make_re
(v
, res
)
2170 redef class ACrangeExpr
2173 var e1
= v
.expr
(self.n_expr
)
2174 if e1
== null then return null
2175 var e2
= v
.expr
(self.n_expr2
)
2176 if e2
== null then return null
2177 var mtype
= v
.unanchor_type
(self.mtype
.as(not null))
2178 var res
= new MutableInstance(mtype
)
2179 v
.init_instance
(res
)
2180 v
.callsite
(init_callsite
, [res
, e1
, e2
])
2185 redef class AOrangeExpr
2188 var e1
= v
.expr
(self.n_expr
)
2189 if e1
== null then return null
2190 var e2
= v
.expr
(self.n_expr2
)
2191 if e2
== null then return null
2192 var mtype
= v
.unanchor_type
(self.mtype
.as(not null))
2193 var res
= new MutableInstance(mtype
)
2194 v
.init_instance
(res
)
2195 v
.callsite
(init_callsite
, [res
, e1
, e2
])
2200 redef class ATrueExpr
2203 return v
.bool_instance
(true)
2207 redef class AFalseExpr
2210 return v
.bool_instance
(false)
2214 redef class ANullExpr
2217 return v
.null_instance
2221 redef class AIsaExpr
2224 var i
= v
.expr
(self.n_expr
)
2225 if i
== null then return null
2226 var mtype
= v
.unanchor_type
(self.cast_type
.as(not null))
2227 return v
.bool_instance
(v
.is_subtype
(i
.mtype
, mtype
))
2231 redef class AAsCastExpr
2234 var i
= v
.expr
(self.n_expr
)
2235 if i
== null then return null
2236 var mtype
= self.mtype
.as(not null)
2237 var amtype
= v
.unanchor_type
(mtype
)
2238 if not v
.is_subtype
(i
.mtype
, amtype
) then
2239 fatal
(v
, "Cast failed. Expected `{amtype}`, got `{i.mtype}`")
2245 redef class AAsNotnullExpr
2248 var i
= v
.expr
(self.n_expr
)
2249 if i
== null then return null
2251 fatal
(v
, "Cast failed")
2257 redef class AParExpr
2260 return v
.expr
(self.n_expr
)
2264 redef class AOnceExpr
2267 if v
.onces
.has_key
(self) then
2268 return v
.onces
[self]
2270 var res
= v
.expr
(self.n_expr
)
2271 if res
== null then return null
2278 redef class ASendExpr
2281 var recv
= v
.expr
(self.n_expr
)
2282 if recv
== null then return null
2284 # Safe call shortcut if recv is null
2285 if is_safe
and recv
.is_null
then
2289 var args
= v
.varargize
(callsite
.mpropdef
, callsite
.signaturemap
, recv
, self.raw_arguments
)
2290 if args
== null then return null
2291 var res
= v
.callsite
(callsite
, args
)
2296 redef class ACallrefExpr
2299 var recv
= v
.expr
(self.n_expr
)
2300 if recv
== null then return null
2301 var mtype
= self.mtype
2302 assert mtype
!= null
2303 # In case we are in generic class where formal parameter can not
2305 var mtype2
= v
.unanchor_type
(mtype
)
2306 var inst
= new CallrefInstance(mtype2
, recv
, callsite
.as(not null))
2311 redef class ASendReassignFormExpr
2314 var recv
= v
.expr
(self.n_expr
)
2315 if recv
== null then return
2316 var args
= v
.varargize
(callsite
.mpropdef
, callsite
.signaturemap
, recv
, self.raw_arguments
)
2317 if args
== null then return
2318 var value
= v
.expr
(self.n_value
)
2319 if value
== null then return
2321 var read
= v
.callsite
(callsite
, args
)
2324 var write
= v
.callsite
(reassign_callsite
, [read
, value
])
2325 assert write
!= null
2329 v
.callsite
(write_callsite
, args
)
2333 redef class ASuperExpr
2336 var recv
= v
.frame
.arguments
.first
2338 var callsite
= self.callsite
2339 if callsite
!= null then
2341 if self.n_args
.n_exprs
.is_empty
then
2342 # Add automatic arguments for the super init call
2344 for i
in [0..callsite
.msignature
.arity
[ do
2345 args
.add
(v
.frame
.arguments
[i
+1])
2348 args
= v
.varargize
(callsite
.mpropdef
, callsite
.signaturemap
, recv
, self.n_args
.n_exprs
)
2349 if args
== null then return null
2353 var res
= v
.callsite
(callsite
, args
)
2357 # Standard call-next-method
2358 var mpropdef
= self.mpropdef
2359 mpropdef
= mpropdef
.lookup_next_definition
(v
.mainmodule
, recv
.mtype
)
2362 if self.n_args
.n_exprs
.is_empty
then
2363 args
= v
.frame
.arguments
2365 args
= v
.varargize
(mpropdef
, signaturemap
, recv
, self.n_args
.n_exprs
)
2366 if args
== null then return null
2369 var res
= v
.call
(mpropdef
, args
)
2374 redef class ANewExpr
2377 var mtype
= v
.unanchor_type
(self.recvtype
.as(not null))
2378 var recv
: Instance = new MutableInstance(mtype
)
2379 v
.init_instance
(recv
)
2380 var callsite
= self.callsite
2381 if callsite
== null then return recv
2383 var args
= v
.varargize
(callsite
.mpropdef
, callsite
.signaturemap
, recv
, self.n_args
.n_exprs
)
2384 if args
== null then return null
2385 var res2
= v
.callsite
(callsite
, args
)
2386 if res2
!= null then
2387 #self.debug("got {res2} from {mproperty}. drop {recv}")
2394 redef class AAttrExpr
2397 var recv
= v
.expr
(self.n_expr
)
2398 if recv
== null then return null
2399 if recv
.is_null
then fatal
(v
, "Receiver is null")
2400 var mproperty
= self.mproperty
.as(not null)
2401 return v
.read_attribute
(mproperty
, recv
)
2405 redef class AAttrAssignExpr
2408 var recv
= v
.expr
(self.n_expr
)
2409 if recv
== null then return
2410 if recv
.is_null
then fatal
(v
, "Receiver is null")
2411 var i
= v
.expr
(self.n_value
)
2412 if i
== null then return
2413 var mproperty
= self.mproperty
.as(not null)
2414 v
.write_attribute
(mproperty
, recv
, i
)
2418 redef class AAttrReassignExpr
2421 var recv
= v
.expr
(self.n_expr
)
2422 if recv
== null then return
2423 if recv
.is_null
then fatal
(v
, "Receiver is null")
2424 var value
= v
.expr
(self.n_value
)
2425 if value
== null then return
2426 var mproperty
= self.mproperty
.as(not null)
2427 var attr
= v
.read_attribute
(mproperty
, recv
)
2428 var res
= v
.callsite
(reassign_callsite
, [attr
, value
])
2430 v
.write_attribute
(mproperty
, recv
, res
)
2434 redef class AIssetAttrExpr
2437 var recv
= v
.expr
(self.n_expr
)
2438 if recv
== null then return null
2439 if recv
.is_null
then fatal
(v
, "Receiver is null")
2440 var mproperty
= self.mproperty
.as(not null)
2441 return v
.bool_instance
(v
.isset_attribute
(mproperty
, recv
))
2445 redef class AVarargExpr
2448 return v
.expr
(self.n_expr
)
2452 redef class ASafeExpr
2455 return v
.expr
(self.n_expr
)
2459 redef class ANamedargExpr
2462 return v
.expr
(self.n_expr
)
2466 redef class ADebugTypeExpr