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