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