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