bench: replace shootout_binarytrees with bench_bintree_gen
[nit.git] / src / global_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 # Global compilation of a Nit program
18 #
19 # Techniques used are:
20 # * heterogeneous generics
21 # * customization
22 # * switch dispatch
23 # * inlining
24 module global_compiler
25
26 import literal
27 import typing
28 import auto_super_init
29 import rapid_type_analysis
30
31 redef class ToolContext
32 # --output
33 var opt_output: OptionString = new OptionString("Output file", "-o", "--output")
34
35 # --no-cc
36 var opt_no_cc: OptionBool = new OptionBool("Do not invoke C compiler", "--no-cc")
37
38 # --hardening
39 var opt_hardening: OptionBool = new OptionBool("Generate contracts in the C code against bugs in the compiler", "--hardening")
40
41 # --no-check-covariance
42 var opt_no_check_covariance: OptionBool = new OptionBool("Disable type tests of covariant parameters (dangerous)", "--no-check-covariance")
43
44 # --no-check-initialization
45 var opt_no_check_initialization: OptionBool = new OptionBool("Disable isset tests at the end of constructors (dangerous)", "--no-check-initialization")
46
47 # --no-check-assert
48 var opt_no_check_assert: OptionBool = new OptionBool("Disable the evaluation of explicit 'assert' and 'as' (dangerous)", "--no-check-assert")
49
50 # --no-check-autocast
51 var opt_no_check_autocast: OptionBool = new OptionBool("Disable implicit casts on unsafe expression usage (dangerous)", "--no-check-autocast")
52
53 # --no-check-other
54 var opt_no_check_other: OptionBool = new OptionBool("Disable implicit tests: unset attribute, null receiver (dangerous)", "--no-check-other")
55
56 redef init
57 do
58 super
59 self.option_context.add_option(self.opt_output, self.opt_no_cc, self.opt_hardening)
60 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)
61 end
62 end
63
64 redef class ModelBuilder
65 # Entry point to performs a global compilation on the AST of a complete program.
66 # `mainmodule` is the main module of the program
67 # `runtime_type_analysis` is a already computer type analysis.
68 fun run_global_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
69 do
70 var time0 = get_time
71 self.toolcontext.info("*** COMPILING TO C ***", 1)
72
73 var compiler = new GlobalCompiler(mainmodule, runtime_type_analysis, self)
74 var v = compiler.header
75
76 for t in runtime_type_analysis.live_types do
77 compiler.declare_runtimeclass(v, t)
78 end
79
80 compiler.compile_class_names
81
82 # Init instance code (allocate and init-arguments)
83 for t in runtime_type_analysis.live_types do
84 if t.ctype == "val*" then
85 compiler.generate_init_instance(t)
86 compiler.generate_check_init_instance(t)
87 else
88 compiler.generate_box_instance(t)
89 end
90 end
91
92 # The main function of the C
93 compiler.compile_main_function
94
95 # Compile until all runtime_functions are visited
96 while not compiler.todos.is_empty do
97 var m = compiler.todos.shift
98 self.toolcontext.info("Compile {m} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3)
99 m.compile_to_c(compiler)
100 end
101 self.toolcontext.info("Total methods to compile to C: {compiler.visitors.length}", 2)
102
103 var time1 = get_time
104 self.toolcontext.info("*** END VISITING: {time1-time0} ***", 2)
105 write_and_make(compiler)
106 end
107
108 protected fun write_and_make(compiler: GlobalCompiler)
109 do
110 var mainmodule = compiler.mainmodule
111
112 # Generate the .h and .c files
113 # A single C file regroups many compiled rumtime functions
114 # 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
115 var time0 = get_time
116
117 var outname = self.toolcontext.opt_output.value
118 if outname == null then
119 outname = "{mainmodule.name}.bin"
120 end
121
122 var hfilename = ".nit_compile/{mainmodule.name}.1.h"
123 var h = new OFStream.open(hfilename)
124 for l in compiler.header.decl_lines do
125 h.write l
126 h.write "\n"
127 end
128 h.close
129
130 var cfiles = new Array[String]
131
132 var file: nullable OFStream = null
133 var count = 0
134
135 ".nit_compile".mkdir
136 var i = 0
137 for vis in compiler.visitors do
138 count += vis.lines.length
139 if file == null or count > 10000 then
140 i += 1
141 if file != null then file.close
142 var cfilename = ".nit_compile/{mainmodule.name}.{i}.c"
143 cfiles.add(cfilename)
144 file = new OFStream.open(cfilename)
145 file.write "#include \"{mainmodule.name}.1.h\"\n"
146 count = vis.lines.length
147 end
148 if vis != compiler.header then
149 for l in vis.decl_lines do
150 file.write l
151 file.write "\n"
152 end
153 end
154 for l in vis.lines do
155 file.write l
156 file.write "\n"
157 end
158 end
159 if file != null then file.close
160
161 self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
162
163 # Generate the Makefile
164
165 var makename = ".nit_compile/{mainmodule.name}.mk"
166 var makefile = new OFStream.open(makename)
167
168 makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc\n\n")
169 makefile.write("all: {outname}\n\n")
170
171 var ofiles = new Array[String]
172 # Compile each generated file
173 for f in cfiles do
174 var o = f.strip_extension(".c") + ".o"
175 makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) -D NONITCNI -c -o {o} {f}\n\n")
176 ofiles.add(o)
177 end
178 # Compile each required extern body into a specific .o
179 for f in compiler.extern_bodies do
180 i += 1
181 var o = ".nit_compile/{mainmodule.name}.{i}.o"
182 makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) -D NONITCNI -c -o {o} {f}\n\n")
183 ofiles.add(o)
184 end
185 # Link edition
186 makefile.write("{outname}: {ofiles.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outname} {ofiles.join(" ")} $(LDLIBS)\n\n")
187 # Clean
188 makefile.write("clean:\n\trm {ofiles.join(" ")} 2>/dev/null\n\n")
189 makefile.close
190 self.toolcontext.info("Generated makefile: {makename}", 2)
191
192 var time1 = get_time
193 self.toolcontext.info("*** END COMPILING TO C: {time1-time0} ***", 2)
194
195 # Execute the Makefile
196
197 if self.toolcontext.opt_no_cc.value then return
198
199 time0 = time1
200 self.toolcontext.info("*** COMPILING C ***", 1)
201 self.toolcontext.info("make -B -f {makename} -j 4", 2)
202
203 var res
204 if self.toolcontext.verbose_level >= 3 then
205 res = sys.system("make -B -f {makename} -j 4 2>&1")
206 else
207 res = sys.system("make -B -f {makename} -j 4 2>&1 >/dev/null")
208 end
209 if res != 0 then
210 toolcontext.error(null, "make failed! Error code: {res}.")
211 end
212
213 time1 = get_time
214 self.toolcontext.info("*** END COMPILING C: {time1-time0} ***", 2)
215 end
216 end
217
218 # Singleton that store the knowledge about the compilation process
219 class GlobalCompiler
220 # The main module of the program
221 var mainmodule: MModule writable
222
223 # The result of the RTA (used to know live types and methods)
224 var runtime_type_analysis: RapidTypeAnalysis
225
226 # The modeulbuilder used to know the model and the AST
227 var modelbuilder: ModelBuilder
228
229 # Is hardening asked? (see --hardening)
230 fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value
231
232 init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis, modelbuilder: ModelBuilder)
233 do
234 self.header = new_visitor
235 self.mainmodule = mainmodule
236 self.runtime_type_analysis = runtime_type_analysis
237 self.modelbuilder = modelbuilder
238 self.live_primitive_types = new Array[MClassType]
239 for t in runtime_type_analysis.live_types do
240 if t.ctype != "val*" then
241 self.live_primitive_types.add(t)
242 end
243 end
244
245 # Header declarations
246 self.compile_header
247 end
248
249 protected fun compile_header do
250 var v = self.header
251 self.header.add_decl("#include <stdlib.h>")
252 self.header.add_decl("#include <stdio.h>")
253 self.header.add_decl("#include <string.h>")
254 # TODO: Better way to activate the GC
255 self.header.add_decl("#include <gc/gc.h>")
256 #self.header.add_decl("#define GC_MALLOC(x) calloc(1, (x))")
257
258 compile_header_structs
259
260 # Global variable used by the legacy native interface
261 self.header.add_decl("extern int glob_argc;")
262 self.header.add_decl("extern char **glob_argv;")
263 self.header.add_decl("extern val *glob_sys;")
264 end
265
266 # Class names (for the class_name and output_class_name methods)
267 protected fun compile_class_names do
268 self.header.add_decl("extern const char const * class_names[];")
269 self.header.add("const char const * class_names[] = \{")
270 for t in self.runtime_type_analysis.live_types do
271 self.header.add("\"{t}\", /* {self.classid(t)} */")
272 end
273 self.header.add("\};")
274 end
275
276 # Declaration of structures the live Nit types
277 # Each live type is generated as an independent C `struct' type.
278 # They only share a common first field `classid` used to implement the polymorphism.
279 # Usualy, all C variables that refers to a Nit object are typed on the abstract struct `val' that contains only the `classid` field.
280 protected fun compile_header_structs do
281 self.header.add_decl("typedef struct \{int classid;\} val; /* general C type representing a Nit instance. */")
282 end
283
284 # Subset of runtime_type_analysis.live_types that contains only primitive types
285 # Used to implement the equal test
286 var live_primitive_types: Array[MClassType]
287
288 # runtime_functions that need to be compiled
289 private var todos: List[AbstractRuntimeFunction] = new List[AbstractRuntimeFunction]
290
291 # runtime_functions already seen (todo or done)
292 private var seen: HashSet[AbstractRuntimeFunction] = new HashSet[AbstractRuntimeFunction]
293 fun todo(m: AbstractRuntimeFunction)
294 do
295 if seen.has(m) then return
296 todos.add(m)
297 seen.add(m)
298 end
299
300 # Where global declaration are stored (the main .h)
301 #
302 # FIXME: should not be a vistor but just somewhere to store lines
303 # FIXME: should not have a global .h since it does not help recompilations
304 var header: GlobalCompilerVisitor writable
305
306 # The list of all associated visitors
307 # Used to generate .c files
308 # FIXME: should not be vistors but just somewhere to store lines
309 private var visitors: List[GlobalCompilerVisitor] = new List[GlobalCompilerVisitor]
310
311 # List of additional .c files required to compile (native interface)
312 var extern_bodies = new ArraySet[String]
313
314 # Return the C symbol associated to a live type runtime
315 # REQUIRE: self.runtime_type_analysis.live_types.has(mtype)
316 fun classid(mtype: MClassType): String
317 do
318 if self.classids.has_key(mtype) then
319 return self.classids[mtype]
320 end
321 print "No classid for {mtype}"
322 abort
323 end
324
325 # Cache for classid (computed by declare_runtimeclass)
326 protected var classids: HashMap[MClassType, String] = new HashMap[MClassType, String]
327
328 # Declare C structures and identifiers for a runtime class
329 fun declare_runtimeclass(v: GlobalCompilerVisitor, mtype: MClassType)
330 do
331 assert self.runtime_type_analysis.live_types.has(mtype)
332 v.add_decl("/* runtime class {mtype} */")
333 var idnum = classids.length
334 var idname = "ID_" + mtype.c_name
335 self.classids[mtype] = idname
336 v.add_decl("#define {idname} {idnum} /* {mtype} */")
337
338 v.add_decl("struct {mtype.c_name} \{")
339 v.add_decl("int classid; /* must be {idname} */")
340
341 if mtype.mclass.name == "NativeArray" then
342 # NativeArrays are just a instance header followed by an array of values
343 v.add_decl("{mtype.arguments.first.ctype} values[1];")
344 end
345
346 if mtype.ctype != "val*" then
347 # Is the Nit type is native then the struct is a box with two fields:
348 # * the `classid` to be polymorph
349 # * the `value` that contains the native value.
350 v.add_decl("{mtype.ctype} value;")
351 end
352
353 # Collect all attributes and associate them a field in the structure.
354 # Note: we do not try to optimize the order and helps CC to optimize the client code.
355 for cd in mtype.collect_mclassdefs(self.mainmodule) do
356 for p in cd.intro_mproperties do
357 if not p isa MAttribute then continue
358 var t = p.intro.static_mtype.as(not null)
359 t = t.anchor_to(self.mainmodule, mtype)
360 v.add_decl("{t.ctype} {p.intro.c_name}; /* {p}: {t} */")
361 end
362 end
363 v.add_decl("\};")
364 end
365
366 # Generate the init-instance of a live type (allocate + init-instance)
367 fun generate_init_instance(mtype: MClassType)
368 do
369 assert self.runtime_type_analysis.live_types.has(mtype)
370 assert mtype.ctype == "val*"
371 var v = self.new_visitor
372
373 var is_native_array = mtype.mclass.name == "NativeArray"
374
375 var sig
376 if is_native_array then
377 sig = "int length"
378 else
379 sig = "void"
380 end
381
382 self.header.add_decl("{mtype.ctype} NEW_{mtype.c_name}({sig});")
383 v.add_decl("/* allocate {mtype} */")
384 v.add_decl("{mtype.ctype} NEW_{mtype.c_name}({sig}) \{")
385 var res = v.new_var(mtype)
386 res.is_exact = true
387 if is_native_array then
388 var mtype_elt = mtype.arguments.first
389 v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}) + length*sizeof({mtype_elt.ctype}));")
390 else
391 v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}));")
392 end
393 v.add("{res}->classid = {self.classid(mtype)};")
394
395 self.generate_init_attr(v, res, mtype)
396 v.add("return {res};")
397 v.add("\}")
398 end
399
400 fun generate_check_init_instance(mtype: MClassType)
401 do
402 if self.modelbuilder.toolcontext.opt_no_check_initialization.value then return
403
404 var v = self.new_visitor
405 var res = new RuntimeVariable("self", mtype, mtype)
406 self.header.add_decl("void CHECK_NEW_{mtype.c_name}({mtype.ctype});")
407 v.add_decl("/* allocate {mtype} */")
408 v.add_decl("void CHECK_NEW_{mtype.c_name}({mtype.ctype} {res}) \{")
409 self.generate_check_attr(v, res, mtype)
410 v.add("\}")
411 end
412
413 # Generate code that collect initialize the attributes on a new instance
414 fun generate_init_attr(v: GlobalCompilerVisitor, recv: RuntimeVariable, mtype: MClassType)
415 do
416 for cd in mtype.collect_mclassdefs(self.mainmodule)
417 do
418 var n = self.modelbuilder.mclassdef2nclassdef[cd]
419 for npropdef in n.n_propdefs do
420 if npropdef isa AAttrPropdef then
421 npropdef.init_expr(v, recv)
422 end
423 end
424 end
425 end
426
427 # Generate a check-init-instance
428 fun generate_check_attr(v: GlobalCompilerVisitor, recv: RuntimeVariable, mtype: MClassType)
429 do
430 for cd in mtype.collect_mclassdefs(self.mainmodule)
431 do
432 var n = self.modelbuilder.mclassdef2nclassdef[cd]
433 for npropdef in n.n_propdefs do
434 if npropdef isa AAttrPropdef then
435 npropdef.check_expr(v, recv)
436 end
437 end
438 end
439 end
440
441 fun generate_box_instance(mtype: MClassType)
442 do
443 assert self.runtime_type_analysis.live_types.has(mtype)
444 assert mtype.ctype != "val*"
445 var v = self.new_visitor
446
447 self.header.add_decl("val* BOX_{mtype.c_name}({mtype.ctype});")
448 v.add_decl("/* allocate {mtype} */")
449 v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
450 v.add("struct {mtype.c_name}*res = GC_MALLOC(sizeof(struct {mtype.c_name}));")
451 v.add("res->classid = {self.classid(mtype)};")
452 v.add("res->value = value;")
453 v.add("return (val*)res;")
454 v.add("\}")
455
456 end
457
458 # look for a needed .h and .c file for a given .nit source-file
459 # FIXME: bad API, parameter should be a MModule, not its source-file
460 fun add_extern(file: String)
461 do
462 file = file.strip_extension(".nit")
463 var tryfile = file + ".nit.h"
464 if tryfile.file_exists then
465 self.header.add_decl("#include \"{"..".join_path(tryfile)}\"")
466 end
467 tryfile = file + "_nit.h"
468 if tryfile.file_exists then
469 self.header.add_decl("#include \"{"..".join_path(tryfile)}\"")
470 end
471 tryfile = file + ".nit.c"
472 if tryfile.file_exists then
473 self.extern_bodies.add(tryfile)
474 end
475 tryfile = file + "_nit.c"
476 if tryfile.file_exists then
477 self.extern_bodies.add(tryfile)
478 end
479 end
480
481 # Initialize a visitor specific for a compiler engine
482 fun new_visitor: GlobalCompilerVisitor do return new GlobalCompilerVisitor(self)
483
484 # Generate the main C function.
485 # This function:
486 # allocate the Sys object if it exists
487 # call init if is exists
488 # call main if it exists
489 fun compile_main_function
490 do
491 var v = self.new_visitor
492 v.add_decl("int glob_argc;")
493 v.add_decl("char **glob_argv;")
494 v.add_decl("val *glob_sys;")
495 v.add_decl("int main(int argc, char** argv) \{")
496 v.add("glob_argc = argc; glob_argv = argv;")
497 var main_type = mainmodule.sys_type
498 if main_type != null then
499 var mainmodule = v.compiler.mainmodule
500 var glob_sys = v.init_instance(main_type)
501 v.add("glob_sys = {glob_sys};")
502 var main_init = mainmodule.try_get_primitive_method("init", main_type)
503 if main_init != null then
504 v.send(main_init, [glob_sys])
505 end
506 var main_method = mainmodule.try_get_primitive_method("main", main_type)
507 if main_method != null then
508 v.send(main_method, [glob_sys])
509 end
510 end
511 v.add("return 0;")
512 v.add("\}")
513
514 end
515
516 private var collect_types_cache: HashMap[MType, Array[MClassType]] = new HashMap[MType, Array[MClassType]]
517 end
518
519 redef class String
520 # Mangle a string to be a unique valid C identifier
521 fun to_cmangle: String
522 do
523 var res = new Buffer
524 var underscore = false
525 for c in self do
526 if (c >= 'a' and c <= 'z') or (c >='A' and c <= 'Z') then
527 res.add(c)
528 underscore = false
529 continue
530 end
531 if underscore then
532 res.append('_'.ascii.to_s)
533 res.add('d')
534 end
535 if c >= '0' and c <= '9' then
536 res.add(c)
537 underscore = false
538 else if c == '_' then
539 res.add(c)
540 underscore = true
541 else
542 res.add('_')
543 res.append(c.ascii.to_s)
544 res.add('d')
545 underscore = false
546 end
547 end
548 return res.to_s
549 end
550
551 # Escape " \ ' and non printable characters for literal C strings or characters
552 fun escape_to_c: String
553 do
554 var b = new Buffer
555 for c in self do
556 if c == '\n' then
557 b.append("\\n")
558 else if c == '\0' then
559 b.append("\\0")
560 else if c == '"' then
561 b.append("\\\"")
562 else if c == '\'' then
563 b.append("\\\'")
564 else if c == '\\' then
565 b.append("\\\\")
566 else if c.ascii < 32 then
567 b.append("\\{c.ascii.to_base(8, false)}")
568 else
569 b.add(c)
570 end
571 end
572 return b.to_s
573 end
574 end
575
576 redef class MType
577 # Return the C type associated to a given Nit static type
578 fun ctype: String
579 do
580 return "val*"
581 end
582
583 # Return the name of the C structure associated to a Nit live type
584 # FIXME: move to GlobalCompiler so we can check that self is a live type
585 fun c_name: String is abstract
586 protected var c_name_cache: nullable String protected writable
587 end
588
589 redef class MClassType
590 redef fun c_name
591 do
592 var res = self.c_name_cache
593 if res != null then return res
594 res = "{mclass.intro_mmodule.name.to_cmangle}__{mclass.name.to_cmangle}"
595 self.c_name_cache = res
596 return res
597 end
598
599 redef fun ctype: String
600 do
601 if mclass.name == "Int" then
602 return "long"
603 else if mclass.name == "Bool" then
604 return "short int"
605 else if mclass.name == "Char" then
606 return "char"
607 else if mclass.name == "Float" then
608 return "double"
609 else if mclass.name == "NativeString" then
610 return "char*"
611 else if mclass.name == "NativeArray" then
612 #return "{self.arguments.first.ctype}*"
613 return "val*"
614 else if mclass.kind == extern_kind then
615 return "void*"
616 else
617 return "val*"
618 end
619 end
620 end
621
622 redef class MGenericType
623 redef fun c_name
624 do
625 var res = self.c_name_cache
626 if res != null then return res
627 res = super
628 for t in self.arguments do
629 res = res + t.c_name
630 end
631 self.c_name_cache = res
632 return res
633 end
634 end
635
636 # A C function associated to a Nit method
637 # Because of customization, a given Nit method can be compiler more that once
638 abstract class AbstractRuntimeFunction
639 # The associated Nit method
640 var mmethoddef: MMethodDef
641
642 # The mangled c name of the runtime_function
643 # Subclasses should redefine `build_c_name` instead
644 fun c_name: String
645 do
646 var res = self.c_name_cache
647 if res != null then return res
648 res = self.build_c_name
649 self.c_name_cache = res
650 return res
651 end
652
653 # Non cached version of `c_name`
654 protected fun build_c_name: String is abstract
655
656 private var c_name_cache: nullable String = null
657
658 # Implements a call of the runtime_function
659 # May inline the body or generate a C function call
660 fun call(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable is abstract
661
662 # Generate the code for the RuntimeFunction
663 # Warning: compile more than once compilation makes CC unhappy
664 fun compile_to_c(compiler: GlobalCompiler) is abstract
665 end
666
667 # A runtime function customized on a specific monomrph receiver type
668 private class CustomizedRuntimeFunction
669 super AbstractRuntimeFunction
670
671 # The considered reciever
672 # (usually is a live type but no strong guarantee)
673 var recv: MClassType
674
675 init(mmethoddef: MMethodDef, recv: MClassType)
676 do
677 super(mmethoddef)
678 self.recv = recv
679 end
680
681 redef fun build_c_name: String
682 do
683 var res = self.c_name_cache
684 if res != null then return res
685 if self.mmethoddef.mclassdef.bound_mtype == self.recv then
686 res = self.mmethoddef.c_name
687 else
688 res = "{mmethoddef.c_name}__{recv.c_name}"
689 end
690 self.c_name_cache = res
691 return res
692 end
693
694 redef fun ==(o)
695 # used in the compiler worklist
696 do
697 if not o isa CustomizedRuntimeFunction then return false
698 if self.mmethoddef != o.mmethoddef then return false
699 if self.recv != o.recv then return false
700 return true
701 end
702
703 redef fun hash
704 # used in the compiler work-list
705 do
706 var res = self.mmethoddef.hash + self.recv.hash
707 return res
708 end
709
710 redef fun to_s
711 do
712 if self.mmethoddef.mclassdef.bound_mtype == self.recv then
713 return self.mmethoddef.to_s
714 else
715 return "{self.mmethoddef}@{self.recv}"
716 end
717 end
718
719 # compile the code customized for the reciever
720 redef fun compile_to_c(compiler)
721 do
722 var recv = self.recv
723 var mmethoddef = self.mmethoddef
724 if not recv.is_subtype(compiler.mainmodule, null, mmethoddef.mclassdef.bound_mtype) then
725 print("problem: why do we compile {self} for {recv}?")
726 abort
727 end
728
729 var v = compiler.new_visitor
730 var selfvar = new RuntimeVariable("self", recv, recv)
731 if compiler.runtime_type_analysis.live_types.has(recv) then
732 selfvar.is_exact = true
733 end
734 var arguments = new Array[RuntimeVariable]
735 var frame = new Frame(v, mmethoddef, recv, arguments)
736 v.frame = frame
737
738 var sig = new Buffer
739 var comment = new Buffer
740 var ret = mmethoddef.msignature.return_mtype
741 if ret != null then
742 ret = v.resolve_for(ret, selfvar)
743 sig.append("{ret.ctype} ")
744 else if mmethoddef.mproperty.is_new then
745 ret = recv
746 sig.append("{ret.ctype} ")
747 else
748 sig.append("void ")
749 end
750 sig.append(self.c_name)
751 sig.append("({recv.ctype} {selfvar}")
752 comment.append("(self: {recv}")
753 arguments.add(selfvar)
754 for i in [0..mmethoddef.msignature.arity[ do
755 var mtype = mmethoddef.msignature.mparameters[i].mtype
756 if i == mmethoddef.msignature.vararg_rank then
757 mtype = v.get_class("Array").get_mtype([mtype])
758 end
759 mtype = v.resolve_for(mtype, selfvar)
760 comment.append(", {mtype}")
761 sig.append(", {mtype.ctype} p{i}")
762 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
763 arguments.add(argvar)
764 end
765 sig.append(")")
766 comment.append(")")
767 if ret != null then
768 comment.append(": {ret}")
769 end
770 compiler.header.add_decl("{sig};")
771
772 v.add_decl("/* method {self} for {comment} */")
773 v.add_decl("{sig} \{")
774 #v.add("printf(\"method {self} for {comment}\\n\");")
775 if ret != null then
776 frame.returnvar = v.new_var(ret)
777 end
778 frame.returnlabel = v.get_name("RET_LABEL")
779
780 mmethoddef.compile_inside_to_c(v, arguments)
781
782 v.add("{frame.returnlabel.as(not null)}:;")
783 if ret != null then
784 v.add("return {frame.returnvar.as(not null)};")
785 end
786 v.add("\}")
787 end
788
789 redef fun call(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
790 do
791 var ret = self.mmethoddef.msignature.return_mtype
792 if self.mmethoddef.mproperty.is_new then
793 ret = recv
794 end
795 if ret != null then
796 ret = v.resolve_for(ret, arguments.first)
797 end
798 if self.mmethoddef.can_inline(v) then
799 var frame = new Frame(v, self.mmethoddef, self.recv, arguments)
800 frame.returnlabel = v.get_name("RET_LABEL")
801 if ret != null then
802 frame.returnvar = v.new_var(ret)
803 end
804 var old_frame = v.frame
805 v.frame = frame
806 v.add("\{ /* Inline {self} ({arguments.join(",")}) */")
807 self.mmethoddef.compile_inside_to_c(v, arguments)
808 v.add("{frame.returnlabel.as(not null)}:(void)0;")
809 v.add("\}")
810 v.frame = old_frame
811 return frame.returnvar
812 end
813 v.adapt_signature(self.mmethoddef, arguments)
814 v.compiler.todo(self)
815 if ret == null then
816 v.add("{self.c_name}({arguments.join(",")});")
817 return null
818 else
819 var res = v.new_var(ret)
820 v.add("{res} = {self.c_name}({arguments.join(",")});")
821 return res
822 end
823 end
824 end
825
826 # A runtime variable hold a runtime value in C.
827 # Runtime variables are associated to Nit local variables and intermediate results in Nit expressions.
828 #
829 # 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.
830 class RuntimeVariable
831 # The name of the variable in the C code
832 var name: String
833
834 # The static type of the variable (as declard in C)
835 var mtype: MType
836
837 # The current casted type of the variable (as known in Nit)
838 var mcasttype: MType writable
839
840 # If the variable exaclty a mcasttype?
841 # false (usual value) means that the variable is a mcasttype or a subtype.
842 var is_exact: Bool writable = false
843
844 init(name: String, mtype: MType, mcasttype: MType)
845 do
846 self.name = name
847 self.mtype = mtype
848 self.mcasttype = mcasttype
849 assert not mtype.need_anchor
850 assert not mcasttype.need_anchor
851 end
852
853 redef fun to_s do return name
854
855 redef fun inspect
856 do
857 var exact_str
858 if self.is_exact then
859 exact_str = " exact"
860 else
861 exact_str = ""
862 end
863 var type_str
864 if self.mtype == self.mcasttype then
865 type_str = "{mtype}{exact_str}"
866 else
867 type_str = "{mtype}({mcasttype}{exact_str})"
868 end
869 return "<{name}:{type_str}>"
870 end
871 end
872
873 # A visitor on the AST of property definition that generate the C code.
874 # Because of inlining, a visitor can visit more than one property.
875 class GlobalCompilerVisitor
876 # The associated compiler
877 var compiler: GlobalCompiler
878
879 init(compiler: GlobalCompiler)
880 do
881 self.compiler = compiler
882 compiler.visitors.add(self)
883 end
884
885 # Alias for self.compiler.mainmodule.object_type
886 fun object_type: MClassType do return self.compiler.mainmodule.object_type
887
888 # Alias for self.compiler.mainmodule.bool_type
889 fun bool_type: MClassType do return self.compiler.mainmodule.bool_type
890
891 # Force to get the primitive class named `name' or abort
892 fun get_class(name: String): MClass
893 do
894 return self.compiler.mainmodule.get_primitive_class(name)
895 end
896
897 # Force to get the primitive property named `name' in the instance `recv' or abort
898 fun get_property(name: String, recv: MType): MMethod
899 do
900 return self.compiler.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, recv, self.compiler.mainmodule)
901 end
902
903 # The current Frame
904 var frame: nullable Frame writable
905
906 # Anchor a type to the main module and the current receiver
907 fun anchor(mtype: MType): MType
908 do
909 if not mtype.need_anchor then return mtype
910 #debug("anchor {mtype} to {self.reciever.as(not null)}:{self.reciever.mtype}")
911 return mtype.anchor_to(self.compiler.mainmodule, self.frame.receiver)
912 end
913
914 # Add a line in the main part of the generated C
915 fun add(s: String)
916 do
917 self.lines.add(s)
918 end
919
920 # Add a line in the
921 # (used for local or global declaration)
922 fun add_decl(s: String)
923 do
924 self.decl_lines.add(s)
925 end
926
927 private var lines: List[String] = new List[String]
928 private var decl_lines: List[String] = new List[String]
929
930 # The current visited AST node
931 var current_node: nullable ANode = null
932
933 # Compile an expression an return its result
934 # `mtype` is the expected return type, pass null if no specific type is expected.
935 fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable
936 do
937 var old = self.current_node
938 self.current_node = nexpr
939 var res = nexpr.expr(self).as(not null)
940 if mtype != null then
941 mtype = self.anchor(mtype)
942 res = self.autobox(res, mtype)
943 end
944 var implicit_cast_to = nexpr.implicit_cast_to
945 if implicit_cast_to != null and not self.compiler.modelbuilder.toolcontext.opt_no_check_autocast.value then
946 var castres = self.type_test(res, implicit_cast_to)
947 self.add("if (!{castres}) \{")
948 self.add_abort("Cast failed")
949 self.add("\}")
950 end
951 self.current_node = old
952 return res
953 end
954
955 # Unsafely cast a value to a new type
956 # ie the result share the same C variable but my have a different mcasttype
957 # NOTE: if the adaptation is useless then `value' is returned as it.
958 # ENSURE: return.name == value.name
959 fun autoadapt(value: RuntimeVariable, mtype: MType): RuntimeVariable
960 do
961 mtype = self.anchor(mtype)
962 var valmtype = value.mcasttype
963 if valmtype.is_subtype(self.compiler.mainmodule, null, mtype) then
964 return value
965 end
966
967 if valmtype isa MNullableType and valmtype.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
968 var res = new RuntimeVariable(value.name, valmtype, valmtype.mtype)
969 return res
970 else
971 var res = new RuntimeVariable(value.name, valmtype, mtype)
972 return res
973 end
974 end
975
976 # Box or unbox a value to another type iff a C type conversion is needed
977 # ENSURE: result.mtype.ctype == mtype.ctype
978 fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable
979 do
980 if value.mtype == mtype then
981 return value
982 else if value.mtype.ctype == "val*" and mtype.ctype == "val*" then
983 return value
984 else if value.mtype.ctype == "val*" then
985 return self.new_expr("((struct {mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
986 else if mtype.ctype == "val*" then
987 var valtype = value.mtype.as(MClassType)
988 var res = self.new_var(mtype)
989 if not compiler.runtime_type_analysis.live_types.has(valtype) then
990 self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
991 self.add("printf(\"Dead code executed!\\n\"); exit(1);")
992 return res
993 end
994 self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
995 return res
996 else
997 # Bad things will appen!
998 var res = self.new_var(mtype)
999 self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
1000 self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); exit(1);")
1001 return res
1002 end
1003 end
1004
1005 # Correctly assign a left and a right value
1006 # Boxing and unboxing is performed if required
1007 fun assign(left, right: RuntimeVariable)
1008 do
1009 right = self.autobox(right, left.mtype)
1010 self.add("{left} = {right};")
1011 end
1012
1013
1014 # Alias for `self.expr(nexpr, self.bool_type)'
1015 fun expr_bool(nexpr: AExpr): RuntimeVariable
1016 do
1017 return expr(nexpr, bool_type)
1018 end
1019
1020 # Compile a statement (if any)
1021 fun stmt(nexpr: nullable AExpr)
1022 do
1023 if nexpr == null then return
1024 var old = self.current_node
1025 self.current_node = nexpr
1026 nexpr.stmt(self)
1027 self.current_node = old
1028 end
1029
1030 # Safely show a debug message on the current node and repeat the message in the C code as a comment
1031 fun debug(message: String)
1032 do
1033 var node = self.current_node
1034 if node == null then
1035 print "?: {message}"
1036 else
1037 node.debug(message)
1038 end
1039 self.add("/* DEBUG: {message} */")
1040 end
1041
1042 # Return a new uninitialized local runtime_variable
1043 fun new_var(mtype: MType): RuntimeVariable
1044 do
1045 mtype = self.anchor(mtype)
1046 var name = self.get_name("var")
1047 var res = new RuntimeVariable(name, mtype, mtype)
1048 self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
1049 return res
1050 end
1051
1052 # Return a new uninitialized named runtime_variable
1053 fun new_named_var(mtype: MType, name: String): RuntimeVariable
1054 do
1055 mtype = self.anchor(mtype)
1056 var res = new RuntimeVariable(name, mtype, mtype)
1057 self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
1058 return res
1059 end
1060
1061 # Return a new local runtime_variable initialized with the C expression `cexpr'.
1062 fun new_expr(cexpr: String, mtype: MType): RuntimeVariable
1063 do
1064 var res = new_var(mtype)
1065 self.add("{res} = {cexpr};")
1066 return res
1067 end
1068
1069 # Return the local runtime_variable associated to a Nit local variable
1070 fun variable(variable: Variable): RuntimeVariable
1071 do
1072 if self.variables.has_key(variable) then
1073 return self.variables[variable]
1074 else
1075 var name = self.get_name("var_{variable.name}")
1076 var mtype = variable.declared_type.as(not null)
1077 mtype = self.anchor(mtype)
1078 var res = new RuntimeVariable(name, mtype, mtype)
1079 self.add_decl("{mtype.ctype} {name} /* var {variable}: {mtype} */;")
1080 self.variables[variable] = res
1081 return res
1082 end
1083 end
1084
1085 private var variables: HashMap[Variable, RuntimeVariable] = new HashMap[Variable, RuntimeVariable]
1086
1087 # Return an unique and stable identifier associated with an escapemark
1088 fun escapemark_name(e: nullable EscapeMark): String
1089 do
1090 assert e != null
1091 if escapemark_names.has_key(e) then return escapemark_names[e]
1092 var name = e.name
1093 if name == null then name = "label"
1094 name = get_name(name)
1095 escapemark_names[e] = name
1096 return name
1097 end
1098
1099 private var escapemark_names = new HashMap[EscapeMark, String]
1100
1101 # Return a new name based on `s' and unique in the visitor
1102 fun get_name(s: String): String
1103 do
1104 if not self.names.has(s) then
1105 self.names.add(s)
1106 return s
1107 end
1108 var i = self.last + 1
1109 loop
1110 var s2 = s + i.to_s
1111 if not self.names.has(s2) then
1112 self.last = i
1113 self.names.add(s2)
1114 return s2
1115 end
1116 i = i + 1
1117 end
1118 end
1119
1120 private var last: Int = 0
1121
1122 private var names: HashSet[String] = new HashSet[String]
1123
1124 # Generate a return with the value `s'
1125 fun ret(s: RuntimeVariable)
1126 do
1127 self.assign(self.frame.returnvar.as(not null), s)
1128 self.add("goto {self.frame.returnlabel.as(not null)};")
1129 end
1130
1131 # The runtime types that are acceptable for a given receiver.
1132 fun collect_types(recv: RuntimeVariable): Array[MClassType]
1133 do
1134 var mtype = recv.mcasttype
1135 if recv.is_exact then
1136 assert mtype isa MClassType
1137 assert self.compiler.runtime_type_analysis.live_types.has(mtype)
1138 var types = [mtype]
1139 return types
1140 end
1141 var cache = self.compiler.collect_types_cache
1142 if cache.has_key(mtype) then
1143 return cache[mtype]
1144 end
1145 var types = new Array[MClassType]
1146 var mainmodule = self.compiler.mainmodule
1147 for t in self.compiler.runtime_type_analysis.live_types do
1148 if not t.is_subtype(mainmodule, null, mtype) then continue
1149 types.add(t)
1150 end
1151 cache[mtype] = types
1152 return types
1153 end
1154
1155 fun resolve_for(mtype: MType, recv: RuntimeVariable): MType
1156 do
1157 if not mtype.need_anchor then return mtype
1158 #debug("resolve for {mtype} to {recv}:{recv.mcasttype}(declared as {recv.mtype}) (in {self.reciever.to_s}:{self.reciever.mtype})")
1159 var res = mtype.resolve_for(recv.mcasttype, self.frame.receiver, self.compiler.mainmodule, true)
1160 return res
1161 end
1162
1163 fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable])
1164 do
1165 var elttype = arguments.first.mtype
1166 var recv = "((struct {arguments[0].mcasttype.c_name}*){arguments[0]})->values"
1167 if pname == "[]" then
1168 self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null)))
1169 return
1170 else if pname == "[]=" then
1171 self.add("{recv}[{arguments[1]}]={arguments[2]};")
1172 return
1173 else if pname == "copy_to" then
1174 var recv1 = "((struct {arguments[1].mcasttype.c_name}*){arguments[1]})->values"
1175 self.add("memcpy({recv1},{recv},{arguments[2]}*sizeof({elttype.ctype}));")
1176 return
1177 end
1178 end
1179
1180 fun calloc_array(ret_type: MType, arguments: Array[RuntimeVariable])
1181 do
1182 self.ret(self.new_expr("NEW_{ret_type.c_name}({arguments[1]})", ret_type))
1183 end
1184
1185 # Add a check and an abort for a null reciever is needed
1186 fun check_recv_notnull(recv: RuntimeVariable)
1187 do
1188 if self.compiler.modelbuilder.toolcontext.opt_no_check_other.value then return
1189
1190 var maybenull = recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType
1191 if maybenull then
1192 self.add("if ({recv} == NULL) \{")
1193 self.add_abort("Reciever is null")
1194 self.add("\}")
1195 end
1196 end
1197
1198 fun compile_callsite(callsite: CallSite, args: Array[RuntimeVariable]): nullable RuntimeVariable
1199 do
1200 var ret = self.send(callsite.mproperty, args)
1201 return ret
1202 end
1203
1204 # Generate a polymorphic send for the method `m' and the arguments `args'
1205 fun send(m: MMethod, args: Array[RuntimeVariable]): nullable RuntimeVariable
1206 do
1207 var types = self.collect_types(args.first)
1208
1209 var res: nullable RuntimeVariable
1210 var ret = m.intro.msignature.return_mtype
1211 if m.is_new then
1212 ret = args.first.mtype
1213 res = self.new_var(ret)
1214 else if ret == null then
1215 res = null
1216 else
1217 ret = self.resolve_for(ret, args.first)
1218 res = self.new_var(ret)
1219 end
1220
1221 self.add("/* send {m} on {args.first.inspect} */")
1222 if args.first.mtype.ctype != "val*" then
1223 var mclasstype = args.first.mtype.as(MClassType)
1224 if not self.compiler.runtime_type_analysis.live_types.has(mclasstype) then
1225 self.add("/* skip, no method {m} */")
1226 return res
1227 end
1228 var propdefs = m.lookup_definitions(self.compiler.mainmodule, mclasstype)
1229 if propdefs.length == 0 then
1230 self.add("/* skip, no method {m} */")
1231 return res
1232 end
1233 assert propdefs.length == 1
1234 var propdef = propdefs.first
1235 var res2 = self.call(propdef, mclasstype, args)
1236 if res != null then self.assign(res, res2.as(not null))
1237 return res
1238 end
1239 var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value or m.name == "==" or m.name == "!="
1240 if args.first.mcasttype isa MNullableType or args.first.mcasttype isa MNullType and consider_null then
1241 # The reciever is potentially null, so we have to 3 cases: ==, != or NullPointerException
1242 self.add("if ({args.first} == NULL) \{ /* Special null case */")
1243 if m.name == "==" then
1244 assert res != null
1245 if args[1].mcasttype isa MNullableType then
1246 self.add("{res} = ({args[1]} == NULL);")
1247 else if args[1].mcasttype isa MNullType then
1248 self.add("{res} = 1; /* is null */")
1249 else
1250 self.add("{res} = 0; /* {args[1].inspect} cannot be null */")
1251 end
1252 else if m.name == "!=" then
1253 assert res != null
1254 if args[1].mcasttype isa MNullableType then
1255 self.add("{res} = ({args[1]} != NULL);")
1256 else if args[1].mcasttype isa MNullType then
1257 self.add("{res} = 0; /* is null */")
1258 else
1259 self.add("{res} = 1; /* {args[1].inspect} cannot be null */")
1260 end
1261 else
1262 self.add_abort("Reciever is null")
1263 end
1264 self.add "\} else"
1265 end
1266 if types.is_empty then
1267 self.add("\{")
1268 self.add("/*BUG: no live types for {args.first.inspect} . {m}*/")
1269 self.bugtype(args.first)
1270 self.add("\}")
1271 return res
1272 end
1273
1274 self.add("switch({args.first}->classid) \{")
1275 var last = types.last
1276 var defaultpropdef: nullable MMethodDef = null
1277 for t in types do
1278 var propdefs = m.lookup_definitions(self.compiler.mainmodule, t)
1279 if propdefs.length == 0 then
1280 self.add("/* skip {t}, no method {m} */")
1281 continue
1282 end
1283 if propdefs.length > 1 then
1284 self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first")
1285 end
1286 var propdef = propdefs.first
1287 if propdef.mclassdef.mclass.name == "Object" and t.ctype == "val*" then
1288 defaultpropdef = propdef
1289 continue
1290 end
1291 if not self.compiler.hardening and t == last and defaultpropdef == null then
1292 self.add("default: /* test {t} */")
1293 else
1294 self.add("case {self.compiler.classid(t)}: /* test {t} */")
1295 end
1296 var res2 = self.call(propdef, t, args)
1297 if res != null then self.assign(res, res2.as(not null))
1298 self.add "break;"
1299 end
1300 if defaultpropdef != null then
1301 self.add("default: /* default is Object */")
1302 var res2 = self.call(defaultpropdef, defaultpropdef.mclassdef.bound_mtype, args)
1303 if res != null then self.assign(res, res2.as(not null))
1304 else if self.compiler.hardening then
1305 self.add("default: /* bug */")
1306 self.bugtype(args.first)
1307 end
1308 self.add("\}")
1309 return res
1310 end
1311
1312 # Generate a monomorphic send for the method `m', the type `t' and the arguments `args'
1313 fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable
1314 do
1315 assert t isa MClassType
1316 var propdefs = m.lookup_definitions(self.compiler.mainmodule, t)
1317 if propdefs.length == 0 then
1318 abort
1319 end
1320 if propdefs.length > 1 then
1321 self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first")
1322 end
1323 var propdef = propdefs.first
1324 return self.call(propdef, t, args)
1325 end
1326
1327 fun check_valid_reciever(recvtype: MClassType)
1328 do
1329 if self.compiler.runtime_type_analysis.live_types.has(recvtype) or recvtype.mclass.name == "Object" then return
1330 print "{recvtype} is not a live type"
1331 abort
1332 end
1333
1334 # Generate a static call on a method definition
1335 fun call(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
1336 do
1337 check_valid_reciever(recvtype)
1338 #debug("call {m} on {recvtype} on {args.first}:{args.first.mtype}")
1339 if m.mclassdef.mclass.name == "Object" and recvtype.ctype == "val*" then
1340 recvtype = m.mclassdef.bound_mtype
1341 end
1342 var recv = self.autobox(args.first, recvtype)
1343 recv = self.autoadapt(recv, recvtype)
1344
1345 args = args.to_a
1346 self.varargize(m.msignature.as(not null), args)
1347 if args.length != m.msignature.arity + 1 then # because of self
1348 add("printf(\"NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.\\n\"); exit(1);")
1349 debug("NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.")
1350 return null
1351 end
1352
1353 args.first = recv
1354 var rm = new CustomizedRuntimeFunction(m, recvtype)
1355 return rm.call(self, args)
1356 end
1357
1358 fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
1359 do
1360 var recv = args.first
1361 for i in [0..m.msignature.arity[ do
1362 var t = m.msignature.mparameters[i].mtype
1363 if i == m.msignature.vararg_rank then
1364 t = args[i+1].mtype
1365 end
1366 t = self.resolve_for(t, recv)
1367 args[i+1] = self.autobox(args[i+1], t)
1368 end
1369 end
1370
1371 # Transform varargs, in raw arguments, into a single argument of type Array
1372 # Note: this method modify the given `args`
1373 # If there is no vararg, then `args` is not modified.
1374 fun varargize(msignature: MSignature, args: Array[RuntimeVariable])
1375 do
1376 var recv = args.first
1377 var vararg_rank = msignature.vararg_rank
1378 if vararg_rank >= 0 then
1379 assert args.length >= msignature.arity + 1 # because of self
1380 var rawargs = args
1381 args = new Array[RuntimeVariable]
1382
1383 args.add(rawargs.first) # recv
1384
1385 for i in [0..vararg_rank[ do
1386 args.add(rawargs[i+1])
1387 end
1388
1389 var vararg_lastrank = vararg_rank + rawargs.length-1-msignature.arity
1390 var vararg = new Array[RuntimeVariable]
1391 for i in [vararg_rank..vararg_lastrank] do
1392 vararg.add(rawargs[i+1])
1393 end
1394 # FIXME: its it to late to determine the vararg type, this should have been done during a previous analysis
1395 var elttype = msignature.mparameters[vararg_rank].mtype
1396 elttype = self.resolve_for(elttype, recv)
1397 args.add(self.array_instance(vararg, elttype))
1398
1399 for i in [vararg_lastrank+1..rawargs.length-1[ do
1400 args.add(rawargs[i+1])
1401 end
1402 rawargs.clear
1403 rawargs.add_all(args)
1404 end
1405 end
1406
1407 fun bugtype(recv: RuntimeVariable)
1408 do
1409 if recv.mtype.ctype != "val*" then return
1410 self.add("fprintf(stderr, \"BTD BUG: Dynamic type is %s, static type is %s\\n\", class_names[{recv}->classid], \"{recv.mcasttype}\");")
1411 self.add("exit(1);")
1412 end
1413
1414 # Generate a polymorphic attribute is_set test
1415 fun isset_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable
1416 do
1417 check_recv_notnull(recv)
1418
1419 var types = self.collect_types(recv)
1420
1421 var res = self.new_var(bool_type)
1422
1423 if types.is_empty then
1424 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1425 self.bugtype(recv)
1426 return res
1427 end
1428 self.add("/* isset {a} on {recv.inspect} */")
1429 self.add("switch({recv}->classid) \{")
1430 var last = types.last
1431 for t in types do
1432 if not self.compiler.hardening and t == last then
1433 self.add("default: /*{self.compiler.classid(t)}*/")
1434 else
1435 self.add("case {self.compiler.classid(t)}:")
1436 end
1437 var recv2 = self.autoadapt(recv, t)
1438 var ta = a.intro.static_mtype.as(not null)
1439 ta = self.resolve_for(ta, recv2)
1440 var attr = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
1441 if not ta isa MNullableType then
1442 if ta.ctype == "val*" then
1443 self.add("{res} = ({attr} != NULL);")
1444 else
1445 self.add("{res} = 1; /*NOTYET isset on primitive attributes*/")
1446 end
1447 end
1448 self.add("break;")
1449 end
1450 if self.compiler.hardening then
1451 self.add("default: /* Bug */")
1452 self.bugtype(recv)
1453 end
1454 self.add("\}")
1455
1456 return res
1457 end
1458
1459 # Generate a polymorphic attribute read
1460 fun read_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable
1461 do
1462 check_recv_notnull(recv)
1463
1464 var types = self.collect_types(recv)
1465
1466 var ret = a.intro.static_mtype.as(not null)
1467 ret = self.resolve_for(ret, recv)
1468 var res = self.new_var(ret)
1469
1470 if types.is_empty then
1471 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1472 self.bugtype(recv)
1473 return res
1474 end
1475 self.add("/* read {a} on {recv.inspect} */")
1476 self.add("switch({recv}->classid) \{")
1477 var last = types.last
1478 for t in types do
1479 if not self.compiler.hardening and t == last then
1480 self.add("default: /*{self.compiler.classid(t)}*/")
1481 else
1482 self.add("case {self.compiler.classid(t)}:")
1483 end
1484 var recv2 = self.autoadapt(recv, t)
1485 var ta = a.intro.static_mtype.as(not null)
1486 ta = self.resolve_for(ta, recv2)
1487 var res2 = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
1488 if not ta isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value then
1489 if ta.ctype == "val*" then
1490 self.add("if ({res2} == NULL) \{")
1491 self.add_abort("Uninitialized attribute {a.name}")
1492 self.add("\}")
1493 else
1494 self.add("/*NOTYET isset on primitive attributes*/")
1495 end
1496 end
1497 self.assign(res, res2)
1498 self.add("break;")
1499 end
1500 if self.compiler.hardening then
1501 self.add("default: /* Bug */")
1502 self.bugtype(recv)
1503 end
1504 self.add("\}")
1505
1506 return res
1507 end
1508
1509 # Generate a polymorphic attribute write
1510 fun write_attribute(a: MAttribute, recv: RuntimeVariable, value: RuntimeVariable)
1511 do
1512 check_recv_notnull(recv)
1513
1514 var types = self.collect_types(recv)
1515
1516 if types.is_empty then
1517 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1518 self.bugtype(recv)
1519 return
1520 end
1521 self.add("/* write {a} on {recv.inspect} */")
1522 self.add("switch({recv}->classid) \{")
1523 var last = types.last
1524 for t in types do
1525 if not self.compiler.hardening and t == last then
1526 self.add("default: /*{self.compiler.classid(t)}*/")
1527 else
1528 self.add("case {self.compiler.classid(t)}:")
1529 end
1530 var recv2 = self.autoadapt(recv, t)
1531 var ta = a.intro.static_mtype.as(not null)
1532 ta = self.resolve_for(ta, recv2)
1533 self.add("((struct {t.c_name}*){recv})->{a.intro.c_name} = {self.autobox(value, ta)};")
1534 self.add("break;")
1535 end
1536 if self.compiler.hardening then
1537 self.add("default: /* Bug*/")
1538 self.bugtype(recv)
1539 end
1540 self.add("\}")
1541 end
1542
1543 # Generate a alloc-instance + init-attributes
1544 fun init_instance(mtype: MClassType): RuntimeVariable
1545 do
1546 mtype = self.anchor(mtype).as(MClassType)
1547 if not self.compiler.runtime_type_analysis.live_types.has(mtype) then
1548 debug "problem: {mtype} was detected dead"
1549 end
1550 var res = self.new_expr("NEW_{mtype.c_name}()", mtype)
1551 res.is_exact = true
1552 return res
1553 end
1554
1555 # Generate a polymorphic subtype test
1556 fun type_test(value: RuntimeVariable, mtype: MType): RuntimeVariable
1557 do
1558 mtype = self.anchor(mtype)
1559 var mclasstype = mtype
1560 if mtype isa MNullableType then mclasstype = mtype.mtype
1561 assert mclasstype isa MClassType
1562 if not self.compiler.runtime_type_analysis.live_cast_types.has(mclasstype) then
1563 debug "problem: {mtype} was detected cast-dead"
1564 abort
1565 end
1566
1567 var types = self.collect_types(value)
1568
1569 var res = self.new_var(bool_type)
1570
1571 self.add("/* isa {mtype} on {value.inspect} */")
1572 if value.mtype.ctype != "val*" then
1573 if value.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
1574 self.add("{res} = 1;")
1575 else
1576 self.add("{res} = 0;")
1577 end
1578 return res
1579 end
1580 if value.mcasttype isa MNullableType or value.mcasttype isa MNullType then
1581 self.add("if ({value} == NULL) \{")
1582 if mtype isa MNullableType then
1583 self.add("{res} = 1; /* isa {mtype} */")
1584 else
1585 self.add("{res} = 0; /* not isa {mtype} */")
1586 end
1587 self.add("\} else ")
1588 end
1589 self.add("switch({value}->classid) \{")
1590 for t in types do
1591 if t.is_subtype(self.compiler.mainmodule, null, mtype) then
1592 self.add("case {self.compiler.classid(t)}: /* {t} */")
1593 end
1594 end
1595 self.add("{res} = 1;")
1596 self.add("break;")
1597 self.add("default:")
1598 self.add("{res} = 0;")
1599 self.add("\}")
1600
1601 return res
1602 end
1603
1604 # Generate the code required to dynamically check if 2 objects share the same runtime type
1605 fun is_same_type_test(value1, value2: RuntimeVariable): RuntimeVariable
1606 do
1607 var res = self.new_var(bool_type)
1608 if value2.mtype.ctype == "val*" then
1609 if value1.mtype.ctype == "val*" then
1610 self.add "{res} = {value1}->classid == {value2}->classid;"
1611 else
1612 self.add "{res} = {self.compiler.classid(value1.mtype.as(MClassType))} == {value2}->classid;"
1613 end
1614 else
1615 if value1.mtype.ctype == "val*" then
1616 self.add "{res} = {value1}->classid == {self.compiler.classid(value2.mtype.as(MClassType))};"
1617 else if value1.mcasttype == value2.mcasttype then
1618 self.add "{res} = 1;"
1619 else
1620 self.add "{res} = 0;"
1621 end
1622 end
1623 return res
1624 end
1625
1626 # Return a "const char*" variable associated to the classname of the dynamic type of an object
1627 # NOTE: we do not return a RuntimeVariable "NativeString" as the class may not exist in the module/program
1628 fun class_name_string(value: RuntimeVariable): String
1629 do
1630 var res = self.get_name("var_class_name")
1631 self.add_decl("const char* {res};")
1632 if value.mtype.ctype == "val*" then
1633 self.add "{res} = class_names[{value}->classid];"
1634 else
1635 self.add "{res} = class_names[{self.compiler.classid(value.mtype.as(MClassType))}];"
1636 end
1637 return res
1638 end
1639
1640 # Generate a Nit "is" for two runtime_variables
1641 fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable
1642 do
1643 var res = self.new_var(bool_type)
1644 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1645 var tmp = value1
1646 value1 = value2
1647 value2 = tmp
1648 end
1649 if value1.mtype.ctype != "val*" then
1650 if value2.mtype == value1.mtype then
1651 self.add("{res} = {value1} == {value2};")
1652 else if value2.mtype.ctype != "val*" then
1653 self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
1654 else
1655 var mtype1 = value1.mtype.as(MClassType)
1656 self.add("{res} = ({value2} != NULL) && ({value2}->classid == {self.compiler.classid(mtype1)});")
1657 self.add("if ({res}) \{")
1658 self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
1659 self.add("\}")
1660 end
1661 else
1662 var s = new Array[String]
1663 for t in self.compiler.live_primitive_types do
1664 if not t.is_subtype(self.compiler.mainmodule, null, value1.mcasttype) then continue
1665 if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
1666 s.add "({value1}->classid == {self.compiler.classid(t)} && ((struct {t.c_name}*){value1})->value == ((struct {t.c_name}*){value2})->value)"
1667 end
1668 if s.is_empty then
1669 self.add("{res} = {value1} == {value2};")
1670 else
1671 self.add("{res} = {value1} == {value2} || ({value1} != NULL && {value2} != NULL && {value1}->classid == {value2}->classid && ({s.join(" || ")}));")
1672 end
1673 end
1674 return res
1675 end
1676
1677 # Generate a check-init-instance
1678 fun check_init_instance(recv: RuntimeVariable, mtype: MClassType)
1679 do
1680 if self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then return
1681
1682 mtype = self.anchor(mtype).as(MClassType)
1683 if not self.compiler.runtime_type_analysis.live_types.has(mtype) then
1684 debug "problem: {mtype} was detected dead"
1685 end
1686
1687 self.add("CHECK_NEW_{mtype.c_name}({recv});")
1688 end
1689
1690 # Generate an integer value
1691 fun int_instance(value: Int): RuntimeVariable
1692 do
1693 var res = self.new_var(self.get_class("Int").mclass_type)
1694 self.add("{res} = {value};")
1695 return res
1696 end
1697
1698 # Generate an array value
1699 fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable
1700 do
1701 elttype = self.anchor(elttype)
1702 var arraytype = self.get_class("Array").get_mtype([elttype])
1703 var res = self.init_instance(arraytype)
1704 self.add("\{ /* {res} = array_instance Array[{elttype}] */")
1705 var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
1706 nat.is_exact = true
1707 self.add("{nat} = NEW_{nat.mtype.c_name}({array.length});")
1708 for i in [0..array.length[ do
1709 var r = self.autobox(array[i], elttype)
1710 self.add("((struct {nat.mtype.c_name}*) {nat})->values[{i}] = {r};")
1711 end
1712 var length = self.int_instance(array.length)
1713 self.send(self.get_property("with_native", arraytype), [res, nat, length])
1714 self.check_init_instance(res, arraytype)
1715 self.add("\}")
1716 return res
1717 end
1718
1719 # Generate a string value
1720 fun string_instance(string: String): RuntimeVariable
1721 do
1722 var mtype = self.get_class("String").mclass_type
1723 var name = self.get_name("varonce")
1724 self.add_decl("static {mtype.ctype} {name};")
1725 var res = self.new_var(mtype)
1726 self.add("if ({name}) \{")
1727 self.add("{res} = {name};")
1728 self.add("\} else \{")
1729 var nat = self.new_var(self.get_class("NativeString").mclass_type)
1730 self.add("{nat} = \"{string.escape_to_c}\";")
1731 var res2 = self.init_instance(mtype)
1732 self.add("{res} = {res2};")
1733 var length = self.int_instance(string.length)
1734 self.send(self.get_property("with_native", mtype), [res, nat, length])
1735 self.check_init_instance(res, mtype)
1736 self.add("{name} = {res};")
1737 self.add("\}")
1738 return res
1739 end
1740
1741 # Generate generic abort
1742 # used by aborts, asserts, casts, etc.
1743 fun add_abort(message: String)
1744 do
1745 if self.current_node != null and self.current_node.location.file != null then
1746 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});")
1747 else
1748 self.add("fprintf(stderr, \"Runtime error: %s\\n\", \"{message.escape_to_c}\");")
1749 end
1750 self.add("exit(1);")
1751 end
1752 end
1753
1754 # A frame correspond to a visited property in a GlobalCompilerVisitor
1755 class Frame
1756 # The associated visitor
1757
1758 var visitor: GlobalCompilerVisitor
1759
1760 # The executed property.
1761 # A Method in case of a call, an attribute in case of a default initialization.
1762 var mpropdef: MPropDef
1763
1764 # The static type of the receiver
1765 var receiver: MClassType
1766
1767 # Arguments of the method (the first is the receiver)
1768 var arguments: Array[RuntimeVariable]
1769
1770 # The runtime_variable associated to the return (in a function)
1771 var returnvar: nullable RuntimeVariable writable = null
1772
1773 # The label at the end of the property
1774 var returnlabel: nullable String writable = null
1775 end
1776
1777 redef class MPropDef
1778 private var c_name_cache: nullable String
1779
1780 # The mangled name associated to the property
1781 fun c_name: String
1782 do
1783 var res = self.c_name_cache
1784 if res != null then return res
1785 res = "{self.mclassdef.mmodule.name.to_cmangle}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
1786 self.c_name_cache = res
1787 return res
1788 end
1789 end
1790
1791 redef class MMethodDef
1792 # Can the body be inlined?
1793 fun can_inline(v: GlobalCompilerVisitor): Bool
1794 do
1795 var modelbuilder = v.compiler.modelbuilder
1796 if modelbuilder.mpropdef2npropdef.has_key(self) then
1797 var npropdef = modelbuilder.mpropdef2npropdef[self]
1798 return npropdef.can_inline
1799 else if self.mproperty.name == "init" then
1800 # Automatic free init is always inlined since it is empty or contains only attribtes assigments
1801 return true
1802 else
1803 abort
1804 end
1805 end
1806
1807 # Inline the body in another visitor
1808 fun compile_inside_to_c(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
1809 do
1810 var modelbuilder = v.compiler.modelbuilder
1811 if modelbuilder.mpropdef2npropdef.has_key(self) then
1812 var npropdef = modelbuilder.mpropdef2npropdef[self]
1813 var oldnode = v.current_node
1814 v.current_node = npropdef
1815 self.compile_parameter_check(v, arguments)
1816 npropdef.compile_to_c(v, self, arguments)
1817 v.current_node = oldnode
1818 else if self.mproperty.name == "init" then
1819 var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
1820 var oldnode = v.current_node
1821 v.current_node = nclassdef
1822 self.compile_parameter_check(v, arguments)
1823 nclassdef.compile_to_c(v, self, arguments)
1824 v.current_node = oldnode
1825 else
1826 abort
1827 end
1828 return null
1829 end
1830
1831 # Generate type checks in the C code to check covariant parameters
1832 fun compile_parameter_check(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable])
1833 do
1834 if v.compiler.modelbuilder.toolcontext.opt_no_check_covariance.value then return
1835
1836 for i in [0..msignature.arity[ do
1837 # skip test for vararg since the array is instantiated with the correct polymorphic type
1838 if msignature.vararg_rank == i then continue
1839
1840 # skip if the cast is not required
1841 var origmtype = self.mproperty.intro.msignature.mparameters[i].mtype
1842 if not origmtype.need_anchor then continue
1843
1844 # get the parameter type
1845 var mtype = self.msignature.mparameters[i].mtype
1846
1847 # generate the cast
1848 # note that v decides if and how to implements the cast
1849 v.add("/* Covariant cast for argument {i} ({self.msignature.mparameters[i].name}) {arguments[i+1].inspect} isa {mtype} */")
1850 var cond = v.type_test( arguments[i+1], mtype)
1851 v.add("if (!{cond}) \{")
1852 #var x = v.class_name_string(arguments[i+1])
1853 #var y = v.class_name_string(arguments.first)
1854 #v.add("fprintf(stderr, \"expected {mtype} (self is %s), got %s for {arguments[i+1].inspect}\\n\", {y}, {x});")
1855 v.add_abort("Cast failed")
1856 v.add("\}")
1857 end
1858 end
1859 end
1860
1861 redef class APropdef
1862 fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1863 do
1864 v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
1865 debug("Not yet implemented")
1866 end
1867
1868 fun can_inline: Bool do return true
1869 end
1870
1871 redef class AConcreteMethPropdef
1872 redef fun compile_to_c(v, mpropdef, arguments)
1873 do
1874 for i in [0..mpropdef.msignature.arity[ do
1875 var variable = self.n_signature.n_params[i].variable.as(not null)
1876 v.assign(v.variable(variable), arguments[i+1])
1877 end
1878 # Call the implicit super-init
1879 var auto_super_inits = self.auto_super_inits
1880 if auto_super_inits != null then
1881 var selfarg = [arguments.first]
1882 for auto_super_init in auto_super_inits do
1883 if auto_super_init.intro.msignature.arity == 0 then
1884 v.send(auto_super_init, selfarg)
1885 else
1886 v.send(auto_super_init, arguments)
1887 end
1888 end
1889 end
1890 v.stmt(self.n_block)
1891 end
1892
1893 redef fun can_inline
1894 do
1895 if self.auto_super_inits != null then return false
1896 var nblock = self.n_block
1897 if nblock == null then return true
1898 if (mpropdef.mproperty.name == "==" or mpropdef.mproperty.name == "!=") and mpropdef.mclassdef.mclass.name == "Object" then return true
1899 if nblock isa ABlockExpr and nblock.n_expr.length == 0 then return true
1900 return false
1901 end
1902 end
1903
1904 redef class AInternMethPropdef
1905 redef fun compile_to_c(v, mpropdef, arguments)
1906 do
1907 var pname = mpropdef.mproperty.name
1908 var cname = mpropdef.mclassdef.mclass.name
1909 var ret = mpropdef.msignature.return_mtype
1910 if ret != null then
1911 ret = v.resolve_for(ret, arguments.first)
1912 end
1913 if pname != "==" and pname != "!=" then
1914 v.adapt_signature(mpropdef, arguments)
1915 end
1916 if cname == "Int" then
1917 if pname == "output" then
1918 v.add("printf(\"%ld\\n\", {arguments.first});")
1919 return
1920 else if pname == "object_id" then
1921 v.ret(arguments.first)
1922 return
1923 else if pname == "+" then
1924 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1925 return
1926 else if pname == "-" then
1927 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1928 return
1929 else if pname == "unary -" then
1930 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1931 return
1932 else if pname == "succ" then
1933 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1934 return
1935 else if pname == "prec" then
1936 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1937 return
1938 else if pname == "*" then
1939 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1940 return
1941 else if pname == "/" then
1942 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1943 return
1944 else if pname == "%" then
1945 v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
1946 return
1947 else if pname == "lshift" then
1948 v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
1949 return
1950 else if pname == "rshift" then
1951 v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
1952 return
1953 else if pname == "==" then
1954 v.ret(v.equal_test(arguments[0], arguments[1]))
1955 return
1956 else if pname == "!=" then
1957 var res = v.equal_test(arguments[0], arguments[1])
1958 v.ret(v.new_expr("!{res}", ret.as(not null)))
1959 return
1960 else if pname == "<" then
1961 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1962 return
1963 else if pname == ">" then
1964 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1965 return
1966 else if pname == "<=" then
1967 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1968 return
1969 else if pname == ">=" then
1970 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1971 return
1972 else if pname == "to_f" then
1973 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1974 return
1975 else if pname == "ascii" then
1976 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1977 return
1978 end
1979 else if cname == "Char" then
1980 if pname == "output" then
1981 v.add("printf(\"%c\", {arguments.first});")
1982 return
1983 else if pname == "object_id" then
1984 v.ret(arguments.first)
1985 return
1986 else if pname == "+" then
1987 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1988 return
1989 else if pname == "-" then
1990 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1991 return
1992 else if pname == "==" then
1993 v.ret(v.equal_test(arguments[0], arguments[1]))
1994 return
1995 else if pname == "!=" then
1996 var res = v.equal_test(arguments[0], arguments[1])
1997 v.ret(v.new_expr("!{res}", ret.as(not null)))
1998 return
1999 else if pname == "succ" then
2000 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
2001 return
2002 else if pname == "prec" then
2003 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
2004 return
2005 else if pname == "<" then
2006 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
2007 return
2008 else if pname == ">" then
2009 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
2010 return
2011 else if pname == "<=" then
2012 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
2013 return
2014 else if pname == ">=" then
2015 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
2016 return
2017 else if pname == "to_i" then
2018 v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
2019 return
2020 else if pname == "ascii" then
2021 v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
2022 return
2023 end
2024 else if cname == "Bool" then
2025 if pname == "output" then
2026 v.add("printf({arguments.first}?\"true\\n\":\"false\\n\");")
2027 return
2028 else if pname == "object_id" then
2029 v.ret(arguments.first)
2030 return
2031 else if pname == "==" then
2032 v.ret(v.equal_test(arguments[0], arguments[1]))
2033 return
2034 else if pname == "!=" then
2035 var res = v.equal_test(arguments[0], arguments[1])
2036 v.ret(v.new_expr("!{res}", ret.as(not null)))
2037 return
2038 end
2039 else if cname == "Float" then
2040 if pname == "output" then
2041 v.add("printf(\"%f\\n\", {arguments.first});")
2042 return
2043 else if pname == "object_id" then
2044 v.ret(v.new_expr("(double){arguments.first}", ret.as(not null)))
2045 return
2046 else if pname == "+" then
2047 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
2048 return
2049 else if pname == "-" then
2050 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
2051 return
2052 else if pname == "unary -" then
2053 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
2054 return
2055 else if pname == "succ" then
2056 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
2057 return
2058 else if pname == "prec" then
2059 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
2060 return
2061 else if pname == "*" then
2062 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
2063 return
2064 else if pname == "/" then
2065 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
2066 return
2067 else if pname == "==" then
2068 v.ret(v.equal_test(arguments[0], arguments[1]))
2069 return
2070 else if pname == "!=" then
2071 var res = v.equal_test(arguments[0], arguments[1])
2072 v.ret(v.new_expr("!{res}", ret.as(not null)))
2073 return
2074 else if pname == "<" then
2075 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
2076 return
2077 else if pname == ">" then
2078 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
2079 return
2080 else if pname == "<=" then
2081 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
2082 return
2083 else if pname == ">=" then
2084 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
2085 return
2086 else if pname == "to_i" then
2087 v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
2088 return
2089 end
2090 else if cname == "Char" then
2091 if pname == "output" then
2092 v.add("printf(\"%c\", {arguments.first});")
2093 return
2094 else if pname == "object_id" then
2095 v.ret(arguments.first)
2096 return
2097 else if pname == "==" then
2098 v.ret(v.equal_test(arguments[0], arguments[1]))
2099 return
2100 else if pname == "!=" then
2101 var res = v.equal_test(arguments[0], arguments[1])
2102 v.ret(v.new_expr("!{res}", ret.as(not null)))
2103 return
2104 else if pname == "ascii" then
2105 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
2106 return
2107 end
2108 else if cname == "NativeString" then
2109 if pname == "[]" then
2110 v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
2111 return
2112 else if pname == "[]=" then
2113 v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
2114 return
2115 else if pname == "copy_to" then
2116 v.add("memcpy({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
2117 return
2118 else if pname == "atoi" then
2119 v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
2120 return
2121 end
2122 else if cname == "NativeArray" then
2123 v.native_array_def(pname, ret, arguments)
2124 return
2125 end
2126 if pname == "exit" then
2127 v.add("exit({arguments[1]});")
2128 return
2129 else if pname == "sys" then
2130 v.ret(v.new_expr("glob_sys", ret.as(not null)))
2131 return
2132 else if pname == "calloc_string" then
2133 v.ret(v.new_expr("(char*)GC_MALLOC({arguments[1]})", ret.as(not null)))
2134 return
2135 else if pname == "calloc_array" then
2136 v.calloc_array(ret.as(not null), arguments)
2137 return
2138 else if pname == "object_id" then
2139 v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
2140 return
2141 else if pname == "is_same_type" then
2142 v.ret(v.is_same_type_test(arguments[0], arguments[1]))
2143 return
2144 else if pname == "output_class_name" then
2145 var nat = v.class_name_string(arguments.first)
2146 v.add("printf(\"%s\\n\", {nat});")
2147 return
2148 else if pname == "native_class_name" then
2149 var nat = v.class_name_string(arguments.first)
2150 v.ret(v.new_expr("(char*){nat}", ret.as(not null)))
2151 return
2152 else if pname == "force_garbage_collection" then
2153 v.add("GC_gcollect();")
2154 return
2155 end
2156 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
2157 debug("Not implemented {mpropdef}")
2158 end
2159 end
2160
2161 redef class AExternMethPropdef
2162 redef fun compile_to_c(v, mpropdef, arguments)
2163 do
2164 var externname
2165 var nextern = self.n_extern
2166 if nextern == null then
2167 v.add("fprintf(stderr, \"NOT YET IMPLEMENTED nitni for {mpropdef} at {location.to_s}\\n\");")
2168 v.add("exit(1);")
2169 return
2170 end
2171 externname = nextern.text.substring(1, nextern.text.length-2)
2172 if location.file != null then
2173 var file = location.file.filename
2174 v.compiler.add_extern(file)
2175 end
2176 var res: nullable RuntimeVariable = null
2177 var ret = mpropdef.msignature.return_mtype
2178 if ret != null then
2179 ret = v.resolve_for(ret, arguments.first)
2180 res = v.new_var(ret)
2181 end
2182 v.adapt_signature(mpropdef, arguments)
2183
2184 if res == null then
2185 v.add("{externname}({arguments.join(", ")});")
2186 else
2187 v.add("{res} = {externname}({arguments.join(", ")});")
2188 v.ret(res)
2189 end
2190 end
2191 end
2192
2193 redef class AExternInitPropdef
2194 redef fun compile_to_c(v, mpropdef, arguments)
2195 do
2196 var externname
2197 var nextern = self.n_extern
2198 if nextern == null then
2199 debug("{mpropdef} need extern name")
2200 return
2201 end
2202 externname = nextern.text.substring(1, nextern.text.length-2)
2203 if location.file != null then
2204 var file = location.file.filename
2205 v.compiler.add_extern(file)
2206 end
2207 v.adapt_signature(mpropdef, arguments)
2208 var ret = arguments.first.mtype
2209 var res = v.new_var(ret)
2210
2211 arguments.shift
2212
2213 v.add("{res} = {externname}({arguments.join(", ")});")
2214 v.ret(res)
2215 end
2216 end
2217
2218 redef class AAttrPropdef
2219 redef fun compile_to_c(v, mpropdef, arguments)
2220 do
2221 if arguments.length == 1 then
2222 var res = v.read_attribute(self.mpropdef.mproperty, arguments.first)
2223 v.assign(v.frame.returnvar.as(not null), res)
2224 else
2225 v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
2226 end
2227 end
2228
2229 fun init_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
2230 do
2231 var nexpr = self.n_expr
2232 if nexpr != null then
2233 var oldnode = v.current_node
2234 v.current_node = self
2235 var old_frame = v.frame
2236 var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
2237 v.frame = frame
2238 var value = v.expr(nexpr, self.mpropdef.static_mtype)
2239 v.write_attribute(self.mpropdef.mproperty, recv, value)
2240 v.frame = old_frame
2241 v.current_node = oldnode
2242 end
2243 end
2244
2245 fun check_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
2246 do
2247 var nexpr = self.n_expr
2248 if nexpr != null then return
2249
2250 var oldnode = v.current_node
2251 v.current_node = self
2252 var old_frame = v.frame
2253 var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
2254 v.frame = frame
2255 # Force read to check the initialization
2256 v.read_attribute(self.mpropdef.mproperty, recv)
2257 v.frame = old_frame
2258 v.current_node = oldnode
2259 end
2260 end
2261
2262 redef class AClassdef
2263 private fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
2264 do
2265 if mpropdef == self.mfree_init then
2266 var super_inits = self.super_inits
2267 if super_inits != null then
2268 assert arguments.length == 1
2269 for su in super_inits do
2270 v.send(su, arguments)
2271 end
2272 return
2273 end
2274 var recv = arguments.first
2275 var i = 1
2276 # Collect undefined attributes
2277 for npropdef in self.n_propdefs do
2278 if npropdef isa AAttrPropdef and npropdef.n_expr == null then
2279 v.write_attribute(npropdef.mpropdef.mproperty, recv, arguments[i])
2280 i += 1
2281 end
2282 end
2283 else
2284 abort
2285 end
2286 end
2287 end
2288
2289 redef class ADeferredMethPropdef
2290 redef fun compile_to_c(v, mpropdef, arguments)
2291 do
2292 v.add_abort("Deferred method called")
2293 end
2294
2295 redef fun can_inline do return true
2296 end
2297
2298 redef class AExpr
2299 # Try to compile self as an expression
2300 # Do not call this method directly, use `v.expr' instead
2301 private fun expr(v: GlobalCompilerVisitor): nullable RuntimeVariable
2302 do
2303 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{location.to_s}\\n\");")
2304 var mtype = self.mtype
2305 if mtype == null then
2306 return null
2307 else
2308 var res = v.new_var(mtype)
2309 v.add("/* {res} = NOT YET {class_name} */")
2310 return res
2311 end
2312 end
2313
2314 # Try to compile self as a statement
2315 # Do not call this method directly, use `v.stmt' instead
2316 private fun stmt(v: GlobalCompilerVisitor)
2317 do
2318 var res = expr(v)
2319 if res != null then v.add("{res};")
2320 end
2321
2322 end
2323
2324 redef class ABlockExpr
2325 redef fun stmt(v)
2326 do
2327 for e in self.n_expr do
2328 v.stmt(e)
2329 end
2330 end
2331 end
2332
2333 redef class AVardeclExpr
2334 redef fun stmt(v)
2335 do
2336 var variable = self.variable.as(not null)
2337 var ne = self.n_expr
2338 if ne != null then
2339 var i = v.expr(ne, variable.declared_type)
2340 v.assign(v.variable(variable), i)
2341 end
2342 end
2343 end
2344
2345 redef class AVarExpr
2346 redef fun expr(v)
2347 do
2348 var res = v.variable(self.variable.as(not null))
2349 var mtype = self.mtype.as(not null)
2350 return v.autoadapt(res, mtype)
2351 end
2352 end
2353
2354 redef class AVarAssignExpr
2355 redef fun stmt(v)
2356 do
2357 var variable = self.variable.as(not null)
2358 var i = v.expr(self.n_value, variable.declared_type)
2359 v.assign(v.variable(variable), i)
2360 end
2361 end
2362
2363 redef class AVarReassignExpr
2364 redef fun stmt(v)
2365 do
2366 var variable = self.variable.as(not null)
2367 var vari = v.variable(variable)
2368 var value = v.expr(self.n_value, variable.declared_type)
2369 var res = v.compile_callsite(self.reassign_callsite.as(not null), [vari, value])
2370 assert res != null
2371 v.assign(v.variable(variable), res)
2372 end
2373 end
2374
2375 redef class ASelfExpr
2376 redef fun expr(v)
2377 do
2378 return v.frame.arguments.first
2379 end
2380 end
2381
2382 redef class AContinueExpr
2383 redef fun stmt(v)
2384 do
2385 v.add("goto CONTINUE_{v.escapemark_name(self.escapemark)};")
2386 end
2387 end
2388
2389 redef class ABreakExpr
2390 redef fun stmt(v)
2391 do
2392 v.add("goto BREAK_{v.escapemark_name(self.escapemark)};")
2393 end
2394 end
2395
2396 redef class AReturnExpr
2397 redef fun stmt(v)
2398 do
2399 var nexpr = self.n_expr
2400 if nexpr != null then
2401 var returnvar = v.frame.returnvar.as(not null)
2402 var i = v.expr(nexpr, returnvar.mtype)
2403 v.assign(returnvar, i)
2404 end
2405 v.add("goto {v.frame.returnlabel.as(not null)};")
2406 end
2407 end
2408
2409 redef class AAbortExpr
2410 redef fun stmt(v)
2411 do
2412 v.add_abort("Aborted")
2413 end
2414 end
2415
2416 redef class AIfExpr
2417 redef fun stmt(v)
2418 do
2419 var cond = v.expr_bool(self.n_expr)
2420 v.add("if ({cond})\{")
2421 v.stmt(self.n_then)
2422 v.add("\} else \{")
2423 v.stmt(self.n_else)
2424 v.add("\}")
2425 end
2426 end
2427
2428 redef class AIfexprExpr
2429 redef fun expr(v)
2430 do
2431 var res = v.new_var(self.mtype.as(not null))
2432 var cond = v.expr_bool(self.n_expr)
2433 v.add("if ({cond})\{")
2434 v.assign(res, v.expr(self.n_then, null))
2435 v.add("\} else \{")
2436 v.assign(res, v.expr(self.n_else, null))
2437 v.add("\}")
2438 return res
2439 end
2440 end
2441
2442 redef class ADoExpr
2443 redef fun stmt(v)
2444 do
2445 v.stmt(self.n_block)
2446 var escapemark = self.escapemark
2447 if escapemark != null then
2448 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2449 end
2450 end
2451 end
2452
2453 redef class AWhileExpr
2454 redef fun stmt(v)
2455 do
2456 v.add("for(;;) \{")
2457 var cond = v.expr_bool(self.n_expr)
2458 v.add("if (!{cond}) break;")
2459 v.stmt(self.n_block)
2460 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2461 v.add("\}")
2462 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2463 end
2464 end
2465
2466 redef class ALoopExpr
2467 redef fun stmt(v)
2468 do
2469 v.add("for(;;) \{")
2470 v.stmt(self.n_block)
2471 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2472 v.add("\}")
2473 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2474 end
2475 end
2476
2477 redef class AForExpr
2478 redef fun stmt(v)
2479 do
2480 var cl = v.expr(self.n_expr, null)
2481 var it_meth = self.method_iterator
2482 assert it_meth != null
2483 var it = v.send(it_meth, [cl])
2484 assert it != null
2485 v.add("for(;;) \{")
2486 var isok_meth = self.method_is_ok
2487 assert isok_meth != null
2488 var ok = v.send(isok_meth, [it])
2489 assert ok != null
2490 v.add("if(!{ok}) break;")
2491 if self.variables.length == 1 then
2492 var item_meth = self.method_item
2493 assert item_meth != null
2494 var i = v.send(item_meth, [it])
2495 assert i != null
2496 v.assign(v.variable(variables.first), i)
2497 else if self.variables.length == 2 then
2498 var key_meth = self.method_key
2499 assert key_meth != null
2500 var i = v.send(key_meth, [it])
2501 assert i != null
2502 v.assign(v.variable(variables[0]), i)
2503 var item_meth = self.method_item
2504 assert item_meth != null
2505 i = v.send(item_meth, [it])
2506 assert i != null
2507 v.assign(v.variable(variables[1]), i)
2508 else
2509 abort
2510 end
2511 v.stmt(self.n_block)
2512 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2513 var next_meth = self.method_next
2514 assert next_meth != null
2515 v.send(next_meth, [it])
2516 v.add("\}")
2517 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2518 end
2519 end
2520
2521 redef class AAssertExpr
2522 redef fun stmt(v)
2523 do
2524 if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return
2525
2526 var cond = v.expr_bool(self.n_expr)
2527 v.add("if (!{cond}) \{")
2528 v.stmt(self.n_else)
2529 var nid = self.n_id
2530 if nid != null then
2531 v.add_abort("Assert '{nid.text}' failed")
2532 else
2533 v.add_abort("Assert failed")
2534 end
2535 v.add("\}")
2536 end
2537 end
2538
2539 redef class AOrExpr
2540 redef fun expr(v)
2541 do
2542 var res = v.new_var(self.mtype.as(not null))
2543 var i1 = v.expr_bool(self.n_expr)
2544 v.add("if ({i1}) \{")
2545 v.add("{res} = 1;")
2546 v.add("\} else \{")
2547 var i2 = v.expr_bool(self.n_expr2)
2548 v.add("{res} = {i2};")
2549 v.add("\}")
2550 return res
2551 end
2552 end
2553
2554 redef class AAndExpr
2555 redef fun expr(v)
2556 do
2557 var res = v.new_var(self.mtype.as(not null))
2558 var i1 = v.expr_bool(self.n_expr)
2559 v.add("if (!{i1}) \{")
2560 v.add("{res} = 0;")
2561 v.add("\} else \{")
2562 var i2 = v.expr_bool(self.n_expr2)
2563 v.add("{res} = {i2};")
2564 v.add("\}")
2565 return res
2566 end
2567 end
2568
2569 redef class ANotExpr
2570 redef fun expr(v)
2571 do
2572 var cond = v.expr_bool(self.n_expr)
2573 return v.new_expr("!{cond}", self.mtype.as(not null))
2574 end
2575 end
2576
2577 redef class AOrElseExpr
2578 redef fun expr(v)
2579 do
2580 var res = v.new_var(self.mtype.as(not null))
2581 var i1 = v.expr(self.n_expr, null)
2582 v.add("if ({i1}!=NULL) \{")
2583 v.assign(res, i1)
2584 v.add("\} else \{")
2585 var i2 = v.expr(self.n_expr2, null)
2586 v.assign(res, i2)
2587 v.add("\}")
2588 return res
2589 end
2590 end
2591
2592 redef class AEeExpr
2593 redef fun expr(v)
2594 do
2595 var value1 = v.expr(self.n_expr, null)
2596 var value2 = v.expr(self.n_expr2, null)
2597 return v.equal_test(value1, value2)
2598 end
2599 end
2600
2601 redef class AIntExpr
2602 redef fun expr(v)
2603 do
2604 return v.new_expr("{self.n_number.text}", self.mtype.as(not null))
2605 end
2606 end
2607
2608 redef class AFloatExpr
2609 redef fun expr(v)
2610 do
2611 return v.new_expr("{self.n_float.text}", self.mtype.as(not null))
2612 end
2613 end
2614
2615 redef class ACharExpr
2616 redef fun expr(v)
2617 do
2618 return v.new_expr("{self.n_char.text}", self.mtype.as(not null))
2619 end
2620 end
2621
2622 redef class AArrayExpr
2623 redef fun expr(v)
2624 do
2625 var mtype = self.mtype.as(MClassType).arguments.first
2626 var array = new Array[RuntimeVariable]
2627 for nexpr in self.n_exprs.n_exprs do
2628 var i = v.expr(nexpr, mtype)
2629 array.add(i)
2630 end
2631 return v.array_instance(array, mtype)
2632 end
2633 end
2634
2635 redef class AStringFormExpr
2636 redef fun expr(v)
2637 do
2638 return v.string_instance(self.value.as(not null))
2639 end
2640 end
2641
2642 redef class ASuperstringExpr
2643 redef fun expr(v)
2644 do
2645 var array = new Array[RuntimeVariable]
2646 for ne in self.n_exprs do
2647 if ne isa AStringFormExpr and ne.value == "" then continue # skip empty sub-strings
2648 var i = v.expr(ne, null)
2649 array.add(i)
2650 end
2651 var a = v.array_instance(array, v.object_type)
2652 var res = v.send(v.get_property("to_s", a.mtype), [a])
2653 return res
2654 end
2655 end
2656
2657 redef class ACrangeExpr
2658 redef fun expr(v)
2659 do
2660 var i1 = v.expr(self.n_expr, null)
2661 var i2 = v.expr(self.n_expr2, null)
2662 var mtype = self.mtype.as(MClassType)
2663 var res = v.init_instance(mtype)
2664 var it = v.send(v.get_property("init", res.mtype), [res, i1, i2])
2665 v.check_init_instance(res, mtype)
2666 return res
2667 end
2668 end
2669
2670 redef class AOrangeExpr
2671 redef fun expr(v)
2672 do
2673 var i1 = v.expr(self.n_expr, null)
2674 var i2 = v.expr(self.n_expr2, null)
2675 var mtype = self.mtype.as(MClassType)
2676 var res = v.init_instance(mtype)
2677 var it = v.send(v.get_property("without_last", res.mtype), [res, i1, i2])
2678 v.check_init_instance(res, mtype)
2679 return res
2680 end
2681 end
2682
2683 redef class ATrueExpr
2684 redef fun expr(v)
2685 do
2686 return v.new_expr("1", self.mtype.as(not null))
2687 end
2688 end
2689
2690 redef class AFalseExpr
2691 redef fun expr(v)
2692 do
2693 return v.new_expr("0", self.mtype.as(not null))
2694 end
2695 end
2696
2697 redef class ANullExpr
2698 redef fun expr(v)
2699 do
2700 var res = v.new_expr("NULL", self.mtype.as(not null))
2701 return res
2702 end
2703 end
2704
2705 redef class AIsaExpr
2706 redef fun expr(v)
2707 do
2708 var i = v.expr(self.n_expr, null)
2709 return v.type_test(i, self.cast_type.as(not null))
2710 end
2711 end
2712
2713 redef class AAsCastExpr
2714 redef fun expr(v)
2715 do
2716 var i = v.expr(self.n_expr, null)
2717 if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
2718
2719 var cond = v.type_test(i, self.mtype.as(not null))
2720 v.add("if (!{cond}) \{")
2721 v.add_abort("Cast failed")
2722 v.add("\}")
2723 return i
2724 end
2725 end
2726
2727 redef class AAsNotnullExpr
2728 redef fun expr(v)
2729 do
2730 var i = v.expr(self.n_expr, null)
2731 if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
2732
2733 v.add("if ({i} == NULL) \{")
2734 v.add_abort("Cast failed")
2735 v.add("\}")
2736 return i
2737 end
2738 end
2739
2740 redef class AParExpr
2741 redef fun expr(v)
2742 do
2743 return v.expr(self.n_expr, null)
2744 end
2745 end
2746
2747 redef class AOnceExpr
2748 redef fun expr(v)
2749 do
2750 var mtype = self.mtype.as(not null)
2751 var name = v.get_name("varonce")
2752 var guard = v.get_name(name + "_guard")
2753 v.add_decl("static {mtype.ctype} {name};")
2754 v.add_decl("static int {guard};")
2755 var res = v.new_var(mtype)
2756 v.add("if ({guard}) \{")
2757 v.add("{res} = {name};")
2758 v.add("\} else \{")
2759 var i = v.expr(self.n_expr, mtype)
2760 v.add("{res} = {i};")
2761 v.add("{name} = {res};")
2762 v.add("{guard} = 1;")
2763 v.add("\}")
2764 return res
2765 end
2766 end
2767
2768 redef class ASendExpr
2769 redef fun expr(v)
2770 do
2771 var recv = v.expr(self.n_expr, null)
2772 var args = [recv]
2773 for a in self.raw_arguments.as(not null) do
2774 args.add(v.expr(a, null))
2775 end
2776 return v.compile_callsite(self.callsite.as(not null), args)
2777 end
2778 end
2779
2780 redef class ASendReassignFormExpr
2781 redef fun stmt(v)
2782 do
2783 var recv = v.expr(self.n_expr, null)
2784 var args = [recv]
2785 for a in self.raw_arguments.as(not null) do
2786 args.add(v.expr(a, null))
2787 end
2788 var value = v.expr(self.n_value, null)
2789
2790 var left = v.compile_callsite(self.callsite.as(not null), args)
2791 assert left != null
2792
2793 var res = v.compile_callsite(self.reassign_callsite.as(not null), [left, value])
2794 assert res != null
2795
2796 args.add(res)
2797 v.compile_callsite(self.write_callsite.as(not null), args)
2798 end
2799 end
2800
2801 redef class ASuperExpr
2802 redef fun expr(v)
2803 do
2804 var recv = v.frame.arguments.first
2805 var args = [recv]
2806 for a in self.n_args.n_exprs do
2807 args.add(v.expr(a, null))
2808 end
2809 if args.length == 1 then
2810 args = v.frame.arguments
2811 end
2812
2813 var mproperty = self.mproperty
2814 if mproperty != null then
2815 if mproperty.intro.msignature.arity == 0 then
2816 args = [recv]
2817 end
2818 # Super init call
2819 var res = v.send(mproperty, args)
2820 return res
2821 end
2822
2823 # stantard call-next-method
2824 var mpropdef = v.frame.mpropdef
2825 # FIXME: we do not want an ugly static call!
2826 var mpropdefs = mpropdef.mproperty.lookup_super_definitions(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
2827 if mpropdefs.length != 1 then
2828 v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
2829 debug("MPRODFEFS for super {mpropdef} for {recv}: {mpropdefs.join(", ")}")
2830 end
2831 mpropdef = mpropdefs.first
2832 assert mpropdef isa MMethodDef
2833 var res = v.call(mpropdef, recv.mtype.as(MClassType), args)
2834 return res
2835 end
2836 end
2837
2838 redef class ANewExpr
2839 redef fun expr(v)
2840 do
2841 var mtype = self.mtype.as(MClassType)
2842 var recv
2843 var ctype = mtype.ctype
2844 if ctype == "val*" then
2845 recv = v.init_instance(mtype)
2846 else if ctype == "void*" then
2847 recv = v.new_expr("NULL/*special!*/", mtype)
2848 else
2849 debug("cannot new {mtype}")
2850 abort
2851 end
2852 var args = [recv]
2853 for a in self.n_args.n_exprs do
2854 args.add(v.expr(a, null))
2855 end
2856 var res2 = v.compile_callsite(self.callsite.as(not null), args)
2857 if res2 != null then
2858 #self.debug("got {res2} from {mproperty}. drop {recv}")
2859 return res2
2860 end
2861 v.check_init_instance(recv, mtype)
2862 return recv
2863 end
2864 end
2865
2866 redef class AAttrExpr
2867 redef fun expr(v)
2868 do
2869 var recv = v.expr(self.n_expr, null)
2870 var mproperty = self.mproperty.as(not null)
2871 return v.read_attribute(mproperty, recv)
2872 end
2873 end
2874
2875 redef class AAttrAssignExpr
2876 redef fun stmt(v)
2877 do
2878 var recv = v.expr(self.n_expr, null)
2879 var i = v.expr(self.n_value, null)
2880 var mproperty = self.mproperty.as(not null)
2881 v.write_attribute(mproperty, recv, i)
2882 end
2883 end
2884
2885 redef class AAttrReassignExpr
2886 redef fun stmt(v)
2887 do
2888 var recv = v.expr(self.n_expr, null)
2889 var value = v.expr(self.n_value, null)
2890 var mproperty = self.mproperty.as(not null)
2891 var attr = v.read_attribute(mproperty, recv)
2892 var res = v.compile_callsite(self.reassign_callsite.as(not null), [attr, value])
2893 assert res != null
2894 v.write_attribute(mproperty, recv, res)
2895 end
2896 end
2897
2898 redef class AIssetAttrExpr
2899 redef fun expr(v)
2900 do
2901 var recv = v.expr(self.n_expr, null)
2902 var mproperty = self.mproperty.as(not null)
2903 return v.isset_attribute(mproperty, recv)
2904 end
2905 end
2906
2907 redef class ADebugTypeExpr
2908 redef fun stmt(v)
2909 do
2910 # do nothing
2911 end
2912 end