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