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