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