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