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