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