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