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