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