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