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