nitmetrics: add inheritance metrics computation
[nit.git] / src / global_compiler.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 # Global compilation of a Nit program
18 #
19 # Techniques used are:
20 # * heterogeneous generics
21 # * customization
22 # * switch dispatch
23 # * inlining
24 module global_compiler
25
26 import literal
27 import typing
28 import auto_super_init
29 import rapid_type_analysis
30
31 redef class ToolContext
32 # --output
33 var opt_output: OptionString = new OptionString("Output file", "-o", "--output")
34
35 # --no-cc
36 var opt_no_cc: OptionBool = new OptionBool("Do not invoke C compiler", "--no-cc")
37
38 # --hardening
39 var opt_hardening: OptionBool = new OptionBool("Generate contracts in the C code against bugs in the compiler", "--hardening")
40
41 redef init
42 do
43 super
44 self.option_context.add_option(self.opt_output, self.opt_no_cc, self.opt_hardening)
45 end
46 end
47
48 redef class ModelBuilder
49 # Entry point to performs a global compilation on the AST of a complete program.
50 # `mainmodule` is the main module of the program
51 # `runtime_type_analysis` is a already computer type analysis.
52 fun run_global_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
53 do
54 var time0 = get_time
55 self.toolcontext.info("*** COMPILING TO C ***", 1)
56
57 var compiler = new GlobalCompiler(mainmodule, runtime_type_analysis, self)
58 var v = new GlobalCompilerVisitor(compiler)
59
60 v.add_decl("#include <stdlib.h>")
61 v.add_decl("#include <stdio.h>")
62 v.add_decl("#include <string.h>")
63
64 # TODO: Better way to activate the GC
65 v.add_decl("#include <gc/gc.h>")
66 #v.add_decl("#define GC_MALLOC(x) calloc(1, (x))")
67
68 # Declaration of structures the live Nit types
69 # Each live type is generated as an independent C `struct' type.
70 # They only share a common first field `classid` used to implement the polymorphism.
71 # Usualy, all C variables that refers to a Nit object are typed on the abstract struct `val' that contains only the `classid` field.
72
73 v.add_decl("typedef struct \{int classid;\} val; /* general C type representing a Nit instance. */")
74 for t in runtime_type_analysis.live_types do
75 compiler.declare_runtimeclass(v, t)
76 end
77
78 # Global variable used by the legacy native interface
79
80 v.add_decl("extern int glob_argc;")
81 v.add_decl("extern char **glob_argv;")
82 v.add_decl("extern val *glob_sys;")
83
84 # Class names (for the class_name and output_class_name methods)
85
86 v.add_decl("extern const char const * class_names[];")
87 v.add("const char const * class_names[] = \{")
88 for t in runtime_type_analysis.live_types do
89 v.add("\"{t}\", /* {compiler.classid(t)} */")
90 end
91 v.add("\};")
92 compiler.header = v
93
94 # Init instance code (allocate and init-arguments)
95
96 for t in runtime_type_analysis.live_types do
97 if t.ctype == "val*" then
98 compiler.generate_init_instance(t)
99 else
100 compiler.generate_box_instance(t)
101 end
102 end
103
104 # The main function of the C
105
106 v = new GlobalCompilerVisitor(compiler)
107 v.add_decl("int glob_argc;")
108 v.add_decl("char **glob_argv;")
109 v.add_decl("val *glob_sys;")
110 v.add_decl("int main(int argc, char** argv) \{")
111 v.add("glob_argc = argc; glob_argv = argv;")
112 var main_type = mainmodule.sys_type
113 if main_type == null then return # Nothing to compile
114 var glob_sys = v.init_instance(main_type)
115 v.add("glob_sys = {glob_sys};")
116 var main_init = mainmodule.try_get_primitive_method("init", main_type)
117 if main_init != null then
118 v.send(main_init, [glob_sys])
119 end
120 var main_method = mainmodule.try_get_primitive_method("main", main_type)
121 if main_method != null then
122 v.send(main_method, [glob_sys])
123 end
124 v.add("return 0;")
125 v.add("\}")
126
127 # Compile until all runtime_functions are visited
128
129 while not compiler.todos.is_empty do
130 var m = compiler.todos.shift
131 self.toolcontext.info("Compile {m} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3)
132 m.compile_to_c(compiler)
133 end
134 self.toolcontext.info("Total methods to compile to C: {compiler.visitors.length}", 2)
135
136 var time1 = get_time
137 self.toolcontext.info("*** END VISITING: {time1-time0} ***", 2)
138 write_and_make(compiler)
139 end
140
141 private fun write_and_make(compiler: GlobalCompiler)
142 do
143 var mainmodule = compiler.mainmodule
144
145 # Generate the .h and .c files
146 # A single C file regroups many compiled rumtime functions
147 # Note that we do not try to be clever an a small change in a Nit source file may change the content of all the generated .c files
148 var time0 = get_time
149
150 var outname = self.toolcontext.opt_output.value
151 if outname == null then
152 outname = "{mainmodule.name}.bin"
153 end
154
155 var hfilename = ".nit_compile/{mainmodule.name}.1.h"
156 var h = new OFStream.open(hfilename)
157 for l in compiler.header.decl_lines do
158 h.write l
159 h.write "\n"
160 end
161 h.close
162
163 var cfiles = new Array[String]
164
165 var file: nullable OFStream = null
166 var count = 0
167
168 ".nit_compile".mkdir
169 var i = 0
170 for vis in compiler.visitors do
171 count += vis.lines.length
172 if file == null or count > 10000 then
173 i += 1
174 if file != null then file.close
175 var cfilename = ".nit_compile/{mainmodule.name}.{i}.c"
176 cfiles.add(cfilename)
177 file = new OFStream.open(cfilename)
178 file.write "#include \"{mainmodule.name}.1.h\"\n"
179 count = vis.lines.length
180 end
181 if vis != compiler.header then
182 for l in vis.decl_lines do
183 file.write l
184 file.write "\n"
185 end
186 end
187 for l in vis.lines do
188 file.write l
189 file.write "\n"
190 end
191 end
192 if file != null then file.close
193
194 self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
195
196 # Generate the Makefile
197
198 var makename = ".nit_compile/{mainmodule.name}.mk"
199 var makefile = new OFStream.open(makename)
200
201 makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc\n\n")
202 makefile.write("all: {outname}\n\n")
203
204 var ofiles = new Array[String]
205 # Compile each generated file
206 for f in cfiles do
207 var o = f.strip_extension(".c") + ".o"
208 makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) -D NONITCNI -c -o {o} {f}\n\n")
209 ofiles.add(o)
210 end
211 # Compile each required extern body into a specific .o
212 for f in compiler.extern_bodies do
213 i += 1
214 var o = ".nit_compile/{mainmodule.name}.{i}.o"
215 makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) -D NONITCNI -c -o {o} {f}\n\n")
216 ofiles.add(o)
217 end
218 # Link edition
219 makefile.write("{outname}: {ofiles.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outname} {ofiles.join(" ")} $(LDLIBS)\n\n")
220 # Clean
221 makefile.write("clean:\n\trm {ofiles.join(" ")} 2>/dev/null\n\n")
222 makefile.close
223 self.toolcontext.info("Generated makefile: {makename}", 2)
224
225 var time1 = get_time
226 self.toolcontext.info("*** END COMPILING TO C: {time1-time0} ***", 2)
227
228 # Execute the Makefile
229
230 if self.toolcontext.opt_no_cc.value then return
231
232 time0 = time1
233 self.toolcontext.info("*** COMPILING C ***", 1)
234 self.toolcontext.info("make -B -f {makename} -j 4", 2)
235
236 var res
237 if self.toolcontext.verbose_level >= 3 then
238 res = sys.system("make -B -f {makename} -j 4 2>&1")
239 else
240 res = sys.system("make -B -f {makename} -j 4 2>&1 >/dev/null")
241 end
242 if res != 0 then
243 toolcontext.error(null, "make failed! Error code: {res}.")
244 end
245
246 time1 = get_time
247 self.toolcontext.info("*** END COMPILING C: {time1-time0} ***", 2)
248 end
249 end
250
251 # Singleton that store the knowledge about the compilation process
252 private class GlobalCompiler
253 # The main module of the program
254 var mainmodule: MModule
255
256 # The result of the RTA (used to know live types and methods)
257 var runtime_type_analysis: RapidTypeAnalysis
258
259 # The modeulbuilder used to know the model and the AST
260 var modelbuilder: ModelBuilder
261
262 # Is hardening asked? (see --hardening)
263 fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value
264
265 init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis, modelbuilder: ModelBuilder)
266 do
267 self.mainmodule = mainmodule
268 self.runtime_type_analysis = runtime_type_analysis
269 self.modelbuilder = modelbuilder
270 self.live_primitive_types = new Array[MClassType]
271 for t in runtime_type_analysis.live_types do
272 if t.ctype != "val*" then
273 self.live_primitive_types.add(t)
274 end
275 end
276 end
277
278 # Subset of runtime_type_analysis.live_types that contains only primitive types
279 # Used to implement the equal test
280 var live_primitive_types: Array[MClassType]
281
282 # runtime_functions that need to be compiled
283 private var todos: List[RuntimeFunction] = new List[RuntimeFunction]
284
285 # runtime_functions already seen (todo or done)
286 private var seen: HashSet[RuntimeFunction] = new HashSet[RuntimeFunction]
287 fun todo(m: RuntimeFunction)
288 do
289 if seen.has(m) then return
290 todos.add(m)
291 seen.add(m)
292 end
293
294 # Where global declaration are stored (the main .h)
295 #
296 # FIXME: should not be a vistor but just somewhere to store lines
297 # FIXME: should not have a global .h since it does not help recompilations
298 var header: nullable GlobalCompilerVisitor = null
299
300 # The list of all associated visitors
301 # Used to generate .c files
302 # FIXME: should not be vistors but just somewhere to store lines
303 private var visitors: List[GlobalCompilerVisitor] = new List[GlobalCompilerVisitor]
304
305 # List of additional .c files required to compile (native interface)
306 var extern_bodies = new ArraySet[String]
307
308 # Return the C symbol associated to a live type runtime
309 # REQUIRE: self.runtime_type_analysis.live_types.has(mtype)
310 fun classid(mtype: MClassType): String
311 do
312 if self.classids.has_key(mtype) then
313 return self.classids[mtype]
314 end
315 print "No classid for {mtype}"
316 abort
317 end
318
319 # Cache for classid (computed by declare_runtimeclass)
320 private var classids: HashMap[MClassType, String] = new HashMap[MClassType, String]
321
322 # Declare C structures and identifiers for a runtime class
323 fun declare_runtimeclass(v: GlobalCompilerVisitor, mtype: MClassType)
324 do
325 assert self.runtime_type_analysis.live_types.has(mtype)
326 v.add_decl("/* runtime class {mtype} */")
327 var idnum = classids.length
328 var idname = "ID_" + mtype.c_name
329 self.classids[mtype] = idname
330 v.add_decl("#define {idname} {idnum} /* {mtype} */")
331
332 v.add_decl("struct {mtype.c_name} \{")
333 v.add_decl("int classid; /* must be {idname} */")
334
335 if mtype.ctype != "val*" then
336 # Is the Nit type is native then the struct is a box with two fields:
337 # * the `classid` to be polymorph
338 # * the `value` that contains the native value.
339 v.add_decl("{mtype.ctype} value;")
340 end
341
342 # Collect all attributes and associate them a field in the structure.
343 # Note: we do not try to optimize the order and helps CC to optimize the client code.
344 for cd in mtype.collect_mclassdefs(self.mainmodule) do
345 for p in cd.intro_mproperties do
346 if not p isa MAttribute then continue
347 var t = p.intro.static_mtype.as(not null)
348 t = t.anchor_to(self.mainmodule, mtype)
349 v.add_decl("{t.ctype} {p.intro.c_name}; /* {p}: {t} */")
350 end
351 end
352 v.add_decl("\};")
353 end
354
355 # Generate the init-instance of a live type (allocate + init-instance)
356 fun generate_init_instance(mtype: MClassType)
357 do
358 assert self.runtime_type_analysis.live_types.has(mtype)
359 assert mtype.ctype == "val*"
360 var v = new GlobalCompilerVisitor(self)
361
362 self.header.add_decl("{mtype.ctype} NEW_{mtype.c_name}(void);")
363 v.add_decl("/* allocate {mtype} */")
364 v.add_decl("{mtype.ctype} NEW_{mtype.c_name}(void) \{")
365 var res = v.new_var(mtype)
366 res.is_exact = true
367 v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}));")
368 v.add("{res}->classid = {self.classid(mtype)};")
369
370 for cd in mtype.collect_mclassdefs(self.mainmodule)
371 do
372 var n = self.modelbuilder.mclassdef2nclassdef[cd]
373 for npropdef in n.n_propdefs do
374 if npropdef isa AAttrPropdef then
375 npropdef.init_expr(v, res)
376 end
377 end
378 end
379 v.add("return {res};")
380 v.add("\}")
381 end
382
383 fun generate_box_instance(mtype: MClassType)
384 do
385 assert self.runtime_type_analysis.live_types.has(mtype)
386 assert mtype.ctype != "val*"
387 var v = new GlobalCompilerVisitor(self)
388
389 self.header.add_decl("val* BOX_{mtype.c_name}({mtype.ctype});")
390 v.add_decl("/* allocate {mtype} */")
391 v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
392 v.add("struct {mtype.c_name}*res = GC_MALLOC(sizeof(struct {mtype.c_name}));")
393 v.add("res->classid = {self.classid(mtype)};")
394 v.add("res->value = value;")
395 v.add("return (val*)res;")
396 v.add("\}")
397
398 end
399
400 # look for a needed .h and .c file for a given .nit source-file
401 # FIXME: bad API, parameter should be a MModule, not its source-file
402 fun add_extern(file: String)
403 do
404 file = file.strip_extension(".nit")
405 var tryfile = file + ".nit.h"
406 if tryfile.file_exists then
407 self.header.add_decl("#include \"{"..".join_path(tryfile)}\"")
408 end
409 tryfile = file + "_nit.h"
410 if tryfile.file_exists then
411 self.header.add_decl("#include \"{"..".join_path(tryfile)}\"")
412 end
413 tryfile = file + ".nit.c"
414 if tryfile.file_exists then
415 self.extern_bodies.add(tryfile)
416 end
417 tryfile = file + "_nit.c"
418 if tryfile.file_exists then
419 self.extern_bodies.add(tryfile)
420 end
421 end
422
423 private var collect_types_cache: HashMap[MType, Array[MClassType]] = new HashMap[MType, Array[MClassType]]
424 end
425
426 redef class String
427 # Mangle a string to be a unique valid C identifier
428 fun to_cmangle: String
429 do
430 var res = new Buffer
431 var underscore = false
432 for c in self do
433 if (c >= 'a' and c <= 'z') or (c >='A' and c <= 'Z') then
434 res.add(c)
435 underscore = false
436 continue
437 end
438 if underscore then
439 res.append('_'.ascii.to_s)
440 res.add('d')
441 end
442 if c >= '0' and c <= '9' then
443 res.add(c)
444 underscore = false
445 else if c == '_' then
446 res.add(c)
447 underscore = true
448 else
449 res.add('_')
450 res.append(c.ascii.to_s)
451 res.add('d')
452 underscore = false
453 end
454 end
455 return res.to_s
456 end
457
458 # Escape " \ ' and non printable characters for literal C strings or characters
459 fun escape_to_c: String
460 do
461 var b = new Buffer
462 for c in self do
463 if c == '\n' then
464 b.append("\\n")
465 else if c == '\0' then
466 b.append("\\0")
467 else if c == '"' then
468 b.append("\\\"")
469 else if c == '\'' then
470 b.append("\\\'")
471 else if c == '\\' then
472 b.append("\\\\")
473 else if c.ascii < 32 then
474 b.append("\\{c.ascii.to_base(8, false)}")
475 else
476 b.add(c)
477 end
478 end
479 return b.to_s
480 end
481 end
482
483 redef class MType
484 # Return the C type associated to a given Nit static type
485 fun ctype: String
486 do
487 return "val*"
488 end
489
490 # Return the name of the C structure associated to a Nit live type
491 # FIXME: move to GlobalCompiler so we can check that self is a live type
492 fun c_name: String is abstract
493 private var c_name_cache: nullable String
494 end
495
496 redef class MClassType
497 redef fun c_name
498 do
499 var res = self.c_name_cache
500 if res != null then return res
501 res = "{mclass.intro_mmodule.name.to_cmangle}__{mclass.name.to_cmangle}"
502 self.c_name_cache = res
503 return res
504 end
505
506 redef fun ctype: String
507 do
508 if mclass.name == "Int" then
509 return "long"
510 else if mclass.name == "Bool" then
511 return "short int"
512 else if mclass.name == "Char" then
513 return "char"
514 else if mclass.name == "Float" then
515 return "double"
516 else if mclass.name == "NativeString" then
517 return "char*"
518 else if mclass.name == "NativeArray" then
519 assert self isa MGenericType
520 return "{self.arguments.first.ctype}*"
521 else if mclass.kind == extern_kind then
522 return "void*"
523 else
524 return "val*"
525 end
526 end
527 end
528
529 redef class MGenericType
530 redef fun c_name
531 do
532 var res = self.c_name_cache
533 if res != null then return res
534 res = super
535 for t in self.arguments do
536 res = res + t.c_name
537 end
538 self.c_name_cache = res
539 return res
540 end
541 end
542
543 redef class MNullableType
544 redef fun c_name
545 do
546 var res = self.c_name_cache
547 if res != null then return res
548 res = "nullable_{self.mtype.c_name}"
549 self.c_name_cache = res
550 return res
551 end
552 end
553
554 # A C function associated to a Nit method
555 # Because of customization, a given Nit method can be compiler more that once
556 private abstract class RuntimeFunction
557 # The associated Nit method
558 var mmethoddef: MMethodDef
559
560 # The mangled c name of the runtime_function
561 fun c_name: String is abstract
562
563 # Implements a call of the runtime_function
564 # May inline the body or generate a C function call
565 fun call(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
566
567 # Generate the code for the RuntimeFunction
568 # Warning: compile more than once compilation makes CC unhappy
569 fun compile_to_c(compiler: GlobalCompiler) is abstract
570 end
571
572 # A runtime function customized on a specific monomrph receiver type
573 private class CustomizedRuntimeFunction
574 super RuntimeFunction
575
576 # The considered reciever
577 # (usually is a live type but no strong guarantee)
578 var recv: MClassType
579
580 init(mmethoddef: MMethodDef, recv: MClassType)
581 do
582 super(mmethoddef)
583 self.recv = recv
584 end
585
586 # The mangled c name of the runtime_function
587 redef fun c_name: String
588 do
589 var res = self.c_name_cache
590 if res != null then return res
591 if self.mmethoddef.mclassdef.bound_mtype == self.recv then
592 res = self.mmethoddef.c_name
593 else
594 res = "{mmethoddef.c_name}__{recv.c_name}"
595 end
596 self.c_name_cache = res
597 return res
598 end
599
600 private var c_name_cache: nullable String = null
601
602 redef fun ==(o)
603 # used in the compiler worklist
604 do
605 if not o isa CustomizedRuntimeFunction then return false
606 if self.mmethoddef != o.mmethoddef then return false
607 if self.recv != o.recv then return false
608 return true
609 end
610
611 redef fun hash
612 # used in the compiler work-list
613 do
614 var res = self.mmethoddef.hash + self.recv.hash
615 return res
616 end
617
618 redef fun to_s
619 do
620 if self.mmethoddef.mclassdef.bound_mtype == self.recv then
621 return self.mmethoddef.to_s
622 else
623 return "{self.mmethoddef}@{self.recv}"
624 end
625 end
626
627 # compile the code customized for the reciever
628 redef fun compile_to_c(compiler)
629 do
630 var recv = self.recv
631 var mmethoddef = self.mmethoddef
632 if not recv.is_subtype(compiler.mainmodule, null, mmethoddef.mclassdef.bound_mtype) then
633 print("problem: why do we compile {self} for {recv}?")
634 abort
635 end
636
637 var v = new GlobalCompilerVisitor(compiler)
638 var selfvar = new RuntimeVariable("self", recv, recv)
639 if compiler.runtime_type_analysis.live_types.has(recv) then
640 selfvar.is_exact = true
641 end
642 var arguments = new Array[RuntimeVariable]
643 var frame = new Frame(v, mmethoddef, recv, arguments)
644 v.frame = frame
645
646 var sig = new Buffer
647 var comment = new Buffer
648 var ret = mmethoddef.msignature.return_mtype
649 if ret != null then
650 ret = v.resolve_for(ret, selfvar)
651 sig.append("{ret.ctype} ")
652 else if mmethoddef.mproperty.is_new then
653 ret = recv
654 sig.append("{ret.ctype} ")
655 else
656 sig.append("void ")
657 end
658 sig.append(self.c_name)
659 sig.append("({recv.ctype} self")
660 comment.append("(self: {recv}")
661 arguments.add(selfvar)
662 for i in [0..mmethoddef.msignature.arity[ do
663 var mtype = mmethoddef.msignature.mparameters[i].mtype
664 if i == mmethoddef.msignature.vararg_rank then
665 mtype = v.get_class("Array").get_mtype([mtype])
666 end
667 mtype = v.resolve_for(mtype, selfvar)
668 comment.append(", {mtype}")
669 sig.append(", {mtype.ctype} p{i}")
670 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
671 arguments.add(argvar)
672 end
673 sig.append(")")
674 comment.append(")")
675 if ret != null then
676 comment.append(": {ret}")
677 end
678 compiler.header.add_decl("{sig};")
679
680 v.add_decl("/* method {self} for {comment} */")
681 v.add_decl("{sig} \{")
682 #v.add("printf(\"method {self} for {comment}\\n\");")
683 if ret != null then
684 frame.returnvar = v.new_var(ret)
685 end
686 frame.returnlabel = v.get_name("RET_LABEL")
687
688 mmethoddef.compile_inside_to_c(v, arguments)
689
690 v.add("{frame.returnlabel.as(not null)}:;")
691 if ret != null then
692 v.add("return {frame.returnvar.as(not null)};")
693 end
694 v.add("\}")
695 end
696
697 redef fun call(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
698 do
699 var ret = self.mmethoddef.msignature.return_mtype
700 if self.mmethoddef.mproperty.is_new then
701 ret = recv
702 end
703 if ret != null then
704 ret = v.resolve_for(ret, arguments.first)
705 end
706 if self.mmethoddef.can_inline(v) then
707 var frame = new Frame(v, self.mmethoddef, self.recv, arguments)
708 frame.returnlabel = v.get_name("RET_LABEL")
709 if ret != null then
710 frame.returnvar = v.new_var(ret)
711 end
712 var old_frame = v.frame
713 v.frame = frame
714 v.add("\{ /* Inline {self} ({arguments.join(",")}) */")
715 self.mmethoddef.compile_inside_to_c(v, arguments)
716 v.add("{frame.returnlabel.as(not null)}:(void)0;")
717 v.add("\}")
718 v.frame = old_frame
719 return frame.returnvar
720 end
721 v.adapt_signature(self.mmethoddef, arguments)
722 v.compiler.todo(self)
723 if ret == null then
724 v.add("{self.c_name}({arguments.join(",")});")
725 return null
726 else
727 var res = v.new_var(ret)
728 v.add("{res} = {self.c_name}({arguments.join(",")});")
729 return res
730 end
731 end
732 end
733
734 # A runtime variable hold a runtime value in C.
735 # Runtime variables are associated to Nit local variables and intermediate results in Nit expressions.
736 #
737 # The tricky point is that a single C variable can be associated to more than one RuntimeVariable because the static knowledge of the type of an expression can vary in the C code.
738 private class RuntimeVariable
739 # The name of the variable in the C code
740 var name: String
741
742 # The static type of the variable (as declard in C)
743 var mtype: MType
744
745 # The current casted type of the variable (as known in Nit)
746 var mcasttype: MType
747
748 # If the variable exaclty a mcasttype?
749 # false (usual value) means that the variable is a mcasttype or a subtype.
750 var is_exact: Bool = false
751
752 init(name: String, mtype: MType, mcasttype: MType)
753 do
754 self.name = name
755 self.mtype = mtype
756 self.mcasttype = mcasttype
757 assert not mtype.need_anchor
758 assert not mcasttype.need_anchor
759 end
760
761 redef fun to_s do return name
762
763 redef fun inspect
764 do
765 var exact_str
766 if self.is_exact then
767 exact_str = " exact"
768 else
769 exact_str = ""
770 end
771 var type_str
772 if self.mtype == self.mcasttype then
773 type_str = "{mtype}{exact_str}"
774 else
775 type_str = "{mtype}({mcasttype}{exact_str})"
776 end
777 return "<{name}:{type_str}>"
778 end
779 end
780
781 # A visitor on the AST of property definition that generate the C code.
782 # Because of inlining, a visitor can visit more than one property.
783 private class GlobalCompilerVisitor
784 # The associated compiler
785 var compiler: GlobalCompiler
786
787 init(compiler: GlobalCompiler)
788 do
789 self.compiler = compiler
790 compiler.visitors.add(self)
791 end
792
793 # Alias for self.compiler.mainmodule.object_type
794 fun object_type: MClassType do return self.compiler.mainmodule.object_type
795
796 # Alias for self.compiler.mainmodule.bool_type
797 fun bool_type: MClassType do return self.compiler.mainmodule.bool_type
798
799 # Force to get the primitive class named `name' or abort
800 fun get_class(name: String): MClass
801 do
802 return self.compiler.mainmodule.get_primitive_class(name)
803 end
804
805 # Force to get the primitive property named `name' in the instance `recv' or abort
806 fun get_property(name: String, recv: MType): MMethod
807 do
808 return self.compiler.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, recv, self.compiler.mainmodule)
809 end
810
811 # The current Frame
812 var frame: nullable Frame
813
814 # Anchor a type to the main module and the current receiver
815 fun anchor(mtype: MType): MType
816 do
817 if not mtype.need_anchor then return mtype
818 #debug("anchor {mtype} to {self.reciever.as(not null)}:{self.reciever.mtype}")
819 return mtype.anchor_to(self.compiler.mainmodule, self.frame.receiver)
820 end
821
822 # Add a line in the main part of the generated C
823 fun add(s: String)
824 do
825 self.lines.add(s)
826 end
827
828 # Add a line in the
829 # (used for local or global declaration)
830 fun add_decl(s: String)
831 do
832 self.decl_lines.add(s)
833 end
834
835 private var lines: List[String] = new List[String]
836 private var decl_lines: List[String] = new List[String]
837
838 # The current visited AST node
839 var current_node: nullable AExpr = null
840
841 # Compile an expression an return its result
842 # `mtype` is the expected return type, pass null if no specific type is expected.
843 fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable
844 do
845 var old = self.current_node
846 self.current_node = nexpr
847 var res = nexpr.expr(self).as(not null)
848 if mtype != null then
849 mtype = self.anchor(mtype)
850 res = self.autobox(res, mtype)
851 end
852 self.current_node = old
853 return res
854 end
855
856 # Unsafely cast a value to a new type
857 # ie the result share the same C variable but my have a different mcasttype
858 # NOTE: if the adaptation is useless then `value' is returned as it.
859 # ENSURE: return.name == value.name
860 fun autoadapt(value: RuntimeVariable, mtype: MType): RuntimeVariable
861 do
862 mtype = self.anchor(mtype)
863 var valmtype = value.mcasttype
864 if valmtype.is_subtype(self.compiler.mainmodule, null, mtype) then
865 return value
866 end
867
868 if valmtype isa MNullableType and valmtype.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
869 var res = new RuntimeVariable(value.name, valmtype, valmtype.mtype)
870 return res
871 else
872 var res = new RuntimeVariable(value.name, valmtype, mtype)
873 return res
874 end
875 end
876
877 # Box or unbox a value to another type iff a C type conversion is needed
878 # ENSURE: result.mtype.ctype == mtype.ctype
879 fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable
880 do
881 if value.mtype.ctype == mtype.ctype then
882 return value
883 else if value.mtype.ctype == "val*" then
884 return self.new_expr("((struct {mtype.c_name}*){value})->value /* autounbox from {value.mtype} to {mtype} */", mtype)
885 else if mtype.ctype == "val*" then
886 var valtype = value.mtype.as(MClassType)
887 var res = self.new_var(mtype)
888 if not compiler.runtime_type_analysis.live_types.has(valtype) then
889 self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
890 self.add("printf(\"Dead code executed!\\n\"); exit(1);")
891 return res
892 end
893 self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
894 return res
895 else
896 # Bad things will appen!
897 var res = self.new_var(mtype)
898 self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
899 self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); exit(1);")
900 return res
901 end
902 end
903
904 # Correctly assign a left and a right value
905 # Boxing and unboxing is performed if required
906 fun assign(left, right: RuntimeVariable)
907 do
908 right = self.autobox(right, left.mtype)
909 self.add("{left} = {right};")
910 end
911
912
913 # Alias for `self.expr(nexpr, self.bool_type)'
914 fun expr_bool(nexpr: AExpr): RuntimeVariable
915 do
916 return expr(nexpr, bool_type)
917 end
918
919 # Compile a statement (if any)
920 fun stmt(nexpr: nullable AExpr)
921 do
922 if nexpr == null then return
923 var old = self.current_node
924 self.current_node = nexpr
925 nexpr.stmt(self)
926 self.current_node = old
927 end
928
929 # Safely show a debug message on the current node and repeat the message in the C code as a comment
930 fun debug(message: String)
931 do
932 var node = self.current_node
933 if node == null then
934 print "?: {message}"
935 else
936 node.debug(message)
937 end
938 self.add("/* DEBUG: {message} */")
939 end
940
941 # Return a new uninitialized local runtime_variable
942 fun new_var(mtype: MType): RuntimeVariable
943 do
944 mtype = self.anchor(mtype)
945 var name = self.get_name("var")
946 var res = new RuntimeVariable(name, mtype, mtype)
947 self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
948 return res
949 end
950
951 # Return a new local runtime_variable initialized with the C expression `cexpr'.
952 fun new_expr(cexpr: String, mtype: MType): RuntimeVariable
953 do
954 var res = new_var(mtype)
955 self.add("{res} = {cexpr};")
956 return res
957 end
958
959 # Return the local runtime_variable associated to a Nit local variable
960 fun variable(variable: Variable): RuntimeVariable
961 do
962 if self.variables.has_key(variable) then
963 return self.variables[variable]
964 else
965 var name = self.get_name("var_{variable.name}")
966 var mtype = variable.declared_type.as(not null)
967 mtype = self.anchor(mtype)
968 var res = new RuntimeVariable(name, mtype, mtype)
969 self.add_decl("{mtype.ctype} {name} /* var {variable}: {mtype} */;")
970 self.variables[variable] = res
971 return res
972 end
973 end
974
975 private var variables: HashMap[Variable, RuntimeVariable] = new HashMap[Variable, RuntimeVariable]
976
977 # Return an unique and stable identifier associated with an escapemark
978 fun escapemark_name(e: nullable EscapeMark): String
979 do
980 assert e != null
981 if escapemark_names.has_key(e) then return escapemark_names[e]
982 var name = e.name
983 if name == null then name = "label"
984 name = get_name(name)
985 escapemark_names[e] = name
986 return name
987 end
988
989 private var escapemark_names = new HashMap[EscapeMark, String]
990
991 # Return a new name based on `s' and unique in the visitor
992 fun get_name(s: String): String
993 do
994 if not self.names.has(s) then
995 self.names.add(s)
996 return s
997 end
998 var i = self.last + 1
999 loop
1000 var s2 = s + i.to_s
1001 if not self.names.has(s2) then
1002 self.last = i
1003 self.names.add(s2)
1004 return s2
1005 end
1006 i = i + 1
1007 end
1008 end
1009
1010 private var last: Int = 0
1011
1012 private var names: HashSet[String] = new HashSet[String]
1013
1014 # Generate a return with the value `s'
1015 fun ret(s: RuntimeVariable)
1016 do
1017 self.assign(self.frame.returnvar.as(not null), s)
1018 self.add("goto {self.frame.returnlabel.as(not null)};")
1019 end
1020
1021 # The runtime types that are acceptable for a given receiver.
1022 fun collect_types(recv: RuntimeVariable): Array[MClassType]
1023 do
1024 var mtype = recv.mcasttype
1025 if recv.is_exact then
1026 assert mtype isa MClassType
1027 assert self.compiler.runtime_type_analysis.live_types.has(mtype)
1028 var types = [mtype]
1029 return types
1030 end
1031 var cache = self.compiler.collect_types_cache
1032 if cache.has_key(mtype) then
1033 return cache[mtype]
1034 end
1035 var types = new Array[MClassType]
1036 var mainmodule = self.compiler.mainmodule
1037 for t in self.compiler.runtime_type_analysis.live_types do
1038 if not t.is_subtype(mainmodule, null, mtype) then continue
1039 types.add(t)
1040 end
1041 cache[mtype] = types
1042 return types
1043 end
1044
1045 fun resolve_for(mtype: MType, recv: RuntimeVariable): MType
1046 do
1047 if not mtype.need_anchor then return mtype
1048 #debug("resolve for {mtype} to {recv}:{recv.mcasttype}(declared as {recv.mtype}) (in {self.reciever.to_s}:{self.reciever.mtype})")
1049 var res = mtype.resolve_for(recv.mcasttype, self.frame.receiver, self.compiler.mainmodule, true)
1050 return res
1051 end
1052
1053 # Generate a polymorphic send for the method `m' and the arguments `args'
1054 fun send(m: MMethod, args: Array[RuntimeVariable]): nullable RuntimeVariable
1055 do
1056 var types = self.collect_types(args.first)
1057
1058 var res: nullable RuntimeVariable
1059 var ret = m.intro.msignature.return_mtype
1060 if m.is_new then
1061 ret = args.first.mtype
1062 res = self.new_var(ret)
1063 else if ret == null then
1064 res = null
1065 else
1066 ret = self.resolve_for(ret, args.first)
1067 res = self.new_var(ret)
1068 end
1069
1070 if types.is_empty then
1071 self.add("/*BUG: no live types for {args.first.inspect} . {m}*/")
1072 return res
1073 end
1074 self.add("/* send {m} on {args.first.inspect} */")
1075 if args.first.mtype.ctype != "val*" then
1076 var propdefs = m.lookup_definitions(self.compiler.mainmodule, args.first.mtype)
1077 if propdefs.length == 0 then
1078 self.add("/* skip, no method {m} */")
1079 return res
1080 end
1081 assert propdefs.length == 1
1082 var propdef = propdefs.first
1083 var res2 = self.call(propdef, args.first.mtype.as(MClassType), args)
1084 if res != null then self.assign(res, res2.as(not null))
1085 return res
1086 end
1087 if args.first.mcasttype isa MNullableType then
1088 # The reciever is potentially null, so we have to 3 cases: ==, != or NullPointerException
1089 self.add("if ({args.first} == NULL) \{ /* Special null case */")
1090 if m.name == "==" then
1091 assert res != null
1092 if args[1].mcasttype isa MNullableType then
1093 self.add("{res} = ({args[1]} == NULL);")
1094 else if args[1].mcasttype isa MNullType then
1095 self.add("{res} = 1; /* is null */")
1096 else
1097 self.add("{res} = 0; /* {args[1].inspect} cannot be null */")
1098 end
1099 else if m.name == "!=" then
1100 assert res != null
1101 if args[1].mcasttype isa MNullableType then
1102 self.add("{res} = ({args[1]} != NULL);")
1103 else if args[1].mcasttype isa MNullType then
1104 self.add("{res} = 0; /* is null */")
1105 else
1106 self.add("{res} = 1; /* {args[1].inspect} cannot be null */")
1107 end
1108 else
1109 self.add_abort("Reciever is null")
1110 end
1111 self.add "\} else"
1112 end
1113 self.add("switch({args.first}->classid) \{")
1114 var last = types.last
1115 var defaultpropdef: nullable MMethodDef = null
1116 for t in types do
1117 var propdefs = m.lookup_definitions(self.compiler.mainmodule, t)
1118 if propdefs.length == 0 then
1119 self.add("/* skip {t}, no method {m} */")
1120 continue
1121 end
1122 if propdefs.length > 1 then
1123 self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first")
1124 end
1125 var propdef = propdefs.first
1126 if propdef.mclassdef.mclass.name == "Object" and t.ctype == "val*" then
1127 defaultpropdef = propdef
1128 continue
1129 end
1130 if not self.compiler.hardening and t == last and defaultpropdef == null then
1131 self.add("default: /* test {t} */")
1132 else
1133 self.add("case {self.compiler.classid(t)}: /* test {t} */")
1134 end
1135 var res2 = self.call(propdef, t, args)
1136 if res != null then self.assign(res, res2.as(not null))
1137 self.add "break;"
1138 end
1139 if defaultpropdef != null then
1140 self.add("default: /* default is Object */")
1141 var res2 = self.call(defaultpropdef, defaultpropdef.mclassdef.bound_mtype, args)
1142 if res != null then self.assign(res, res2.as(not null))
1143 else if self.compiler.hardening then
1144 self.add("default: /* bug */")
1145 self.bugtype(args.first)
1146 end
1147 self.add("\}")
1148 return res
1149 end
1150
1151 # Generate a monomorphic send for the method `m', the type `t' and the arguments `args'
1152 fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable
1153 do
1154 assert t isa MClassType
1155 var propdefs = m.lookup_definitions(self.compiler.mainmodule, t)
1156 if propdefs.length == 0 then
1157 abort
1158 end
1159 if propdefs.length > 1 then
1160 self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first")
1161 end
1162 var propdef = propdefs.first
1163 return self.call(propdef, t, args)
1164 end
1165
1166 fun check_valid_reciever(recvtype: MClassType)
1167 do
1168 if self.compiler.runtime_type_analysis.live_types.has(recvtype) or recvtype.mclass.name == "Object" then return
1169 print "{recvtype} is not a live type"
1170 abort
1171 end
1172
1173 # Generate a static call on a method definition
1174 fun call(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
1175 do
1176 check_valid_reciever(recvtype)
1177 #debug("call {m} on {recvtype} on {args.first}:{args.first.mtype}")
1178 if m.mclassdef.mclass.name == "Object" and recvtype.ctype == "val*" then
1179 recvtype = m.mclassdef.bound_mtype
1180 end
1181 var recv = self.autobox(args.first, recvtype)
1182 recv = self.autoadapt(recv, recvtype)
1183
1184 var vararg_rank = m.msignature.vararg_rank
1185 if vararg_rank >= 0 then
1186 assert args.length >= m.msignature.arity + 1 # because of self
1187 var rawargs = args
1188 args = new Array[RuntimeVariable]
1189
1190 args.add(rawargs.first) # recv
1191
1192 for i in [0..vararg_rank[ do
1193 args.add(rawargs[i+1])
1194 end
1195
1196 var vararg_lastrank = vararg_rank + rawargs.length-1-m.msignature.arity
1197 var vararg = new Array[RuntimeVariable]
1198 for i in [vararg_rank..vararg_lastrank] do
1199 vararg.add(rawargs[i+1])
1200 end
1201 # FIXME: its it to late to determine the vararg type, this should have been done during a previous analysis
1202 var elttype = m.msignature.mparameters[vararg_rank].mtype
1203 elttype = self.resolve_for(elttype, recv)
1204 args.add(self.array_instance(vararg, elttype))
1205
1206 for i in [vararg_lastrank+1..rawargs.length-1[ do
1207 args.add(rawargs[i+1])
1208 end
1209 else
1210 args = args.to_a
1211 end
1212 if args.length != m.msignature.arity + 1 then # because of self
1213 add("printf(\"NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.\\n\"); exit(1);")
1214 debug("NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.")
1215 return null
1216 end
1217
1218 args.first = recv
1219 var rm = new CustomizedRuntimeFunction(m, recvtype)
1220 return rm.call(self, args)
1221 end
1222
1223 fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
1224 do
1225 var recv = args.first
1226 for i in [0..m.msignature.arity[ do
1227 var t = m.msignature.mparameters[i].mtype
1228 if i == m.msignature.vararg_rank then
1229 t = args[i+1].mtype
1230 end
1231 t = self.resolve_for(t, recv)
1232 args[i+1] = self.autobox(args[i+1], t)
1233 end
1234 end
1235
1236 fun bugtype(recv: RuntimeVariable)
1237 do
1238 if recv.mtype.ctype != "val*" then return
1239 self.add("fprintf(stderr, \"BTD BUG: Dynamic type is %s, static type is %s\\n\", class_names[{recv}->classid], \"{recv.mcasttype}\");")
1240 end
1241
1242 # Generate a polymorphic attribute read
1243 fun read_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable
1244 do
1245 var types = self.collect_types(recv)
1246
1247 var ret = a.intro.static_mtype.as(not null)
1248 ret = self.resolve_for(ret, recv)
1249 var res = self.new_var(ret)
1250
1251 if types.is_empty then
1252 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1253 return res
1254 end
1255 self.add("/* read {a} on {recv.inspect} */")
1256 self.add("switch({recv}->classid) \{")
1257 var last = types.last
1258 for t in types do
1259 if not self.compiler.hardening and t == last then
1260 self.add("default: /*{self.compiler.classid(t)}*/")
1261 else
1262 self.add("case {self.compiler.classid(t)}:")
1263 end
1264 var recv2 = self.autoadapt(recv, t)
1265 var ta = a.intro.static_mtype.as(not null)
1266 ta = self.resolve_for(ta, recv2)
1267 var res2 = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
1268 if not ta isa MNullableType then
1269 if ta.ctype == "val*" then
1270 self.add("if ({res2} == NULL) \{")
1271 self.add_abort("Uninitialized attribute {a.name}")
1272 self.add("\}")
1273 else
1274 self.add("/*NOTYET isset on primitive attributes*/")
1275 end
1276 end
1277 self.assign(res, res2)
1278 self.add("break;")
1279 end
1280 if self.compiler.hardening then
1281 self.add("default: /* Bug */")
1282 self.bugtype(recv)
1283 end
1284 self.add("\}")
1285
1286 return res
1287 end
1288
1289 # Generate a polymorphic attribute write
1290 fun write_attribute(a: MAttribute, recv: RuntimeVariable, value: RuntimeVariable)
1291 do
1292 var types = self.collect_types(recv)
1293
1294 if types.is_empty then
1295 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1296 return
1297 end
1298 self.add("/* write {a} on {recv.inspect} */")
1299 self.add("switch({recv}->classid) \{")
1300 var last = types.last
1301 for t in types do
1302 if not self.compiler.hardening and t == last then
1303 self.add("default: /*{self.compiler.classid(t)}*/")
1304 else
1305 self.add("case {self.compiler.classid(t)}:")
1306 end
1307 var recv2 = self.autoadapt(recv, t)
1308 var ta = a.intro.static_mtype.as(not null)
1309 ta = self.resolve_for(ta, recv2)
1310 self.add("((struct {t.c_name}*){recv})->{a.intro.c_name} = {self.autobox(value, ta)};")
1311 self.add("break;")
1312 end
1313 if self.compiler.hardening then
1314 self.add("default: /* Bug*/")
1315 self.bugtype(recv)
1316 end
1317 self.add("\}")
1318 end
1319
1320 # Generate a alloc-instance + init-attributes
1321 fun init_instance(mtype: MClassType): RuntimeVariable
1322 do
1323 mtype = self.anchor(mtype).as(MClassType)
1324 if not self.compiler.runtime_type_analysis.live_types.has(mtype) then
1325 debug "problem: {mtype} was detected dead"
1326 end
1327 var res = self.new_expr("NEW_{mtype.c_name}()", mtype)
1328 res.is_exact = true
1329 return res
1330 end
1331
1332 # Generate a polymorphic subtype test
1333 fun type_test(value: RuntimeVariable, mtype: MType): RuntimeVariable
1334 do
1335 mtype = self.anchor(mtype)
1336 var types = self.collect_types(value)
1337
1338 var res = self.new_var(bool_type)
1339
1340 self.add("/* isa {mtype} on {value.inspect} */")
1341 if value.mcasttype isa MNullableType then
1342 self.add("if ({value} == NULL) \{")
1343 if mtype isa MNullableType then
1344 self.add("{res} = 1; /* isa {mtype} */")
1345 else
1346 self.add("{res} = 0; /* not isa {mtype} */")
1347 end
1348 self.add("\} else ")
1349 end
1350 self.add("switch({value}->classid) \{")
1351 for t in types do
1352 if t.is_subtype(self.compiler.mainmodule, null, mtype) then
1353 self.add("case {self.compiler.classid(t)}: /* {t} */")
1354 end
1355 end
1356 self.add("{res} = 1;")
1357 self.add("break;")
1358 self.add("default:")
1359 self.add("{res} = 0;")
1360 self.add("\}")
1361
1362 return res
1363 end
1364
1365 # Generate a Nit "is" for two runtime_variables
1366 fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable
1367 do
1368 var res = self.new_var(bool_type)
1369 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1370 var tmp = value1
1371 value1 = value2
1372 value2 = tmp
1373 end
1374 if value1.mtype.ctype != "val*" then
1375 if value2.mtype.ctype == value1.mtype.ctype then
1376 self.add("{res} = {value1} == {value2};")
1377 else if value2.mtype.ctype != "val*" then
1378 self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
1379 else
1380 var mtype1 = value1.mtype.as(MClassType)
1381 self.add("{res} = ({value2} != NULL) && ({value2}->classid == {self.compiler.classid(mtype1)});")
1382 self.add("if ({res}) \{")
1383 self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
1384 self.add("\}")
1385 end
1386 else
1387 var s = new Array[String]
1388 for t in self.compiler.live_primitive_types do
1389 if not t.is_subtype(self.compiler.mainmodule, null, value1.mcasttype) then continue
1390 if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
1391 s.add "({value1}->classid == {self.compiler.classid(t)} && ((struct {t.c_name}*){value1})->value == ((struct {t.c_name}*){value2})->value)"
1392 end
1393 if s.is_empty then
1394 self.add("{res} = {value1} == {value2};")
1395 else
1396 self.add("{res} = {value1} == {value2} || ({value1} != NULL && {value2} != NULL && {value1}->classid == {value2}->classid && ({s.join(" || ")}));")
1397 end
1398 end
1399 return res
1400 end
1401
1402 # Generate a check-init-instance
1403 # TODO: is an empty stub currently
1404 fun check_init_instance(recv: RuntimeVariable)
1405 do
1406 end
1407
1408 # Generate an integer value
1409 fun int_instance(value: Int): RuntimeVariable
1410 do
1411 var res = self.new_var(self.get_class("Int").mclass_type)
1412 self.add("{res} = {value};")
1413 return res
1414 end
1415
1416 # Generate an array value
1417 fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable
1418 do
1419 elttype = self.anchor(elttype)
1420 var arraytype = self.get_class("Array").get_mtype([elttype])
1421 var res = self.init_instance(arraytype)
1422 self.add("\{ /* {res} = array_instance Array[{elttype}] */")
1423 var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
1424 nat.is_exact = true
1425 self.add("{nat} = GC_MALLOC({array.length} * sizeof({elttype.ctype}));")
1426 for i in [0..array.length[ do
1427 var r = self.autobox(array[i], elttype)
1428 self.add("{nat}[{i}] = {r};")
1429 end
1430 var length = self.int_instance(array.length)
1431 self.send(self.get_property("with_native", arraytype), [res, nat, length])
1432 self.check_init_instance(res)
1433 self.add("\}")
1434 return res
1435 end
1436
1437 # Generate a string value
1438 fun string_instance(string: String): RuntimeVariable
1439 do
1440 var mtype = self.get_class("String").mclass_type
1441 var name = self.get_name("varonce")
1442 self.add_decl("static {mtype.ctype} {name};")
1443 var res = self.new_var(mtype)
1444 self.add("if ({name}) \{")
1445 self.add("{res} = {name};")
1446 self.add("\} else \{")
1447 var nat = self.new_var(self.get_class("NativeString").mclass_type)
1448 self.add("{nat} = \"{string.escape_to_c}\";")
1449 var res2 = self.init_instance(mtype)
1450 self.add("{res} = {res2};")
1451 var length = self.int_instance(string.length)
1452 self.send(self.get_property("with_native", mtype), [res, nat, length])
1453 self.check_init_instance(res)
1454 self.add("{name} = {res};")
1455 self.add("\}")
1456 return res
1457 end
1458
1459 # Generate generic abort
1460 # used by aborts, asserts, casts, etc.
1461 fun add_abort(message: String)
1462 do
1463 if self.current_node != null and self.current_node.location.file != null then
1464 self.add("fprintf(stderr, \"Runtime error: %s (%s:%d)\\n\", \"{message.escape_to_c}\", \"{self.current_node.location.file.filename.escape_to_c}\", {current_node.location.line_start});")
1465 else
1466 self.add("fprintf(stderr, \"Runtime error: %s\\n\", \"{message.escape_to_c}\");")
1467 end
1468 self.add("exit(1);")
1469 end
1470 end
1471
1472 # A frame correspond to a visited property in a GlobalCompilerVisitor
1473 private class Frame
1474 # The associated visitor
1475
1476 var visitor: GlobalCompilerVisitor
1477
1478 # The executed property.
1479 # A Method in case of a call, an attribute in case of a default initialization.
1480 var mpropdef: MPropDef
1481
1482 # The static type of the receiver
1483 var receiver: MClassType
1484
1485 # Arguments of the method (the first is the receiver)
1486 var arguments: Array[RuntimeVariable]
1487
1488 # The runtime_variable associated to the return (in a function)
1489 var returnvar: nullable RuntimeVariable = null
1490
1491 # The label at the end of the property
1492 var returnlabel: nullable String = null
1493 end
1494
1495 redef class MPropDef
1496 private var c_name_cache: nullable String
1497
1498 # The mangled name associated to the property
1499 fun c_name: String
1500 do
1501 var res = self.c_name_cache
1502 if res != null then return res
1503 res = "{self.mclassdef.mmodule.name.to_cmangle}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
1504 self.c_name_cache = res
1505 return res
1506 end
1507 end
1508
1509 redef class MMethodDef
1510 # Can the body be inlined?
1511 private fun can_inline(v: GlobalCompilerVisitor): Bool
1512 do
1513 var modelbuilder = v.compiler.modelbuilder
1514 if modelbuilder.mpropdef2npropdef.has_key(self) then
1515 var npropdef = modelbuilder.mpropdef2npropdef[self]
1516 return npropdef.can_inline
1517 else if self.mproperty.name == "init" then
1518 # Automatic free init is always inlined since it is empty or contains only attribtes assigments
1519 return true
1520 else
1521 abort
1522 end
1523 end
1524
1525 # Inline the body in another visitor
1526 private fun compile_inside_to_c(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
1527 do
1528 var modelbuilder = v.compiler.modelbuilder
1529 if modelbuilder.mpropdef2npropdef.has_key(self) then
1530 var npropdef = modelbuilder.mpropdef2npropdef[self]
1531 npropdef.compile_to_c(v, self, arguments)
1532 else if self.mproperty.name == "init" then
1533 var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
1534 nclassdef.compile_to_c(v, self, arguments)
1535 else
1536 abort
1537 end
1538 return null
1539 end
1540 end
1541
1542 redef class APropdef
1543 private fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1544 do
1545 v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
1546 debug("Not yet implemented")
1547 end
1548
1549 private fun can_inline: Bool do return true
1550 end
1551
1552 redef class AConcreteMethPropdef
1553 redef fun compile_to_c(v, mpropdef, arguments)
1554 do
1555 for i in [0..mpropdef.msignature.arity[ do
1556 var variable = self.n_signature.n_params[i].variable.as(not null)
1557 v.assign(v.variable(variable), arguments[i+1])
1558 end
1559 # Call the implicit super-init
1560 var auto_super_inits = self.auto_super_inits
1561 if auto_super_inits != null then
1562 var selfarg = [arguments.first]
1563 for auto_super_init in auto_super_inits do
1564 if auto_super_init.intro.msignature.arity == 0 then
1565 v.send(auto_super_init, selfarg)
1566 else
1567 v.send(auto_super_init, arguments)
1568 end
1569 end
1570 end
1571
1572 v.stmt(self.n_block)
1573 end
1574
1575 redef fun can_inline
1576 do
1577 if self.auto_super_inits != null then return false
1578 var nblock = self.n_block
1579 if nblock == null then return true
1580 if (mpropdef.mproperty.name == "==" or mpropdef.mproperty.name == "!=") and mpropdef.mclassdef.mclass.name == "Object" then return true
1581 if nblock isa ABlockExpr and nblock.n_expr.length == 0 then return true
1582 return false
1583 end
1584 end
1585
1586 redef class AInternMethPropdef
1587 redef fun compile_to_c(v, mpropdef, arguments)
1588 do
1589 var pname = mpropdef.mproperty.name
1590 var cname = mpropdef.mclassdef.mclass.name
1591 var ret = mpropdef.msignature.return_mtype
1592 if ret != null then
1593 ret = v.resolve_for(ret, arguments.first)
1594 end
1595 if pname != "==" and pname != "!=" then
1596 v.adapt_signature(mpropdef, arguments)
1597 end
1598 if cname == "Int" then
1599 if pname == "output" then
1600 v.add("printf(\"%ld\\n\", {arguments.first});")
1601 return
1602 else if pname == "object_id" then
1603 v.ret(arguments.first)
1604 return
1605 else if pname == "+" then
1606 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1607 return
1608 else if pname == "-" then
1609 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1610 return
1611 else if pname == "unary -" then
1612 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1613 return
1614 else if pname == "succ" then
1615 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1616 return
1617 else if pname == "prec" then
1618 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1619 return
1620 else if pname == "*" then
1621 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1622 return
1623 else if pname == "/" then
1624 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1625 return
1626 else if pname == "%" then
1627 v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
1628 return
1629 else if pname == "lshift" then
1630 v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
1631 return
1632 else if pname == "rshift" then
1633 v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
1634 return
1635 else if pname == "==" then
1636 v.ret(v.equal_test(arguments[0], arguments[1]))
1637 return
1638 else if pname == "!=" then
1639 var res = v.equal_test(arguments[0], arguments[1])
1640 v.ret(v.new_expr("!{res}", ret.as(not null)))
1641 return
1642 else if pname == "<" then
1643 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1644 return
1645 else if pname == ">" then
1646 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1647 return
1648 else if pname == "<=" then
1649 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1650 return
1651 else if pname == ">=" then
1652 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1653 return
1654 else if pname == "to_f" then
1655 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1656 return
1657 else if pname == "ascii" then
1658 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1659 return
1660 end
1661 else if cname == "Char" then
1662 if pname == "output" then
1663 v.add("printf(\"%c\", {arguments.first});")
1664 return
1665 else if pname == "object_id" then
1666 v.ret(arguments.first)
1667 return
1668 else if pname == "==" then
1669 v.ret(v.equal_test(arguments[0], arguments[1]))
1670 return
1671 else if pname == "!=" then
1672 var res = v.equal_test(arguments[0], arguments[1])
1673 v.ret(v.new_expr("!{res}", ret.as(not null)))
1674 return
1675 else if pname == "succ" then
1676 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1677 return
1678 else if pname == "prec" then
1679 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1680 return
1681 else if pname == "<" then
1682 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1683 return
1684 else if pname == ">" then
1685 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1686 return
1687 else if pname == "<=" then
1688 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1689 return
1690 else if pname == ">=" then
1691 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1692 return
1693 else if pname == "to_i" then
1694 v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
1695 return
1696 else if pname == "ascii" then
1697 v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
1698 return
1699 end
1700 else if cname == "Bool" then
1701 if pname == "output" then
1702 v.add("printf({arguments.first}?\"true\\n\":\"false\\n\");")
1703 return
1704 else if pname == "object_id" then
1705 v.ret(arguments.first)
1706 return
1707 else if pname == "==" then
1708 v.ret(v.equal_test(arguments[0], arguments[1]))
1709 return
1710 else if pname == "!=" then
1711 var res = v.equal_test(arguments[0], arguments[1])
1712 v.ret(v.new_expr("!{res}", ret.as(not null)))
1713 return
1714 end
1715 else if cname == "Float" then
1716 if pname == "output" then
1717 v.add("printf(\"%f\\n\", {arguments.first});")
1718 return
1719 else if pname == "object_id" then
1720 v.ret(v.new_expr("(double){arguments.first}", ret.as(not null)))
1721 return
1722 else if pname == "+" then
1723 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1724 return
1725 else if pname == "-" then
1726 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1727 return
1728 else if pname == "unary -" then
1729 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1730 return
1731 else if pname == "succ" then
1732 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1733 return
1734 else if pname == "prec" then
1735 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1736 return
1737 else if pname == "*" then
1738 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1739 return
1740 else if pname == "/" then
1741 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1742 return
1743 else if pname == "==" then
1744 v.ret(v.equal_test(arguments[0], arguments[1]))
1745 return
1746 else if pname == "!=" then
1747 var res = v.equal_test(arguments[0], arguments[1])
1748 v.ret(v.new_expr("!{res}", ret.as(not null)))
1749 return
1750 else if pname == "<" then
1751 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1752 return
1753 else if pname == ">" then
1754 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1755 return
1756 else if pname == "<=" then
1757 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1758 return
1759 else if pname == ">=" then
1760 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1761 return
1762 else if pname == "to_i" then
1763 v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
1764 return
1765 end
1766 else if cname == "Char" then
1767 if pname == "output" then
1768 v.add("printf(\"%c\", {arguments.first});")
1769 return
1770 else if pname == "object_id" then
1771 v.ret(arguments.first)
1772 return
1773 else if pname == "==" then
1774 v.ret(v.equal_test(arguments[0], arguments[1]))
1775 return
1776 else if pname == "!=" then
1777 var res = v.equal_test(arguments[0], arguments[1])
1778 v.ret(v.new_expr("!{res}", ret.as(not null)))
1779 return
1780 else if pname == "ascii" then
1781 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1782 return
1783 end
1784 else if cname == "NativeString" then
1785 if pname == "[]" then
1786 v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
1787 return
1788 else if pname == "[]=" then
1789 v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
1790 return
1791 else if pname == "copy_to" then
1792 v.add("memcpy({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
1793 return
1794 else if pname == "atoi" then
1795 v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
1796 return
1797 end
1798 else if cname == "NativeArray" then
1799 var elttype = arguments.first.mtype
1800 if pname == "[]" then
1801 v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
1802 return
1803 else if pname == "[]=" then
1804 v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
1805 return
1806 else if pname == "copy_to" then
1807 v.add("memcpy({arguments[1]},{arguments[0]},{arguments[2]}*sizeof({elttype.ctype}));")
1808 return
1809 end
1810 end
1811 if pname == "exit" then
1812 v.add("exit({arguments[1]});")
1813 return
1814 else if pname == "sys" then
1815 v.ret(v.new_expr("glob_sys", ret.as(not null)))
1816 return
1817 else if pname == "calloc_string" then
1818 v.ret(v.new_expr("(char*)GC_MALLOC({arguments[1]})", ret.as(not null)))
1819 return
1820 else if pname == "calloc_array" then
1821 var elttype = arguments.first.mtype.supertype_to(v.compiler.mainmodule,arguments.first.mtype.as(MClassType),v.get_class("ArrayCapable")).as(MGenericType).arguments.first
1822 v.ret(v.new_expr("({elttype.ctype}*)GC_MALLOC({arguments[1]} * sizeof({elttype.ctype}))", ret.as(not null)))
1823 return
1824 else if pname == "object_id" then
1825 v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
1826 return
1827 else if pname == "is_same_type" then
1828 if arguments[0].mtype.ctype == "val*" then
1829 v.ret(v.new_expr("{arguments[0]}->classid == {arguments[1]}->classid", ret.as(not null)))
1830 else
1831 v.ret(v.new_expr("{v.compiler.classid(arguments[0].mtype.as(MClassType))} == {arguments[1]}->classid", ret.as(not null)))
1832 end
1833 return
1834 else if pname == "output_class_name" then
1835 if arguments[0].mtype.ctype == "val*" then
1836 v.add("printf(\"%s\\n\", class_names[{arguments.first}->classid]);")
1837 else
1838 v.add("printf(\"%s\\n\", class_names[{v.compiler.classid(arguments.first.mtype.as(MClassType))}]);")
1839 end
1840 return
1841 else if pname == "native_class_name" then
1842 if arguments[0].mtype.ctype == "val*" then
1843 v.ret(v.new_expr("(char*)(void*)class_names[{arguments.first}->classid]", ret.as(not null)))
1844 else
1845 v.ret(v.new_expr("(char*)(void*)class_names[{v.compiler.classid(arguments.first.mtype.as(MClassType))}]", ret.as(not null)))
1846 end
1847 return
1848 end
1849 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
1850 debug("Not implemented {mpropdef}")
1851 end
1852 end
1853
1854 redef class AExternMethPropdef
1855 redef fun compile_to_c(v, mpropdef, arguments)
1856 do
1857 var externname
1858 var nextern = self.n_extern
1859 if nextern == null then
1860 debug("{mpropdef} need extern name")
1861 return
1862 end
1863 externname = nextern.text.substring(1, nextern.text.length-2)
1864 if location.file != null then
1865 var file = location.file.filename
1866 v.compiler.add_extern(file)
1867 end
1868 var res: nullable RuntimeVariable = null
1869 var ret = mpropdef.msignature.return_mtype
1870 if ret != null then
1871 ret = v.resolve_for(ret, arguments.first)
1872 res = v.new_var(ret)
1873 end
1874
1875 if res == null then
1876 v.add("{externname}({arguments.join(", ")});")
1877 else
1878 v.add("{res} = {externname}({arguments.join(", ")});")
1879 v.ret(res)
1880 end
1881 end
1882 end
1883
1884 redef class AExternInitPropdef
1885 redef fun compile_to_c(v, mpropdef, arguments)
1886 do
1887 var externname
1888 var nextern = self.n_extern
1889 if nextern == null then
1890 debug("{mpropdef} need extern name")
1891 return
1892 end
1893 externname = nextern.text.substring(1, nextern.text.length-2)
1894 if location.file != null then
1895 var file = location.file.filename
1896 v.compiler.add_extern(file)
1897 end
1898 var ret = arguments.first.mtype
1899 var res = v.new_var(ret)
1900
1901 arguments.shift
1902
1903 v.add("{res} = {externname}({arguments.join(", ")});")
1904 v.ret(res)
1905 end
1906 end
1907
1908 redef class AAttrPropdef
1909 redef fun compile_to_c(v, mpropdef, arguments)
1910 do
1911 if arguments.length == 1 then
1912 var res = v.read_attribute(self.mpropdef.mproperty, arguments.first)
1913 v.assign(v.frame.returnvar.as(not null), res)
1914 else
1915 v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
1916 end
1917 end
1918
1919 private fun init_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
1920 do
1921 var nexpr = self.n_expr
1922 if nexpr != null then
1923 var old_frame = v.frame
1924 var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
1925 v.frame = frame
1926 var value = v.expr(nexpr, self.mpropdef.static_mtype)
1927 v.write_attribute(self.mpropdef.mproperty, recv, value)
1928 v.frame = old_frame
1929 end
1930 end
1931 end
1932
1933 redef class AClassdef
1934 private fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1935 do
1936 if mpropdef == self.mfree_init then
1937 var super_inits = self.super_inits
1938 if super_inits != null then
1939 assert arguments.length == 1
1940 for su in super_inits do
1941 v.send(su, arguments)
1942 end
1943 return
1944 end
1945 var recv = arguments.first
1946 var i = 1
1947 # Collect undefined attributes
1948 for npropdef in self.n_propdefs do
1949 if npropdef isa AAttrPropdef and npropdef.n_expr == null then
1950 v.write_attribute(npropdef.mpropdef.mproperty, recv, arguments[i])
1951 i += 1
1952 end
1953 end
1954 else
1955 abort
1956 end
1957 end
1958 end
1959
1960 redef class ADeferredMethPropdef
1961 redef fun compile_to_c(v, mpropdef, arguments)
1962 do
1963 v.add("printf(\"Not implemented {class_name} {mpropdef} at {location.to_s}\\n\");")
1964 v.add("exit(1);")
1965 end
1966
1967 redef fun can_inline do return true
1968 end
1969
1970 redef class AExpr
1971 # Try to compile self as an expression
1972 # Do not call this method directly, use `v.expr' instead
1973 private fun expr(v: GlobalCompilerVisitor): nullable RuntimeVariable
1974 do
1975 debug("Unimplemented expr {class_name}")
1976 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{location.to_s}\\n\");")
1977 var mtype = self.mtype
1978 if mtype == null then
1979 return null
1980 else
1981 var res = v.new_var(mtype)
1982 v.add("/* {res} = NOT YET {class_name} */")
1983 return res
1984 end
1985 end
1986
1987 # Try to compile self as a statement
1988 # Do not call this method directly, use `v.stmt' instead
1989 private fun stmt(v: GlobalCompilerVisitor)
1990 do
1991 var res = expr(v)
1992 if res != null then v.add("{res};")
1993 end
1994
1995 end
1996
1997 redef class ABlockExpr
1998 redef fun stmt(v)
1999 do
2000 for e in self.n_expr do
2001 v.stmt(e)
2002 end
2003 end
2004 end
2005
2006 redef class AVardeclExpr
2007 redef fun stmt(v)
2008 do
2009 var variable = self.variable.as(not null)
2010 var ne = self.n_expr
2011 if ne != null then
2012 var i = v.expr(ne, variable.declared_type)
2013 v.assign(v.variable(variable), i)
2014 end
2015 end
2016 end
2017
2018 redef class AVarExpr
2019 redef fun expr(v)
2020 do
2021 var res = v.variable(self.variable.as(not null))
2022 var mtype = self.mtype.as(not null)
2023 return v.autoadapt(res, mtype)
2024 end
2025 end
2026
2027 redef class AVarAssignExpr
2028 redef fun stmt(v)
2029 do
2030 var variable = self.variable.as(not null)
2031 var i = v.expr(self.n_value, variable.declared_type)
2032 v.assign(v.variable(variable), i)
2033 end
2034 end
2035
2036 redef class AVarReassignExpr
2037 redef fun stmt(v)
2038 do
2039 var variable = self.variable.as(not null)
2040 var vari = v.variable(variable)
2041 var value = v.expr(self.n_value, variable.declared_type)
2042 var res = v.send(reassign_property.mproperty, [vari, value])
2043 assert res != null
2044 v.assign(v.variable(variable), res)
2045 end
2046 end
2047
2048 redef class ASelfExpr
2049 redef fun expr(v)
2050 do
2051 return v.frame.arguments.first
2052 end
2053 end
2054
2055 redef class AContinueExpr
2056 redef fun stmt(v)
2057 do
2058 v.add("goto CONTINUE_{v.escapemark_name(self.escapemark)};")
2059 end
2060 end
2061
2062 redef class ABreakExpr
2063 redef fun stmt(v)
2064 do
2065 v.add("goto BREAK_{v.escapemark_name(self.escapemark)};")
2066 end
2067 end
2068
2069 redef class AReturnExpr
2070 redef fun stmt(v)
2071 do
2072 var nexpr = self.n_expr
2073 if nexpr != null then
2074 var returnvar = v.frame.returnvar.as(not null)
2075 var i = v.expr(nexpr, returnvar.mtype)
2076 v.assign(returnvar, i)
2077 end
2078 v.add("goto {v.frame.returnlabel.as(not null)};")
2079 end
2080 end
2081
2082 redef class AAbortExpr
2083 redef fun stmt(v)
2084 do
2085 v.add_abort("Aborted")
2086 end
2087 end
2088
2089 redef class AIfExpr
2090 redef fun stmt(v)
2091 do
2092 var cond = v.expr_bool(self.n_expr)
2093 v.add("if ({cond})\{")
2094 v.stmt(self.n_then)
2095 v.add("\} else \{")
2096 v.stmt(self.n_else)
2097 v.add("\}")
2098 end
2099 end
2100
2101 redef class AIfexprExpr
2102 redef fun expr(v)
2103 do
2104 var res = v.new_var(self.mtype.as(not null))
2105 var cond = v.expr_bool(self.n_expr)
2106 v.add("if ({cond})\{")
2107 v.assign(res, v.expr(self.n_then, null))
2108 v.add("\} else \{")
2109 v.assign(res, v.expr(self.n_else, null))
2110 v.add("\}")
2111 return res
2112 end
2113 end
2114
2115 redef class ADoExpr
2116 redef fun stmt(v)
2117 do
2118 v.stmt(self.n_block)
2119 var escapemark = self.escapemark
2120 if escapemark != null then
2121 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2122 end
2123 end
2124 end
2125
2126 redef class AWhileExpr
2127 redef fun stmt(v)
2128 do
2129 v.add("for(;;) \{")
2130 var cond = v.expr_bool(self.n_expr)
2131 v.add("if (!{cond}) break;")
2132 v.stmt(self.n_block)
2133 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2134 v.add("\}")
2135 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2136 end
2137 end
2138
2139 redef class ALoopExpr
2140 redef fun stmt(v)
2141 do
2142 v.add("for(;;) \{")
2143 v.stmt(self.n_block)
2144 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2145 v.add("\}")
2146 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2147 end
2148 end
2149
2150 redef class AForExpr
2151 redef fun stmt(v)
2152 do
2153 var cl = v.expr(self.n_expr, null)
2154 var it = v.send(v.get_property("iterator", cl.mtype), [cl])
2155 assert it != null
2156 v.add("for(;;) \{")
2157 var ok = v.send(v.get_property("is_ok", it.mtype), [it])
2158 assert ok != null
2159 v.add("if(!{ok}) break;")
2160 if self.variables.length == 1 then
2161 var i = v.send(v.get_property("item", it.mtype), [it])
2162 assert i != null
2163 v.assign(v.variable(variables.first), i)
2164 else if self.variables.length == 2 then
2165 var i = v.send(v.get_property("key", it.mtype), [it])
2166 assert i != null
2167 v.assign(v.variable(variables[0]), i)
2168 i = v.send(v.get_property("item", it.mtype), [it])
2169 assert i != null
2170 v.assign(v.variable(variables[1]), i)
2171 else
2172 abort
2173 end
2174 v.stmt(self.n_block)
2175 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2176 v.send(v.get_property("next", it.mtype), [it])
2177 v.add("\}")
2178 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2179 end
2180 end
2181
2182 redef class AAssertExpr
2183 redef fun stmt(v)
2184 do
2185 var cond = v.expr_bool(self.n_expr)
2186 v.add("if (!{cond}) \{")
2187 v.stmt(self.n_else)
2188 var nid = self.n_id
2189 if nid != null then
2190 v.add_abort("Assert '{nid.text}' failed")
2191 else
2192 v.add_abort("Assert failed")
2193 end
2194 v.add("\}")
2195 end
2196 end
2197
2198 redef class AOrExpr
2199 redef fun expr(v)
2200 do
2201 var res = v.new_var(self.mtype.as(not null))
2202 var i1 = v.expr_bool(self.n_expr)
2203 v.add("if ({i1}) \{")
2204 v.add("{res} = 1;")
2205 v.add("\} else \{")
2206 var i2 = v.expr_bool(self.n_expr2)
2207 v.add("{res} = {i2};")
2208 v.add("\}")
2209 return res
2210 end
2211 end
2212
2213 redef class AAndExpr
2214 redef fun expr(v)
2215 do
2216 var res = v.new_var(self.mtype.as(not null))
2217 var i1 = v.expr_bool(self.n_expr)
2218 v.add("if (!{i1}) \{")
2219 v.add("{res} = 0;")
2220 v.add("\} else \{")
2221 var i2 = v.expr_bool(self.n_expr2)
2222 v.add("{res} = {i2};")
2223 v.add("\}")
2224 return res
2225 end
2226 end
2227
2228 redef class ANotExpr
2229 redef fun expr(v)
2230 do
2231 var cond = v.expr_bool(self.n_expr)
2232 return v.new_expr("!{cond}", self.mtype.as(not null))
2233 end
2234 end
2235
2236 redef class AOrElseExpr
2237 redef fun expr(v)
2238 do
2239 var res = v.new_var(self.mtype.as(not null))
2240 var i1 = v.expr(self.n_expr, null)
2241 v.add("if ({i1}!=NULL) \{")
2242 v.assign(res, i1)
2243 v.add("\} else \{")
2244 var i2 = v.expr(self.n_expr2, null)
2245 v.assign(res, i2)
2246 v.add("\}")
2247 return res
2248 end
2249 end
2250
2251 redef class AEeExpr
2252 redef fun expr(v)
2253 do
2254 var value1 = v.expr(self.n_expr, null)
2255 var value2 = v.expr(self.n_expr2, null)
2256 return v.equal_test(value1, value2)
2257 end
2258 end
2259
2260 redef class AIntExpr
2261 redef fun expr(v)
2262 do
2263 return v.new_expr("{self.n_number.text}", self.mtype.as(not null))
2264 end
2265 end
2266
2267 redef class AFloatExpr
2268 redef fun expr(v)
2269 do
2270 return v.new_expr("{self.n_float.text}", self.mtype.as(not null))
2271 end
2272 end
2273
2274 redef class ACharExpr
2275 redef fun expr(v)
2276 do
2277 return v.new_expr("{self.n_char.text}", self.mtype.as(not null))
2278 end
2279 end
2280
2281 redef class AArrayExpr
2282 redef fun expr(v)
2283 do
2284 var mtype = self.mtype.as(MGenericType).arguments.first
2285 var array = new Array[RuntimeVariable]
2286 for nexpr in self.n_exprs.n_exprs do
2287 var i = v.expr(nexpr, mtype)
2288 array.add(i)
2289 end
2290 return v.array_instance(array, mtype)
2291 end
2292 end
2293
2294 redef class AStringFormExpr
2295 redef fun expr(v)
2296 do
2297 return v.string_instance(self.value.as(not null))
2298 end
2299 end
2300
2301 redef class ASuperstringExpr
2302 redef fun expr(v)
2303 do
2304 var array = new Array[RuntimeVariable]
2305 for ne in self.n_exprs do
2306 if ne isa AStringFormExpr and ne.value == "" then continue # skip empty sub-strings
2307 var i = v.expr(ne, null)
2308 array.add(i)
2309 end
2310 var a = v.array_instance(array, v.object_type)
2311 var res = v.send(v.get_property("to_s", a.mtype), [a])
2312 return res
2313 end
2314 end
2315
2316 redef class ACrangeExpr
2317 redef fun expr(v)
2318 do
2319 var i1 = v.expr(self.n_expr, null)
2320 var i2 = v.expr(self.n_expr2, null)
2321 var res = v.init_instance(self.mtype.as(MClassType))
2322 var it = v.send(v.get_property("init", res.mtype), [res, i1, i2])
2323 v.check_init_instance(res)
2324 return res
2325 end
2326 end
2327
2328 redef class AOrangeExpr
2329 redef fun expr(v)
2330 do
2331 var i1 = v.expr(self.n_expr, null)
2332 var i2 = v.expr(self.n_expr2, null)
2333 var res = v.init_instance(self.mtype.as(MClassType))
2334 var it = v.send(v.get_property("without_last", res.mtype), [res, i1, i2])
2335 v.check_init_instance(res)
2336 return res
2337 end
2338 end
2339
2340 redef class ATrueExpr
2341 redef fun expr(v)
2342 do
2343 return v.new_expr("1", self.mtype.as(not null))
2344 end
2345 end
2346
2347 redef class AFalseExpr
2348 redef fun expr(v)
2349 do
2350 return v.new_expr("0", self.mtype.as(not null))
2351 end
2352 end
2353
2354 redef class ANullExpr
2355 redef fun expr(v)
2356 do
2357 var res = v.new_expr("NULL", self.mtype.as(not null))
2358 return res
2359 end
2360 end
2361
2362 redef class AIsaExpr
2363 redef fun expr(v)
2364 do
2365 var i = v.expr(self.n_expr, null)
2366 return v.type_test(i, self.cast_type.as(not null))
2367 end
2368 end
2369
2370 redef class AAsCastExpr
2371 redef fun expr(v)
2372 do
2373 var i = v.expr(self.n_expr, null)
2374 var cond = v.type_test(i, self.mtype.as(not null))
2375 v.add("if (!{cond}) \{")
2376 v.add_abort("Cast failed")
2377 v.add("\}")
2378 return i
2379 end
2380 end
2381
2382 redef class AAsNotnullExpr
2383 redef fun expr(v)
2384 do
2385 var i = v.expr(self.n_expr, null)
2386 v.add("if ({i} == NULL) \{")
2387 v.add_abort("Cast failed")
2388 v.add("\}")
2389 return i
2390 end
2391 end
2392
2393 redef class AParExpr
2394 redef fun expr(v)
2395 do
2396 return v.expr(self.n_expr, null)
2397 end
2398 end
2399
2400 redef class AOnceExpr
2401 redef fun expr(v)
2402 do
2403 var mtype = self.mtype.as(not null)
2404 var name = v.get_name("varonce")
2405 var guard = v.get_name(name + "_guard")
2406 v.add_decl("static {mtype.ctype} {name};")
2407 v.add_decl("static int {guard};")
2408 var res = v.new_var(mtype)
2409 v.add("if ({guard}) \{")
2410 v.add("{res} = {name};")
2411 v.add("\} else \{")
2412 var i = v.expr(self.n_expr, mtype)
2413 v.add("{res} = {i};")
2414 v.add("{name} = {res};")
2415 v.add("{guard} = 1;")
2416 v.add("\}")
2417 return res
2418 end
2419 end
2420
2421 redef class ASendExpr
2422 redef fun expr(v)
2423 do
2424 var recv = v.expr(self.n_expr, null)
2425 var args = [recv]
2426 for a in self.raw_arguments.as(not null) do
2427 args.add(v.expr(a, null))
2428 end
2429 var mproperty = self.mproperty.as(not null)
2430 return v.send(mproperty, args)
2431 end
2432 end
2433
2434 redef class ASendReassignFormExpr
2435 redef fun stmt(v)
2436 do
2437 var recv = v.expr(self.n_expr, null)
2438 var args = [recv]
2439 for a in self.raw_arguments.as(not null) do
2440 args.add(v.expr(a, null))
2441 end
2442 var value = v.expr(self.n_value, null)
2443
2444 var mproperty = self.mproperty.as(not null)
2445 var left = v.send(mproperty, args)
2446 assert left != null
2447
2448 var res = v.send(reassign_property.mproperty, [left, value])
2449 assert res != null
2450
2451 args.add(res)
2452 v.send(self.write_mproperty.as(not null), args)
2453 end
2454 end
2455
2456 redef class ASuperExpr
2457 redef fun expr(v)
2458 do
2459 var recv = v.frame.arguments.first
2460 var args = [recv]
2461 for a in self.n_args.n_exprs do
2462 args.add(v.expr(a, null))
2463 end
2464 if args.length == 1 then
2465 args = v.frame.arguments
2466 end
2467
2468 var mproperty = self.mproperty
2469 if mproperty != null then
2470 if mproperty.intro.msignature.arity == 0 then
2471 args = [recv]
2472 end
2473 # Super init call
2474 var res = v.send(mproperty, args)
2475 return res
2476 end
2477
2478 # stantard call-next-method
2479 var mpropdef = v.frame.mpropdef
2480 # FIXME: we do not want an ugly static call!
2481 var mpropdefs = mpropdef.mproperty.lookup_super_definitions(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
2482 if mpropdefs.length != 1 then
2483 v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
2484 debug("MPRODFEFS for super {mpropdef} for {recv}: {mpropdefs.join(", ")}")
2485 end
2486 mpropdef = mpropdefs.first
2487 assert mpropdef isa MMethodDef
2488 var res = v.call(mpropdef, recv.mtype.as(MClassType), args)
2489 return res
2490 end
2491 end
2492
2493 redef class ANewExpr
2494 redef fun expr(v)
2495 do
2496 var mproperty = self.mproperty.as(not null)
2497 var mtype = self.mtype.as(MClassType)
2498 var recv
2499 var ctype = mtype.ctype
2500 if ctype == "val*" then
2501 recv = v.init_instance(mtype)
2502 else if ctype == "void*" then
2503 recv = v.new_expr("NULL/*special!*/", mtype)
2504 else
2505 debug("cannot new {mtype}")
2506 abort
2507 end
2508 var args = [recv]
2509 for a in self.n_args.n_exprs do
2510 args.add(v.expr(a, null))
2511 end
2512 var res2 = v.send(mproperty, args)
2513 if res2 != null then
2514 #self.debug("got {res2} from {mproperty}. drop {recv}")
2515 return res2
2516 end
2517 v.check_init_instance(recv)
2518 return recv
2519 end
2520 end
2521
2522 redef class AAttrExpr
2523 redef fun expr(v)
2524 do
2525 var recv = v.expr(self.n_expr, null)
2526 var mproperty = self.mproperty.as(not null)
2527 return v.read_attribute(mproperty, recv)
2528 end
2529 end
2530
2531 redef class AAttrAssignExpr
2532 redef fun stmt(v)
2533 do
2534 var recv = v.expr(self.n_expr, null)
2535 var i = v.expr(self.n_value, null)
2536 var mproperty = self.mproperty.as(not null)
2537 v.write_attribute(mproperty, recv, i)
2538 end
2539 end
2540
2541 redef class AAttrReassignExpr
2542 redef fun stmt(v)
2543 do
2544 var recv = v.expr(self.n_expr, null)
2545 var value = v.expr(self.n_value, null)
2546 var mproperty = self.mproperty.as(not null)
2547 var attr = v.read_attribute(mproperty, recv)
2548 var res = v.send(reassign_property.mproperty, [attr, value])
2549 assert res != null
2550 v.write_attribute(mproperty, recv, res)
2551 end
2552 end
2553
2554 redef class AIssetAttrExpr
2555 end
2556
2557 redef class ADebugTypeExpr
2558 redef fun stmt(v)
2559 do
2560 # do nothing
2561 end
2562 end