b5613c6fa5f501697330a3f77de31413041880db
[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 # Generate a super call from a method definition
547 fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
548
549 fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable]) is abstract
550
551 # Box or unbox a value to another type iff a C type conversion is needed
552 # ENSURE: result.mtype.ctype == mtype.ctype
553 fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable is abstract
554
555 # Generate a polymorphic subtype test
556 fun type_test(value: RuntimeVariable, mtype: MType, tag: String): RuntimeVariable is abstract
557
558 # Generate the code required to dynamically check if 2 objects share the same runtime type
559 fun is_same_type_test(value1, value2: RuntimeVariable): RuntimeVariable is abstract
560
561 # Generate a Nit "is" for two runtime_variables
562 fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable is abstract
563
564 # Sends
565
566 # Generate a static call on a method definition
567 fun call(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
568
569 # Generate a polymorphic send for the method `m' and the arguments `args'
570 fun send(m: MMethod, args: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
571
572 # Generate a monomorphic send for the method `m', the type `t' and the arguments `args'
573 fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable
574 do
575 assert t isa MClassType
576 var propdef = m.lookup_first_definition(self.compiler.mainmodule, t)
577 return self.call(propdef, t, args)
578 end
579
580 # Attributes handling
581
582 # Generate a polymorphic attribute is_set test
583 fun isset_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable is abstract
584
585 # Generate a polymorphic attribute read
586 fun read_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable is abstract
587
588 # Generate a polymorphic attribute write
589 fun write_attribute(a: MAttribute, recv: RuntimeVariable, value: RuntimeVariable) is abstract
590
591 # Checks
592
593 # Add a check and an abort for a null reciever if needed
594 fun check_recv_notnull(recv: RuntimeVariable)
595 do
596 if self.compiler.modelbuilder.toolcontext.opt_no_check_other.value then return
597
598 var maybenull = recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType
599 if maybenull then
600 self.add("if ({recv} == NULL) \{")
601 self.add_abort("Reciever is null")
602 self.add("\}")
603 end
604 end
605
606 # Generate a check-init-instance
607 fun check_init_instance(recv: RuntimeVariable, mtype: MClassType) is abstract
608
609 # Names handling
610
611 private var names: HashSet[String] = new HashSet[String]
612 private var last: Int = 0
613
614 # Return a new name based on `s' and unique in the visitor
615 fun get_name(s: String): String
616 do
617 if not self.names.has(s) then
618 self.names.add(s)
619 return s
620 end
621 var i = self.last + 1
622 loop
623 var s2 = s + i.to_s
624 if not self.names.has(s2) then
625 self.last = i
626 self.names.add(s2)
627 return s2
628 end
629 i = i + 1
630 end
631 end
632
633 # Return an unique and stable identifier associated with an escapemark
634 fun escapemark_name(e: nullable EscapeMark): String
635 do
636 assert e != null
637 if escapemark_names.has_key(e) then return escapemark_names[e]
638 var name = e.name
639 if name == null then name = "label"
640 name = get_name(name)
641 escapemark_names[e] = name
642 return name
643 end
644
645 private var escapemark_names = new HashMap[EscapeMark, String]
646
647 # Return a "const char*" variable associated to the classname of the dynamic type of an object
648 # NOTE: we do not return a RuntimeVariable "NativeString" as the class may not exist in the module/program
649 fun class_name_string(value: RuntimeVariable): String is abstract
650
651 # Variables handling
652
653 protected var variables: HashMap[Variable, RuntimeVariable] = new HashMap[Variable, RuntimeVariable]
654
655 # Return the local runtime_variable associated to a Nit local variable
656 fun variable(variable: Variable): RuntimeVariable
657 do
658 if self.variables.has_key(variable) then
659 return self.variables[variable]
660 else
661 var name = self.get_name("var_{variable.name}")
662 var mtype = variable.declared_type.as(not null)
663 mtype = self.anchor(mtype)
664 var res = new RuntimeVariable(name, mtype, mtype)
665 self.add_decl("{mtype.ctype} {name} /* var {variable}: {mtype} */;")
666 self.variables[variable] = res
667 return res
668 end
669 end
670
671 # Return a new uninitialized local runtime_variable
672 fun new_var(mtype: MType): RuntimeVariable
673 do
674 mtype = self.anchor(mtype)
675 var name = self.get_name("var")
676 var res = new RuntimeVariable(name, mtype, mtype)
677 self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
678 return res
679 end
680
681 # Return a new uninitialized named runtime_variable
682 fun new_named_var(mtype: MType, name: String): RuntimeVariable
683 do
684 mtype = self.anchor(mtype)
685 var res = new RuntimeVariable(name, mtype, mtype)
686 self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
687 return res
688 end
689
690 # Correctly assign a left and a right value
691 # Boxing and unboxing is performed if required
692 fun assign(left, right: RuntimeVariable)
693 do
694 right = self.autobox(right, left.mtype)
695 self.add("{left} = {right};")
696 end
697
698 # Generate instances
699
700 # Generate a alloc-instance + init-attributes
701 fun init_instance(mtype: MClassType): RuntimeVariable is abstract
702
703 # Generate an integer value
704 fun int_instance(value: Int): RuntimeVariable
705 do
706 var res = self.new_var(self.get_class("Int").mclass_type)
707 self.add("{res} = {value};")
708 return res
709 end
710
711 # Generate a string value
712 fun string_instance(string: String): RuntimeVariable
713 do
714 var mtype = self.get_class("String").mclass_type
715 var name = self.get_name("varonce")
716 self.add_decl("static {mtype.ctype} {name};")
717 var res = self.new_var(mtype)
718 self.add("if ({name}) \{")
719 self.add("{res} = {name};")
720 self.add("\} else \{")
721 var nat = self.new_var(self.get_class("NativeString").mclass_type)
722 self.add("{nat} = \"{string.escape_to_c}\";")
723 var res2 = self.init_instance(mtype)
724 self.add("{res} = {res2};")
725 var length = self.int_instance(string.length)
726 self.send(self.get_property("with_native", mtype), [res, nat, length])
727 self.check_init_instance(res, mtype)
728 self.add("{name} = {res};")
729 self.add("\}")
730 return res
731 end
732
733 # Generate an array value
734 fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable is abstract
735
736 # Get an instance of a array for a vararg
737 fun vararg_instance(mpropdef: MPropDef, recv: RuntimeVariable, varargs: Array[RuntimeVariable], elttype: MType): RuntimeVariable is abstract
738
739 # Code generation
740
741 private var lines: List[String] = new List[String]
742 private var decl_lines: List[String] = new List[String]
743
744 # Add a line in the main part of the generated C
745 fun add(s: String) do self.lines.add(s)
746
747 # Add a line in the
748 # (used for local or global declaration)
749 fun add_decl(s: String) do self.decl_lines.add(s)
750
751 # Return a new local runtime_variable initialized with the C expression `cexpr'.
752 fun new_expr(cexpr: String, mtype: MType): RuntimeVariable
753 do
754 var res = new_var(mtype)
755 self.add("{res} = {cexpr};")
756 return res
757 end
758
759 # Generate generic abort
760 # used by aborts, asserts, casts, etc.
761 fun add_abort(message: String)
762 do
763 if self.current_node != null and self.current_node.location.file != null then
764 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});")
765 else
766 self.add("fprintf(stderr, \"Runtime error: %s\\n\", \"{message.escape_to_c}\");")
767 end
768 self.add("exit(1);")
769 end
770
771 # Generate a return with the value `s'
772 fun ret(s: RuntimeVariable)
773 do
774 self.assign(self.frame.returnvar.as(not null), s)
775 self.add("goto {self.frame.returnlabel.as(not null)};")
776 end
777
778 # Compile a statement (if any)
779 fun stmt(nexpr: nullable AExpr)
780 do
781 if nexpr == null then return
782 var old = self.current_node
783 self.current_node = nexpr
784 nexpr.stmt(self)
785 self.current_node = old
786 end
787
788 # Compile an expression an return its result
789 # `mtype` is the expected return type, pass null if no specific type is expected.
790 fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable
791 do
792 var old = self.current_node
793 self.current_node = nexpr
794 var res = nexpr.expr(self).as(not null)
795 if mtype != null then
796 mtype = self.anchor(mtype)
797 res = self.autobox(res, mtype)
798 end
799 res = autoadapt(res, nexpr.mtype.as(not null))
800 var implicit_cast_to = nexpr.implicit_cast_to
801 if implicit_cast_to != null and not self.compiler.modelbuilder.toolcontext.opt_no_check_autocast.value then
802 var castres = self.type_test(res, implicit_cast_to, "auto")
803 self.add("if (!{castres}) \{")
804 self.add_abort("Cast failed")
805 self.add("\}")
806 res = autoadapt(res, implicit_cast_to)
807 end
808 self.current_node = old
809 return res
810 end
811
812 # Alias for `self.expr(nexpr, self.bool_type)'
813 fun expr_bool(nexpr: AExpr): RuntimeVariable do return expr(nexpr, bool_type)
814
815 # Safely show a debug message on the current node and repeat the message in the C code as a comment
816 fun debug(message: String)
817 do
818 var node = self.current_node
819 if node == null then
820 print "?: {message}"
821 else
822 node.debug(message)
823 end
824 self.add("/* DEBUG: {message} */")
825 end
826 end
827
828 # A C function associated to a Nit method
829 # Because of customization, a given Nit method can be compiler more that once
830 abstract class AbstractRuntimeFunction
831
832 type COMPILER: AbstractCompiler
833 type VISITOR: AbstractCompilerVisitor
834
835 # The associated Nit method
836 var mmethoddef: MMethodDef
837
838 # The mangled c name of the runtime_function
839 # Subclasses should redefine `build_c_name` instead
840 fun c_name: String
841 do
842 var res = self.c_name_cache
843 if res != null then return res
844 res = self.build_c_name
845 self.c_name_cache = res
846 return res
847 end
848
849 # Non cached version of `c_name`
850 protected fun build_c_name: String is abstract
851
852 protected var c_name_cache: nullable String writable = null
853
854 # Implements a call of the runtime_function
855 # May inline the body or generate a C function call
856 fun call(v: VISITOR, arguments: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
857
858 # Generate the code for the RuntimeFunction
859 # Warning: compile more than once compilation makes CC unhappy
860 fun compile_to_c(compiler: COMPILER) is abstract
861 end
862
863 # A runtime variable hold a runtime value in C.
864 # Runtime variables are associated to Nit local variables and intermediate results in Nit expressions.
865 #
866 # 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.
867 class RuntimeVariable
868 # The name of the variable in the C code
869 var name: String
870
871 # The static type of the variable (as declard in C)
872 var mtype: MType
873
874 # The current casted type of the variable (as known in Nit)
875 var mcasttype: MType writable
876
877 # If the variable exaclty a mcasttype?
878 # false (usual value) means that the variable is a mcasttype or a subtype.
879 var is_exact: Bool writable = false
880
881 init(name: String, mtype: MType, mcasttype: MType)
882 do
883 self.name = name
884 self.mtype = mtype
885 self.mcasttype = mcasttype
886 assert not mtype.need_anchor
887 assert not mcasttype.need_anchor
888 end
889
890 redef fun to_s do return name
891
892 redef fun inspect
893 do
894 var exact_str
895 if self.is_exact then
896 exact_str = " exact"
897 else
898 exact_str = ""
899 end
900 var type_str
901 if self.mtype == self.mcasttype then
902 type_str = "{mtype}{exact_str}"
903 else
904 type_str = "{mtype}({mcasttype}{exact_str})"
905 end
906 return "<{name}:{type_str}>"
907 end
908 end
909
910 # A frame correspond to a visited property in a GlobalCompilerVisitor
911 class Frame
912
913 type VISITOR: AbstractCompilerVisitor
914
915 # The associated visitor
916 var visitor: VISITOR
917
918 # The executed property.
919 # A Method in case of a call, an attribute in case of a default initialization.
920 var mpropdef: MPropDef
921
922 # The static type of the receiver
923 var receiver: MClassType
924
925 # Arguments of the method (the first is the receiver)
926 var arguments: Array[RuntimeVariable]
927
928 # The runtime_variable associated to the return (in a function)
929 var returnvar: nullable RuntimeVariable writable = null
930
931 # The label at the end of the property
932 var returnlabel: nullable String writable = null
933 end
934
935 redef class String
936 # Mangle a string to be a unique valid C identifier
937 fun to_cmangle: String
938 do
939 var res = new Buffer
940 var underscore = false
941 for c in self do
942 if (c >= 'a' and c <= 'z') or (c >='A' and c <= 'Z') then
943 res.add(c)
944 underscore = false
945 continue
946 end
947 if underscore then
948 res.append('_'.ascii.to_s)
949 res.add('d')
950 end
951 if c >= '0' and c <= '9' then
952 res.add(c)
953 underscore = false
954 else if c == '_' then
955 res.add(c)
956 underscore = true
957 else
958 res.add('_')
959 res.append(c.ascii.to_s)
960 res.add('d')
961 underscore = false
962 end
963 end
964 return res.to_s
965 end
966
967 # Escape " \ ' and non printable characters for literal C strings or characters
968 fun escape_to_c: String
969 do
970 var b = new Buffer
971 for c in self do
972 if c == '\n' then
973 b.append("\\n")
974 else if c == '\0' then
975 b.append("\\0")
976 else if c == '"' then
977 b.append("\\\"")
978 else if c == '\'' then
979 b.append("\\\'")
980 else if c == '\\' then
981 b.append("\\\\")
982 else if c.ascii < 32 then
983 b.append("\\{c.ascii.to_base(8, false)}")
984 else
985 b.add(c)
986 end
987 end
988 return b.to_s
989 end
990 end
991
992 redef class MType
993 # Return the C type associated to a given Nit static type
994 fun ctype: String do return "val*"
995
996 fun ctypename: String do return "val"
997
998 # Return the name of the C structure associated to a Nit live type
999 fun c_name: String is abstract
1000 protected var c_name_cache: nullable String protected writable
1001 end
1002
1003 redef class MClassType
1004 redef fun c_name
1005 do
1006 var res = self.c_name_cache
1007 if res != null then return res
1008 res = "{mclass.intro_mmodule.name.to_cmangle}__{mclass.name.to_cmangle}"
1009 self.c_name_cache = res
1010 return res
1011 end
1012
1013 redef fun ctype: String
1014 do
1015 if mclass.name == "Int" then
1016 return "long"
1017 else if mclass.name == "Bool" then
1018 return "short int"
1019 else if mclass.name == "Char" then
1020 return "char"
1021 else if mclass.name == "Float" then
1022 return "double"
1023 else if mclass.name == "NativeString" then
1024 return "char*"
1025 else if mclass.name == "NativeArray" then
1026 return "val*"
1027 else if mclass.kind == extern_kind then
1028 return "void*"
1029 else
1030 return "val*"
1031 end
1032 end
1033
1034 redef fun ctypename: String
1035 do
1036 if mclass.name == "Int" then
1037 return "l"
1038 else if mclass.name == "Bool" then
1039 return "s"
1040 else if mclass.name == "Char" then
1041 return "c"
1042 else if mclass.name == "Float" then
1043 return "d"
1044 else if mclass.name == "NativeString" then
1045 return "str"
1046 else if mclass.name == "NativeArray" then
1047 #return "{self.arguments.first.ctype}*"
1048 return "val"
1049 else if mclass.kind == extern_kind then
1050 return "ptr"
1051 else
1052 return "val"
1053 end
1054 end
1055 end
1056
1057 redef class MGenericType
1058 redef fun c_name
1059 do
1060 var res = self.c_name_cache
1061 if res != null then return res
1062 res = super
1063 for t in self.arguments do
1064 res = res + t.c_name
1065 end
1066 self.c_name_cache = res
1067 return res
1068 end
1069 end
1070
1071 redef class MParameterType
1072 redef fun c_name
1073 do
1074 var res = self.c_name_cache
1075 if res != null then return res
1076 res = "{self.mclass.c_name}_FT{self.rank}"
1077 self.c_name_cache = res
1078 return res
1079 end
1080 end
1081
1082 redef class MVirtualType
1083 redef fun c_name
1084 do
1085 var res = self.c_name_cache
1086 if res != null then return res
1087 res = "{self.mproperty.intro.mclassdef.mclass.c_name}_VT{self.mproperty.name}"
1088 self.c_name_cache = res
1089 return res
1090 end
1091 end
1092
1093 redef class MNullableType
1094 redef fun c_name
1095 do
1096 var res = self.c_name_cache
1097 if res != null then return res
1098 res = "nullable_{self.mtype.c_name}"
1099 self.c_name_cache = res
1100 return res
1101 end
1102 end
1103
1104 redef class MClass
1105 # Return the name of the C structure associated to a Nit class
1106 fun c_name: String do
1107 var res = self.c_name_cache
1108 if res != null then return res
1109 res = "{intro_mmodule.name.to_cmangle}__{name.to_cmangle}"
1110 self.c_name_cache = res
1111 return res
1112 end
1113 private var c_name_cache: nullable String
1114 end
1115
1116 redef class MProperty
1117 fun c_name: String do
1118 var res = self.c_name_cache
1119 if res != null then return res
1120 res = "{self.intro.c_name}"
1121 self.c_name_cache = res
1122 return res
1123 end
1124 private var c_name_cache: nullable String
1125 end
1126
1127 redef class MPropDef
1128 type VISITOR: AbstractCompilerVisitor
1129
1130 private var c_name_cache: nullable String
1131
1132 # The mangled name associated to the property
1133 fun c_name: String
1134 do
1135 var res = self.c_name_cache
1136 if res != null then return res
1137 res = "{self.mclassdef.mmodule.name.to_cmangle}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
1138 self.c_name_cache = res
1139 return res
1140 end
1141 end
1142
1143 redef class MMethodDef
1144 # Can the body be inlined?
1145 fun can_inline(v: VISITOR): Bool
1146 do
1147 var modelbuilder = v.compiler.modelbuilder
1148 if modelbuilder.mpropdef2npropdef.has_key(self) then
1149 var npropdef = modelbuilder.mpropdef2npropdef[self]
1150 return npropdef.can_inline
1151 else if self.mproperty.name == "init" then
1152 # Automatic free init is always inlined since it is empty or contains only attribtes assigments
1153 return true
1154 else
1155 abort
1156 end
1157 end
1158
1159 # Inline the body in another visitor
1160 fun compile_inside_to_c(v: VISITOR, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
1161 do
1162 var modelbuilder = v.compiler.modelbuilder
1163 if modelbuilder.mpropdef2npropdef.has_key(self) then
1164 var npropdef = modelbuilder.mpropdef2npropdef[self]
1165 var oldnode = v.current_node
1166 v.current_node = npropdef
1167 self.compile_parameter_check(v, arguments)
1168 npropdef.compile_to_c(v, self, arguments)
1169 v.current_node = oldnode
1170 else if self.mproperty.name == "init" then
1171 var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
1172 var oldnode = v.current_node
1173 v.current_node = nclassdef
1174 self.compile_parameter_check(v, arguments)
1175 nclassdef.compile_to_c(v, self, arguments)
1176 v.current_node = oldnode
1177 else
1178 abort
1179 end
1180 return null
1181 end
1182
1183 # Generate type checks in the C code to check covariant parameters
1184 fun compile_parameter_check(v: VISITOR, arguments: Array[RuntimeVariable])
1185 do
1186 if v.compiler.modelbuilder.toolcontext.opt_no_check_covariance.value then return
1187
1188 for i in [0..msignature.arity[ do
1189 # skip test for vararg since the array is instantiated with the correct polymorphic type
1190 if msignature.vararg_rank == i then continue
1191
1192 # skip if the cast is not required
1193 var origmtype = self.mproperty.intro.msignature.mparameters[i].mtype
1194 if not origmtype.need_anchor then continue
1195
1196 # get the parameter type
1197 var mtype = self.msignature.mparameters[i].mtype
1198
1199 # generate the cast
1200 # note that v decides if and how to implements the cast
1201 v.add("/* Covariant cast for argument {i} ({self.msignature.mparameters[i].name}) {arguments[i+1].inspect} isa {mtype} */")
1202 var cond = v.type_test(arguments[i+1], mtype, "covariance")
1203 v.add("if (!{cond}) \{")
1204 v.add_abort("Cast failed")
1205 v.add("\}")
1206 end
1207 end
1208 end
1209
1210 # Node visit
1211
1212 redef class APropdef
1213 fun compile_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1214 do
1215 v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
1216 debug("Not yet implemented")
1217 end
1218
1219 fun can_inline: Bool do return true
1220 end
1221
1222 redef class AConcreteMethPropdef
1223 redef fun compile_to_c(v, mpropdef, arguments)
1224 do
1225 for i in [0..mpropdef.msignature.arity[ do
1226 var variable = self.n_signature.n_params[i].variable.as(not null)
1227 v.assign(v.variable(variable), arguments[i+1])
1228 end
1229 # Call the implicit super-init
1230 var auto_super_inits = self.auto_super_inits
1231 if auto_super_inits != null then
1232 var selfarg = [arguments.first]
1233 for auto_super_init in auto_super_inits do
1234 if auto_super_init.intro.msignature.arity == 0 then
1235 v.send(auto_super_init, selfarg)
1236 else
1237 v.send(auto_super_init, arguments)
1238 end
1239 end
1240 end
1241 v.stmt(self.n_block)
1242 end
1243
1244 redef fun can_inline
1245 do
1246 if self.auto_super_inits != null then return false
1247 var nblock = self.n_block
1248 if nblock == null then return true
1249 if (mpropdef.mproperty.name == "==" or mpropdef.mproperty.name == "!=") and mpropdef.mclassdef.mclass.name == "Object" then return true
1250 if nblock isa ABlockExpr and nblock.n_expr.length == 0 then return true
1251 return false
1252 end
1253 end
1254
1255 redef class AInternMethPropdef
1256 redef fun compile_to_c(v, mpropdef, arguments)
1257 do
1258 var pname = mpropdef.mproperty.name
1259 var cname = mpropdef.mclassdef.mclass.name
1260 var ret = mpropdef.msignature.return_mtype
1261 if ret != null then
1262 ret = v.resolve_for(ret, arguments.first)
1263 end
1264 if pname != "==" and pname != "!=" then
1265 v.adapt_signature(mpropdef, arguments)
1266 end
1267 if cname == "Int" then
1268 if pname == "output" then
1269 v.add("printf(\"%ld\\n\", {arguments.first});")
1270 return
1271 else if pname == "object_id" then
1272 v.ret(arguments.first)
1273 return
1274 else if pname == "+" then
1275 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1276 return
1277 else if pname == "-" then
1278 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1279 return
1280 else if pname == "unary -" then
1281 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1282 return
1283 else if pname == "succ" then
1284 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1285 return
1286 else if pname == "prec" then
1287 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1288 return
1289 else if pname == "*" then
1290 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1291 return
1292 else if pname == "/" then
1293 v.ret(v.new_expr("{arguments[0]} / {arguments[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 == "lshift" then
1299 v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
1300 return
1301 else if pname == "rshift" then
1302 v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
1303 return
1304 else if pname == "==" then
1305 v.ret(v.equal_test(arguments[0], arguments[1]))
1306 return
1307 else if pname == "!=" then
1308 var res = v.equal_test(arguments[0], arguments[1])
1309 v.ret(v.new_expr("!{res}", ret.as(not null)))
1310 return
1311 else if pname == "<" then
1312 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1313 return
1314 else if pname == ">" then
1315 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", 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 == "to_f" then
1324 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1325 return
1326 else if pname == "ascii" then
1327 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1328 return
1329 end
1330 else if cname == "Char" then
1331 if pname == "output" then
1332 v.add("printf(\"%c\", {arguments.first});")
1333 return
1334 else if pname == "object_id" then
1335 v.ret(arguments.first)
1336 return
1337 else if pname == "+" then
1338 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1339 return
1340 else if pname == "-" then
1341 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1342 return
1343 else if pname == "==" then
1344 v.ret(v.equal_test(arguments[0], arguments[1]))
1345 return
1346 else if pname == "!=" then
1347 var res = v.equal_test(arguments[0], arguments[1])
1348 v.ret(v.new_expr("!{res}", ret.as(not null)))
1349 return
1350 else if pname == "succ" then
1351 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1352 return
1353 else if pname == "prec" then
1354 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1355 return
1356 else if pname == "<" then
1357 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1358 return
1359 else if pname == ">" then
1360 v.ret(v.new_expr("{arguments[0]} > {arguments[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 == "to_i" then
1369 v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
1370 return
1371 else if pname == "ascii" then
1372 v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
1373 return
1374 end
1375 else if cname == "Bool" then
1376 if pname == "output" then
1377 v.add("printf({arguments.first}?\"true\\n\":\"false\\n\");")
1378 return
1379 else if pname == "object_id" then
1380 v.ret(arguments.first)
1381 return
1382 else if pname == "==" then
1383 v.ret(v.equal_test(arguments[0], arguments[1]))
1384 return
1385 else if pname == "!=" then
1386 var res = v.equal_test(arguments[0], arguments[1])
1387 v.ret(v.new_expr("!{res}", ret.as(not null)))
1388 return
1389 end
1390 else if cname == "Float" then
1391 if pname == "output" then
1392 v.add("printf(\"%f\\n\", {arguments.first});")
1393 return
1394 else if pname == "object_id" then
1395 v.ret(v.new_expr("(double){arguments.first}", ret.as(not null)))
1396 return
1397 else if pname == "+" then
1398 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1399 return
1400 else if pname == "-" then
1401 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1402 return
1403 else if pname == "unary -" then
1404 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1405 return
1406 else if pname == "succ" then
1407 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1408 return
1409 else if pname == "prec" then
1410 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1411 return
1412 else if pname == "*" then
1413 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1414 return
1415 else if pname == "/" then
1416 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1417 return
1418 else if pname == "==" then
1419 v.ret(v.equal_test(arguments[0], arguments[1]))
1420 return
1421 else if pname == "!=" then
1422 var res = v.equal_test(arguments[0], arguments[1])
1423 v.ret(v.new_expr("!{res}", ret.as(not null)))
1424 return
1425 else if pname == "<" then
1426 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1427 return
1428 else if pname == ">" then
1429 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", 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 == "to_i" then
1438 v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
1439 return
1440 end
1441 else if cname == "Char" then
1442 if pname == "output" then
1443 v.add("printf(\"%c\", {arguments.first});")
1444 return
1445 else if pname == "object_id" then
1446 v.ret(arguments.first)
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 == "ascii" then
1456 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1457 return
1458 end
1459 else if cname == "NativeString" then
1460 if pname == "[]" then
1461 v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
1462 return
1463 else if pname == "[]=" then
1464 v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
1465 return
1466 else if pname == "copy_to" then
1467 v.add("memcpy({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
1468 return
1469 else if pname == "atoi" then
1470 v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
1471 return
1472 end
1473 else if cname == "NativeArray" then
1474 v.native_array_def(pname, ret, arguments)
1475 return
1476 end
1477 if pname == "exit" then
1478 v.add("exit({arguments[1]});")
1479 return
1480 else if pname == "sys" then
1481 v.ret(v.new_expr("glob_sys", ret.as(not null)))
1482 return
1483 else if pname == "calloc_string" then
1484 v.ret(v.new_expr("(char*)GC_MALLOC_ATOMIC({arguments[1]})", ret.as(not null)))
1485 return
1486 else if pname == "calloc_array" then
1487 v.calloc_array(ret.as(not null), arguments)
1488 return
1489 else if pname == "object_id" then
1490 v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
1491 return
1492 else if pname == "is_same_type" then
1493 v.ret(v.is_same_type_test(arguments[0], arguments[1]))
1494 return
1495 else if pname == "output_class_name" then
1496 var nat = v.class_name_string(arguments.first)
1497 v.add("printf(\"%s\\n\", {nat});")
1498 return
1499 else if pname == "native_class_name" then
1500 var nat = v.class_name_string(arguments.first)
1501 v.ret(v.new_expr("(char*){nat}", ret.as(not null)))
1502 return
1503 else if pname == "force_garbage_collection" then
1504 v.add("GC_gcollect();")
1505 return
1506 end
1507 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
1508 debug("Not implemented {mpropdef}")
1509 end
1510 end
1511
1512 redef class AExternMethPropdef
1513 redef fun compile_to_c(v, mpropdef, arguments)
1514 do
1515 var externname
1516 var nextern = self.n_extern
1517 if nextern == null then
1518 v.add("fprintf(stderr, \"NOT YET IMPLEMENTED nitni for {mpropdef} at {location.to_s}\\n\");")
1519 v.add("exit(1);")
1520 return
1521 end
1522 externname = nextern.text.substring(1, nextern.text.length-2)
1523 if location.file != null then
1524 var file = location.file.filename
1525 v.compiler.add_extern(file)
1526 end
1527 var res: nullable RuntimeVariable = null
1528 var ret = mpropdef.msignature.return_mtype
1529 if ret != null then
1530 ret = v.resolve_for(ret, arguments.first)
1531 res = v.new_var(ret)
1532 end
1533 v.adapt_signature(mpropdef, arguments)
1534
1535 if res == null then
1536 v.add("{externname}({arguments.join(", ")});")
1537 else
1538 v.add("{res} = {externname}({arguments.join(", ")});")
1539 v.ret(res)
1540 end
1541 end
1542 end
1543
1544 redef class AExternInitPropdef
1545 redef fun compile_to_c(v, mpropdef, arguments)
1546 do
1547 var externname
1548 var nextern = self.n_extern
1549 if nextern == null then
1550 debug("{mpropdef} need extern name")
1551 return
1552 end
1553 externname = nextern.text.substring(1, nextern.text.length-2)
1554 if location.file != null then
1555 var file = location.file.filename
1556 v.compiler.add_extern(file)
1557 end
1558 v.adapt_signature(mpropdef, arguments)
1559 var ret = arguments.first.mtype
1560 var res = v.new_var(ret)
1561
1562 arguments.shift
1563
1564 v.add("{res} = {externname}({arguments.join(", ")});")
1565 v.ret(res)
1566 end
1567 end
1568
1569 redef class AAttrPropdef
1570 redef fun compile_to_c(v, mpropdef, arguments)
1571 do
1572 if arguments.length == 1 then
1573 var res = v.read_attribute(self.mpropdef.mproperty, arguments.first)
1574 v.assign(v.frame.returnvar.as(not null), res)
1575 else
1576 v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
1577 end
1578 end
1579
1580 fun init_expr(v: AbstractCompilerVisitor, recv: RuntimeVariable)
1581 do
1582 var nexpr = self.n_expr
1583 if nexpr != null then
1584 var oldnode = v.current_node
1585 v.current_node = self
1586 var old_frame = v.frame
1587 var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
1588 v.frame = frame
1589 var value = v.expr(nexpr, self.mpropdef.static_mtype)
1590 v.write_attribute(self.mpropdef.mproperty, recv, value)
1591 v.frame = old_frame
1592 v.current_node = oldnode
1593 end
1594 end
1595
1596 fun check_expr(v: AbstractCompilerVisitor, recv: RuntimeVariable)
1597 do
1598 var nexpr = self.n_expr
1599 if nexpr != null then return
1600
1601 var oldnode = v.current_node
1602 v.current_node = self
1603 var old_frame = v.frame
1604 var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
1605 v.frame = frame
1606 # Force read to check the initialization
1607 v.read_attribute(self.mpropdef.mproperty, recv)
1608 v.frame = old_frame
1609 v.current_node = oldnode
1610 end
1611 end
1612
1613 redef class AClassdef
1614 private fun compile_to_c(v: AbstractCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1615 do
1616 if mpropdef == self.mfree_init then
1617 var super_inits = self.super_inits
1618 if super_inits != null then
1619 assert arguments.length == 1
1620 for su in super_inits do
1621 v.send(su, arguments)
1622 end
1623 return
1624 end
1625 var recv = arguments.first
1626 var i = 1
1627 # Collect undefined attributes
1628 for npropdef in self.n_propdefs do
1629 if npropdef isa AAttrPropdef and npropdef.n_expr == null then
1630 v.write_attribute(npropdef.mpropdef.mproperty, recv, arguments[i])
1631 i += 1
1632 end
1633 end
1634 else
1635 abort
1636 end
1637 end
1638 end
1639
1640 redef class ADeferredMethPropdef
1641 redef fun compile_to_c(v, mpropdef, arguments) do v.add_abort("Deferred method called")
1642 redef fun can_inline do return true
1643 end
1644
1645 redef class AExpr
1646 # Try to compile self as an expression
1647 # Do not call this method directly, use `v.expr' instead
1648 private fun expr(v: AbstractCompilerVisitor): nullable RuntimeVariable
1649 do
1650 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{location.to_s}\\n\");")
1651 var mtype = self.mtype
1652 if mtype == null then
1653 return null
1654 else
1655 var res = v.new_var(mtype)
1656 v.add("/* {res} = NOT YET {class_name} */")
1657 return res
1658 end
1659 end
1660
1661 # Try to compile self as a statement
1662 # Do not call this method directly, use `v.stmt' instead
1663 private fun stmt(v: AbstractCompilerVisitor)
1664 do
1665 var res = expr(v)
1666 if res != null then v.add("{res};")
1667 end
1668 end
1669
1670 redef class ABlockExpr
1671 redef fun stmt(v)
1672 do
1673 for e in self.n_expr do v.stmt(e)
1674 end
1675 end
1676
1677 redef class AVardeclExpr
1678 redef fun stmt(v)
1679 do
1680 var variable = self.variable.as(not null)
1681 var ne = self.n_expr
1682 if ne != null then
1683 var i = v.expr(ne, variable.declared_type)
1684 v.assign(v.variable(variable), i)
1685 end
1686 end
1687 end
1688
1689 redef class AVarExpr
1690 redef fun expr(v)
1691 do
1692 var res = v.variable(self.variable.as(not null))
1693 var mtype = self.mtype.as(not null)
1694 return v.autoadapt(res, mtype)
1695 end
1696 end
1697
1698 redef class AVarAssignExpr
1699 redef fun stmt(v)
1700 do
1701 var variable = self.variable.as(not null)
1702 var i = v.expr(self.n_value, variable.declared_type)
1703 v.assign(v.variable(variable), i)
1704 end
1705 end
1706
1707 redef class AVarReassignExpr
1708 redef fun stmt(v)
1709 do
1710 var variable = self.variable.as(not null)
1711 var vari = v.variable(variable)
1712 var value = v.expr(self.n_value, variable.declared_type)
1713 var res = v.compile_callsite(self.reassign_callsite.as(not null), [vari, value])
1714 assert res != null
1715 v.assign(v.variable(variable), res)
1716 end
1717 end
1718
1719 redef class ASelfExpr
1720 redef fun expr(v) do return v.frame.arguments.first
1721 end
1722
1723 redef class AContinueExpr
1724 redef fun stmt(v) do v.add("goto CONTINUE_{v.escapemark_name(self.escapemark)};")
1725 end
1726
1727 redef class ABreakExpr
1728 redef fun stmt(v) do v.add("goto BREAK_{v.escapemark_name(self.escapemark)};")
1729 end
1730
1731 redef class AReturnExpr
1732 redef fun stmt(v)
1733 do
1734 var nexpr = self.n_expr
1735 if nexpr != null then
1736 var returnvar = v.frame.returnvar.as(not null)
1737 var i = v.expr(nexpr, returnvar.mtype)
1738 v.assign(returnvar, i)
1739 end
1740 v.add("goto {v.frame.returnlabel.as(not null)};")
1741 end
1742 end
1743
1744 redef class AAbortExpr
1745 redef fun stmt(v) do v.add_abort("Aborted")
1746 end
1747
1748 redef class AIfExpr
1749 redef fun stmt(v)
1750 do
1751 var cond = v.expr_bool(self.n_expr)
1752 v.add("if ({cond})\{")
1753 v.stmt(self.n_then)
1754 v.add("\} else \{")
1755 v.stmt(self.n_else)
1756 v.add("\}")
1757 end
1758 end
1759
1760 redef class AIfexprExpr
1761 redef fun expr(v)
1762 do
1763 var res = v.new_var(self.mtype.as(not null))
1764 var cond = v.expr_bool(self.n_expr)
1765 v.add("if ({cond})\{")
1766 v.assign(res, v.expr(self.n_then, null))
1767 v.add("\} else \{")
1768 v.assign(res, v.expr(self.n_else, null))
1769 v.add("\}")
1770 return res
1771 end
1772 end
1773
1774 redef class ADoExpr
1775 redef fun stmt(v)
1776 do
1777 v.stmt(self.n_block)
1778 var escapemark = self.escapemark
1779 if escapemark != null then
1780 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
1781 end
1782 end
1783 end
1784
1785 redef class AWhileExpr
1786 redef fun stmt(v)
1787 do
1788 v.add("for(;;) \{")
1789 var cond = v.expr_bool(self.n_expr)
1790 v.add("if (!{cond}) break;")
1791 v.stmt(self.n_block)
1792 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
1793 v.add("\}")
1794 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
1795 end
1796 end
1797
1798 redef class ALoopExpr
1799 redef fun stmt(v)
1800 do
1801 v.add("for(;;) \{")
1802 v.stmt(self.n_block)
1803 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
1804 v.add("\}")
1805 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
1806 end
1807 end
1808
1809 redef class AForExpr
1810 redef fun stmt(v)
1811 do
1812 # Shortcut on explicit range
1813 # Avoid the instantiation of the range and the iterator
1814 var nexpr = self.n_expr
1815 if self.variables.length == 1 and nexpr isa AOrangeExpr and not v.compiler.modelbuilder.toolcontext.opt_no_shortcut_range.value then
1816 var from = v.expr(nexpr.n_expr, null)
1817 var to = v.expr(nexpr.n_expr2, null)
1818 var variable = v.variable(variables.first)
1819
1820 v.assign(variable, from)
1821 v.add("for(;;) \{ /* shortcut range */")
1822
1823 var ok = v.send(v.get_property("<", variable.mtype), [variable, to])
1824 assert ok != null
1825 v.add("if(!{ok}) break;")
1826
1827 v.stmt(self.n_block)
1828
1829 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
1830 var succ = v.send(v.get_property("succ", variable.mtype), [variable])
1831 assert succ != null
1832 v.assign(variable, succ)
1833 v.add("\}")
1834 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
1835 return
1836 end
1837
1838 var cl = v.expr(self.n_expr, null)
1839 var it_meth = self.method_iterator
1840 assert it_meth != null
1841 var it = v.send(it_meth, [cl])
1842 assert it != null
1843 v.add("for(;;) \{")
1844 var isok_meth = self.method_is_ok
1845 assert isok_meth != null
1846 var ok = v.send(isok_meth, [it])
1847 assert ok != null
1848 v.add("if(!{ok}) break;")
1849 if self.variables.length == 1 then
1850 var item_meth = self.method_item
1851 assert item_meth != null
1852 var i = v.send(item_meth, [it])
1853 assert i != null
1854 v.assign(v.variable(variables.first), i)
1855 else if self.variables.length == 2 then
1856 var key_meth = self.method_key
1857 assert key_meth != null
1858 var i = v.send(key_meth, [it])
1859 assert i != null
1860 v.assign(v.variable(variables[0]), i)
1861 var item_meth = self.method_item
1862 assert item_meth != null
1863 i = v.send(item_meth, [it])
1864 assert i != null
1865 v.assign(v.variable(variables[1]), i)
1866 else
1867 abort
1868 end
1869 v.stmt(self.n_block)
1870 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
1871 var next_meth = self.method_next
1872 assert next_meth != null
1873 v.send(next_meth, [it])
1874 v.add("\}")
1875 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
1876 end
1877 end
1878
1879 redef class AAssertExpr
1880 redef fun stmt(v)
1881 do
1882 if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return
1883
1884 var cond = v.expr_bool(self.n_expr)
1885 v.add("if (!{cond}) \{")
1886 v.stmt(self.n_else)
1887 var nid = self.n_id
1888 if nid != null then
1889 v.add_abort("Assert '{nid.text}' failed")
1890 else
1891 v.add_abort("Assert failed")
1892 end
1893 v.add("\}")
1894 end
1895 end
1896
1897 redef class AOrExpr
1898 redef fun expr(v)
1899 do
1900 var res = v.new_var(self.mtype.as(not null))
1901 var i1 = v.expr_bool(self.n_expr)
1902 v.add("if ({i1}) \{")
1903 v.add("{res} = 1;")
1904 v.add("\} else \{")
1905 var i2 = v.expr_bool(self.n_expr2)
1906 v.add("{res} = {i2};")
1907 v.add("\}")
1908 return res
1909 end
1910 end
1911
1912 redef class AAndExpr
1913 redef fun expr(v)
1914 do
1915 var res = v.new_var(self.mtype.as(not null))
1916 var i1 = v.expr_bool(self.n_expr)
1917 v.add("if (!{i1}) \{")
1918 v.add("{res} = 0;")
1919 v.add("\} else \{")
1920 var i2 = v.expr_bool(self.n_expr2)
1921 v.add("{res} = {i2};")
1922 v.add("\}")
1923 return res
1924 end
1925 end
1926
1927 redef class ANotExpr
1928 redef fun expr(v)
1929 do
1930 var cond = v.expr_bool(self.n_expr)
1931 return v.new_expr("!{cond}", self.mtype.as(not null))
1932 end
1933 end
1934
1935 redef class AOrElseExpr
1936 redef fun expr(v)
1937 do
1938 var res = v.new_var(self.mtype.as(not null))
1939 var i1 = v.expr(self.n_expr, null)
1940 v.add("if ({i1}!=NULL) \{")
1941 v.assign(res, i1)
1942 v.add("\} else \{")
1943 var i2 = v.expr(self.n_expr2, null)
1944 v.assign(res, i2)
1945 v.add("\}")
1946 return res
1947 end
1948 end
1949
1950 redef class AEeExpr
1951 redef fun expr(v)
1952 do
1953 var value1 = v.expr(self.n_expr, null)
1954 var value2 = v.expr(self.n_expr2, null)
1955 return v.equal_test(value1, value2)
1956 end
1957 end
1958
1959 redef class AIntExpr
1960 redef fun expr(v) do return v.new_expr("{self.n_number.text}", self.mtype.as(not null))
1961 end
1962
1963 redef class AFloatExpr
1964 redef fun expr(v) do return v.new_expr("{self.n_float.text}", self.mtype.as(not null))
1965 end
1966
1967 redef class ACharExpr
1968 redef fun expr(v) do return v.new_expr("{self.n_char.text}", self.mtype.as(not null))
1969 end
1970
1971 redef class AArrayExpr
1972 redef fun expr(v)
1973 do
1974 var mtype = self.mtype.as(MClassType).arguments.first
1975 var array = new Array[RuntimeVariable]
1976 for nexpr in self.n_exprs.n_exprs do
1977 var i = v.expr(nexpr, mtype)
1978 array.add(i)
1979 end
1980 return v.array_instance(array, mtype)
1981 end
1982 end
1983
1984 redef class AStringFormExpr
1985 redef fun expr(v) do return v.string_instance(self.value.as(not null))
1986 end
1987
1988 redef class ASuperstringExpr
1989 redef fun expr(v)
1990 do
1991 var array = new Array[RuntimeVariable]
1992 for ne in self.n_exprs do
1993 if ne isa AStringFormExpr and ne.value == "" then continue # skip empty sub-strings
1994 var i = v.expr(ne, null)
1995 array.add(i)
1996 end
1997 var a = v.array_instance(array, v.object_type)
1998 var res = v.send(v.get_property("to_s", a.mtype), [a])
1999 return res
2000 end
2001 end
2002
2003 redef class ACrangeExpr
2004 redef fun expr(v)
2005 do
2006 var i1 = v.expr(self.n_expr, null)
2007 var i2 = v.expr(self.n_expr2, null)
2008 var mtype = self.mtype.as(MClassType)
2009 var res = v.init_instance(mtype)
2010 var it = v.send(v.get_property("init", res.mtype), [res, i1, i2])
2011 v.check_init_instance(res, mtype)
2012 return res
2013 end
2014 end
2015
2016 redef class AOrangeExpr
2017 redef fun expr(v)
2018 do
2019 var i1 = v.expr(self.n_expr, null)
2020 var i2 = v.expr(self.n_expr2, null)
2021 var mtype = self.mtype.as(MClassType)
2022 var res = v.init_instance(mtype)
2023 var it = v.send(v.get_property("without_last", res.mtype), [res, i1, i2])
2024 v.check_init_instance(res, mtype)
2025 return res
2026 end
2027 end
2028
2029 redef class ATrueExpr
2030 redef fun expr(v) do return v.new_expr("1", self.mtype.as(not null))
2031 end
2032
2033 redef class AFalseExpr
2034 redef fun expr(v) do return v.new_expr("0", self.mtype.as(not null))
2035 end
2036
2037 redef class ANullExpr
2038 redef fun expr(v) do return v.new_expr("NULL", self.mtype.as(not null))
2039 end
2040
2041 redef class AIsaExpr
2042 redef fun expr(v)
2043 do
2044 var i = v.expr(self.n_expr, null)
2045 return v.type_test(i, self.cast_type.as(not null), "isa")
2046 end
2047 end
2048
2049 redef class AAsCastExpr
2050 redef fun expr(v)
2051 do
2052 var i = v.expr(self.n_expr, null)
2053 if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
2054
2055 var cond = v.type_test(i, self.mtype.as(not null), "as")
2056 v.add("if (!{cond}) \{")
2057 v.add_abort("Cast failed")
2058 v.add("\}")
2059 return i
2060 end
2061 end
2062
2063 redef class AAsNotnullExpr
2064 redef fun expr(v)
2065 do
2066 var i = v.expr(self.n_expr, null)
2067 if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
2068
2069 v.add("if ({i} == NULL) \{")
2070 v.add_abort("Cast failed")
2071 v.add("\}")
2072 return i
2073 end
2074 end
2075
2076 redef class AParExpr
2077 redef fun expr(v) do return v.expr(self.n_expr, null)
2078 end
2079
2080 redef class AOnceExpr
2081 redef fun expr(v)
2082 do
2083 var mtype = self.mtype.as(not null)
2084 var name = v.get_name("varonce")
2085 var guard = v.get_name(name + "_guard")
2086 v.add_decl("static {mtype.ctype} {name};")
2087 v.add_decl("static int {guard};")
2088 var res = v.new_var(mtype)
2089 v.add("if ({guard}) \{")
2090 v.add("{res} = {name};")
2091 v.add("\} else \{")
2092 var i = v.expr(self.n_expr, mtype)
2093 v.add("{res} = {i};")
2094 v.add("{name} = {res};")
2095 v.add("{guard} = 1;")
2096 v.add("\}")
2097 return res
2098 end
2099 end
2100
2101 redef class ASendExpr
2102 redef fun expr(v)
2103 do
2104 var recv = v.expr(self.n_expr, null)
2105 var args = [recv]
2106 for a in self.raw_arguments.as(not null) do
2107 args.add(v.expr(a, null))
2108 end
2109 return v.compile_callsite(self.callsite.as(not null), args)
2110 end
2111 end
2112
2113 redef class ASendReassignFormExpr
2114 redef fun stmt(v)
2115 do
2116 var recv = v.expr(self.n_expr, null)
2117 var args = [recv]
2118 for a in self.raw_arguments.as(not null) do
2119 args.add(v.expr(a, null))
2120 end
2121 var value = v.expr(self.n_value, null)
2122
2123 var left = v.compile_callsite(self.callsite.as(not null), args)
2124 assert left != null
2125
2126 var res = v.compile_callsite(self.reassign_callsite.as(not null), [left, value])
2127 assert res != null
2128
2129 args.add(res)
2130 v.compile_callsite(self.write_callsite.as(not null), args)
2131 end
2132 end
2133
2134 redef class ASuperExpr
2135 redef fun expr(v)
2136 do
2137 var recv = v.frame.arguments.first
2138 var args = [recv]
2139 for a in self.n_args.n_exprs do
2140 args.add(v.expr(a, null))
2141 end
2142 if args.length == 1 then
2143 args = v.frame.arguments
2144 end
2145
2146 var mproperty = self.mproperty
2147 if mproperty != null then
2148 if mproperty.intro.msignature.arity == 0 then
2149 args = [recv]
2150 end
2151 # Super init call
2152 var res = v.send(mproperty, args)
2153 return res
2154 end
2155
2156 # stantard call-next-method
2157 return v.supercall(v.frame.mpropdef.as(MMethodDef), recv.mtype.as(MClassType), args)
2158 end
2159 end
2160
2161 redef class ANewExpr
2162 redef fun expr(v)
2163 do
2164 var mtype = self.mtype.as(MClassType)
2165 var recv
2166 var ctype = mtype.ctype
2167 if ctype == "val*" then
2168 recv = v.init_instance(mtype)
2169 else if ctype == "void*" then
2170 recv = v.new_expr("NULL/*special!*/", mtype)
2171 else
2172 debug("cannot new {mtype}")
2173 abort
2174 end
2175 var args = [recv]
2176 for a in self.n_args.n_exprs do
2177 args.add(v.expr(a, null))
2178 end
2179 var res2 = v.compile_callsite(self.callsite.as(not null), args)
2180 if res2 != null then
2181 #self.debug("got {res2} from {mproperty}. drop {recv}")
2182 return res2
2183 end
2184 v.check_init_instance(recv, mtype)
2185 return recv
2186 end
2187 end
2188
2189 redef class AAttrExpr
2190 redef fun expr(v)
2191 do
2192 var recv = v.expr(self.n_expr, null)
2193 var mproperty = self.mproperty.as(not null)
2194 return v.read_attribute(mproperty, recv)
2195 end
2196 end
2197
2198 redef class AAttrAssignExpr
2199 redef fun stmt(v)
2200 do
2201 var recv = v.expr(self.n_expr, null)
2202 var i = v.expr(self.n_value, null)
2203 var mproperty = self.mproperty.as(not null)
2204 v.write_attribute(mproperty, recv, i)
2205 end
2206 end
2207
2208 redef class AAttrReassignExpr
2209 redef fun stmt(v)
2210 do
2211 var recv = v.expr(self.n_expr, null)
2212 var value = v.expr(self.n_value, null)
2213 var mproperty = self.mproperty.as(not null)
2214 var attr = v.read_attribute(mproperty, recv)
2215 var res = v.compile_callsite(self.reassign_callsite.as(not null), [attr, value])
2216 assert res != null
2217 v.write_attribute(mproperty, recv, res)
2218 end
2219 end
2220
2221 redef class AIssetAttrExpr
2222 redef fun expr(v)
2223 do
2224 var recv = v.expr(self.n_expr, null)
2225 var mproperty = self.mproperty.as(not null)
2226 return v.isset_attribute(mproperty, recv)
2227 end
2228 end
2229
2230 redef class ADebugTypeExpr
2231 redef fun stmt(v)
2232 do
2233 # do nothing
2234 end
2235 end
2236
2237 # Utils
2238
2239 redef class HashSet[E]
2240 init from(elements: Collection[E]) do
2241 init
2242 self.add_all(elements)
2243 end
2244 end
2245
2246 redef class Array[E]
2247 init from(elements: Collection[E]) do
2248 init
2249 self.add_all(elements)
2250 end
2251
2252 # Return a new Array with the elements only contened in 'self' and not in 'o'
2253 fun -(o: Array[E]): Array[E] do
2254 var res = new Array[E]
2255 for e in self do if not o.has(e) then res.add(e)
2256 return res
2257 end
2258 end
2259
2260 redef class MModule
2261
2262 # Return a linearization of a set of mtypes
2263 fun linearize_mtypes(mtypes: Set[MType]): Array[MType] do
2264 var lin = new Array[MType].from(mtypes)
2265 var sorter = new TypeSorter(self)
2266 sorter.sort(lin)
2267 return lin
2268 end
2269
2270 # Return a reverse linearization of a set of mtypes
2271 fun reverse_linearize_mtypes(mtypes: Set[MType]): Array[MType] do
2272 var lin = new Array[MType].from(mtypes)
2273 var sorter = new ReverseTypeSorter(self)
2274 sorter.sort(lin)
2275 return lin
2276 end
2277
2278 # Return super types of a `mtype` in `self`
2279 fun super_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do
2280 if not self.super_mtypes_cache.has_key(mtype) then
2281 var supers = new HashSet[MType]
2282 for otype in mtypes do
2283 if otype == mtype then continue
2284 if mtype.is_subtype(self, null, otype) then
2285 supers.add(otype)
2286 end
2287 end
2288 self.super_mtypes_cache[mtype] = supers
2289 end
2290 return self.super_mtypes_cache[mtype]
2291 end
2292
2293 private var super_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
2294
2295 # Return all sub mtypes (directs and indirects) of a `mtype` in `self`
2296 fun sub_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do
2297 if not self.sub_mtypes_cache.has_key(mtype) then
2298 var subs = new HashSet[MType]
2299 for otype in mtypes do
2300 if otype == mtype then continue
2301 if otype.is_subtype(self, null, mtype) then
2302 subs.add(otype)
2303 end
2304 end
2305 self.sub_mtypes_cache[mtype] = subs
2306 end
2307 return self.sub_mtypes_cache[mtype]
2308 end
2309
2310 private var sub_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]]
2311
2312 # Return a linearization of a set of mclasses
2313 fun linearize_mclasses_2(mclasses: Set[MClass]): Array[MClass] do
2314 var lin = new Array[MClass].from(mclasses)
2315 var sorter = new ClassSorter(self)
2316 sorter.sort(lin)
2317 return lin
2318 end
2319
2320 # Return a reverse linearization of a set of mtypes
2321 fun reverse_linearize_mclasses(mclasses: Set[MClass]): Array[MClass] do
2322 var lin = new Array[MClass].from(mclasses)
2323 var sorter = new ReverseClassSorter(self)
2324 sorter.sort(lin)
2325 return lin
2326 end
2327
2328 # Return all super mclasses (directs and indirects) of a `mclass` in `self`
2329 fun super_mclasses(mclass: MClass): Set[MClass] do
2330 if not self.super_mclasses_cache.has_key(mclass) then
2331 var supers = new HashSet[MClass]
2332 if self.flatten_mclass_hierarchy.has(mclass) then
2333 for sup in self.flatten_mclass_hierarchy[mclass].greaters do
2334 if sup == mclass then continue
2335 supers.add(sup)
2336 end
2337 end
2338 self.super_mclasses_cache[mclass] = supers
2339 end
2340 return self.super_mclasses_cache[mclass]
2341 end
2342
2343 private var super_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
2344
2345 # Return all parents of a `mclass` in `self`
2346 fun parent_mclasses(mclass: MClass): Set[MClass] do
2347 if not self.parent_mclasses_cache.has_key(mclass) then
2348 var parents = new HashSet[MClass]
2349 if self.flatten_mclass_hierarchy.has(mclass) then
2350 for sup in self.flatten_mclass_hierarchy[mclass].direct_greaters do
2351 if sup == mclass then continue
2352 parents.add(sup)
2353 end
2354 end
2355 self.parent_mclasses_cache[mclass] = parents
2356 end
2357 return self.parent_mclasses_cache[mclass]
2358 end
2359
2360 private var parent_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
2361
2362 # Return all sub mclasses (directs and indirects) of a `mclass` in `self`
2363 fun sub_mclasses(mclass: MClass): Set[MClass] do
2364 if not self.sub_mclasses_cache.has_key(mclass) then
2365 var subs = new HashSet[MClass]
2366 if self.flatten_mclass_hierarchy.has(mclass) then
2367 for sub in self.flatten_mclass_hierarchy[mclass].smallers do
2368 if sub == mclass then continue
2369 subs.add(sub)
2370 end
2371 end
2372 self.sub_mclasses_cache[mclass] = subs
2373 end
2374 return self.sub_mclasses_cache[mclass]
2375 end
2376
2377 private var sub_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]]
2378
2379 # All 'mproperties' associated to all 'mclassdefs' of `mclass`
2380 fun properties(mclass: MClass): Set[MProperty] do
2381 if not self.properties_cache.has_key(mclass) then
2382 var properties = new HashSet[MProperty]
2383 var parents = self.super_mclasses(mclass)
2384 for parent in parents do
2385 properties.add_all(self.properties(parent))
2386 end
2387
2388 for mclassdef in mclass.mclassdefs do
2389 for mpropdef in mclassdef.mpropdefs do
2390 properties.add(mpropdef.mproperty)
2391 end
2392 end
2393 self.properties_cache[mclass] = properties
2394 end
2395 return properties_cache[mclass]
2396 end
2397
2398 private var properties_cache: Map[MClass, Set[MProperty]] = new HashMap[MClass, Set[MProperty]]
2399 end
2400
2401 # A sorter for linearize list of types
2402 private class TypeSorter
2403 super AbstractSorter[MType]
2404
2405 private var mmodule: MModule
2406
2407 init(mmodule: MModule) do self.mmodule = mmodule
2408
2409 redef fun compare(a, b) do
2410 if a == b then
2411 return 0
2412 else if a.is_subtype(self.mmodule, null, b) then
2413 return -1
2414 end
2415 return 1
2416 end
2417 end
2418
2419 # A sorter for reverse linearization
2420 private class ReverseTypeSorter
2421 super TypeSorter
2422
2423 init(mmodule: MModule) do end
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 linearize list of classes
2436 private class ClassSorter
2437 super AbstractSorter[MClass]
2438
2439 var mmodule: MModule
2440
2441 redef fun compare(a, b) do
2442 if a == b then
2443 return 0
2444 else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then
2445 return -1
2446 end
2447 return 1
2448 end
2449 end
2450
2451 # A sorter for reverse linearization
2452 private class ReverseClassSorter
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