nitg: extract varargize into its own method
[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 private var c_name_cache: nullable String
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.mcasttype isa MNullableType then
1465 self.add("if ({value} == NULL) \{")
1466 if mtype isa MNullableType then
1467 self.add("{res} = 1; /* isa {mtype} */")
1468 else
1469 self.add("{res} = 0; /* not isa {mtype} */")
1470 end
1471 self.add("\} else ")
1472 end
1473 self.add("switch({value}->classid) \{")
1474 for t in types do
1475 if t.is_subtype(self.compiler.mainmodule, null, mtype) then
1476 self.add("case {self.compiler.classid(t)}: /* {t} */")
1477 end
1478 end
1479 self.add("{res} = 1;")
1480 self.add("break;")
1481 self.add("default:")
1482 self.add("{res} = 0;")
1483 self.add("\}")
1484
1485 return res
1486 end
1487
1488 # Generate the code required to dynamically check if 2 objects share the same runtime type
1489 fun is_same_type_test(value1, value2: RuntimeVariable): RuntimeVariable
1490 do
1491 var res = self.new_var(bool_type)
1492 if value2.mtype.ctype == "val*" then
1493 if value1.mtype.ctype == "val*" then
1494 self.add "{res} = {value1}->classid == {value2}->classid;"
1495 else
1496 self.add "{res} = {self.compiler.classid(value1.mtype.as(MClassType))} == {value2}->classid;"
1497 end
1498 else
1499 if value1.mtype.ctype == "val*" then
1500 self.add "{res} = {value1}->classid == {self.compiler.classid(value2.mtype.as(MClassType))};"
1501 else if value1.mcasttype == value2.mcasttype then
1502 self.add "{res} = 1;"
1503 else
1504 self.add "{res} = 0;"
1505 end
1506 end
1507 return res
1508 end
1509
1510 # Return a "const char*" variable associated to the classname of the dynamic type of an object
1511 # NOTE: we do not return a RuntimeVariable "NativeString" as the class may not exist in the module/program
1512 fun class_name_string(value: RuntimeVariable): String
1513 do
1514 var res = self.get_name("var_class_name")
1515 self.add_decl("const char* {res};")
1516 if value.mtype.ctype == "val*" then
1517 self.add "{res} = class_names[{value}->classid];"
1518 else
1519 self.add "{res} = class_names[{self.compiler.classid(value.mtype.as(MClassType))}];"
1520 end
1521 return res
1522 end
1523
1524 # Generate a Nit "is" for two runtime_variables
1525 fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable
1526 do
1527 var res = self.new_var(bool_type)
1528 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1529 var tmp = value1
1530 value1 = value2
1531 value2 = tmp
1532 end
1533 if value1.mtype.ctype != "val*" then
1534 if value2.mtype.ctype == value1.mtype.ctype then
1535 self.add("{res} = {value1} == {value2};")
1536 else if value2.mtype.ctype != "val*" then
1537 self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
1538 else
1539 var mtype1 = value1.mtype.as(MClassType)
1540 self.add("{res} = ({value2} != NULL) && ({value2}->classid == {self.compiler.classid(mtype1)});")
1541 self.add("if ({res}) \{")
1542 self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
1543 self.add("\}")
1544 end
1545 else
1546 var s = new Array[String]
1547 for t in self.compiler.live_primitive_types do
1548 if not t.is_subtype(self.compiler.mainmodule, null, value1.mcasttype) then continue
1549 if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
1550 s.add "({value1}->classid == {self.compiler.classid(t)} && ((struct {t.c_name}*){value1})->value == ((struct {t.c_name}*){value2})->value)"
1551 end
1552 if s.is_empty then
1553 self.add("{res} = {value1} == {value2};")
1554 else
1555 self.add("{res} = {value1} == {value2} || ({value1} != NULL && {value2} != NULL && {value1}->classid == {value2}->classid && ({s.join(" || ")}));")
1556 end
1557 end
1558 return res
1559 end
1560
1561 # Generate a check-init-instance
1562 fun check_init_instance(recv: RuntimeVariable)
1563 do
1564 var mtype = self.anchor(recv.mcasttype)
1565 for cd in mtype.collect_mclassdefs(self.compiler.mainmodule)
1566 do
1567 var n = self.compiler.modelbuilder.mclassdef2nclassdef[cd]
1568 for npropdef in n.n_propdefs do
1569 if npropdef isa AAttrPropdef then
1570 # Force read to check the initialization
1571 self.read_attribute(npropdef.mpropdef.mproperty, recv)
1572 end
1573 end
1574 end
1575 end
1576
1577 # Generate an integer value
1578 fun int_instance(value: Int): RuntimeVariable
1579 do
1580 var res = self.new_var(self.get_class("Int").mclass_type)
1581 self.add("{res} = {value};")
1582 return res
1583 end
1584
1585 # Generate an array value
1586 fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable
1587 do
1588 elttype = self.anchor(elttype)
1589 var arraytype = self.get_class("Array").get_mtype([elttype])
1590 var res = self.init_instance(arraytype)
1591 self.add("\{ /* {res} = array_instance Array[{elttype}] */")
1592 var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
1593 nat.is_exact = true
1594 self.add("{nat} = NEW_{nat.mtype.c_name}({array.length});")
1595 for i in [0..array.length[ do
1596 var r = self.autobox(array[i], elttype)
1597 self.add("((struct {nat.mtype.c_name}*) {nat})->values[{i}] = {r};")
1598 end
1599 var length = self.int_instance(array.length)
1600 self.send(self.get_property("with_native", arraytype), [res, nat, length])
1601 self.check_init_instance(res)
1602 self.add("\}")
1603 return res
1604 end
1605
1606 # Generate a string value
1607 fun string_instance(string: String): RuntimeVariable
1608 do
1609 var mtype = self.get_class("String").mclass_type
1610 var name = self.get_name("varonce")
1611 self.add_decl("static {mtype.ctype} {name};")
1612 var res = self.new_var(mtype)
1613 self.add("if ({name}) \{")
1614 self.add("{res} = {name};")
1615 self.add("\} else \{")
1616 var nat = self.new_var(self.get_class("NativeString").mclass_type)
1617 self.add("{nat} = \"{string.escape_to_c}\";")
1618 var res2 = self.init_instance(mtype)
1619 self.add("{res} = {res2};")
1620 var length = self.int_instance(string.length)
1621 self.send(self.get_property("with_native", mtype), [res, nat, length])
1622 self.check_init_instance(res)
1623 self.add("{name} = {res};")
1624 self.add("\}")
1625 return res
1626 end
1627
1628 # Generate generic abort
1629 # used by aborts, asserts, casts, etc.
1630 fun add_abort(message: String)
1631 do
1632 if self.current_node != null and self.current_node.location.file != null then
1633 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});")
1634 else
1635 self.add("fprintf(stderr, \"Runtime error: %s\\n\", \"{message.escape_to_c}\");")
1636 end
1637 self.add("exit(1);")
1638 end
1639 end
1640
1641 # A frame correspond to a visited property in a GlobalCompilerVisitor
1642 class Frame
1643 # The associated visitor
1644
1645 var visitor: GlobalCompilerVisitor
1646
1647 # The executed property.
1648 # A Method in case of a call, an attribute in case of a default initialization.
1649 var mpropdef: MPropDef
1650
1651 # The static type of the receiver
1652 var receiver: MClassType
1653
1654 # Arguments of the method (the first is the receiver)
1655 var arguments: Array[RuntimeVariable]
1656
1657 # The runtime_variable associated to the return (in a function)
1658 var returnvar: nullable RuntimeVariable writable = null
1659
1660 # The label at the end of the property
1661 var returnlabel: nullable String writable = null
1662 end
1663
1664 redef class MPropDef
1665 private var c_name_cache: nullable String
1666
1667 # The mangled name associated to the property
1668 fun c_name: String
1669 do
1670 var res = self.c_name_cache
1671 if res != null then return res
1672 res = "{self.mclassdef.mmodule.name.to_cmangle}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
1673 self.c_name_cache = res
1674 return res
1675 end
1676 end
1677
1678 redef class MMethodDef
1679 # Can the body be inlined?
1680 fun can_inline(v: GlobalCompilerVisitor): Bool
1681 do
1682 var modelbuilder = v.compiler.modelbuilder
1683 if modelbuilder.mpropdef2npropdef.has_key(self) then
1684 var npropdef = modelbuilder.mpropdef2npropdef[self]
1685 return npropdef.can_inline
1686 else if self.mproperty.name == "init" then
1687 # Automatic free init is always inlined since it is empty or contains only attribtes assigments
1688 return true
1689 else
1690 abort
1691 end
1692 end
1693
1694 # Inline the body in another visitor
1695 fun compile_inside_to_c(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
1696 do
1697 var modelbuilder = v.compiler.modelbuilder
1698 if modelbuilder.mpropdef2npropdef.has_key(self) then
1699 var npropdef = modelbuilder.mpropdef2npropdef[self]
1700 var oldnode = v.current_node
1701 v.current_node = npropdef
1702 npropdef.compile_to_c(v, self, arguments)
1703 v.current_node = oldnode
1704 else if self.mproperty.name == "init" then
1705 var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
1706 var oldnode = v.current_node
1707 v.current_node = nclassdef
1708 nclassdef.compile_to_c(v, self, arguments)
1709 v.current_node = oldnode
1710 else
1711 abort
1712 end
1713 return null
1714 end
1715 end
1716
1717 redef class APropdef
1718 fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1719 do
1720 v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
1721 debug("Not yet implemented")
1722 end
1723
1724 fun can_inline: Bool do return true
1725 end
1726
1727 redef class AConcreteMethPropdef
1728 redef fun compile_to_c(v, mpropdef, arguments)
1729 do
1730 for i in [0..mpropdef.msignature.arity[ do
1731 var variable = self.n_signature.n_params[i].variable.as(not null)
1732 v.assign(v.variable(variable), arguments[i+1])
1733 end
1734 # Call the implicit super-init
1735 var auto_super_inits = self.auto_super_inits
1736 if auto_super_inits != null then
1737 var selfarg = [arguments.first]
1738 for auto_super_init in auto_super_inits do
1739 if auto_super_init.intro.msignature.arity == 0 then
1740 v.send(auto_super_init, selfarg)
1741 else
1742 v.send(auto_super_init, arguments)
1743 end
1744 end
1745 end
1746 v.stmt(self.n_block)
1747 end
1748
1749 redef fun can_inline
1750 do
1751 if self.auto_super_inits != null then return false
1752 var nblock = self.n_block
1753 if nblock == null then return true
1754 if (mpropdef.mproperty.name == "==" or mpropdef.mproperty.name == "!=") and mpropdef.mclassdef.mclass.name == "Object" then return true
1755 if nblock isa ABlockExpr and nblock.n_expr.length == 0 then return true
1756 return false
1757 end
1758 end
1759
1760 redef class AInternMethPropdef
1761 redef fun compile_to_c(v, mpropdef, arguments)
1762 do
1763 var pname = mpropdef.mproperty.name
1764 var cname = mpropdef.mclassdef.mclass.name
1765 var ret = mpropdef.msignature.return_mtype
1766 if ret != null then
1767 ret = v.resolve_for(ret, arguments.first)
1768 end
1769 if pname != "==" and pname != "!=" then
1770 v.adapt_signature(mpropdef, arguments)
1771 end
1772 if cname == "Int" then
1773 if pname == "output" then
1774 v.add("printf(\"%ld\\n\", {arguments.first});")
1775 return
1776 else if pname == "object_id" then
1777 v.ret(arguments.first)
1778 return
1779 else if pname == "+" then
1780 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1781 return
1782 else if pname == "-" then
1783 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1784 return
1785 else if pname == "unary -" then
1786 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1787 return
1788 else if pname == "succ" then
1789 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1790 return
1791 else if pname == "prec" then
1792 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1793 return
1794 else if pname == "*" then
1795 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1796 return
1797 else if pname == "/" then
1798 v.ret(v.new_expr("{arguments[0]} / {arguments[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 == "lshift" then
1804 v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
1805 return
1806 else if pname == "rshift" then
1807 v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
1808 return
1809 else if pname == "==" then
1810 v.ret(v.equal_test(arguments[0], arguments[1]))
1811 return
1812 else if pname == "!=" then
1813 var res = v.equal_test(arguments[0], arguments[1])
1814 v.ret(v.new_expr("!{res}", 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 == ">=" then
1826 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1827 return
1828 else if pname == "to_f" then
1829 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1830 return
1831 else if pname == "ascii" then
1832 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1833 return
1834 end
1835 else if cname == "Char" then
1836 if pname == "output" then
1837 v.add("printf(\"%c\", {arguments.first});")
1838 return
1839 else if pname == "object_id" then
1840 v.ret(arguments.first)
1841 return
1842 else if pname == "+" then
1843 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1844 return
1845 else if pname == "-" then
1846 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1847 return
1848 else if pname == "==" then
1849 v.ret(v.equal_test(arguments[0], arguments[1]))
1850 return
1851 else if pname == "!=" then
1852 var res = v.equal_test(arguments[0], arguments[1])
1853 v.ret(v.new_expr("!{res}", ret.as(not null)))
1854 return
1855 else if pname == "succ" then
1856 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1857 return
1858 else if pname == "prec" then
1859 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1860 return
1861 else if pname == "<" then
1862 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1863 return
1864 else if pname == ">" then
1865 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1866 return
1867 else if pname == "<=" then
1868 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1869 return
1870 else if pname == ">=" then
1871 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1872 return
1873 else if pname == "to_i" then
1874 v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
1875 return
1876 else if pname == "ascii" then
1877 v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
1878 return
1879 end
1880 else if cname == "Bool" then
1881 if pname == "output" then
1882 v.add("printf({arguments.first}?\"true\\n\":\"false\\n\");")
1883 return
1884 else if pname == "object_id" then
1885 v.ret(arguments.first)
1886 return
1887 else if pname == "==" then
1888 v.ret(v.equal_test(arguments[0], arguments[1]))
1889 return
1890 else if pname == "!=" then
1891 var res = v.equal_test(arguments[0], arguments[1])
1892 v.ret(v.new_expr("!{res}", ret.as(not null)))
1893 return
1894 end
1895 else if cname == "Float" then
1896 if pname == "output" then
1897 v.add("printf(\"%f\\n\", {arguments.first});")
1898 return
1899 else if pname == "object_id" then
1900 v.ret(v.new_expr("(double){arguments.first}", ret.as(not null)))
1901 return
1902 else if pname == "+" then
1903 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1904 return
1905 else if pname == "-" then
1906 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1907 return
1908 else if pname == "unary -" then
1909 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1910 return
1911 else if pname == "succ" then
1912 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1913 return
1914 else if pname == "prec" then
1915 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1916 return
1917 else if pname == "*" then
1918 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1919 return
1920 else if pname == "/" then
1921 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1922 return
1923 else if pname == "==" then
1924 v.ret(v.equal_test(arguments[0], arguments[1]))
1925 return
1926 else if pname == "!=" then
1927 var res = v.equal_test(arguments[0], arguments[1])
1928 v.ret(v.new_expr("!{res}", ret.as(not null)))
1929 return
1930 else if pname == "<" then
1931 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1932 return
1933 else if pname == ">" then
1934 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1935 return
1936 else if pname == "<=" then
1937 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1938 return
1939 else if pname == ">=" then
1940 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1941 return
1942 else if pname == "to_i" then
1943 v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
1944 return
1945 end
1946 else if cname == "Char" then
1947 if pname == "output" then
1948 v.add("printf(\"%c\", {arguments.first});")
1949 return
1950 else if pname == "object_id" then
1951 v.ret(arguments.first)
1952 return
1953 else if pname == "==" then
1954 v.ret(v.equal_test(arguments[0], arguments[1]))
1955 return
1956 else if pname == "!=" then
1957 var res = v.equal_test(arguments[0], arguments[1])
1958 v.ret(v.new_expr("!{res}", ret.as(not null)))
1959 return
1960 else if pname == "ascii" then
1961 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1962 return
1963 end
1964 else if cname == "NativeString" then
1965 if pname == "[]" then
1966 v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
1967 return
1968 else if pname == "[]=" then
1969 v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
1970 return
1971 else if pname == "copy_to" then
1972 v.add("memcpy({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
1973 return
1974 else if pname == "atoi" then
1975 v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
1976 return
1977 end
1978 else if cname == "NativeArray" then
1979 v.native_array_def(pname, ret, arguments)
1980 return
1981 end
1982 if pname == "exit" then
1983 v.add("exit({arguments[1]});")
1984 return
1985 else if pname == "sys" then
1986 v.ret(v.new_expr("glob_sys", ret.as(not null)))
1987 return
1988 else if pname == "calloc_string" then
1989 v.ret(v.new_expr("(char*)GC_MALLOC({arguments[1]})", ret.as(not null)))
1990 return
1991 else if pname == "calloc_array" then
1992 v.calloc_array(ret.as(not null), arguments)
1993 return
1994 else if pname == "object_id" then
1995 v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
1996 return
1997 else if pname == "is_same_type" then
1998 v.ret(v.is_same_type_test(arguments[0], arguments[1]))
1999 return
2000 else if pname == "output_class_name" then
2001 var nat = v.class_name_string(arguments.first)
2002 v.add("printf(\"%s\\n\", {nat});")
2003 return
2004 else if pname == "native_class_name" then
2005 var nat = v.class_name_string(arguments.first)
2006 v.ret(v.new_expr("(char*){nat}", ret.as(not null)))
2007 return
2008 end
2009 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
2010 debug("Not implemented {mpropdef}")
2011 end
2012 end
2013
2014 redef class AExternMethPropdef
2015 redef fun compile_to_c(v, mpropdef, arguments)
2016 do
2017 var externname
2018 var nextern = self.n_extern
2019 if nextern == null then
2020 debug("{mpropdef} need extern name")
2021 return
2022 end
2023 externname = nextern.text.substring(1, nextern.text.length-2)
2024 if location.file != null then
2025 var file = location.file.filename
2026 v.compiler.add_extern(file)
2027 end
2028 var res: nullable RuntimeVariable = null
2029 var ret = mpropdef.msignature.return_mtype
2030 if ret != null then
2031 ret = v.resolve_for(ret, arguments.first)
2032 res = v.new_var(ret)
2033 end
2034 v.adapt_signature(mpropdef, arguments)
2035
2036 if res == null then
2037 v.add("{externname}({arguments.join(", ")});")
2038 else
2039 v.add("{res} = {externname}({arguments.join(", ")});")
2040 v.ret(res)
2041 end
2042 end
2043 end
2044
2045 redef class AExternInitPropdef
2046 redef fun compile_to_c(v, mpropdef, arguments)
2047 do
2048 var externname
2049 var nextern = self.n_extern
2050 if nextern == null then
2051 debug("{mpropdef} need extern name")
2052 return
2053 end
2054 externname = nextern.text.substring(1, nextern.text.length-2)
2055 if location.file != null then
2056 var file = location.file.filename
2057 v.compiler.add_extern(file)
2058 end
2059 v.adapt_signature(mpropdef, arguments)
2060 var ret = arguments.first.mtype
2061 var res = v.new_var(ret)
2062
2063 arguments.shift
2064
2065 v.add("{res} = {externname}({arguments.join(", ")});")
2066 v.ret(res)
2067 end
2068 end
2069
2070 redef class AAttrPropdef
2071 redef fun compile_to_c(v, mpropdef, arguments)
2072 do
2073 if arguments.length == 1 then
2074 var res = v.read_attribute(self.mpropdef.mproperty, arguments.first)
2075 v.assign(v.frame.returnvar.as(not null), res)
2076 else
2077 v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
2078 end
2079 end
2080
2081 fun init_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
2082 do
2083 var nexpr = self.n_expr
2084 if nexpr != null then
2085 var old_frame = v.frame
2086 var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
2087 v.frame = frame
2088 var value = v.expr(nexpr, self.mpropdef.static_mtype)
2089 v.write_attribute(self.mpropdef.mproperty, recv, value)
2090 v.frame = old_frame
2091 end
2092 end
2093 end
2094
2095 redef class AClassdef
2096 private fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
2097 do
2098 if mpropdef == self.mfree_init then
2099 var super_inits = self.super_inits
2100 if super_inits != null then
2101 assert arguments.length == 1
2102 for su in super_inits do
2103 v.send(su, arguments)
2104 end
2105 return
2106 end
2107 var recv = arguments.first
2108 var i = 1
2109 # Collect undefined attributes
2110 for npropdef in self.n_propdefs do
2111 if npropdef isa AAttrPropdef and npropdef.n_expr == null then
2112 v.write_attribute(npropdef.mpropdef.mproperty, recv, arguments[i])
2113 i += 1
2114 end
2115 end
2116 else
2117 abort
2118 end
2119 end
2120 end
2121
2122 redef class ADeferredMethPropdef
2123 redef fun compile_to_c(v, mpropdef, arguments)
2124 do
2125 v.add("printf(\"Not implemented {class_name} {mpropdef} at {location.to_s}\\n\");")
2126 v.add("exit(1);")
2127 end
2128
2129 redef fun can_inline do return true
2130 end
2131
2132 redef class AExpr
2133 # Try to compile self as an expression
2134 # Do not call this method directly, use `v.expr' instead
2135 private fun expr(v: GlobalCompilerVisitor): nullable RuntimeVariable
2136 do
2137 debug("Unimplemented expr {class_name}")
2138 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{location.to_s}\\n\");")
2139 var mtype = self.mtype
2140 if mtype == null then
2141 return null
2142 else
2143 var res = v.new_var(mtype)
2144 v.add("/* {res} = NOT YET {class_name} */")
2145 return res
2146 end
2147 end
2148
2149 # Try to compile self as a statement
2150 # Do not call this method directly, use `v.stmt' instead
2151 private fun stmt(v: GlobalCompilerVisitor)
2152 do
2153 var res = expr(v)
2154 if res != null then v.add("{res};")
2155 end
2156
2157 end
2158
2159 redef class ABlockExpr
2160 redef fun stmt(v)
2161 do
2162 for e in self.n_expr do
2163 v.stmt(e)
2164 end
2165 end
2166 end
2167
2168 redef class AVardeclExpr
2169 redef fun stmt(v)
2170 do
2171 var variable = self.variable.as(not null)
2172 var ne = self.n_expr
2173 if ne != null then
2174 var i = v.expr(ne, variable.declared_type)
2175 v.assign(v.variable(variable), i)
2176 end
2177 end
2178 end
2179
2180 redef class AVarExpr
2181 redef fun expr(v)
2182 do
2183 var res = v.variable(self.variable.as(not null))
2184 var mtype = self.mtype.as(not null)
2185 return v.autoadapt(res, mtype)
2186 end
2187 end
2188
2189 redef class AVarAssignExpr
2190 redef fun stmt(v)
2191 do
2192 var variable = self.variable.as(not null)
2193 var i = v.expr(self.n_value, variable.declared_type)
2194 v.assign(v.variable(variable), i)
2195 end
2196 end
2197
2198 redef class AVarReassignExpr
2199 redef fun stmt(v)
2200 do
2201 var variable = self.variable.as(not null)
2202 var vari = v.variable(variable)
2203 var value = v.expr(self.n_value, variable.declared_type)
2204 var res = v.send(reassign_property.mproperty, [vari, value])
2205 assert res != null
2206 v.assign(v.variable(variable), res)
2207 end
2208 end
2209
2210 redef class ASelfExpr
2211 redef fun expr(v)
2212 do
2213 return v.frame.arguments.first
2214 end
2215 end
2216
2217 redef class AContinueExpr
2218 redef fun stmt(v)
2219 do
2220 v.add("goto CONTINUE_{v.escapemark_name(self.escapemark)};")
2221 end
2222 end
2223
2224 redef class ABreakExpr
2225 redef fun stmt(v)
2226 do
2227 v.add("goto BREAK_{v.escapemark_name(self.escapemark)};")
2228 end
2229 end
2230
2231 redef class AReturnExpr
2232 redef fun stmt(v)
2233 do
2234 var nexpr = self.n_expr
2235 if nexpr != null then
2236 var returnvar = v.frame.returnvar.as(not null)
2237 var i = v.expr(nexpr, returnvar.mtype)
2238 v.assign(returnvar, i)
2239 end
2240 v.add("goto {v.frame.returnlabel.as(not null)};")
2241 end
2242 end
2243
2244 redef class AAbortExpr
2245 redef fun stmt(v)
2246 do
2247 v.add_abort("Aborted")
2248 end
2249 end
2250
2251 redef class AIfExpr
2252 redef fun stmt(v)
2253 do
2254 var cond = v.expr_bool(self.n_expr)
2255 v.add("if ({cond})\{")
2256 v.stmt(self.n_then)
2257 v.add("\} else \{")
2258 v.stmt(self.n_else)
2259 v.add("\}")
2260 end
2261 end
2262
2263 redef class AIfexprExpr
2264 redef fun expr(v)
2265 do
2266 var res = v.new_var(self.mtype.as(not null))
2267 var cond = v.expr_bool(self.n_expr)
2268 v.add("if ({cond})\{")
2269 v.assign(res, v.expr(self.n_then, null))
2270 v.add("\} else \{")
2271 v.assign(res, v.expr(self.n_else, null))
2272 v.add("\}")
2273 return res
2274 end
2275 end
2276
2277 redef class ADoExpr
2278 redef fun stmt(v)
2279 do
2280 v.stmt(self.n_block)
2281 var escapemark = self.escapemark
2282 if escapemark != null then
2283 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2284 end
2285 end
2286 end
2287
2288 redef class AWhileExpr
2289 redef fun stmt(v)
2290 do
2291 v.add("for(;;) \{")
2292 var cond = v.expr_bool(self.n_expr)
2293 v.add("if (!{cond}) break;")
2294 v.stmt(self.n_block)
2295 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2296 v.add("\}")
2297 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2298 end
2299 end
2300
2301 redef class ALoopExpr
2302 redef fun stmt(v)
2303 do
2304 v.add("for(;;) \{")
2305 v.stmt(self.n_block)
2306 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2307 v.add("\}")
2308 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2309 end
2310 end
2311
2312 redef class AForExpr
2313 redef fun stmt(v)
2314 do
2315 var cl = v.expr(self.n_expr, null)
2316 var it_meth = self.method_iterator
2317 assert it_meth != null
2318 var it = v.send(it_meth, [cl])
2319 assert it != null
2320 v.add("for(;;) \{")
2321 var isok_meth = self.method_is_ok
2322 assert isok_meth != null
2323 var ok = v.send(isok_meth, [it])
2324 assert ok != null
2325 v.add("if(!{ok}) break;")
2326 if self.variables.length == 1 then
2327 var item_meth = self.method_item
2328 assert item_meth != null
2329 var i = v.send(item_meth, [it])
2330 assert i != null
2331 v.assign(v.variable(variables.first), i)
2332 else if self.variables.length == 2 then
2333 var key_meth = self.method_key
2334 assert key_meth != null
2335 var i = v.send(key_meth, [it])
2336 assert i != null
2337 v.assign(v.variable(variables[0]), i)
2338 var item_meth = self.method_item
2339 assert item_meth != null
2340 i = v.send(item_meth, [it])
2341 assert i != null
2342 v.assign(v.variable(variables[1]), i)
2343 else
2344 abort
2345 end
2346 v.stmt(self.n_block)
2347 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2348 var next_meth = self.method_next
2349 assert next_meth != null
2350 v.send(next_meth, [it])
2351 v.add("\}")
2352 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2353 end
2354 end
2355
2356 redef class AAssertExpr
2357 redef fun stmt(v)
2358 do
2359 var cond = v.expr_bool(self.n_expr)
2360 v.add("if (!{cond}) \{")
2361 v.stmt(self.n_else)
2362 var nid = self.n_id
2363 if nid != null then
2364 v.add_abort("Assert '{nid.text}' failed")
2365 else
2366 v.add_abort("Assert failed")
2367 end
2368 v.add("\}")
2369 end
2370 end
2371
2372 redef class AOrExpr
2373 redef fun expr(v)
2374 do
2375 var res = v.new_var(self.mtype.as(not null))
2376 var i1 = v.expr_bool(self.n_expr)
2377 v.add("if ({i1}) \{")
2378 v.add("{res} = 1;")
2379 v.add("\} else \{")
2380 var i2 = v.expr_bool(self.n_expr2)
2381 v.add("{res} = {i2};")
2382 v.add("\}")
2383 return res
2384 end
2385 end
2386
2387 redef class AAndExpr
2388 redef fun expr(v)
2389 do
2390 var res = v.new_var(self.mtype.as(not null))
2391 var i1 = v.expr_bool(self.n_expr)
2392 v.add("if (!{i1}) \{")
2393 v.add("{res} = 0;")
2394 v.add("\} else \{")
2395 var i2 = v.expr_bool(self.n_expr2)
2396 v.add("{res} = {i2};")
2397 v.add("\}")
2398 return res
2399 end
2400 end
2401
2402 redef class ANotExpr
2403 redef fun expr(v)
2404 do
2405 var cond = v.expr_bool(self.n_expr)
2406 return v.new_expr("!{cond}", self.mtype.as(not null))
2407 end
2408 end
2409
2410 redef class AOrElseExpr
2411 redef fun expr(v)
2412 do
2413 var res = v.new_var(self.mtype.as(not null))
2414 var i1 = v.expr(self.n_expr, null)
2415 v.add("if ({i1}!=NULL) \{")
2416 v.assign(res, i1)
2417 v.add("\} else \{")
2418 var i2 = v.expr(self.n_expr2, null)
2419 v.assign(res, i2)
2420 v.add("\}")
2421 return res
2422 end
2423 end
2424
2425 redef class AEeExpr
2426 redef fun expr(v)
2427 do
2428 var value1 = v.expr(self.n_expr, null)
2429 var value2 = v.expr(self.n_expr2, null)
2430 return v.equal_test(value1, value2)
2431 end
2432 end
2433
2434 redef class AIntExpr
2435 redef fun expr(v)
2436 do
2437 return v.new_expr("{self.n_number.text}", self.mtype.as(not null))
2438 end
2439 end
2440
2441 redef class AFloatExpr
2442 redef fun expr(v)
2443 do
2444 return v.new_expr("{self.n_float.text}", self.mtype.as(not null))
2445 end
2446 end
2447
2448 redef class ACharExpr
2449 redef fun expr(v)
2450 do
2451 return v.new_expr("{self.n_char.text}", self.mtype.as(not null))
2452 end
2453 end
2454
2455 redef class AArrayExpr
2456 redef fun expr(v)
2457 do
2458 var mtype = self.mtype.as(MClassType).arguments.first
2459 var array = new Array[RuntimeVariable]
2460 for nexpr in self.n_exprs.n_exprs do
2461 var i = v.expr(nexpr, mtype)
2462 array.add(i)
2463 end
2464 return v.array_instance(array, mtype)
2465 end
2466 end
2467
2468 redef class AStringFormExpr
2469 redef fun expr(v)
2470 do
2471 return v.string_instance(self.value.as(not null))
2472 end
2473 end
2474
2475 redef class ASuperstringExpr
2476 redef fun expr(v)
2477 do
2478 var array = new Array[RuntimeVariable]
2479 for ne in self.n_exprs do
2480 if ne isa AStringFormExpr and ne.value == "" then continue # skip empty sub-strings
2481 var i = v.expr(ne, null)
2482 array.add(i)
2483 end
2484 var a = v.array_instance(array, v.object_type)
2485 var res = v.send(v.get_property("to_s", a.mtype), [a])
2486 return res
2487 end
2488 end
2489
2490 redef class ACrangeExpr
2491 redef fun expr(v)
2492 do
2493 var i1 = v.expr(self.n_expr, null)
2494 var i2 = v.expr(self.n_expr2, null)
2495 var res = v.init_instance(self.mtype.as(MClassType))
2496 var it = v.send(v.get_property("init", res.mtype), [res, i1, i2])
2497 v.check_init_instance(res)
2498 return res
2499 end
2500 end
2501
2502 redef class AOrangeExpr
2503 redef fun expr(v)
2504 do
2505 var i1 = v.expr(self.n_expr, null)
2506 var i2 = v.expr(self.n_expr2, null)
2507 var res = v.init_instance(self.mtype.as(MClassType))
2508 var it = v.send(v.get_property("without_last", res.mtype), [res, i1, i2])
2509 v.check_init_instance(res)
2510 return res
2511 end
2512 end
2513
2514 redef class ATrueExpr
2515 redef fun expr(v)
2516 do
2517 return v.new_expr("1", self.mtype.as(not null))
2518 end
2519 end
2520
2521 redef class AFalseExpr
2522 redef fun expr(v)
2523 do
2524 return v.new_expr("0", self.mtype.as(not null))
2525 end
2526 end
2527
2528 redef class ANullExpr
2529 redef fun expr(v)
2530 do
2531 var res = v.new_expr("NULL", self.mtype.as(not null))
2532 return res
2533 end
2534 end
2535
2536 redef class AIsaExpr
2537 redef fun expr(v)
2538 do
2539 var i = v.expr(self.n_expr, null)
2540 return v.type_test(i, self.cast_type.as(not null))
2541 end
2542 end
2543
2544 redef class AAsCastExpr
2545 redef fun expr(v)
2546 do
2547 var i = v.expr(self.n_expr, null)
2548 var cond = v.type_test(i, self.mtype.as(not null))
2549 v.add("if (!{cond}) \{")
2550 v.add_abort("Cast failed")
2551 v.add("\}")
2552 return i
2553 end
2554 end
2555
2556 redef class AAsNotnullExpr
2557 redef fun expr(v)
2558 do
2559 var i = v.expr(self.n_expr, null)
2560 v.add("if ({i} == NULL) \{")
2561 v.add_abort("Cast failed")
2562 v.add("\}")
2563 return i
2564 end
2565 end
2566
2567 redef class AParExpr
2568 redef fun expr(v)
2569 do
2570 return v.expr(self.n_expr, null)
2571 end
2572 end
2573
2574 redef class AOnceExpr
2575 redef fun expr(v)
2576 do
2577 var mtype = self.mtype.as(not null)
2578 var name = v.get_name("varonce")
2579 var guard = v.get_name(name + "_guard")
2580 v.add_decl("static {mtype.ctype} {name};")
2581 v.add_decl("static int {guard};")
2582 var res = v.new_var(mtype)
2583 v.add("if ({guard}) \{")
2584 v.add("{res} = {name};")
2585 v.add("\} else \{")
2586 var i = v.expr(self.n_expr, mtype)
2587 v.add("{res} = {i};")
2588 v.add("{name} = {res};")
2589 v.add("{guard} = 1;")
2590 v.add("\}")
2591 return res
2592 end
2593 end
2594
2595 redef class ASendExpr
2596 redef fun expr(v)
2597 do
2598 var recv = v.expr(self.n_expr, null)
2599 var args = [recv]
2600 for a in self.raw_arguments.as(not null) do
2601 args.add(v.expr(a, null))
2602 end
2603 var mproperty = self.mproperty.as(not null)
2604 return v.send(mproperty, args)
2605 end
2606 end
2607
2608 redef class ASendReassignFormExpr
2609 redef fun stmt(v)
2610 do
2611 var recv = v.expr(self.n_expr, null)
2612 var args = [recv]
2613 for a in self.raw_arguments.as(not null) do
2614 args.add(v.expr(a, null))
2615 end
2616 var value = v.expr(self.n_value, null)
2617
2618 var mproperty = self.mproperty.as(not null)
2619 var left = v.send(mproperty, args)
2620 assert left != null
2621
2622 var res = v.send(reassign_property.mproperty, [left, value])
2623 assert res != null
2624
2625 args.add(res)
2626 v.send(self.write_mproperty.as(not null), args)
2627 end
2628 end
2629
2630 redef class ASuperExpr
2631 redef fun expr(v)
2632 do
2633 var recv = v.frame.arguments.first
2634 var args = [recv]
2635 for a in self.n_args.n_exprs do
2636 args.add(v.expr(a, null))
2637 end
2638 if args.length == 1 then
2639 args = v.frame.arguments
2640 end
2641
2642 var mproperty = self.mproperty
2643 if mproperty != null then
2644 if mproperty.intro.msignature.arity == 0 then
2645 args = [recv]
2646 end
2647 # Super init call
2648 var res = v.send(mproperty, args)
2649 return res
2650 end
2651
2652 # stantard call-next-method
2653 var mpropdef = v.frame.mpropdef
2654 # FIXME: we do not want an ugly static call!
2655 var mpropdefs = mpropdef.mproperty.lookup_super_definitions(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
2656 if mpropdefs.length != 1 then
2657 v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
2658 debug("MPRODFEFS for super {mpropdef} for {recv}: {mpropdefs.join(", ")}")
2659 end
2660 mpropdef = mpropdefs.first
2661 assert mpropdef isa MMethodDef
2662 var res = v.call(mpropdef, recv.mtype.as(MClassType), args)
2663 return res
2664 end
2665 end
2666
2667 redef class ANewExpr
2668 redef fun expr(v)
2669 do
2670 var mproperty = self.mproperty.as(not null)
2671 var mtype = self.mtype.as(MClassType)
2672 var recv
2673 var ctype = mtype.ctype
2674 if ctype == "val*" then
2675 recv = v.init_instance(mtype)
2676 else if ctype == "void*" then
2677 recv = v.new_expr("NULL/*special!*/", mtype)
2678 else
2679 debug("cannot new {mtype}")
2680 abort
2681 end
2682 var args = [recv]
2683 for a in self.n_args.n_exprs do
2684 args.add(v.expr(a, null))
2685 end
2686 var res2 = v.send(mproperty, args)
2687 if res2 != null then
2688 #self.debug("got {res2} from {mproperty}. drop {recv}")
2689 return res2
2690 end
2691 v.check_init_instance(recv)
2692 return recv
2693 end
2694 end
2695
2696 redef class AAttrExpr
2697 redef fun expr(v)
2698 do
2699 var recv = v.expr(self.n_expr, null)
2700 var mproperty = self.mproperty.as(not null)
2701 return v.read_attribute(mproperty, recv)
2702 end
2703 end
2704
2705 redef class AAttrAssignExpr
2706 redef fun stmt(v)
2707 do
2708 var recv = v.expr(self.n_expr, null)
2709 var i = v.expr(self.n_value, null)
2710 var mproperty = self.mproperty.as(not null)
2711 v.write_attribute(mproperty, recv, i)
2712 end
2713 end
2714
2715 redef class AAttrReassignExpr
2716 redef fun stmt(v)
2717 do
2718 var recv = v.expr(self.n_expr, null)
2719 var value = v.expr(self.n_value, null)
2720 var mproperty = self.mproperty.as(not null)
2721 var attr = v.read_attribute(mproperty, recv)
2722 var res = v.send(reassign_property.mproperty, [attr, value])
2723 assert res != null
2724 v.write_attribute(mproperty, recv, res)
2725 end
2726 end
2727
2728 redef class AIssetAttrExpr
2729 redef fun expr(v)
2730 do
2731 var recv = v.expr(self.n_expr, null)
2732 var mproperty = self.mproperty.as(not null)
2733 return v.isset_attribute(mproperty, recv)
2734 end
2735 end
2736
2737 redef class ADebugTypeExpr
2738 redef fun stmt(v)
2739 do
2740 # do nothing
2741 end
2742 end