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