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