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