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