tests: add test_new_native.nit
[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 native_array_instance(elttype: MType, length: RuntimeVariable): RuntimeVariable is abstract
892
893 fun calloc_array(ret_type: MType, arguments: Array[RuntimeVariable]) is abstract
894
895 fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable]) is abstract
896
897 # Transform varargs, in raw arguments, into a single argument of type `Array`
898 # Note: this method modify the given `args`
899 # If there is no vararg, then `args` is not modified.
900 fun varargize(mpropdef: MPropDef, msignature: MSignature, args: Array[RuntimeVariable])
901 do
902 var recv = args.first
903 var vararg_rank = msignature.vararg_rank
904 if vararg_rank >= 0 then
905 assert args.length >= msignature.arity + 1 # because of self
906 var rawargs = args
907 args = new Array[RuntimeVariable]
908
909 args.add(rawargs.first) # recv
910
911 for i in [0..vararg_rank[ do
912 args.add(rawargs[i+1])
913 end
914
915 var vararg_lastrank = vararg_rank + rawargs.length-1-msignature.arity
916 var vararg = new Array[RuntimeVariable]
917 for i in [vararg_rank..vararg_lastrank] do
918 vararg.add(rawargs[i+1])
919 end
920
921 var elttype = msignature.mparameters[vararg_rank].mtype
922 args.add(self.vararg_instance(mpropdef, recv, vararg, elttype))
923
924 for i in [vararg_lastrank+1..rawargs.length-1[ do
925 args.add(rawargs[i+1])
926 end
927 rawargs.clear
928 rawargs.add_all(args)
929 end
930 end
931
932 # Type handling
933
934 # Anchor a type to the main module and the current receiver
935 fun anchor(mtype: MType): MType
936 do
937 if not mtype.need_anchor then return mtype
938 return mtype.anchor_to(self.compiler.mainmodule, self.frame.receiver)
939 end
940
941 fun resolve_for(mtype: MType, recv: RuntimeVariable): MType
942 do
943 if not mtype.need_anchor then return mtype
944 return mtype.resolve_for(recv.mcasttype, self.frame.receiver, self.compiler.mainmodule, true)
945 end
946
947 # Unsafely cast a value to a new type
948 # ie the result share the same C variable but my have a different mcasttype
949 # NOTE: if the adaptation is useless then `value` is returned as it.
950 # ENSURE: `result.name == value.name`
951 fun autoadapt(value: RuntimeVariable, mtype: MType): RuntimeVariable
952 do
953 mtype = self.anchor(mtype)
954 var valmtype = value.mcasttype
955 if valmtype.is_subtype(self.compiler.mainmodule, null, mtype) then
956 return value
957 end
958
959 if valmtype isa MNullableType and valmtype.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
960 var res = new RuntimeVariable(value.name, valmtype, valmtype.mtype)
961 return res
962 else
963 var res = new RuntimeVariable(value.name, valmtype, mtype)
964 return res
965 end
966 end
967
968 # Generate a super call from a method definition
969 fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
970
971 fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable]) is abstract
972
973 # Box or unbox a value to another type iff a C type conversion is needed
974 # ENSURE: `result.mtype.ctype == mtype.ctype`
975 fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable is abstract
976
977 # Generate a polymorphic subtype test
978 fun type_test(value: RuntimeVariable, mtype: MType, tag: String): RuntimeVariable is abstract
979
980 # Generate the code required to dynamically check if 2 objects share the same runtime type
981 fun is_same_type_test(value1, value2: RuntimeVariable): RuntimeVariable is abstract
982
983 # Generate a Nit "is" for two runtime_variables
984 fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable is abstract
985
986 # Sends
987
988 # Generate a static call on a method definition
989 fun call(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
990
991 # Generate a polymorphic send for the method `m` and the arguments `args`
992 fun send(m: MMethod, args: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
993
994 # Generate a monomorphic send for the method `m`, the type `t` and the arguments `args`
995 fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable
996 do
997 assert t isa MClassType
998 var propdef = m.lookup_first_definition(self.compiler.mainmodule, t)
999 return self.call(propdef, t, args)
1000 end
1001
1002 # Generate a monomorphic super send from the method `m`, the type `t` and the arguments `args`
1003 fun monomorphic_super_send(m: MMethodDef, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable
1004 do
1005 assert t isa MClassType
1006 m = m.lookup_next_definition(self.compiler.mainmodule, t)
1007 return self.call(m, t, args)
1008 end
1009
1010 # Attributes handling
1011
1012 # Generate a polymorphic attribute is_set test
1013 fun isset_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable is abstract
1014
1015 # Generate a polymorphic attribute read
1016 fun read_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable is abstract
1017
1018 # Generate a polymorphic attribute write
1019 fun write_attribute(a: MAttribute, recv: RuntimeVariable, value: RuntimeVariable) is abstract
1020
1021 # Checks
1022
1023 # Add a check and an abort for a null reciever if needed
1024 fun check_recv_notnull(recv: RuntimeVariable)
1025 do
1026 if self.compiler.modelbuilder.toolcontext.opt_no_check_other.value then return
1027
1028 var maybenull = recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType
1029 if maybenull then
1030 self.add("if (unlikely({recv} == NULL)) \{")
1031 self.add_abort("Receiver is null")
1032 self.add("\}")
1033 end
1034 end
1035
1036 # Names handling
1037
1038 private var names: HashSet[String] = new HashSet[String]
1039 private var last: Int = 0
1040
1041 # Return a new name based on `s` and unique in the visitor
1042 fun get_name(s: String): String
1043 do
1044 if not self.names.has(s) then
1045 self.names.add(s)
1046 return s
1047 end
1048 var i = self.last + 1
1049 loop
1050 var s2 = s + i.to_s
1051 if not self.names.has(s2) then
1052 self.last = i
1053 self.names.add(s2)
1054 return s2
1055 end
1056 i = i + 1
1057 end
1058 end
1059
1060 # Return an unique and stable identifier associated with an escapemark
1061 fun escapemark_name(e: nullable EscapeMark): String
1062 do
1063 assert e != null
1064 if escapemark_names.has_key(e) then return escapemark_names[e]
1065 var name = e.name
1066 if name == null then name = "label"
1067 name = get_name(name)
1068 escapemark_names[e] = name
1069 return name
1070 end
1071
1072 private var escapemark_names = new HashMap[EscapeMark, String]
1073
1074 # Return a "const char*" variable associated to the classname of the dynamic type of an object
1075 # NOTE: we do not return a `RuntimeVariable` "NativeString" as the class may not exist in the module/program
1076 fun class_name_string(value: RuntimeVariable): String is abstract
1077
1078 # Variables handling
1079
1080 protected var variables: HashMap[Variable, RuntimeVariable] = new HashMap[Variable, RuntimeVariable]
1081
1082 # Return the local runtime_variable associated to a Nit local variable
1083 fun variable(variable: Variable): RuntimeVariable
1084 do
1085 if self.variables.has_key(variable) then
1086 return self.variables[variable]
1087 else
1088 var name = self.get_name("var_{variable.name}")
1089 var mtype = variable.declared_type.as(not null)
1090 mtype = self.anchor(mtype)
1091 var res = new RuntimeVariable(name, mtype, mtype)
1092 self.add_decl("{mtype.ctype} {name} /* var {variable}: {mtype} */;")
1093 self.variables[variable] = res
1094 return res
1095 end
1096 end
1097
1098 # Return a new uninitialized local runtime_variable
1099 fun new_var(mtype: MType): RuntimeVariable
1100 do
1101 mtype = self.anchor(mtype)
1102 var name = self.get_name("var")
1103 var res = new RuntimeVariable(name, mtype, mtype)
1104 self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
1105 return res
1106 end
1107
1108 # Return a new uninitialized named runtime_variable
1109 fun new_named_var(mtype: MType, name: String): RuntimeVariable
1110 do
1111 mtype = self.anchor(mtype)
1112 var res = new RuntimeVariable(name, mtype, mtype)
1113 self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
1114 return res
1115 end
1116
1117 # Correctly assign a left and a right value
1118 # Boxing and unboxing is performed if required
1119 fun assign(left, right: RuntimeVariable)
1120 do
1121 right = self.autobox(right, left.mtype)
1122 self.add("{left} = {right};")
1123 end
1124
1125 # Generate instances
1126
1127 # Generate a alloc-instance + init-attributes
1128 fun init_instance(mtype: MClassType): RuntimeVariable is abstract
1129
1130 # Generate an integer value
1131 fun int_instance(value: Int): RuntimeVariable
1132 do
1133 var res = self.new_var(self.get_class("Int").mclass_type)
1134 self.add("{res} = {value};")
1135 return res
1136 end
1137
1138 # Generate a string value
1139 fun string_instance(string: String): RuntimeVariable
1140 do
1141 var mtype = self.get_class("String").mclass_type
1142 var name = self.get_name("varonce")
1143 self.add_decl("static {mtype.ctype} {name};")
1144 var res = self.new_var(mtype)
1145 self.add("if ({name}) \{")
1146 self.add("{res} = {name};")
1147 self.add("\} else \{")
1148 var native_mtype = self.get_class("NativeString").mclass_type
1149 var nat = self.new_var(native_mtype)
1150 self.add("{nat} = \"{string.escape_to_c}\";")
1151 var length = self.int_instance(string.length)
1152 self.add("{res} = {self.send(self.get_property("to_s_with_length", native_mtype), [nat, length]).as(not null)};")
1153 self.add("{name} = {res};")
1154 self.add("\}")
1155 return res
1156 end
1157
1158 # Generate an array value
1159 fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable is abstract
1160
1161 # Get an instance of a array for a vararg
1162 fun vararg_instance(mpropdef: MPropDef, recv: RuntimeVariable, varargs: Array[RuntimeVariable], elttype: MType): RuntimeVariable is abstract
1163
1164 # Code generation
1165
1166 # Add a line in the main part of the generated C
1167 fun add(s: String) do self.writer.lines.add(s)
1168
1169 # Add a line in the
1170 # (used for local or global declaration)
1171 fun add_decl(s: String) do self.writer.decl_lines.add(s)
1172
1173 # Request the presence of a global declaration
1174 fun require_declaration(key: String)
1175 do
1176 var reqs = self.writer.file.required_declarations
1177 if reqs.has(key) then return
1178 reqs.add(key)
1179 var node = current_node
1180 if node != null then compiler.requirers_of_declarations[key] = node
1181 end
1182
1183 # Add a declaration in the local-header
1184 # The declaration is ensured to be present once
1185 fun declare_once(s: String)
1186 do
1187 self.compiler.provide_declaration(s, s)
1188 self.require_declaration(s)
1189 end
1190
1191 # look for a needed .h and .c file for a given .nit source-file
1192 # FIXME: bad API, parameter should be a `MModule`, not its source-file
1193 fun add_extern(file: String)
1194 do
1195 file = file.strip_extension(".nit")
1196 var tryfile = file + ".nit.h"
1197 if tryfile.file_exists then
1198 self.declare_once("#include \"{tryfile.basename("")}\"")
1199 self.compiler.files_to_copy.add(tryfile)
1200 end
1201 tryfile = file + "_nit.h"
1202 if tryfile.file_exists then
1203 self.declare_once("#include \"{tryfile.basename("")}\"")
1204 self.compiler.files_to_copy.add(tryfile)
1205 end
1206
1207 if self.compiler.seen_extern.has(file) then return
1208 self.compiler.seen_extern.add(file)
1209 tryfile = file + ".nit.c"
1210 if not tryfile.file_exists then
1211 tryfile = file + "_nit.c"
1212 if not tryfile.file_exists then return
1213 end
1214 var f = new ExternCFile(tryfile.basename(""), "")
1215 self.compiler.extern_bodies.add(f)
1216 self.compiler.files_to_copy.add(tryfile)
1217 end
1218
1219 # Return a new local runtime_variable initialized with the C expression `cexpr`.
1220 fun new_expr(cexpr: String, mtype: MType): RuntimeVariable
1221 do
1222 var res = new_var(mtype)
1223 self.add("{res} = {cexpr};")
1224 return res
1225 end
1226
1227 # Generate generic abort
1228 # used by aborts, asserts, casts, etc.
1229 fun add_abort(message: String)
1230 do
1231 self.add("PRINT_ERROR(\"Runtime error: %s\", \"{message.escape_to_c}\");")
1232 add_raw_abort
1233 end
1234
1235 fun add_raw_abort
1236 do
1237 if self.current_node != null and self.current_node.location.file != null then
1238 self.add("PRINT_ERROR(\" (%s:%d)\\n\", \"{self.current_node.location.file.filename.escape_to_c}\", {current_node.location.line_start});")
1239 else
1240 self.add("PRINT_ERROR(\"\\n\");")
1241 end
1242 self.add("show_backtrace(1);")
1243 end
1244
1245 # Add a dynamic cast
1246 fun add_cast(value: RuntimeVariable, mtype: MType, tag: String)
1247 do
1248 var res = self.type_test(value, mtype, tag)
1249 self.add("if (unlikely(!{res})) \{")
1250 var cn = self.class_name_string(value)
1251 self.add("PRINT_ERROR(\"Runtime error: Cast failed. Expected `%s`, got `%s`\", \"{mtype.to_s.escape_to_c}\", {cn});")
1252 self.add_raw_abort
1253 self.add("\}")
1254 end
1255
1256 # Generate a return with the value `s`
1257 fun ret(s: RuntimeVariable)
1258 do
1259 self.assign(self.frame.returnvar.as(not null), s)
1260 self.add("goto {self.frame.returnlabel.as(not null)};")
1261 end
1262
1263 # Compile a statement (if any)
1264 fun stmt(nexpr: nullable AExpr)
1265 do
1266 if nexpr == null then return
1267 var old = self.current_node
1268 self.current_node = nexpr
1269 nexpr.stmt(self)
1270 self.current_node = old
1271 end
1272
1273 # Compile an expression an return its result
1274 # `mtype` is the expected return type, pass null if no specific type is expected.
1275 fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable
1276 do
1277 var old = self.current_node
1278 self.current_node = nexpr
1279 var res = nexpr.expr(self).as(not null)
1280 if mtype != null then
1281 mtype = self.anchor(mtype)
1282 res = self.autobox(res, mtype)
1283 end
1284 res = autoadapt(res, nexpr.mtype.as(not null))
1285 var implicit_cast_to = nexpr.implicit_cast_to
1286 if implicit_cast_to != null and not self.compiler.modelbuilder.toolcontext.opt_no_check_autocast.value then
1287 add_cast(res, implicit_cast_to, "auto")
1288 res = autoadapt(res, implicit_cast_to)
1289 end
1290 self.current_node = old
1291 return res
1292 end
1293
1294 # Alias for `self.expr(nexpr, self.bool_type)`
1295 fun expr_bool(nexpr: AExpr): RuntimeVariable do return expr(nexpr, bool_type)
1296
1297 # Safely show a debug message on the current node and repeat the message in the C code as a comment
1298 fun debug(message: String)
1299 do
1300 var node = self.current_node
1301 if node == null then
1302 print "?: {message}"
1303 else
1304 node.debug(message)
1305 end
1306 self.add("/* DEBUG: {message} */")
1307 end
1308 end
1309
1310 # A C function associated to a Nit method
1311 # Because of customization, a given Nit method can be compiler more that once
1312 abstract class AbstractRuntimeFunction
1313
1314 type COMPILER: AbstractCompiler
1315 type VISITOR: AbstractCompilerVisitor
1316
1317 # The associated Nit method
1318 var mmethoddef: MMethodDef
1319
1320 # The mangled c name of the runtime_function
1321 # Subclasses should redefine `build_c_name` instead
1322 fun c_name: String
1323 do
1324 var res = self.c_name_cache
1325 if res != null then return res
1326 res = self.build_c_name
1327 self.c_name_cache = res
1328 return res
1329 end
1330
1331 # Non cached version of `c_name`
1332 protected fun build_c_name: String is abstract
1333
1334 protected var c_name_cache: nullable String writable = null
1335
1336 # Implements a call of the runtime_function
1337 # May inline the body or generate a C function call
1338 fun call(v: VISITOR, arguments: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
1339
1340 # Generate the code for the `AbstractRuntimeFunction`
1341 # Warning: compile more than once compilation makes CC unhappy
1342 fun compile_to_c(compiler: COMPILER) is abstract
1343 end
1344
1345 # A runtime variable hold a runtime value in C.
1346 # Runtime variables are associated to Nit local variables and intermediate results in Nit expressions.
1347 #
1348 # 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.
1349 class RuntimeVariable
1350 # The name of the variable in the C code
1351 var name: String
1352
1353 # The static type of the variable (as declard in C)
1354 var mtype: MType
1355
1356 # The current casted type of the variable (as known in Nit)
1357 var mcasttype: MType writable
1358
1359 # If the variable exaclty a mcasttype?
1360 # false (usual value) means that the variable is a mcasttype or a subtype.
1361 var is_exact: Bool writable = false
1362
1363 init(name: String, mtype: MType, mcasttype: MType)
1364 do
1365 self.name = name
1366 self.mtype = mtype
1367 self.mcasttype = mcasttype
1368 assert not mtype.need_anchor
1369 assert not mcasttype.need_anchor
1370 end
1371
1372 redef fun to_s do return name
1373
1374 redef fun inspect
1375 do
1376 var exact_str
1377 if self.is_exact then
1378 exact_str = " exact"
1379 else
1380 exact_str = ""
1381 end
1382 var type_str
1383 if self.mtype == self.mcasttype then
1384 type_str = "{mtype}{exact_str}"
1385 else
1386 type_str = "{mtype}({mcasttype}{exact_str})"
1387 end
1388 return "<{name}:{type_str}>"
1389 end
1390 end
1391
1392 # A frame correspond to a visited property in a `GlobalCompilerVisitor`
1393 class Frame
1394
1395 type VISITOR: AbstractCompilerVisitor
1396
1397 # The associated visitor
1398 var visitor: VISITOR
1399
1400 # The executed property.
1401 # A Method in case of a call, an attribute in case of a default initialization.
1402 var mpropdef: MPropDef
1403
1404 # The static type of the receiver
1405 var receiver: MClassType
1406
1407 # Arguments of the method (the first is the receiver)
1408 var arguments: Array[RuntimeVariable]
1409
1410 # The runtime_variable associated to the return (in a function)
1411 var returnvar: nullable RuntimeVariable writable = null
1412
1413 # The label at the end of the property
1414 var returnlabel: nullable String writable = null
1415 end
1416
1417 redef class MType
1418 # Return the C type associated to a given Nit static type
1419 fun ctype: String do return "val*"
1420
1421 fun ctypename: String do return "val"
1422
1423 # Return the name of the C structure associated to a Nit live type
1424 fun c_name: String is abstract
1425 protected var c_name_cache: nullable String protected writable
1426 end
1427
1428 redef class MClassType
1429 redef fun c_name
1430 do
1431 var res = self.c_name_cache
1432 if res != null then return res
1433 res = "{mclass.intro_mmodule.name.to_cmangle}__{mclass.name.to_cmangle}"
1434 self.c_name_cache = res
1435 return res
1436 end
1437
1438 redef fun ctype: String
1439 do
1440 if mclass.name == "Int" then
1441 return "long"
1442 else if mclass.name == "Bool" then
1443 return "short int"
1444 else if mclass.name == "Char" then
1445 return "char"
1446 else if mclass.name == "Float" then
1447 return "double"
1448 else if mclass.name == "NativeString" then
1449 return "char*"
1450 else if mclass.name == "NativeArray" then
1451 return "val*"
1452 else if mclass.kind == extern_kind then
1453 return "void*"
1454 else
1455 return "val*"
1456 end
1457 end
1458
1459 redef fun ctypename: String
1460 do
1461 if mclass.name == "Int" then
1462 return "l"
1463 else if mclass.name == "Bool" then
1464 return "s"
1465 else if mclass.name == "Char" then
1466 return "c"
1467 else if mclass.name == "Float" then
1468 return "d"
1469 else if mclass.name == "NativeString" then
1470 return "str"
1471 else if mclass.name == "NativeArray" then
1472 #return "{self.arguments.first.ctype}*"
1473 return "val"
1474 else if mclass.kind == extern_kind then
1475 return "ptr"
1476 else
1477 return "val"
1478 end
1479 end
1480 end
1481
1482 redef class MGenericType
1483 redef fun c_name
1484 do
1485 var res = self.c_name_cache
1486 if res != null then return res
1487 res = super
1488 for t in self.arguments do
1489 res = res + t.c_name
1490 end
1491 self.c_name_cache = res
1492 return res
1493 end
1494 end
1495
1496 redef class MParameterType
1497 redef fun c_name
1498 do
1499 var res = self.c_name_cache
1500 if res != null then return res
1501 res = "{self.mclass.c_name}_FT{self.rank}"
1502 self.c_name_cache = res
1503 return res
1504 end
1505 end
1506
1507 redef class MVirtualType
1508 redef fun c_name
1509 do
1510 var res = self.c_name_cache
1511 if res != null then return res
1512 res = "{self.mproperty.intro.mclassdef.mclass.c_name}_VT{self.mproperty.name}"
1513 self.c_name_cache = res
1514 return res
1515 end
1516 end
1517
1518 redef class MNullableType
1519 redef fun c_name
1520 do
1521 var res = self.c_name_cache
1522 if res != null then return res
1523 res = "nullable_{self.mtype.c_name}"
1524 self.c_name_cache = res
1525 return res
1526 end
1527 end
1528
1529 redef class MClass
1530 # Return the name of the C structure associated to a Nit class
1531 fun c_name: String do
1532 var res = self.c_name_cache
1533 if res != null then return res
1534 res = "{intro_mmodule.name.to_cmangle}__{name.to_cmangle}"
1535 self.c_name_cache = res
1536 return res
1537 end
1538 private var c_name_cache: nullable String
1539 end
1540
1541 redef class MProperty
1542 fun c_name: String do
1543 var res = self.c_name_cache
1544 if res != null then return res
1545 res = "{self.intro.c_name}"
1546 self.c_name_cache = res
1547 return res
1548 end
1549 private var c_name_cache: nullable String
1550 end
1551
1552 redef class MPropDef
1553 type VISITOR: AbstractCompilerVisitor
1554
1555 private var c_name_cache: nullable String
1556
1557 # The mangled name associated to the property
1558 fun c_name: String
1559 do
1560 var res = self.c_name_cache
1561 if res != null then return res
1562 res = "{self.mclassdef.mmodule.name.to_cmangle}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
1563 self.c_name_cache = res
1564 return res
1565 end
1566 end
1567
1568 redef class MMethodDef
1569 # Can the body be inlined?
1570 fun can_inline(v: VISITOR): Bool
1571 do
1572 if is_abstract then return true
1573 var modelbuilder = v.compiler.modelbuilder
1574 if modelbuilder.mpropdef2npropdef.has_key(self) then
1575 var npropdef = modelbuilder.mpropdef2npropdef[self]
1576 return npropdef.can_inline
1577 else if self.mproperty.name == "init" then
1578 # Automatic free init is always inlined since it is empty or contains only attribtes assigments
1579 return true
1580 else
1581 abort
1582 end
1583 end
1584
1585 # Inline the body in another visitor
1586 fun compile_inside_to_c(v: VISITOR, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
1587 do
1588 var modelbuilder = v.compiler.modelbuilder
1589 if modelbuilder.mpropdef2npropdef.has_key(self) then
1590 var npropdef = modelbuilder.mpropdef2npropdef[self]
1591 var oldnode = v.current_node
1592 v.current_node = npropdef
1593 self.compile_parameter_check(v, arguments)
1594 npropdef.compile_to_c(v, self, arguments)
1595 v.current_node = oldnode
1596 else if self.mproperty.name == "init" then
1597 var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
1598 var oldnode = v.current_node
1599 v.current_node = nclassdef
1600 self.compile_parameter_check(v, arguments)
1601 nclassdef.compile_to_c(v, self, arguments)
1602 v.current_node = oldnode
1603 else
1604 abort
1605 end
1606 return null
1607 end
1608
1609 # Generate type checks in the C code to check covariant parameters
1610 fun compile_parameter_check(v: VISITOR, arguments: Array[RuntimeVariable])
1611 do
1612 if v.compiler.modelbuilder.toolcontext.opt_no_check_covariance.value then return
1613
1614 for i in [0..msignature.arity[ do
1615 # skip test for vararg since the array is instantiated with the correct polymorphic type
1616 if msignature.vararg_rank == i then continue
1617
1618 # skip if the cast is not required
1619 var origmtype = self.mproperty.intro.msignature.mparameters[i].mtype
1620 if not origmtype.need_anchor then continue
1621
1622 # get the parameter type
1623 var mtype = self.msignature.mparameters[i].mtype
1624
1625 # generate the cast
1626 # note that v decides if and how to implements the cast
1627 v.add("/* Covariant cast for argument {i} ({self.msignature.mparameters[i].name}) {arguments[i+1].inspect} isa {mtype} */")
1628 v.add_cast(arguments[i+1], mtype, "covariance")
1629 end
1630 end
1631 end
1632
1633 # Node visit
1634
1635 redef class APropdef
1636 fun compile_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1637 do
1638 v.add("PRINT_ERROR(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
1639 debug("Not yet implemented")
1640 end
1641
1642 fun can_inline: Bool do return true
1643 end
1644
1645 redef class AMethPropdef
1646 redef fun compile_to_c(v, mpropdef, arguments)
1647 do
1648 if mpropdef.is_abstract then
1649 var cn = v.class_name_string(arguments.first)
1650 v.add("PRINT_ERROR(\"Runtime error: Abstract method `%s` called on `%s`\", \"{mpropdef.mproperty.name.escape_to_c}\", {cn});")
1651 v.add_raw_abort
1652 return
1653 end
1654
1655 # Call the implicit super-init
1656 var auto_super_inits = self.auto_super_inits
1657 if auto_super_inits != null then
1658 var args = [arguments.first]
1659 for auto_super_init in auto_super_inits do
1660 args.clear
1661 for i in [0..auto_super_init.msignature.arity+1[ do
1662 args.add(arguments[i])
1663 end
1664 v.compile_callsite(auto_super_init, args)
1665 end
1666 end
1667
1668 var n_block = n_block
1669 if n_block != null then
1670 for i in [0..mpropdef.msignature.arity[ do
1671 var variable = self.n_signature.n_params[i].variable.as(not null)
1672 v.assign(v.variable(variable), arguments[i+1])
1673 end
1674 v.stmt(n_block)
1675 else if mpropdef.is_intern then
1676 compile_intern_to_c(v, mpropdef, arguments)
1677 else if mpropdef.is_extern then
1678 if mpropdef.mproperty.is_init then
1679 compile_externinit_to_c(v, mpropdef, arguments)
1680 else
1681 compile_externmeth_to_c(v, mpropdef, arguments)
1682 end
1683 end
1684 end
1685
1686 redef fun can_inline
1687 do
1688 if self.auto_super_inits != null then return false
1689 var nblock = self.n_block
1690 if nblock == null then return true
1691 if (mpropdef.mproperty.name == "==" or mpropdef.mproperty.name == "!=") and mpropdef.mclassdef.mclass.name == "Object" then return true
1692 if nblock isa ABlockExpr and nblock.n_expr.length == 0 then return true
1693 return false
1694 end
1695
1696 fun compile_intern_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1697 do
1698 var pname = mpropdef.mproperty.name
1699 var cname = mpropdef.mclassdef.mclass.name
1700 var ret = mpropdef.msignature.return_mtype
1701 if ret != null then
1702 ret = v.resolve_for(ret, arguments.first)
1703 else if mpropdef.mproperty.is_new then
1704 ret = arguments.first.mcasttype
1705 end
1706 if pname != "==" and pname != "!=" then
1707 v.adapt_signature(mpropdef, arguments)
1708 end
1709 if cname == "Int" then
1710 if pname == "output" then
1711 v.add("printf(\"%ld\\n\", {arguments.first});")
1712 return
1713 else if pname == "object_id" then
1714 v.ret(arguments.first)
1715 return
1716 else if pname == "+" then
1717 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1718 return
1719 else if pname == "-" then
1720 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1721 return
1722 else if pname == "unary -" then
1723 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1724 return
1725 else if pname == "*" then
1726 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1727 return
1728 else if pname == "/" then
1729 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1730 return
1731 else if pname == "%" then
1732 v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
1733 return
1734 else if pname == "lshift" then
1735 v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
1736 return
1737 else if pname == "rshift" then
1738 v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
1739 return
1740 else if pname == "==" then
1741 v.ret(v.equal_test(arguments[0], arguments[1]))
1742 return
1743 else if pname == "!=" then
1744 var res = v.equal_test(arguments[0], arguments[1])
1745 v.ret(v.new_expr("!{res}", ret.as(not null)))
1746 return
1747 else if pname == "<" then
1748 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1749 return
1750 else if pname == ">" then
1751 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1752 return
1753 else if pname == "<=" then
1754 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1755 return
1756 else if pname == ">=" then
1757 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1758 return
1759 else if pname == "to_f" then
1760 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1761 return
1762 else if pname == "ascii" then
1763 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1764 return
1765 end
1766 else if cname == "Char" then
1767 if pname == "output" then
1768 v.add("printf(\"%c\", {arguments.first});")
1769 return
1770 else if pname == "object_id" then
1771 v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
1772 return
1773 else if pname == "successor" then
1774 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1775 return
1776 else if pname == "predecessor" then
1777 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1778 return
1779 else if pname == "==" then
1780 v.ret(v.equal_test(arguments[0], arguments[1]))
1781 return
1782 else if pname == "!=" then
1783 var res = v.equal_test(arguments[0], arguments[1])
1784 v.ret(v.new_expr("!{res}", ret.as(not null)))
1785 return
1786 else if pname == "<" then
1787 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1788 return
1789 else if pname == ">" then
1790 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1791 return
1792 else if pname == "<=" then
1793 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1794 return
1795 else if pname == ">=" then
1796 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1797 return
1798 else if pname == "to_i" then
1799 v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
1800 return
1801 else if pname == "ascii" then
1802 v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
1803 return
1804 end
1805 else if cname == "Bool" then
1806 if pname == "output" then
1807 v.add("printf({arguments.first}?\"true\\n\":\"false\\n\");")
1808 return
1809 else if pname == "object_id" then
1810 v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
1811 return
1812 else if pname == "==" then
1813 v.ret(v.equal_test(arguments[0], arguments[1]))
1814 return
1815 else if pname == "!=" then
1816 var res = v.equal_test(arguments[0], arguments[1])
1817 v.ret(v.new_expr("!{res}", ret.as(not null)))
1818 return
1819 end
1820 else if cname == "Float" then
1821 if pname == "output" then
1822 v.add("printf(\"%f\\n\", {arguments.first});")
1823 return
1824 else if pname == "object_id" then
1825 v.ret(v.new_expr("(double){arguments.first}", ret.as(not null)))
1826 return
1827 else if pname == "+" then
1828 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1829 return
1830 else if pname == "-" then
1831 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1832 return
1833 else if pname == "unary -" then
1834 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1835 return
1836 else if pname == "succ" then
1837 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1838 return
1839 else if pname == "prec" then
1840 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1841 return
1842 else if pname == "*" then
1843 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1844 return
1845 else if pname == "/" then
1846 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1847 return
1848 else if pname == "==" then
1849 v.ret(v.equal_test(arguments[0], arguments[1]))
1850 return
1851 else if pname == "!=" then
1852 var res = v.equal_test(arguments[0], arguments[1])
1853 v.ret(v.new_expr("!{res}", ret.as(not null)))
1854 return
1855 else if pname == "<" then
1856 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1857 return
1858 else if pname == ">" then
1859 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1860 return
1861 else if pname == "<=" then
1862 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1863 return
1864 else if pname == ">=" then
1865 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1866 return
1867 else if pname == "to_i" then
1868 v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
1869 return
1870 end
1871 else if cname == "NativeString" then
1872 if pname == "[]" then
1873 v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
1874 return
1875 else if pname == "[]=" then
1876 v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
1877 return
1878 else if pname == "copy_to" then
1879 v.add("memcpy({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
1880 return
1881 else if pname == "atoi" then
1882 v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
1883 return
1884 else if pname == "init" then
1885 v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
1886 return
1887 end
1888 else if cname == "NativeArray" then
1889 v.native_array_def(pname, ret, arguments)
1890 return
1891 end
1892 if pname == "exit" then
1893 v.add("exit({arguments[1]});")
1894 return
1895 else if pname == "sys" then
1896 v.ret(v.new_expr("glob_sys", ret.as(not null)))
1897 return
1898 else if pname == "calloc_string" then
1899 v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
1900 return
1901 else if pname == "calloc_array" then
1902 v.calloc_array(ret.as(not null), arguments)
1903 return
1904 else if pname == "object_id" then
1905 v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
1906 return
1907 else if pname == "is_same_type" then
1908 v.ret(v.is_same_type_test(arguments[0], arguments[1]))
1909 return
1910 else if pname == "is_same_instance" then
1911 v.ret(v.equal_test(arguments[0], arguments[1]))
1912 return
1913 else if pname == "output_class_name" then
1914 var nat = v.class_name_string(arguments.first)
1915 v.add("printf(\"%s\\n\", {nat});")
1916 return
1917 else if pname == "native_class_name" then
1918 var nat = v.class_name_string(arguments.first)
1919 v.ret(v.new_expr("(char*){nat}", ret.as(not null)))
1920 return
1921 else if pname == "force_garbage_collection" then
1922 v.add("nit_gcollect();")
1923 return
1924 else if pname == "native_argc" then
1925 v.ret(v.new_expr("glob_argc", ret.as(not null)))
1926 return
1927 else if pname == "native_argv" then
1928 v.ret(v.new_expr("glob_argv[{arguments[1]}]", ret.as(not null)))
1929 return
1930 end
1931 v.add("PRINT_ERROR(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
1932 debug("Not implemented {mpropdef}")
1933 end
1934
1935 fun compile_externmeth_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1936 do
1937 var externname
1938 var nextern = self.n_extern
1939 if nextern == null then
1940 v.add("PRINT_ERROR(\"NOT YET IMPLEMENTED nitni for {mpropdef} at {location.to_s}\\n\");")
1941 v.add("show_backtrace(1);")
1942 return
1943 end
1944 externname = nextern.text.substring(1, nextern.text.length-2)
1945 if location.file != null then
1946 var file = location.file.filename
1947 v.add_extern(file)
1948 end
1949 var res: nullable RuntimeVariable = null
1950 var ret = mpropdef.msignature.return_mtype
1951 if ret != null then
1952 ret = v.resolve_for(ret, arguments.first)
1953 res = v.new_var(ret)
1954 end
1955 v.adapt_signature(mpropdef, arguments)
1956
1957 if res == null then
1958 v.add("{externname}({arguments.join(", ")});")
1959 else
1960 v.add("{res} = {externname}({arguments.join(", ")});")
1961 v.ret(res)
1962 end
1963 end
1964
1965 fun compile_externinit_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1966 do
1967 var externname
1968 var nextern = self.n_extern
1969 if nextern == null then
1970 v.add("PRINT_ERROR(\"NOT YET IMPLEMENTED nitni for {mpropdef} at {location.to_s}\\n\");")
1971 v.add("show_backtrace(1);")
1972 return
1973 end
1974 externname = nextern.text.substring(1, nextern.text.length-2)
1975 if location.file != null then
1976 var file = location.file.filename
1977 v.add_extern(file)
1978 end
1979 v.adapt_signature(mpropdef, arguments)
1980 var ret = arguments.first.mtype
1981 var res = v.new_var(ret)
1982
1983 arguments.shift
1984
1985 v.add("{res} = {externname}({arguments.join(", ")});")
1986 v.ret(res)
1987 end
1988 end
1989
1990 redef class AAttrPropdef
1991 redef fun compile_to_c(v, mpropdef, arguments)
1992 do
1993 if arguments.length == 1 then
1994 var res = v.read_attribute(self.mpropdef.mproperty, arguments.first)
1995 v.assign(v.frame.returnvar.as(not null), res)
1996 else
1997 v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
1998 end
1999 end
2000
2001 fun init_expr(v: AbstractCompilerVisitor, recv: RuntimeVariable)
2002 do
2003 var nexpr = self.n_expr
2004 if nexpr != null then
2005 var oldnode = v.current_node
2006 v.current_node = self
2007 var old_frame = v.frame
2008 var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
2009 v.frame = frame
2010 var value = v.expr(nexpr, self.mpropdef.static_mtype)
2011 v.write_attribute(self.mpropdef.mproperty, recv, value)
2012 v.frame = old_frame
2013 v.current_node = oldnode
2014 end
2015 end
2016
2017 fun check_expr(v: AbstractCompilerVisitor, recv: RuntimeVariable)
2018 do
2019 var nexpr = self.n_expr
2020 if nexpr != null then return
2021
2022 var oldnode = v.current_node
2023 v.current_node = self
2024 var old_frame = v.frame
2025 var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
2026 v.frame = frame
2027 # Force read to check the initialization
2028 v.read_attribute(self.mpropdef.mproperty, recv)
2029 v.frame = old_frame
2030 v.current_node = oldnode
2031 end
2032 end
2033
2034 redef class AClassdef
2035 private fun compile_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
2036 do
2037 if mpropdef == self.mfree_init then
2038 var super_inits = self.super_inits
2039 if super_inits != null then
2040 var args_of_super = arguments
2041 if arguments.length > 1 then args_of_super = [arguments.first]
2042 for su in super_inits do
2043 v.send(su, args_of_super)
2044 end
2045 end
2046 var recv = arguments.first
2047 var i = 1
2048 # Collect undefined attributes
2049 for npropdef in self.n_propdefs do
2050 if npropdef isa AAttrPropdef and npropdef.n_expr == null then
2051 v.write_attribute(npropdef.mpropdef.mproperty, recv, arguments[i])
2052 i += 1
2053 end
2054 end
2055 else
2056 abort
2057 end
2058 end
2059 end
2060
2061 redef class AExpr
2062 # Try to compile self as an expression
2063 # Do not call this method directly, use `v.expr` instead
2064 private fun expr(v: AbstractCompilerVisitor): nullable RuntimeVariable
2065 do
2066 v.add("PRINT_ERROR(\"NOT YET IMPLEMENTED {class_name}:{location.to_s}\\n\");")
2067 var mtype = self.mtype
2068 if mtype == null then
2069 return null
2070 else
2071 var res = v.new_var(mtype)
2072 v.add("/* {res} = NOT YET {class_name} */")
2073 return res
2074 end
2075 end
2076
2077 # Try to compile self as a statement
2078 # Do not call this method directly, use `v.stmt` instead
2079 private fun stmt(v: AbstractCompilerVisitor)
2080 do
2081 var res = expr(v)
2082 if res != null then v.add("{res};")
2083 end
2084 end
2085
2086 redef class ABlockExpr
2087 redef fun stmt(v)
2088 do
2089 for e in self.n_expr do v.stmt(e)
2090 end
2091 redef fun expr(v)
2092 do
2093 var last = self.n_expr.last
2094 for e in self.n_expr do
2095 if e == last then break
2096 v.stmt(e)
2097 end
2098 return v.expr(last, null)
2099 end
2100 end
2101
2102 redef class AVardeclExpr
2103 redef fun stmt(v)
2104 do
2105 var variable = self.variable.as(not null)
2106 var ne = self.n_expr
2107 if ne != null then
2108 var i = v.expr(ne, variable.declared_type)
2109 v.assign(v.variable(variable), i)
2110 end
2111 end
2112 end
2113
2114 redef class AVarExpr
2115 redef fun expr(v)
2116 do
2117 var res = v.variable(self.variable.as(not null))
2118 var mtype = self.mtype.as(not null)
2119 return v.autoadapt(res, mtype)
2120 end
2121 end
2122
2123 redef class AVarAssignExpr
2124 redef fun stmt(v)
2125 do
2126 var variable = self.variable.as(not null)
2127 var i = v.expr(self.n_value, variable.declared_type)
2128 v.assign(v.variable(variable), i)
2129 end
2130 redef fun expr(v)
2131 do
2132 var variable = self.variable.as(not null)
2133 var i = v.expr(self.n_value, variable.declared_type)
2134 v.assign(v.variable(variable), i)
2135 return i
2136 end
2137 end
2138
2139 redef class AVarReassignExpr
2140 redef fun stmt(v)
2141 do
2142 var variable = self.variable.as(not null)
2143 var vari = v.variable(variable)
2144 var value = v.expr(self.n_value, variable.declared_type)
2145 var res = v.compile_callsite(self.reassign_callsite.as(not null), [vari, value])
2146 assert res != null
2147 v.assign(v.variable(variable), res)
2148 end
2149 end
2150
2151 redef class ASelfExpr
2152 redef fun expr(v) do return v.frame.arguments.first
2153 end
2154
2155 redef class AContinueExpr
2156 redef fun stmt(v) do v.add("goto CONTINUE_{v.escapemark_name(self.escapemark)};")
2157 end
2158
2159 redef class ABreakExpr
2160 redef fun stmt(v) do v.add("goto BREAK_{v.escapemark_name(self.escapemark)};")
2161 end
2162
2163 redef class AReturnExpr
2164 redef fun stmt(v)
2165 do
2166 var nexpr = self.n_expr
2167 if nexpr != null then
2168 var returnvar = v.frame.returnvar.as(not null)
2169 var i = v.expr(nexpr, returnvar.mtype)
2170 v.assign(returnvar, i)
2171 end
2172 v.add("goto {v.frame.returnlabel.as(not null)};")
2173 end
2174 end
2175
2176 redef class AAbortExpr
2177 redef fun stmt(v) do v.add_abort("Aborted")
2178 end
2179
2180 redef class AIfExpr
2181 redef fun stmt(v)
2182 do
2183 var cond = v.expr_bool(self.n_expr)
2184 v.add("if ({cond})\{")
2185 v.stmt(self.n_then)
2186 v.add("\} else \{")
2187 v.stmt(self.n_else)
2188 v.add("\}")
2189 end
2190
2191 redef fun expr(v)
2192 do
2193 var res = v.new_var(self.mtype.as(not null))
2194 var cond = v.expr_bool(self.n_expr)
2195 v.add("if ({cond})\{")
2196 v.assign(res, v.expr(self.n_then.as(not null), null))
2197 v.add("\} else \{")
2198 v.assign(res, v.expr(self.n_else.as(not null), null))
2199 v.add("\}")
2200 return res
2201 end
2202 end
2203
2204 redef class AIfexprExpr
2205 redef fun expr(v)
2206 do
2207 var res = v.new_var(self.mtype.as(not null))
2208 var cond = v.expr_bool(self.n_expr)
2209 v.add("if ({cond})\{")
2210 v.assign(res, v.expr(self.n_then, null))
2211 v.add("\} else \{")
2212 v.assign(res, v.expr(self.n_else, null))
2213 v.add("\}")
2214 return res
2215 end
2216 end
2217
2218 redef class ADoExpr
2219 redef fun stmt(v)
2220 do
2221 v.stmt(self.n_block)
2222 var escapemark = self.escapemark
2223 if escapemark != null then
2224 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2225 end
2226 end
2227 end
2228
2229 redef class AWhileExpr
2230 redef fun stmt(v)
2231 do
2232 v.add("for(;;) \{")
2233 var cond = v.expr_bool(self.n_expr)
2234 v.add("if (!{cond}) break;")
2235 v.stmt(self.n_block)
2236 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2237 v.add("\}")
2238 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2239 end
2240 end
2241
2242 redef class ALoopExpr
2243 redef fun stmt(v)
2244 do
2245 v.add("for(;;) \{")
2246 v.stmt(self.n_block)
2247 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2248 v.add("\}")
2249 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2250 end
2251 end
2252
2253 redef class AForExpr
2254 redef fun stmt(v)
2255 do
2256 # Shortcut on explicit range
2257 # Avoid the instantiation of the range and the iterator
2258 var nexpr = self.n_expr
2259 if self.variables.length == 1 and nexpr isa AOrangeExpr and not v.compiler.modelbuilder.toolcontext.opt_no_shortcut_range.value then
2260 var from = v.expr(nexpr.n_expr, null)
2261 var to = v.expr(nexpr.n_expr2, null)
2262 var variable = v.variable(variables.first)
2263
2264 v.assign(variable, from)
2265 v.add("for(;;) \{ /* shortcut range */")
2266
2267 var ok = v.send(v.get_property("<", variable.mtype), [variable, to])
2268 assert ok != null
2269 v.add("if(!{ok}) break;")
2270
2271 v.stmt(self.n_block)
2272
2273 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2274 var succ = v.send(v.get_property("succ", variable.mtype), [variable])
2275 assert succ != null
2276 v.assign(variable, succ)
2277 v.add("\}")
2278 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2279 return
2280 end
2281
2282 var cl = v.expr(self.n_expr, null)
2283 var it_meth = self.method_iterator
2284 assert it_meth != null
2285 var it = v.compile_callsite(it_meth, [cl])
2286 assert it != null
2287 v.add("for(;;) \{")
2288 var isok_meth = self.method_is_ok
2289 assert isok_meth != null
2290 var ok = v.compile_callsite(isok_meth, [it])
2291 assert ok != null
2292 v.add("if(!{ok}) break;")
2293 if self.variables.length == 1 then
2294 var item_meth = self.method_item
2295 assert item_meth != null
2296 var i = v.compile_callsite(item_meth, [it])
2297 assert i != null
2298 v.assign(v.variable(variables.first), i)
2299 else if self.variables.length == 2 then
2300 var key_meth = self.method_key
2301 assert key_meth != null
2302 var i = v.compile_callsite(key_meth, [it])
2303 assert i != null
2304 v.assign(v.variable(variables[0]), i)
2305 var item_meth = self.method_item
2306 assert item_meth != null
2307 i = v.compile_callsite(item_meth, [it])
2308 assert i != null
2309 v.assign(v.variable(variables[1]), i)
2310 else
2311 abort
2312 end
2313 v.stmt(self.n_block)
2314 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2315 var next_meth = self.method_next
2316 assert next_meth != null
2317 v.compile_callsite(next_meth, [it])
2318 v.add("\}")
2319 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2320 end
2321 end
2322
2323 redef class AAssertExpr
2324 redef fun stmt(v)
2325 do
2326 if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return
2327
2328 var cond = v.expr_bool(self.n_expr)
2329 v.add("if (unlikely(!{cond})) \{")
2330 v.stmt(self.n_else)
2331 var nid = self.n_id
2332 if nid != null then
2333 v.add_abort("Assert '{nid.text}' failed")
2334 else
2335 v.add_abort("Assert failed")
2336 end
2337 v.add("\}")
2338 end
2339 end
2340
2341 redef class AOrExpr
2342 redef fun expr(v)
2343 do
2344 var res = v.new_var(self.mtype.as(not null))
2345 var i1 = v.expr_bool(self.n_expr)
2346 v.add("if ({i1}) \{")
2347 v.add("{res} = 1;")
2348 v.add("\} else \{")
2349 var i2 = v.expr_bool(self.n_expr2)
2350 v.add("{res} = {i2};")
2351 v.add("\}")
2352 return res
2353 end
2354 end
2355
2356 redef class AImpliesExpr
2357 redef fun expr(v)
2358 do
2359 var res = v.new_var(self.mtype.as(not null))
2360 var i1 = v.expr_bool(self.n_expr)
2361 v.add("if (!{i1}) \{")
2362 v.add("{res} = 1;")
2363 v.add("\} else \{")
2364 var i2 = v.expr_bool(self.n_expr2)
2365 v.add("{res} = {i2};")
2366 v.add("\}")
2367 return res
2368 end
2369 end
2370
2371 redef class AAndExpr
2372 redef fun expr(v)
2373 do
2374 var res = v.new_var(self.mtype.as(not null))
2375 var i1 = v.expr_bool(self.n_expr)
2376 v.add("if (!{i1}) \{")
2377 v.add("{res} = 0;")
2378 v.add("\} else \{")
2379 var i2 = v.expr_bool(self.n_expr2)
2380 v.add("{res} = {i2};")
2381 v.add("\}")
2382 return res
2383 end
2384 end
2385
2386 redef class ANotExpr
2387 redef fun expr(v)
2388 do
2389 var cond = v.expr_bool(self.n_expr)
2390 return v.new_expr("!{cond}", self.mtype.as(not null))
2391 end
2392 end
2393
2394 redef class AOrElseExpr
2395 redef fun expr(v)
2396 do
2397 var res = v.new_var(self.mtype.as(not null))
2398 var i1 = v.expr(self.n_expr, null)
2399 v.add("if ({i1}!=NULL) \{")
2400 v.assign(res, i1)
2401 v.add("\} else \{")
2402 var i2 = v.expr(self.n_expr2, null)
2403 v.assign(res, i2)
2404 v.add("\}")
2405 return res
2406 end
2407 end
2408
2409 redef class AIntExpr
2410 redef fun expr(v) do return v.new_expr("{self.value.to_s}", self.mtype.as(not null))
2411 end
2412
2413 redef class AFloatExpr
2414 redef fun expr(v) do return v.new_expr("{self.n_float.text}", self.mtype.as(not null)) # FIXME use value, not n_float
2415 end
2416
2417 redef class ACharExpr
2418 redef fun expr(v) do return v.new_expr("'{self.value.to_s.escape_to_c}'", self.mtype.as(not null))
2419 end
2420
2421 redef class AArrayExpr
2422 redef fun expr(v)
2423 do
2424 var mtype = self.mtype.as(MClassType).arguments.first
2425 var array = new Array[RuntimeVariable]
2426 for nexpr in self.n_exprs.n_exprs do
2427 var i = v.expr(nexpr, mtype)
2428 array.add(i)
2429 end
2430 return v.array_instance(array, mtype)
2431 end
2432 end
2433
2434 redef class AStringFormExpr
2435 redef fun expr(v) do return v.string_instance(self.value.as(not null))
2436 end
2437
2438 redef class ASuperstringExpr
2439 redef fun expr(v)
2440 do
2441 var array = new Array[RuntimeVariable]
2442 for ne in self.n_exprs do
2443 if ne isa AStringFormExpr and ne.value == "" then continue # skip empty sub-strings
2444 var i = v.expr(ne, null)
2445 array.add(i)
2446 end
2447 var a = v.array_instance(array, v.object_type)
2448 var res = v.send(v.get_property("to_s", a.mtype), [a])
2449 return res
2450 end
2451 end
2452
2453 redef class ACrangeExpr
2454 redef fun expr(v)
2455 do
2456 var i1 = v.expr(self.n_expr, null)
2457 var i2 = v.expr(self.n_expr2, null)
2458 var mtype = self.mtype.as(MClassType)
2459 var res = v.init_instance(mtype)
2460 var it = v.compile_callsite(init_callsite.as(not null), [res, i1, i2])
2461 return res
2462 end
2463 end
2464
2465 redef class AOrangeExpr
2466 redef fun expr(v)
2467 do
2468 var i1 = v.expr(self.n_expr, null)
2469 var i2 = v.expr(self.n_expr2, null)
2470 var mtype = self.mtype.as(MClassType)
2471 var res = v.init_instance(mtype)
2472 var it = v.compile_callsite(init_callsite.as(not null), [res, i1, i2])
2473 return res
2474 end
2475 end
2476
2477 redef class ATrueExpr
2478 redef fun expr(v) do return v.new_expr("1", self.mtype.as(not null))
2479 end
2480
2481 redef class AFalseExpr
2482 redef fun expr(v) do return v.new_expr("0", self.mtype.as(not null))
2483 end
2484
2485 redef class ANullExpr
2486 redef fun expr(v) do return v.new_expr("NULL", self.mtype.as(not null))
2487 end
2488
2489 redef class AIsaExpr
2490 redef fun expr(v)
2491 do
2492 var i = v.expr(self.n_expr, null)
2493 return v.type_test(i, self.cast_type.as(not null), "isa")
2494 end
2495 end
2496
2497 redef class AAsCastExpr
2498 redef fun expr(v)
2499 do
2500 var i = v.expr(self.n_expr, null)
2501 if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
2502
2503 v.add_cast(i, self.mtype.as(not null), "as")
2504 return i
2505 end
2506 end
2507
2508 redef class AAsNotnullExpr
2509 redef fun expr(v)
2510 do
2511 var i = v.expr(self.n_expr, null)
2512 if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
2513
2514 v.add("if (unlikely({i} == NULL)) \{")
2515 v.add_abort("Cast failed")
2516 v.add("\}")
2517 return i
2518 end
2519 end
2520
2521 redef class AParExpr
2522 redef fun expr(v) do return v.expr(self.n_expr, null)
2523 end
2524
2525 redef class AOnceExpr
2526 redef fun expr(v)
2527 do
2528 var mtype = self.mtype.as(not null)
2529 var name = v.get_name("varonce")
2530 var guard = v.get_name(name + "_guard")
2531 v.add_decl("static {mtype.ctype} {name};")
2532 v.add_decl("static int {guard};")
2533 var res = v.new_var(mtype)
2534 v.add("if ({guard}) \{")
2535 v.add("{res} = {name};")
2536 v.add("\} else \{")
2537 var i = v.expr(self.n_expr, mtype)
2538 v.add("{res} = {i};")
2539 v.add("{name} = {res};")
2540 v.add("{guard} = 1;")
2541 v.add("\}")
2542 return res
2543 end
2544 end
2545
2546 redef class ASendExpr
2547 redef fun expr(v)
2548 do
2549 var recv = v.expr(self.n_expr, null)
2550 var args = [recv]
2551 for a in self.raw_arguments.as(not null) do
2552 args.add(v.expr(a, null))
2553 end
2554 return v.compile_callsite(self.callsite.as(not null), args)
2555 end
2556 end
2557
2558 redef class ASendReassignFormExpr
2559 redef fun stmt(v)
2560 do
2561 var recv = v.expr(self.n_expr, null)
2562 var args = [recv]
2563 for a in self.raw_arguments.as(not null) do
2564 args.add(v.expr(a, null))
2565 end
2566 var value = v.expr(self.n_value, null)
2567
2568 var left = v.compile_callsite(self.callsite.as(not null), args)
2569 assert left != null
2570
2571 var res = v.compile_callsite(self.reassign_callsite.as(not null), [left, value])
2572 assert res != null
2573
2574 args.add(res)
2575 v.compile_callsite(self.write_callsite.as(not null), args)
2576 end
2577 end
2578
2579 redef class ASuperExpr
2580 redef fun expr(v)
2581 do
2582 var recv = v.frame.arguments.first
2583 var args = [recv]
2584 for a in self.n_args.n_exprs do
2585 args.add(v.expr(a, null))
2586 end
2587
2588 var callsite = self.callsite
2589 if callsite != null then
2590 # Add additionnals arguments for the super init call
2591 if args.length == 1 then
2592 for i in [0..callsite.msignature.arity[ do
2593 args.add(v.frame.arguments[i+1])
2594 end
2595 end
2596 # Super init call
2597 var res = v.compile_callsite(callsite, args)
2598 return res
2599 end
2600
2601 if args.length == 1 then
2602 args = v.frame.arguments
2603 end
2604
2605 # stantard call-next-method
2606 return v.supercall(mpropdef.as(not null), recv.mtype.as(MClassType), args)
2607 end
2608 end
2609
2610 redef class ANewExpr
2611 redef fun expr(v)
2612 do
2613 var mtype = self.mtype.as(MClassType)
2614 var recv
2615 var ctype = mtype.ctype
2616 if mtype.mclass.name == "NativeArray" then
2617 assert self.n_args.n_exprs.length == 1
2618 var l = v.expr(self.n_args.n_exprs.first, null)
2619 assert mtype isa MGenericType
2620 var elttype = mtype.arguments.first
2621 return v.native_array_instance(elttype, l)
2622 else if ctype == "val*" then
2623 recv = v.init_instance(mtype)
2624 else if ctype == "void*" then
2625 recv = v.new_expr("NULL/*special!*/", mtype)
2626 else
2627 recv = v.new_expr("({ctype})0/*special!*/", mtype)
2628 end
2629 var args = [recv]
2630 for a in self.n_args.n_exprs do
2631 args.add(v.expr(a, null))
2632 end
2633 var res2 = v.compile_callsite(self.callsite.as(not null), args)
2634 if res2 != null then
2635 #self.debug("got {res2} from {mproperty}. drop {recv}")
2636 return res2
2637 end
2638 return recv
2639 end
2640 end
2641
2642 redef class AAttrExpr
2643 redef fun expr(v)
2644 do
2645 var recv = v.expr(self.n_expr, null)
2646 var mproperty = self.mproperty.as(not null)
2647 return v.read_attribute(mproperty, recv)
2648 end
2649 end
2650
2651 redef class AAttrAssignExpr
2652 redef fun stmt(v)
2653 do
2654 var recv = v.expr(self.n_expr, null)
2655 var i = v.expr(self.n_value, null)
2656 var mproperty = self.mproperty.as(not null)
2657 v.write_attribute(mproperty, recv, i)
2658 end
2659 end
2660
2661 redef class AAttrReassignExpr
2662 redef fun stmt(v)
2663 do
2664 var recv = v.expr(self.n_expr, null)
2665 var value = v.expr(self.n_value, null)
2666 var mproperty = self.mproperty.as(not null)
2667 var attr = v.read_attribute(mproperty, recv)
2668 var res = v.compile_callsite(self.reassign_callsite.as(not null), [attr, value])
2669 assert res != null
2670 v.write_attribute(mproperty, recv, res)
2671 end
2672 end
2673
2674 redef class AIssetAttrExpr
2675 redef fun expr(v)
2676 do
2677 var recv = v.expr(self.n_expr, null)
2678 var mproperty = self.mproperty.as(not null)
2679 return v.isset_attribute(mproperty, recv)
2680 end
2681 end
2682
2683 redef class ADebugTypeExpr
2684 redef fun stmt(v)
2685 do
2686 # do nothing
2687 end
2688 end
2689
2690 # Utils
2691
2692 redef class Array[E]
2693 # Return a new `Array` with the elements only contened in self and not in `o`
2694 fun -(o: Array[E]): Array[E] do
2695 var res = new Array[E]
2696 for e in self do if not o.has(e) then res.add(e)
2697 return res
2698 end
2699 end
2700
2701 redef class MModule
2702 # All `MProperty` associated to all `MClassDef` of `mclass`
2703 fun properties(mclass: MClass): Set[MProperty] do
2704 if not self.properties_cache.has_key(mclass) then
2705 var properties = new HashSet[MProperty]
2706 var parents = new Array[MClass]
2707 if self.flatten_mclass_hierarchy.has(mclass) then
2708 parents.add_all(mclass.in_hierarchy(self).direct_greaters)
2709 end
2710 for parent in parents do
2711 properties.add_all(self.properties(parent))
2712 end
2713 for mclassdef in mclass.mclassdefs do
2714 for mprop in mclassdef.intro_mproperties do
2715 properties.add(mprop)
2716 end
2717 end
2718 self.properties_cache[mclass] = properties
2719 end
2720 return properties_cache[mclass]
2721 end
2722 private var properties_cache: Map[MClass, Set[MProperty]] = new HashMap[MClass, Set[MProperty]]
2723
2724 # Write FFI and nitni results to file
2725 fun finalize_ffi(c: AbstractCompiler) do end
2726
2727 # Give requided addinional system libraries (as given to LD_LIBS)
2728 # Note: can return null instead of an empty set
2729 fun collect_linker_libs: nullable Set[String] do return null
2730 end
2731
2732 # Create a tool context to handle options and paths
2733 var toolcontext = new ToolContext
2734
2735 var opt_mixins = new OptionArray("Additionals module to min-in", "-m")
2736 toolcontext.option_context.add_option(opt_mixins)
2737
2738 toolcontext.tooldescription = "Usage: nitg [OPTION]... file.nit\nCompiles Nit programs."
2739
2740 # We do not add other options, so process them now!
2741 toolcontext.process_options(args)
2742
2743 # We need a model to collect stufs
2744 var model = new Model
2745 # An a model builder to parse files
2746 var modelbuilder = new ModelBuilder(model, toolcontext)
2747
2748 var arguments = toolcontext.option_context.rest
2749 if arguments.length > 1 then
2750 print "Too much arguments: {arguments.join(" ")}"
2751 print toolcontext.tooldescription
2752 exit 1
2753 end
2754 var progname = arguments.first
2755
2756 # Here we load an process all modules passed on the command line
2757 var mmodules = modelbuilder.parse([progname])
2758 mmodules.add_all modelbuilder.parse(opt_mixins.value)
2759
2760 if mmodules.is_empty then return
2761 modelbuilder.run_phases
2762
2763 var mainmodule
2764 if mmodules.length == 1 then
2765 mainmodule = mmodules.first
2766 else
2767 mainmodule = new MModule(model, null, mmodules.first.name, mmodules.first.location)
2768 mainmodule.set_imported_mmodules(mmodules)
2769 end
2770
2771 toolcontext.run_global_phases(mmodules)