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