nitg-sep: generic subtyping using heterogeneous tables
[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 protected 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 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[AbstractRuntimeFunction] = new List[AbstractRuntimeFunction]
284
285 # runtime_functions already seen (todo or done)
286 private var seen: HashSet[AbstractRuntimeFunction] = new HashSet[AbstractRuntimeFunction]
287 fun todo(m: AbstractRuntimeFunction)
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 writable = 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 protected 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 MParameterType
544 redef fun c_name
545 do
546 var res = self.c_name_cache
547 if res != null then return res
548 res = "FT{self.rank}"
549 self.c_name_cache = res
550 return res
551 end
552 end
553
554 redef class MNullableType
555 redef fun c_name
556 do
557 var res = self.c_name_cache
558 if res != null then return res
559 res = "nullable_{self.mtype.c_name}"
560 self.c_name_cache = res
561 return res
562 end
563 end
564
565 # A C function associated to a Nit method
566 # Because of customization, a given Nit method can be compiler more that once
567 abstract class AbstractRuntimeFunction
568 # The associated Nit method
569 var mmethoddef: MMethodDef
570
571 # The mangled c name of the runtime_function
572 # Subclasses should redefine `build_c_name` instead
573 fun c_name: String
574 do
575 var res = self.c_name_cache
576 if res != null then return res
577 res = self.build_c_name
578 self.c_name_cache = res
579 return res
580 end
581
582 # Non cached version of `c_name`
583 protected fun build_c_name: String is abstract
584
585 private var c_name_cache: nullable String = null
586
587 # Implements a call of the runtime_function
588 # May inline the body or generate a C function call
589 fun call(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
590
591 # Generate the code for the RuntimeFunction
592 # Warning: compile more than once compilation makes CC unhappy
593 fun compile_to_c(compiler: GlobalCompiler) is abstract
594 end
595
596 # A runtime function customized on a specific monomrph receiver type
597 private class CustomizedRuntimeFunction
598 super AbstractRuntimeFunction
599
600 # The considered reciever
601 # (usually is a live type but no strong guarantee)
602 var recv: MClassType
603
604 init(mmethoddef: MMethodDef, recv: MClassType)
605 do
606 super(mmethoddef)
607 self.recv = recv
608 end
609
610 redef fun build_c_name: String
611 do
612 var res = self.c_name_cache
613 if res != null then return res
614 if self.mmethoddef.mclassdef.bound_mtype == self.recv then
615 res = self.mmethoddef.c_name
616 else
617 res = "{mmethoddef.c_name}__{recv.c_name}"
618 end
619 self.c_name_cache = res
620 return res
621 end
622
623 redef fun ==(o)
624 # used in the compiler worklist
625 do
626 if not o isa CustomizedRuntimeFunction then return false
627 if self.mmethoddef != o.mmethoddef then return false
628 if self.recv != o.recv then return false
629 return true
630 end
631
632 redef fun hash
633 # used in the compiler work-list
634 do
635 var res = self.mmethoddef.hash + self.recv.hash
636 return res
637 end
638
639 redef fun to_s
640 do
641 if self.mmethoddef.mclassdef.bound_mtype == self.recv then
642 return self.mmethoddef.to_s
643 else
644 return "{self.mmethoddef}@{self.recv}"
645 end
646 end
647
648 # compile the code customized for the reciever
649 redef fun compile_to_c(compiler)
650 do
651 var recv = self.recv
652 var mmethoddef = self.mmethoddef
653 if not recv.is_subtype(compiler.mainmodule, null, mmethoddef.mclassdef.bound_mtype) then
654 print("problem: why do we compile {self} for {recv}?")
655 abort
656 end
657
658 var v = new GlobalCompilerVisitor(compiler)
659 var selfvar = new RuntimeVariable("self", recv, recv)
660 if compiler.runtime_type_analysis.live_types.has(recv) then
661 selfvar.is_exact = true
662 end
663 var arguments = new Array[RuntimeVariable]
664 var frame = new Frame(v, mmethoddef, recv, arguments)
665 v.frame = frame
666
667 var sig = new Buffer
668 var comment = new Buffer
669 var ret = mmethoddef.msignature.return_mtype
670 if ret != null then
671 ret = v.resolve_for(ret, selfvar)
672 sig.append("{ret.ctype} ")
673 else if mmethoddef.mproperty.is_new then
674 ret = recv
675 sig.append("{ret.ctype} ")
676 else
677 sig.append("void ")
678 end
679 sig.append(self.c_name)
680 sig.append("({recv.ctype} self")
681 comment.append("(self: {recv}")
682 arguments.add(selfvar)
683 for i in [0..mmethoddef.msignature.arity[ do
684 var mtype = mmethoddef.msignature.mparameters[i].mtype
685 if i == mmethoddef.msignature.vararg_rank then
686 mtype = v.get_class("Array").get_mtype([mtype])
687 end
688 mtype = v.resolve_for(mtype, selfvar)
689 comment.append(", {mtype}")
690 sig.append(", {mtype.ctype} p{i}")
691 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
692 arguments.add(argvar)
693 end
694 sig.append(")")
695 comment.append(")")
696 if ret != null then
697 comment.append(": {ret}")
698 end
699 compiler.header.add_decl("{sig};")
700
701 v.add_decl("/* method {self} for {comment} */")
702 v.add_decl("{sig} \{")
703 #v.add("printf(\"method {self} for {comment}\\n\");")
704 if ret != null then
705 frame.returnvar = v.new_var(ret)
706 end
707 frame.returnlabel = v.get_name("RET_LABEL")
708
709 mmethoddef.compile_inside_to_c(v, arguments)
710
711 v.add("{frame.returnlabel.as(not null)}:;")
712 if ret != null then
713 v.add("return {frame.returnvar.as(not null)};")
714 end
715 v.add("\}")
716 end
717
718 redef fun call(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
719 do
720 var ret = self.mmethoddef.msignature.return_mtype
721 if self.mmethoddef.mproperty.is_new then
722 ret = recv
723 end
724 if ret != null then
725 ret = v.resolve_for(ret, arguments.first)
726 end
727 if self.mmethoddef.can_inline(v) then
728 var frame = new Frame(v, self.mmethoddef, self.recv, arguments)
729 frame.returnlabel = v.get_name("RET_LABEL")
730 if ret != null then
731 frame.returnvar = v.new_var(ret)
732 end
733 var old_frame = v.frame
734 v.frame = frame
735 v.add("\{ /* Inline {self} ({arguments.join(",")}) */")
736 self.mmethoddef.compile_inside_to_c(v, arguments)
737 v.add("{frame.returnlabel.as(not null)}:(void)0;")
738 v.add("\}")
739 v.frame = old_frame
740 return frame.returnvar
741 end
742 v.adapt_signature(self.mmethoddef, arguments)
743 v.compiler.todo(self)
744 if ret == null then
745 v.add("{self.c_name}({arguments.join(",")});")
746 return null
747 else
748 var res = v.new_var(ret)
749 v.add("{res} = {self.c_name}({arguments.join(",")});")
750 return res
751 end
752 end
753 end
754
755 # A runtime variable hold a runtime value in C.
756 # Runtime variables are associated to Nit local variables and intermediate results in Nit expressions.
757 #
758 # 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.
759 class RuntimeVariable
760 # The name of the variable in the C code
761 var name: String
762
763 # The static type of the variable (as declard in C)
764 var mtype: MType
765
766 # The current casted type of the variable (as known in Nit)
767 var mcasttype: MType writable
768
769 # If the variable exaclty a mcasttype?
770 # false (usual value) means that the variable is a mcasttype or a subtype.
771 var is_exact: Bool writable = false
772
773 init(name: String, mtype: MType, mcasttype: MType)
774 do
775 self.name = name
776 self.mtype = mtype
777 self.mcasttype = mcasttype
778 assert not mtype.need_anchor
779 assert not mcasttype.need_anchor
780 end
781
782 redef fun to_s do return name
783
784 redef fun inspect
785 do
786 var exact_str
787 if self.is_exact then
788 exact_str = " exact"
789 else
790 exact_str = ""
791 end
792 var type_str
793 if self.mtype == self.mcasttype then
794 type_str = "{mtype}{exact_str}"
795 else
796 type_str = "{mtype}({mcasttype}{exact_str})"
797 end
798 return "<{name}:{type_str}>"
799 end
800 end
801
802 # A visitor on the AST of property definition that generate the C code.
803 # Because of inlining, a visitor can visit more than one property.
804 class GlobalCompilerVisitor
805 # The associated compiler
806 var compiler: GlobalCompiler
807
808 init(compiler: GlobalCompiler)
809 do
810 self.compiler = compiler
811 compiler.visitors.add(self)
812 end
813
814 # Alias for self.compiler.mainmodule.object_type
815 fun object_type: MClassType do return self.compiler.mainmodule.object_type
816
817 # Alias for self.compiler.mainmodule.bool_type
818 fun bool_type: MClassType do return self.compiler.mainmodule.bool_type
819
820 # Force to get the primitive class named `name' or abort
821 fun get_class(name: String): MClass
822 do
823 return self.compiler.mainmodule.get_primitive_class(name)
824 end
825
826 # Force to get the primitive property named `name' in the instance `recv' or abort
827 fun get_property(name: String, recv: MType): MMethod
828 do
829 return self.compiler.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, recv, self.compiler.mainmodule)
830 end
831
832 # The current Frame
833 var frame: nullable Frame writable
834
835 # Anchor a type to the main module and the current receiver
836 fun anchor(mtype: MType): MType
837 do
838 if not mtype.need_anchor then return mtype
839 #debug("anchor {mtype} to {self.reciever.as(not null)}:{self.reciever.mtype}")
840 return mtype.anchor_to(self.compiler.mainmodule, self.frame.receiver)
841 end
842
843 # Add a line in the main part of the generated C
844 fun add(s: String)
845 do
846 self.lines.add(s)
847 end
848
849 # Add a line in the
850 # (used for local or global declaration)
851 fun add_decl(s: String)
852 do
853 self.decl_lines.add(s)
854 end
855
856 private var lines: List[String] = new List[String]
857 private var decl_lines: List[String] = new List[String]
858
859 # The current visited AST node
860 var current_node: nullable AExpr = null
861
862 # Compile an expression an return its result
863 # `mtype` is the expected return type, pass null if no specific type is expected.
864 fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable
865 do
866 var old = self.current_node
867 self.current_node = nexpr
868 var res = nexpr.expr(self).as(not null)
869 if mtype != null then
870 mtype = self.anchor(mtype)
871 res = self.autobox(res, mtype)
872 end
873 self.current_node = old
874 return res
875 end
876
877 # Unsafely cast a value to a new type
878 # ie the result share the same C variable but my have a different mcasttype
879 # NOTE: if the adaptation is useless then `value' is returned as it.
880 # ENSURE: return.name == value.name
881 fun autoadapt(value: RuntimeVariable, mtype: MType): RuntimeVariable
882 do
883 mtype = self.anchor(mtype)
884 var valmtype = value.mcasttype
885 if valmtype.is_subtype(self.compiler.mainmodule, null, mtype) then
886 return value
887 end
888
889 if valmtype isa MNullableType and valmtype.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
890 var res = new RuntimeVariable(value.name, valmtype, valmtype.mtype)
891 return res
892 else
893 var res = new RuntimeVariable(value.name, valmtype, mtype)
894 return res
895 end
896 end
897
898 # Box or unbox a value to another type iff a C type conversion is needed
899 # ENSURE: result.mtype.ctype == mtype.ctype
900 fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable
901 do
902 if value.mtype.ctype == mtype.ctype then
903 return value
904 else if value.mtype.ctype == "val*" then
905 return self.new_expr("((struct {mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
906 else if mtype.ctype == "val*" then
907 var valtype = value.mtype.as(MClassType)
908 var res = self.new_var(mtype)
909 if not compiler.runtime_type_analysis.live_types.has(valtype) then
910 self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
911 self.add("printf(\"Dead code executed!\\n\"); exit(1);")
912 return res
913 end
914 self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
915 return res
916 else
917 # Bad things will appen!
918 var res = self.new_var(mtype)
919 self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
920 self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); exit(1);")
921 return res
922 end
923 end
924
925 # Correctly assign a left and a right value
926 # Boxing and unboxing is performed if required
927 fun assign(left, right: RuntimeVariable)
928 do
929 right = self.autobox(right, left.mtype)
930 self.add("{left} = {right};")
931 end
932
933
934 # Alias for `self.expr(nexpr, self.bool_type)'
935 fun expr_bool(nexpr: AExpr): RuntimeVariable
936 do
937 return expr(nexpr, bool_type)
938 end
939
940 # Compile a statement (if any)
941 fun stmt(nexpr: nullable AExpr)
942 do
943 if nexpr == null then return
944 var old = self.current_node
945 self.current_node = nexpr
946 nexpr.stmt(self)
947 self.current_node = old
948 end
949
950 # Safely show a debug message on the current node and repeat the message in the C code as a comment
951 fun debug(message: String)
952 do
953 var node = self.current_node
954 if node == null then
955 print "?: {message}"
956 else
957 node.debug(message)
958 end
959 self.add("/* DEBUG: {message} */")
960 end
961
962 # Return a new uninitialized local runtime_variable
963 fun new_var(mtype: MType): RuntimeVariable
964 do
965 mtype = self.anchor(mtype)
966 var name = self.get_name("var")
967 var res = new RuntimeVariable(name, mtype, mtype)
968 self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
969 return res
970 end
971
972 # Return a new local runtime_variable initialized with the C expression `cexpr'.
973 fun new_expr(cexpr: String, mtype: MType): RuntimeVariable
974 do
975 var res = new_var(mtype)
976 self.add("{res} = {cexpr};")
977 return res
978 end
979
980 # Return the local runtime_variable associated to a Nit local variable
981 fun variable(variable: Variable): RuntimeVariable
982 do
983 if self.variables.has_key(variable) then
984 return self.variables[variable]
985 else
986 var name = self.get_name("var_{variable.name}")
987 var mtype = variable.declared_type.as(not null)
988 mtype = self.anchor(mtype)
989 var res = new RuntimeVariable(name, mtype, mtype)
990 self.add_decl("{mtype.ctype} {name} /* var {variable}: {mtype} */;")
991 self.variables[variable] = res
992 return res
993 end
994 end
995
996 private var variables: HashMap[Variable, RuntimeVariable] = new HashMap[Variable, RuntimeVariable]
997
998 # Return an unique and stable identifier associated with an escapemark
999 fun escapemark_name(e: nullable EscapeMark): String
1000 do
1001 assert e != null
1002 if escapemark_names.has_key(e) then return escapemark_names[e]
1003 var name = e.name
1004 if name == null then name = "label"
1005 name = get_name(name)
1006 escapemark_names[e] = name
1007 return name
1008 end
1009
1010 private var escapemark_names = new HashMap[EscapeMark, String]
1011
1012 # Return a new name based on `s' and unique in the visitor
1013 fun get_name(s: String): String
1014 do
1015 if not self.names.has(s) then
1016 self.names.add(s)
1017 return s
1018 end
1019 var i = self.last + 1
1020 loop
1021 var s2 = s + i.to_s
1022 if not self.names.has(s2) then
1023 self.last = i
1024 self.names.add(s2)
1025 return s2
1026 end
1027 i = i + 1
1028 end
1029 end
1030
1031 private var last: Int = 0
1032
1033 private var names: HashSet[String] = new HashSet[String]
1034
1035 # Generate a return with the value `s'
1036 fun ret(s: RuntimeVariable)
1037 do
1038 self.assign(self.frame.returnvar.as(not null), s)
1039 self.add("goto {self.frame.returnlabel.as(not null)};")
1040 end
1041
1042 # The runtime types that are acceptable for a given receiver.
1043 fun collect_types(recv: RuntimeVariable): Array[MClassType]
1044 do
1045 var mtype = recv.mcasttype
1046 if recv.is_exact then
1047 assert mtype isa MClassType
1048 assert self.compiler.runtime_type_analysis.live_types.has(mtype)
1049 var types = [mtype]
1050 return types
1051 end
1052 var cache = self.compiler.collect_types_cache
1053 if cache.has_key(mtype) then
1054 return cache[mtype]
1055 end
1056 var types = new Array[MClassType]
1057 var mainmodule = self.compiler.mainmodule
1058 for t in self.compiler.runtime_type_analysis.live_types do
1059 if not t.is_subtype(mainmodule, null, mtype) then continue
1060 types.add(t)
1061 end
1062 cache[mtype] = types
1063 return types
1064 end
1065
1066 fun resolve_for(mtype: MType, recv: RuntimeVariable): MType
1067 do
1068 if not mtype.need_anchor then return mtype
1069 #debug("resolve for {mtype} to {recv}:{recv.mcasttype}(declared as {recv.mtype}) (in {self.reciever.to_s}:{self.reciever.mtype})")
1070 var res = mtype.resolve_for(recv.mcasttype, self.frame.receiver, self.compiler.mainmodule, true)
1071 return res
1072 end
1073
1074 # Generate a polymorphic send for the method `m' and the arguments `args'
1075 fun send(m: MMethod, args: Array[RuntimeVariable]): nullable RuntimeVariable
1076 do
1077 var types = self.collect_types(args.first)
1078
1079 var res: nullable RuntimeVariable
1080 var ret = m.intro.msignature.return_mtype
1081 if m.is_new then
1082 ret = args.first.mtype
1083 res = self.new_var(ret)
1084 else if ret == null then
1085 res = null
1086 else
1087 ret = self.resolve_for(ret, args.first)
1088 res = self.new_var(ret)
1089 end
1090
1091 if types.is_empty then
1092 self.add("/*BUG: no live types for {args.first.inspect} . {m}*/")
1093 return res
1094 end
1095 self.add("/* send {m} on {args.first.inspect} */")
1096 if args.first.mtype.ctype != "val*" then
1097 var propdefs = m.lookup_definitions(self.compiler.mainmodule, args.first.mtype)
1098 if propdefs.length == 0 then
1099 self.add("/* skip, no method {m} */")
1100 return res
1101 end
1102 assert propdefs.length == 1
1103 var propdef = propdefs.first
1104 var res2 = self.call(propdef, args.first.mtype.as(MClassType), args)
1105 if res != null then self.assign(res, res2.as(not null))
1106 return res
1107 end
1108 if args.first.mcasttype isa MNullableType then
1109 # The reciever is potentially null, so we have to 3 cases: ==, != or NullPointerException
1110 self.add("if ({args.first} == NULL) \{ /* Special null case */")
1111 if m.name == "==" then
1112 assert res != null
1113 if args[1].mcasttype isa MNullableType then
1114 self.add("{res} = ({args[1]} == NULL);")
1115 else if args[1].mcasttype isa MNullType then
1116 self.add("{res} = 1; /* is null */")
1117 else
1118 self.add("{res} = 0; /* {args[1].inspect} cannot be null */")
1119 end
1120 else if m.name == "!=" then
1121 assert res != null
1122 if args[1].mcasttype isa MNullableType then
1123 self.add("{res} = ({args[1]} != NULL);")
1124 else if args[1].mcasttype isa MNullType then
1125 self.add("{res} = 0; /* is null */")
1126 else
1127 self.add("{res} = 1; /* {args[1].inspect} cannot be null */")
1128 end
1129 else
1130 self.add_abort("Reciever is null")
1131 end
1132 self.add "\} else"
1133 end
1134 self.add("switch({args.first}->classid) \{")
1135 var last = types.last
1136 var defaultpropdef: nullable MMethodDef = null
1137 for t in types do
1138 var propdefs = m.lookup_definitions(self.compiler.mainmodule, t)
1139 if propdefs.length == 0 then
1140 self.add("/* skip {t}, no method {m} */")
1141 continue
1142 end
1143 if propdefs.length > 1 then
1144 self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first")
1145 end
1146 var propdef = propdefs.first
1147 if propdef.mclassdef.mclass.name == "Object" and t.ctype == "val*" then
1148 defaultpropdef = propdef
1149 continue
1150 end
1151 if not self.compiler.hardening and t == last and defaultpropdef == null then
1152 self.add("default: /* test {t} */")
1153 else
1154 self.add("case {self.compiler.classid(t)}: /* test {t} */")
1155 end
1156 var res2 = self.call(propdef, t, args)
1157 if res != null then self.assign(res, res2.as(not null))
1158 self.add "break;"
1159 end
1160 if defaultpropdef != null then
1161 self.add("default: /* default is Object */")
1162 var res2 = self.call(defaultpropdef, defaultpropdef.mclassdef.bound_mtype, args)
1163 if res != null then self.assign(res, res2.as(not null))
1164 else if self.compiler.hardening then
1165 self.add("default: /* bug */")
1166 self.bugtype(args.first)
1167 end
1168 self.add("\}")
1169 return res
1170 end
1171
1172 # Generate a monomorphic send for the method `m', the type `t' and the arguments `args'
1173 fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable
1174 do
1175 assert t isa MClassType
1176 var propdefs = m.lookup_definitions(self.compiler.mainmodule, t)
1177 if propdefs.length == 0 then
1178 abort
1179 end
1180 if propdefs.length > 1 then
1181 self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first")
1182 end
1183 var propdef = propdefs.first
1184 return self.call(propdef, t, args)
1185 end
1186
1187 fun check_valid_reciever(recvtype: MClassType)
1188 do
1189 if self.compiler.runtime_type_analysis.live_types.has(recvtype) or recvtype.mclass.name == "Object" then return
1190 print "{recvtype} is not a live type"
1191 abort
1192 end
1193
1194 # Generate a static call on a method definition
1195 fun call(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
1196 do
1197 check_valid_reciever(recvtype)
1198 #debug("call {m} on {recvtype} on {args.first}:{args.first.mtype}")
1199 if m.mclassdef.mclass.name == "Object" and recvtype.ctype == "val*" then
1200 recvtype = m.mclassdef.bound_mtype
1201 end
1202 var recv = self.autobox(args.first, recvtype)
1203 recv = self.autoadapt(recv, recvtype)
1204
1205 var vararg_rank = m.msignature.vararg_rank
1206 if vararg_rank >= 0 then
1207 assert args.length >= m.msignature.arity + 1 # because of self
1208 var rawargs = args
1209 args = new Array[RuntimeVariable]
1210
1211 args.add(rawargs.first) # recv
1212
1213 for i in [0..vararg_rank[ do
1214 args.add(rawargs[i+1])
1215 end
1216
1217 var vararg_lastrank = vararg_rank + rawargs.length-1-m.msignature.arity
1218 var vararg = new Array[RuntimeVariable]
1219 for i in [vararg_rank..vararg_lastrank] do
1220 vararg.add(rawargs[i+1])
1221 end
1222 # FIXME: its it to late to determine the vararg type, this should have been done during a previous analysis
1223 var elttype = m.msignature.mparameters[vararg_rank].mtype
1224 elttype = self.resolve_for(elttype, recv)
1225 args.add(self.array_instance(vararg, elttype))
1226
1227 for i in [vararg_lastrank+1..rawargs.length-1[ do
1228 args.add(rawargs[i+1])
1229 end
1230 else
1231 args = args.to_a
1232 end
1233 if args.length != m.msignature.arity + 1 then # because of self
1234 add("printf(\"NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.\\n\"); exit(1);")
1235 debug("NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.")
1236 return null
1237 end
1238
1239 args.first = recv
1240 var rm = new CustomizedRuntimeFunction(m, recvtype)
1241 return rm.call(self, args)
1242 end
1243
1244 fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
1245 do
1246 var recv = args.first
1247 for i in [0..m.msignature.arity[ do
1248 var t = m.msignature.mparameters[i].mtype
1249 if i == m.msignature.vararg_rank then
1250 t = args[i+1].mtype
1251 end
1252 t = self.resolve_for(t, recv)
1253 args[i+1] = self.autobox(args[i+1], t)
1254 end
1255 end
1256
1257 fun bugtype(recv: RuntimeVariable)
1258 do
1259 if recv.mtype.ctype != "val*" then return
1260 self.add("fprintf(stderr, \"BTD BUG: Dynamic type is %s, static type is %s\\n\", class_names[{recv}->classid], \"{recv.mcasttype}\");")
1261 end
1262
1263 # Generate a polymorphic attribute read
1264 fun read_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable
1265 do
1266 var types = self.collect_types(recv)
1267
1268 var ret = a.intro.static_mtype.as(not null)
1269 ret = self.resolve_for(ret, recv)
1270 var res = self.new_var(ret)
1271
1272 if types.is_empty then
1273 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1274 return res
1275 end
1276 self.add("/* read {a} on {recv.inspect} */")
1277 self.add("switch({recv}->classid) \{")
1278 var last = types.last
1279 for t in types do
1280 if not self.compiler.hardening and t == last then
1281 self.add("default: /*{self.compiler.classid(t)}*/")
1282 else
1283 self.add("case {self.compiler.classid(t)}:")
1284 end
1285 var recv2 = self.autoadapt(recv, t)
1286 var ta = a.intro.static_mtype.as(not null)
1287 ta = self.resolve_for(ta, recv2)
1288 var res2 = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
1289 if not ta isa MNullableType then
1290 if ta.ctype == "val*" then
1291 self.add("if ({res2} == NULL) \{")
1292 self.add_abort("Uninitialized attribute {a.name}")
1293 self.add("\}")
1294 else
1295 self.add("/*NOTYET isset on primitive attributes*/")
1296 end
1297 end
1298 self.assign(res, res2)
1299 self.add("break;")
1300 end
1301 if self.compiler.hardening then
1302 self.add("default: /* Bug */")
1303 self.bugtype(recv)
1304 end
1305 self.add("\}")
1306
1307 return res
1308 end
1309
1310 # Generate a polymorphic attribute write
1311 fun write_attribute(a: MAttribute, recv: RuntimeVariable, value: RuntimeVariable)
1312 do
1313 var types = self.collect_types(recv)
1314
1315 if types.is_empty then
1316 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1317 return
1318 end
1319 self.add("/* write {a} on {recv.inspect} */")
1320 self.add("switch({recv}->classid) \{")
1321 var last = types.last
1322 for t in types do
1323 if not self.compiler.hardening and t == last then
1324 self.add("default: /*{self.compiler.classid(t)}*/")
1325 else
1326 self.add("case {self.compiler.classid(t)}:")
1327 end
1328 var recv2 = self.autoadapt(recv, t)
1329 var ta = a.intro.static_mtype.as(not null)
1330 ta = self.resolve_for(ta, recv2)
1331 self.add("((struct {t.c_name}*){recv})->{a.intro.c_name} = {self.autobox(value, ta)};")
1332 self.add("break;")
1333 end
1334 if self.compiler.hardening then
1335 self.add("default: /* Bug*/")
1336 self.bugtype(recv)
1337 end
1338 self.add("\}")
1339 end
1340
1341 # Generate a alloc-instance + init-attributes
1342 fun init_instance(mtype: MClassType): RuntimeVariable
1343 do
1344 mtype = self.anchor(mtype).as(MClassType)
1345 if not self.compiler.runtime_type_analysis.live_types.has(mtype) then
1346 debug "problem: {mtype} was detected dead"
1347 end
1348 var res = self.new_expr("NEW_{mtype.c_name}()", mtype)
1349 res.is_exact = true
1350 return res
1351 end
1352
1353 # Generate a polymorphic subtype test
1354 fun type_test(value: RuntimeVariable, mtype: MType): RuntimeVariable
1355 do
1356 mtype = self.anchor(mtype)
1357 var types = self.collect_types(value)
1358
1359 var res = self.new_var(bool_type)
1360
1361 self.add("/* isa {mtype} on {value.inspect} */")
1362 if value.mcasttype isa MNullableType then
1363 self.add("if ({value} == NULL) \{")
1364 if mtype isa MNullableType then
1365 self.add("{res} = 1; /* isa {mtype} */")
1366 else
1367 self.add("{res} = 0; /* not isa {mtype} */")
1368 end
1369 self.add("\} else ")
1370 end
1371 self.add("switch({value}->classid) \{")
1372 for t in types do
1373 if t.is_subtype(self.compiler.mainmodule, null, mtype) then
1374 self.add("case {self.compiler.classid(t)}: /* {t} */")
1375 end
1376 end
1377 self.add("{res} = 1;")
1378 self.add("break;")
1379 self.add("default:")
1380 self.add("{res} = 0;")
1381 self.add("\}")
1382
1383 return res
1384 end
1385
1386 # Generate the code required to dynamically check if 2 objects share the same runtime type
1387 fun is_same_type_test(value1, value2: RuntimeVariable): RuntimeVariable
1388 do
1389 var res = self.new_var(bool_type)
1390 if value2.mtype.ctype == "val*" then
1391 if value1.mtype.ctype == "val*" then
1392 self.add "{res} = {value1}->classid == {value2}->classid;"
1393 else
1394 self.add "{res} = {self.compiler.classid(value1.mtype.as(MClassType))} == {value2}->classid;"
1395 end
1396 else
1397 if value1.mtype.ctype == "val*" then
1398 self.add "{res} = {value1}->classid == {self.compiler.classid(value2.mtype.as(MClassType))};"
1399 else if value1.mcasttype == value2.mcasttype then
1400 self.add "{res} = 1;"
1401 else
1402 self.add "{res} = 0;"
1403 end
1404 end
1405 return res
1406 end
1407
1408 # Return a "const char*" variable associated to the classname of the dynamic type of an object
1409 # NOTE: we do not return a RuntimeVariable "NativeString" as the class may not exist in the module/program
1410 fun class_name_string(value: RuntimeVariable): String
1411 do
1412 var res = self.get_name("var_class_name")
1413 self.add_decl("const char* {res};")
1414 if value.mtype.ctype == "val*" then
1415 self.add "{res} = class_names[{value}->classid];"
1416 else
1417 self.add "{res} = class_names[{self.compiler.classid(value.mtype.as(MClassType))}];"
1418 end
1419 return res
1420 end
1421
1422 # Generate a Nit "is" for two runtime_variables
1423 fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable
1424 do
1425 var res = self.new_var(bool_type)
1426 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1427 var tmp = value1
1428 value1 = value2
1429 value2 = tmp
1430 end
1431 if value1.mtype.ctype != "val*" then
1432 if value2.mtype.ctype == value1.mtype.ctype then
1433 self.add("{res} = {value1} == {value2};")
1434 else if value2.mtype.ctype != "val*" then
1435 self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
1436 else
1437 var mtype1 = value1.mtype.as(MClassType)
1438 self.add("{res} = ({value2} != NULL) && ({value2}->classid == {self.compiler.classid(mtype1)});")
1439 self.add("if ({res}) \{")
1440 self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
1441 self.add("\}")
1442 end
1443 else
1444 var s = new Array[String]
1445 for t in self.compiler.live_primitive_types do
1446 if not t.is_subtype(self.compiler.mainmodule, null, value1.mcasttype) then continue
1447 if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
1448 s.add "({value1}->classid == {self.compiler.classid(t)} && ((struct {t.c_name}*){value1})->value == ((struct {t.c_name}*){value2})->value)"
1449 end
1450 if s.is_empty then
1451 self.add("{res} = {value1} == {value2};")
1452 else
1453 self.add("{res} = {value1} == {value2} || ({value1} != NULL && {value2} != NULL && {value1}->classid == {value2}->classid && ({s.join(" || ")}));")
1454 end
1455 end
1456 return res
1457 end
1458
1459 # Generate a check-init-instance
1460 # TODO: is an empty stub currently
1461 fun check_init_instance(recv: RuntimeVariable)
1462 do
1463 end
1464
1465 # Generate an integer value
1466 fun int_instance(value: Int): RuntimeVariable
1467 do
1468 var res = self.new_var(self.get_class("Int").mclass_type)
1469 self.add("{res} = {value};")
1470 return res
1471 end
1472
1473 # Generate an array value
1474 fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable
1475 do
1476 elttype = self.anchor(elttype)
1477 var arraytype = self.get_class("Array").get_mtype([elttype])
1478 var res = self.init_instance(arraytype)
1479 self.add("\{ /* {res} = array_instance Array[{elttype}] */")
1480 var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
1481 nat.is_exact = true
1482 self.add("{nat} = GC_MALLOC({array.length} * sizeof({elttype.ctype}));")
1483 for i in [0..array.length[ do
1484 var r = self.autobox(array[i], elttype)
1485 self.add("{nat}[{i}] = {r};")
1486 end
1487 var length = self.int_instance(array.length)
1488 self.send(self.get_property("with_native", arraytype), [res, nat, length])
1489 self.check_init_instance(res)
1490 self.add("\}")
1491 return res
1492 end
1493
1494 # Generate a string value
1495 fun string_instance(string: String): RuntimeVariable
1496 do
1497 var mtype = self.get_class("String").mclass_type
1498 var name = self.get_name("varonce")
1499 self.add_decl("static {mtype.ctype} {name};")
1500 var res = self.new_var(mtype)
1501 self.add("if ({name}) \{")
1502 self.add("{res} = {name};")
1503 self.add("\} else \{")
1504 var nat = self.new_var(self.get_class("NativeString").mclass_type)
1505 self.add("{nat} = \"{string.escape_to_c}\";")
1506 var res2 = self.init_instance(mtype)
1507 self.add("{res} = {res2};")
1508 var length = self.int_instance(string.length)
1509 self.send(self.get_property("with_native", mtype), [res, nat, length])
1510 self.check_init_instance(res)
1511 self.add("{name} = {res};")
1512 self.add("\}")
1513 return res
1514 end
1515
1516 # Generate generic abort
1517 # used by aborts, asserts, casts, etc.
1518 fun add_abort(message: String)
1519 do
1520 if self.current_node != null and self.current_node.location.file != null then
1521 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});")
1522 else
1523 self.add("fprintf(stderr, \"Runtime error: %s\\n\", \"{message.escape_to_c}\");")
1524 end
1525 self.add("exit(1);")
1526 end
1527 end
1528
1529 # A frame correspond to a visited property in a GlobalCompilerVisitor
1530 class Frame
1531 # The associated visitor
1532
1533 var visitor: GlobalCompilerVisitor
1534
1535 # The executed property.
1536 # A Method in case of a call, an attribute in case of a default initialization.
1537 var mpropdef: MPropDef
1538
1539 # The static type of the receiver
1540 var receiver: MClassType
1541
1542 # Arguments of the method (the first is the receiver)
1543 var arguments: Array[RuntimeVariable]
1544
1545 # The runtime_variable associated to the return (in a function)
1546 var returnvar: nullable RuntimeVariable writable = null
1547
1548 # The label at the end of the property
1549 var returnlabel: nullable String writable = null
1550 end
1551
1552 redef class MPropDef
1553 private var c_name_cache: nullable String
1554
1555 # The mangled name associated to the property
1556 fun c_name: String
1557 do
1558 var res = self.c_name_cache
1559 if res != null then return res
1560 res = "{self.mclassdef.mmodule.name.to_cmangle}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
1561 self.c_name_cache = res
1562 return res
1563 end
1564 end
1565
1566 redef class MMethodDef
1567 # Can the body be inlined?
1568 fun can_inline(v: GlobalCompilerVisitor): Bool
1569 do
1570 var modelbuilder = v.compiler.modelbuilder
1571 if modelbuilder.mpropdef2npropdef.has_key(self) then
1572 var npropdef = modelbuilder.mpropdef2npropdef[self]
1573 return npropdef.can_inline
1574 else if self.mproperty.name == "init" then
1575 # Automatic free init is always inlined since it is empty or contains only attribtes assigments
1576 return true
1577 else
1578 abort
1579 end
1580 end
1581
1582 # Inline the body in another visitor
1583 fun compile_inside_to_c(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
1584 do
1585 var modelbuilder = v.compiler.modelbuilder
1586 if modelbuilder.mpropdef2npropdef.has_key(self) then
1587 var npropdef = modelbuilder.mpropdef2npropdef[self]
1588 npropdef.compile_to_c(v, self, arguments)
1589 else if self.mproperty.name == "init" then
1590 var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
1591 nclassdef.compile_to_c(v, self, arguments)
1592 else
1593 abort
1594 end
1595 return null
1596 end
1597 end
1598
1599 redef class APropdef
1600 fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1601 do
1602 v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
1603 debug("Not yet implemented")
1604 end
1605
1606 fun can_inline: Bool do return true
1607 end
1608
1609 redef class AConcreteMethPropdef
1610 redef fun compile_to_c(v, mpropdef, arguments)
1611 do
1612 for i in [0..mpropdef.msignature.arity[ do
1613 var variable = self.n_signature.n_params[i].variable.as(not null)
1614 v.assign(v.variable(variable), arguments[i+1])
1615 end
1616 # Call the implicit super-init
1617 var auto_super_inits = self.auto_super_inits
1618 if auto_super_inits != null then
1619 var selfarg = [arguments.first]
1620 for auto_super_init in auto_super_inits do
1621 if auto_super_init.intro.msignature.arity == 0 then
1622 v.send(auto_super_init, selfarg)
1623 else
1624 v.send(auto_super_init, arguments)
1625 end
1626 end
1627 end
1628
1629 v.stmt(self.n_block)
1630 end
1631
1632 redef fun can_inline
1633 do
1634 if self.auto_super_inits != null then return false
1635 var nblock = self.n_block
1636 if nblock == null then return true
1637 if (mpropdef.mproperty.name == "==" or mpropdef.mproperty.name == "!=") and mpropdef.mclassdef.mclass.name == "Object" then return true
1638 if nblock isa ABlockExpr and nblock.n_expr.length == 0 then return true
1639 return false
1640 end
1641 end
1642
1643 redef class AInternMethPropdef
1644 redef fun compile_to_c(v, mpropdef, arguments)
1645 do
1646 var pname = mpropdef.mproperty.name
1647 var cname = mpropdef.mclassdef.mclass.name
1648 var ret = mpropdef.msignature.return_mtype
1649 if ret != null then
1650 ret = v.resolve_for(ret, arguments.first)
1651 end
1652 if pname != "==" and pname != "!=" then
1653 v.adapt_signature(mpropdef, arguments)
1654 end
1655 if cname == "Int" then
1656 if pname == "output" then
1657 v.add("printf(\"%ld\\n\", {arguments.first});")
1658 return
1659 else if pname == "object_id" then
1660 v.ret(arguments.first)
1661 return
1662 else if pname == "+" then
1663 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1664 return
1665 else if pname == "-" then
1666 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1667 return
1668 else if pname == "unary -" then
1669 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1670 return
1671 else if pname == "succ" then
1672 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1673 return
1674 else if pname == "prec" then
1675 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1676 return
1677 else if pname == "*" then
1678 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1679 return
1680 else if pname == "/" then
1681 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1682 return
1683 else if pname == "%" then
1684 v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
1685 return
1686 else if pname == "lshift" then
1687 v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
1688 return
1689 else if pname == "rshift" then
1690 v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
1691 return
1692 else if pname == "==" then
1693 v.ret(v.equal_test(arguments[0], arguments[1]))
1694 return
1695 else if pname == "!=" then
1696 var res = v.equal_test(arguments[0], arguments[1])
1697 v.ret(v.new_expr("!{res}", ret.as(not null)))
1698 return
1699 else if pname == "<" then
1700 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1701 return
1702 else if pname == ">" then
1703 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1704 return
1705 else if pname == "<=" then
1706 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1707 return
1708 else if pname == ">=" then
1709 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1710 return
1711 else if pname == "to_f" then
1712 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1713 return
1714 else if pname == "ascii" then
1715 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1716 return
1717 end
1718 else if cname == "Char" then
1719 if pname == "output" then
1720 v.add("printf(\"%c\", {arguments.first});")
1721 return
1722 else if pname == "object_id" then
1723 v.ret(arguments.first)
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 == "-" then
1729 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1730 return
1731 else if pname == "==" then
1732 v.ret(v.equal_test(arguments[0], arguments[1]))
1733 return
1734 else if pname == "!=" then
1735 var res = v.equal_test(arguments[0], arguments[1])
1736 v.ret(v.new_expr("!{res}", ret.as(not null)))
1737 return
1738 else if pname == "succ" then
1739 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1740 return
1741 else if pname == "prec" then
1742 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1743 return
1744 else if pname == "<" then
1745 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1746 return
1747 else if pname == ">" then
1748 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", 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 == "to_i" then
1757 v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
1758 return
1759 else if pname == "ascii" then
1760 v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
1761 return
1762 end
1763 else if cname == "Bool" then
1764 if pname == "output" then
1765 v.add("printf({arguments.first}?\"true\\n\":\"false\\n\");")
1766 return
1767 else if pname == "object_id" then
1768 v.ret(arguments.first)
1769 return
1770 else if pname == "==" then
1771 v.ret(v.equal_test(arguments[0], arguments[1]))
1772 return
1773 else if pname == "!=" then
1774 var res = v.equal_test(arguments[0], arguments[1])
1775 v.ret(v.new_expr("!{res}", ret.as(not null)))
1776 return
1777 end
1778 else if cname == "Float" then
1779 if pname == "output" then
1780 v.add("printf(\"%f\\n\", {arguments.first});")
1781 return
1782 else if pname == "object_id" then
1783 v.ret(v.new_expr("(double){arguments.first}", ret.as(not null)))
1784 return
1785 else 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.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1790 return
1791 else if pname == "unary -" then
1792 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1793 return
1794 else if pname == "succ" then
1795 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1796 return
1797 else if pname == "prec" then
1798 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1799 return
1800 else 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.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1805 return
1806 else if pname == "==" then
1807 v.ret(v.equal_test(arguments[0], arguments[1]))
1808 return
1809 else if pname == "!=" then
1810 var res = v.equal_test(arguments[0], arguments[1])
1811 v.ret(v.new_expr("!{res}", ret.as(not null)))
1812 return
1813 else if pname == "<" then
1814 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1815 return
1816 else if pname == ">" then
1817 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1818 return
1819 else if pname == "<=" then
1820 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1821 return
1822 else if pname == ">=" then
1823 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1824 return
1825 else if pname == "to_i" then
1826 v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
1827 return
1828 end
1829 else if cname == "Char" then
1830 if pname == "output" then
1831 v.add("printf(\"%c\", {arguments.first});")
1832 return
1833 else if pname == "object_id" then
1834 v.ret(arguments.first)
1835 return
1836 else if pname == "==" then
1837 v.ret(v.equal_test(arguments[0], arguments[1]))
1838 return
1839 else if pname == "!=" then
1840 var res = v.equal_test(arguments[0], arguments[1])
1841 v.ret(v.new_expr("!{res}", ret.as(not null)))
1842 return
1843 else if pname == "ascii" then
1844 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1845 return
1846 end
1847 else if cname == "NativeString" then
1848 if pname == "[]" then
1849 v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
1850 return
1851 else if pname == "[]=" then
1852 v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
1853 return
1854 else if pname == "copy_to" then
1855 v.add("memcpy({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
1856 return
1857 else if pname == "atoi" then
1858 v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
1859 return
1860 end
1861 else if cname == "NativeArray" then
1862 var elttype = arguments.first.mtype
1863 if pname == "[]" then
1864 v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
1865 return
1866 else if pname == "[]=" then
1867 v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
1868 return
1869 else if pname == "copy_to" then
1870 v.add("memcpy({arguments[1]},{arguments[0]},{arguments[2]}*sizeof({elttype.ctype}));")
1871 return
1872 end
1873 end
1874 if pname == "exit" then
1875 v.add("exit({arguments[1]});")
1876 return
1877 else if pname == "sys" then
1878 v.ret(v.new_expr("glob_sys", ret.as(not null)))
1879 return
1880 else if pname == "calloc_string" then
1881 v.ret(v.new_expr("(char*)GC_MALLOC({arguments[1]})", ret.as(not null)))
1882 return
1883 else if pname == "calloc_array" then
1884 var elttype = arguments.first.mtype.supertype_to(v.compiler.mainmodule,arguments.first.mtype.as(MClassType),v.get_class("ArrayCapable")).as(MGenericType).arguments.first
1885 v.ret(v.new_expr("({elttype.ctype}*)GC_MALLOC({arguments[1]} * sizeof({elttype.ctype}))", ret.as(not null)))
1886 return
1887 else if pname == "object_id" then
1888 v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
1889 return
1890 else if pname == "is_same_type" then
1891 v.ret(v.is_same_type_test(arguments[0], arguments[1]))
1892 return
1893 else if pname == "output_class_name" then
1894 var nat = v.class_name_string(arguments.first)
1895 v.add("printf(\"%s\\n\", {nat});")
1896 return
1897 else if pname == "native_class_name" then
1898 var nat = v.class_name_string(arguments.first)
1899 v.ret(v.new_expr("(char*){nat}", ret.as(not null)))
1900 return
1901 end
1902 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
1903 debug("Not implemented {mpropdef}")
1904 end
1905 end
1906
1907 redef class AExternMethPropdef
1908 redef fun compile_to_c(v, mpropdef, arguments)
1909 do
1910 var externname
1911 var nextern = self.n_extern
1912 if nextern == null then
1913 debug("{mpropdef} need extern name")
1914 return
1915 end
1916 externname = nextern.text.substring(1, nextern.text.length-2)
1917 if location.file != null then
1918 var file = location.file.filename
1919 v.compiler.add_extern(file)
1920 end
1921 var res: nullable RuntimeVariable = null
1922 var ret = mpropdef.msignature.return_mtype
1923 if ret != null then
1924 ret = v.resolve_for(ret, arguments.first)
1925 res = v.new_var(ret)
1926 end
1927
1928 if res == null then
1929 v.add("{externname}({arguments.join(", ")});")
1930 else
1931 v.add("{res} = {externname}({arguments.join(", ")});")
1932 v.ret(res)
1933 end
1934 end
1935 end
1936
1937 redef class AExternInitPropdef
1938 redef fun compile_to_c(v, mpropdef, arguments)
1939 do
1940 var externname
1941 var nextern = self.n_extern
1942 if nextern == null then
1943 debug("{mpropdef} need extern name")
1944 return
1945 end
1946 externname = nextern.text.substring(1, nextern.text.length-2)
1947 if location.file != null then
1948 var file = location.file.filename
1949 v.compiler.add_extern(file)
1950 end
1951 var ret = arguments.first.mtype
1952 var res = v.new_var(ret)
1953
1954 arguments.shift
1955
1956 v.add("{res} = {externname}({arguments.join(", ")});")
1957 v.ret(res)
1958 end
1959 end
1960
1961 redef class AAttrPropdef
1962 redef fun compile_to_c(v, mpropdef, arguments)
1963 do
1964 if arguments.length == 1 then
1965 var res = v.read_attribute(self.mpropdef.mproperty, arguments.first)
1966 v.assign(v.frame.returnvar.as(not null), res)
1967 else
1968 v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
1969 end
1970 end
1971
1972 fun init_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
1973 do
1974 var nexpr = self.n_expr
1975 if nexpr != null then
1976 var old_frame = v.frame
1977 var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
1978 v.frame = frame
1979 var value = v.expr(nexpr, self.mpropdef.static_mtype)
1980 v.write_attribute(self.mpropdef.mproperty, recv, value)
1981 v.frame = old_frame
1982 end
1983 end
1984 end
1985
1986 redef class AClassdef
1987 private fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1988 do
1989 if mpropdef == self.mfree_init then
1990 var super_inits = self.super_inits
1991 if super_inits != null then
1992 assert arguments.length == 1
1993 for su in super_inits do
1994 v.send(su, arguments)
1995 end
1996 return
1997 end
1998 var recv = arguments.first
1999 var i = 1
2000 # Collect undefined attributes
2001 for npropdef in self.n_propdefs do
2002 if npropdef isa AAttrPropdef and npropdef.n_expr == null then
2003 v.write_attribute(npropdef.mpropdef.mproperty, recv, arguments[i])
2004 i += 1
2005 end
2006 end
2007 else
2008 abort
2009 end
2010 end
2011 end
2012
2013 redef class ADeferredMethPropdef
2014 redef fun compile_to_c(v, mpropdef, arguments)
2015 do
2016 v.add("printf(\"Not implemented {class_name} {mpropdef} at {location.to_s}\\n\");")
2017 v.add("exit(1);")
2018 end
2019
2020 redef fun can_inline do return true
2021 end
2022
2023 redef class AExpr
2024 # Try to compile self as an expression
2025 # Do not call this method directly, use `v.expr' instead
2026 private fun expr(v: GlobalCompilerVisitor): nullable RuntimeVariable
2027 do
2028 debug("Unimplemented expr {class_name}")
2029 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{location.to_s}\\n\");")
2030 var mtype = self.mtype
2031 if mtype == null then
2032 return null
2033 else
2034 var res = v.new_var(mtype)
2035 v.add("/* {res} = NOT YET {class_name} */")
2036 return res
2037 end
2038 end
2039
2040 # Try to compile self as a statement
2041 # Do not call this method directly, use `v.stmt' instead
2042 private fun stmt(v: GlobalCompilerVisitor)
2043 do
2044 var res = expr(v)
2045 if res != null then v.add("{res};")
2046 end
2047
2048 end
2049
2050 redef class ABlockExpr
2051 redef fun stmt(v)
2052 do
2053 for e in self.n_expr do
2054 v.stmt(e)
2055 end
2056 end
2057 end
2058
2059 redef class AVardeclExpr
2060 redef fun stmt(v)
2061 do
2062 var variable = self.variable.as(not null)
2063 var ne = self.n_expr
2064 if ne != null then
2065 var i = v.expr(ne, variable.declared_type)
2066 v.assign(v.variable(variable), i)
2067 end
2068 end
2069 end
2070
2071 redef class AVarExpr
2072 redef fun expr(v)
2073 do
2074 var res = v.variable(self.variable.as(not null))
2075 var mtype = self.mtype.as(not null)
2076 return v.autoadapt(res, mtype)
2077 end
2078 end
2079
2080 redef class AVarAssignExpr
2081 redef fun stmt(v)
2082 do
2083 var variable = self.variable.as(not null)
2084 var i = v.expr(self.n_value, variable.declared_type)
2085 v.assign(v.variable(variable), i)
2086 end
2087 end
2088
2089 redef class AVarReassignExpr
2090 redef fun stmt(v)
2091 do
2092 var variable = self.variable.as(not null)
2093 var vari = v.variable(variable)
2094 var value = v.expr(self.n_value, variable.declared_type)
2095 var res = v.send(reassign_property.mproperty, [vari, value])
2096 assert res != null
2097 v.assign(v.variable(variable), res)
2098 end
2099 end
2100
2101 redef class ASelfExpr
2102 redef fun expr(v)
2103 do
2104 return v.frame.arguments.first
2105 end
2106 end
2107
2108 redef class AContinueExpr
2109 redef fun stmt(v)
2110 do
2111 v.add("goto CONTINUE_{v.escapemark_name(self.escapemark)};")
2112 end
2113 end
2114
2115 redef class ABreakExpr
2116 redef fun stmt(v)
2117 do
2118 v.add("goto BREAK_{v.escapemark_name(self.escapemark)};")
2119 end
2120 end
2121
2122 redef class AReturnExpr
2123 redef fun stmt(v)
2124 do
2125 var nexpr = self.n_expr
2126 if nexpr != null then
2127 var returnvar = v.frame.returnvar.as(not null)
2128 var i = v.expr(nexpr, returnvar.mtype)
2129 v.assign(returnvar, i)
2130 end
2131 v.add("goto {v.frame.returnlabel.as(not null)};")
2132 end
2133 end
2134
2135 redef class AAbortExpr
2136 redef fun stmt(v)
2137 do
2138 v.add_abort("Aborted")
2139 end
2140 end
2141
2142 redef class AIfExpr
2143 redef fun stmt(v)
2144 do
2145 var cond = v.expr_bool(self.n_expr)
2146 v.add("if ({cond})\{")
2147 v.stmt(self.n_then)
2148 v.add("\} else \{")
2149 v.stmt(self.n_else)
2150 v.add("\}")
2151 end
2152 end
2153
2154 redef class AIfexprExpr
2155 redef fun expr(v)
2156 do
2157 var res = v.new_var(self.mtype.as(not null))
2158 var cond = v.expr_bool(self.n_expr)
2159 v.add("if ({cond})\{")
2160 v.assign(res, v.expr(self.n_then, null))
2161 v.add("\} else \{")
2162 v.assign(res, v.expr(self.n_else, null))
2163 v.add("\}")
2164 return res
2165 end
2166 end
2167
2168 redef class ADoExpr
2169 redef fun stmt(v)
2170 do
2171 v.stmt(self.n_block)
2172 var escapemark = self.escapemark
2173 if escapemark != null then
2174 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2175 end
2176 end
2177 end
2178
2179 redef class AWhileExpr
2180 redef fun stmt(v)
2181 do
2182 v.add("for(;;) \{")
2183 var cond = v.expr_bool(self.n_expr)
2184 v.add("if (!{cond}) break;")
2185 v.stmt(self.n_block)
2186 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2187 v.add("\}")
2188 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2189 end
2190 end
2191
2192 redef class ALoopExpr
2193 redef fun stmt(v)
2194 do
2195 v.add("for(;;) \{")
2196 v.stmt(self.n_block)
2197 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2198 v.add("\}")
2199 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2200 end
2201 end
2202
2203 redef class AForExpr
2204 redef fun stmt(v)
2205 do
2206 var cl = v.expr(self.n_expr, null)
2207 var it = v.send(v.get_property("iterator", cl.mtype), [cl])
2208 assert it != null
2209 v.add("for(;;) \{")
2210 var ok = v.send(v.get_property("is_ok", it.mtype), [it])
2211 assert ok != null
2212 v.add("if(!{ok}) break;")
2213 if self.variables.length == 1 then
2214 var i = v.send(v.get_property("item", it.mtype), [it])
2215 assert i != null
2216 v.assign(v.variable(variables.first), i)
2217 else if self.variables.length == 2 then
2218 var i = v.send(v.get_property("key", it.mtype), [it])
2219 assert i != null
2220 v.assign(v.variable(variables[0]), i)
2221 i = v.send(v.get_property("item", it.mtype), [it])
2222 assert i != null
2223 v.assign(v.variable(variables[1]), i)
2224 else
2225 abort
2226 end
2227 v.stmt(self.n_block)
2228 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2229 v.send(v.get_property("next", it.mtype), [it])
2230 v.add("\}")
2231 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2232 end
2233 end
2234
2235 redef class AAssertExpr
2236 redef fun stmt(v)
2237 do
2238 var cond = v.expr_bool(self.n_expr)
2239 v.add("if (!{cond}) \{")
2240 v.stmt(self.n_else)
2241 var nid = self.n_id
2242 if nid != null then
2243 v.add_abort("Assert '{nid.text}' failed")
2244 else
2245 v.add_abort("Assert failed")
2246 end
2247 v.add("\}")
2248 end
2249 end
2250
2251 redef class AOrExpr
2252 redef fun expr(v)
2253 do
2254 var res = v.new_var(self.mtype.as(not null))
2255 var i1 = v.expr_bool(self.n_expr)
2256 v.add("if ({i1}) \{")
2257 v.add("{res} = 1;")
2258 v.add("\} else \{")
2259 var i2 = v.expr_bool(self.n_expr2)
2260 v.add("{res} = {i2};")
2261 v.add("\}")
2262 return res
2263 end
2264 end
2265
2266 redef class AAndExpr
2267 redef fun expr(v)
2268 do
2269 var res = v.new_var(self.mtype.as(not null))
2270 var i1 = v.expr_bool(self.n_expr)
2271 v.add("if (!{i1}) \{")
2272 v.add("{res} = 0;")
2273 v.add("\} else \{")
2274 var i2 = v.expr_bool(self.n_expr2)
2275 v.add("{res} = {i2};")
2276 v.add("\}")
2277 return res
2278 end
2279 end
2280
2281 redef class ANotExpr
2282 redef fun expr(v)
2283 do
2284 var cond = v.expr_bool(self.n_expr)
2285 return v.new_expr("!{cond}", self.mtype.as(not null))
2286 end
2287 end
2288
2289 redef class AOrElseExpr
2290 redef fun expr(v)
2291 do
2292 var res = v.new_var(self.mtype.as(not null))
2293 var i1 = v.expr(self.n_expr, null)
2294 v.add("if ({i1}!=NULL) \{")
2295 v.assign(res, i1)
2296 v.add("\} else \{")
2297 var i2 = v.expr(self.n_expr2, null)
2298 v.assign(res, i2)
2299 v.add("\}")
2300 return res
2301 end
2302 end
2303
2304 redef class AEeExpr
2305 redef fun expr(v)
2306 do
2307 var value1 = v.expr(self.n_expr, null)
2308 var value2 = v.expr(self.n_expr2, null)
2309 return v.equal_test(value1, value2)
2310 end
2311 end
2312
2313 redef class AIntExpr
2314 redef fun expr(v)
2315 do
2316 return v.new_expr("{self.n_number.text}", self.mtype.as(not null))
2317 end
2318 end
2319
2320 redef class AFloatExpr
2321 redef fun expr(v)
2322 do
2323 return v.new_expr("{self.n_float.text}", self.mtype.as(not null))
2324 end
2325 end
2326
2327 redef class ACharExpr
2328 redef fun expr(v)
2329 do
2330 return v.new_expr("{self.n_char.text}", self.mtype.as(not null))
2331 end
2332 end
2333
2334 redef class AArrayExpr
2335 redef fun expr(v)
2336 do
2337 var mtype = self.mtype.as(MGenericType).arguments.first
2338 var array = new Array[RuntimeVariable]
2339 for nexpr in self.n_exprs.n_exprs do
2340 var i = v.expr(nexpr, mtype)
2341 array.add(i)
2342 end
2343 return v.array_instance(array, mtype)
2344 end
2345 end
2346
2347 redef class AStringFormExpr
2348 redef fun expr(v)
2349 do
2350 return v.string_instance(self.value.as(not null))
2351 end
2352 end
2353
2354 redef class ASuperstringExpr
2355 redef fun expr(v)
2356 do
2357 var array = new Array[RuntimeVariable]
2358 for ne in self.n_exprs do
2359 if ne isa AStringFormExpr and ne.value == "" then continue # skip empty sub-strings
2360 var i = v.expr(ne, null)
2361 array.add(i)
2362 end
2363 var a = v.array_instance(array, v.object_type)
2364 var res = v.send(v.get_property("to_s", a.mtype), [a])
2365 return res
2366 end
2367 end
2368
2369 redef class ACrangeExpr
2370 redef fun expr(v)
2371 do
2372 var i1 = v.expr(self.n_expr, null)
2373 var i2 = v.expr(self.n_expr2, null)
2374 var res = v.init_instance(self.mtype.as(MClassType))
2375 var it = v.send(v.get_property("init", res.mtype), [res, i1, i2])
2376 v.check_init_instance(res)
2377 return res
2378 end
2379 end
2380
2381 redef class AOrangeExpr
2382 redef fun expr(v)
2383 do
2384 var i1 = v.expr(self.n_expr, null)
2385 var i2 = v.expr(self.n_expr2, null)
2386 var res = v.init_instance(self.mtype.as(MClassType))
2387 var it = v.send(v.get_property("without_last", res.mtype), [res, i1, i2])
2388 v.check_init_instance(res)
2389 return res
2390 end
2391 end
2392
2393 redef class ATrueExpr
2394 redef fun expr(v)
2395 do
2396 return v.new_expr("1", self.mtype.as(not null))
2397 end
2398 end
2399
2400 redef class AFalseExpr
2401 redef fun expr(v)
2402 do
2403 return v.new_expr("0", self.mtype.as(not null))
2404 end
2405 end
2406
2407 redef class ANullExpr
2408 redef fun expr(v)
2409 do
2410 var res = v.new_expr("NULL", self.mtype.as(not null))
2411 return res
2412 end
2413 end
2414
2415 redef class AIsaExpr
2416 redef fun expr(v)
2417 do
2418 var i = v.expr(self.n_expr, null)
2419 return v.type_test(i, self.cast_type.as(not null))
2420 end
2421 end
2422
2423 redef class AAsCastExpr
2424 redef fun expr(v)
2425 do
2426 var i = v.expr(self.n_expr, null)
2427 var cond = v.type_test(i, self.mtype.as(not null))
2428 v.add("if (!{cond}) \{")
2429 v.add_abort("Cast failed")
2430 v.add("\}")
2431 return i
2432 end
2433 end
2434
2435 redef class AAsNotnullExpr
2436 redef fun expr(v)
2437 do
2438 var i = v.expr(self.n_expr, null)
2439 v.add("if ({i} == NULL) \{")
2440 v.add_abort("Cast failed")
2441 v.add("\}")
2442 return i
2443 end
2444 end
2445
2446 redef class AParExpr
2447 redef fun expr(v)
2448 do
2449 return v.expr(self.n_expr, null)
2450 end
2451 end
2452
2453 redef class AOnceExpr
2454 redef fun expr(v)
2455 do
2456 var mtype = self.mtype.as(not null)
2457 var name = v.get_name("varonce")
2458 var guard = v.get_name(name + "_guard")
2459 v.add_decl("static {mtype.ctype} {name};")
2460 v.add_decl("static int {guard};")
2461 var res = v.new_var(mtype)
2462 v.add("if ({guard}) \{")
2463 v.add("{res} = {name};")
2464 v.add("\} else \{")
2465 var i = v.expr(self.n_expr, mtype)
2466 v.add("{res} = {i};")
2467 v.add("{name} = {res};")
2468 v.add("{guard} = 1;")
2469 v.add("\}")
2470 return res
2471 end
2472 end
2473
2474 redef class ASendExpr
2475 redef fun expr(v)
2476 do
2477 var recv = v.expr(self.n_expr, null)
2478 var args = [recv]
2479 for a in self.raw_arguments.as(not null) do
2480 args.add(v.expr(a, null))
2481 end
2482 var mproperty = self.mproperty.as(not null)
2483 return v.send(mproperty, args)
2484 end
2485 end
2486
2487 redef class ASendReassignFormExpr
2488 redef fun stmt(v)
2489 do
2490 var recv = v.expr(self.n_expr, null)
2491 var args = [recv]
2492 for a in self.raw_arguments.as(not null) do
2493 args.add(v.expr(a, null))
2494 end
2495 var value = v.expr(self.n_value, null)
2496
2497 var mproperty = self.mproperty.as(not null)
2498 var left = v.send(mproperty, args)
2499 assert left != null
2500
2501 var res = v.send(reassign_property.mproperty, [left, value])
2502 assert res != null
2503
2504 args.add(res)
2505 v.send(self.write_mproperty.as(not null), args)
2506 end
2507 end
2508
2509 redef class ASuperExpr
2510 redef fun expr(v)
2511 do
2512 var recv = v.frame.arguments.first
2513 var args = [recv]
2514 for a in self.n_args.n_exprs do
2515 args.add(v.expr(a, null))
2516 end
2517 if args.length == 1 then
2518 args = v.frame.arguments
2519 end
2520
2521 var mproperty = self.mproperty
2522 if mproperty != null then
2523 if mproperty.intro.msignature.arity == 0 then
2524 args = [recv]
2525 end
2526 # Super init call
2527 var res = v.send(mproperty, args)
2528 return res
2529 end
2530
2531 # stantard call-next-method
2532 var mpropdef = v.frame.mpropdef
2533 # FIXME: we do not want an ugly static call!
2534 var mpropdefs = mpropdef.mproperty.lookup_super_definitions(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
2535 if mpropdefs.length != 1 then
2536 v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
2537 debug("MPRODFEFS for super {mpropdef} for {recv}: {mpropdefs.join(", ")}")
2538 end
2539 mpropdef = mpropdefs.first
2540 assert mpropdef isa MMethodDef
2541 var res = v.call(mpropdef, recv.mtype.as(MClassType), args)
2542 return res
2543 end
2544 end
2545
2546 redef class ANewExpr
2547 redef fun expr(v)
2548 do
2549 var mproperty = self.mproperty.as(not null)
2550 var mtype = self.mtype.as(MClassType)
2551 var recv
2552 var ctype = mtype.ctype
2553 if ctype == "val*" then
2554 recv = v.init_instance(mtype)
2555 else if ctype == "void*" then
2556 recv = v.new_expr("NULL/*special!*/", mtype)
2557 else
2558 debug("cannot new {mtype}")
2559 abort
2560 end
2561 var args = [recv]
2562 for a in self.n_args.n_exprs do
2563 args.add(v.expr(a, null))
2564 end
2565 var res2 = v.send(mproperty, args)
2566 if res2 != null then
2567 #self.debug("got {res2} from {mproperty}. drop {recv}")
2568 return res2
2569 end
2570 v.check_init_instance(recv)
2571 return recv
2572 end
2573 end
2574
2575 redef class AAttrExpr
2576 redef fun expr(v)
2577 do
2578 var recv = v.expr(self.n_expr, null)
2579 var mproperty = self.mproperty.as(not null)
2580 return v.read_attribute(mproperty, recv)
2581 end
2582 end
2583
2584 redef class AAttrAssignExpr
2585 redef fun stmt(v)
2586 do
2587 var recv = v.expr(self.n_expr, null)
2588 var i = v.expr(self.n_value, null)
2589 var mproperty = self.mproperty.as(not null)
2590 v.write_attribute(mproperty, recv, i)
2591 end
2592 end
2593
2594 redef class AAttrReassignExpr
2595 redef fun stmt(v)
2596 do
2597 var recv = v.expr(self.n_expr, null)
2598 var value = v.expr(self.n_value, null)
2599 var mproperty = self.mproperty.as(not null)
2600 var attr = v.read_attribute(mproperty, recv)
2601 var res = v.send(reassign_property.mproperty, [attr, value])
2602 assert res != null
2603 v.write_attribute(mproperty, recv, res)
2604 end
2605 end
2606
2607 redef class AIssetAttrExpr
2608 end
2609
2610 redef class ADebugTypeExpr
2611 redef fun stmt(v)
2612 do
2613 # do nothing
2614 end
2615 end