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