nitg-s: add cast to remove c warnings
[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
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 # Generate a polymorphic send for the method `m' and the arguments `args'
1199 fun send(m: MMethod, args: Array[RuntimeVariable]): nullable RuntimeVariable
1200 do
1201 var types = self.collect_types(args.first)
1202
1203 var res: nullable RuntimeVariable
1204 var ret = m.intro.msignature.return_mtype
1205 if m.is_new then
1206 ret = args.first.mtype
1207 res = self.new_var(ret)
1208 else if ret == null then
1209 res = null
1210 else
1211 ret = self.resolve_for(ret, args.first)
1212 res = self.new_var(ret)
1213 end
1214
1215 self.add("/* send {m} on {args.first.inspect} */")
1216 if args.first.mtype.ctype != "val*" then
1217 var mclasstype = args.first.mtype.as(MClassType)
1218 if not self.compiler.runtime_type_analysis.live_types.has(mclasstype) then
1219 self.add("/* skip, no method {m} */")
1220 return res
1221 end
1222 var propdefs = m.lookup_definitions(self.compiler.mainmodule, mclasstype)
1223 if propdefs.length == 0 then
1224 self.add("/* skip, no method {m} */")
1225 return res
1226 end
1227 assert propdefs.length == 1
1228 var propdef = propdefs.first
1229 var res2 = self.call(propdef, mclasstype, args)
1230 if res != null then self.assign(res, res2.as(not null))
1231 return res
1232 end
1233 var consider_null = not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value or m.name == "==" or m.name == "!="
1234 if args.first.mcasttype isa MNullableType or args.first.mcasttype isa MNullType and consider_null then
1235 # The reciever is potentially null, so we have to 3 cases: ==, != or NullPointerException
1236 self.add("if ({args.first} == NULL) \{ /* Special null case */")
1237 if m.name == "==" then
1238 assert res != null
1239 if args[1].mcasttype isa MNullableType then
1240 self.add("{res} = ({args[1]} == NULL);")
1241 else if args[1].mcasttype isa MNullType then
1242 self.add("{res} = 1; /* is null */")
1243 else
1244 self.add("{res} = 0; /* {args[1].inspect} cannot be null */")
1245 end
1246 else if m.name == "!=" then
1247 assert res != null
1248 if args[1].mcasttype isa MNullableType then
1249 self.add("{res} = ({args[1]} != NULL);")
1250 else if args[1].mcasttype isa MNullType then
1251 self.add("{res} = 0; /* is null */")
1252 else
1253 self.add("{res} = 1; /* {args[1].inspect} cannot be null */")
1254 end
1255 else
1256 self.add_abort("Reciever is null")
1257 end
1258 self.add "\} else"
1259 end
1260 if types.is_empty then
1261 self.add("\{")
1262 self.add("/*BUG: no live types for {args.first.inspect} . {m}*/")
1263 self.bugtype(args.first)
1264 self.add("\}")
1265 return res
1266 end
1267
1268 self.add("switch({args.first}->classid) \{")
1269 var last = types.last
1270 var defaultpropdef: nullable MMethodDef = null
1271 for t in types do
1272 var propdefs = m.lookup_definitions(self.compiler.mainmodule, t)
1273 if propdefs.length == 0 then
1274 self.add("/* skip {t}, no method {m} */")
1275 continue
1276 end
1277 if propdefs.length > 1 then
1278 self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first")
1279 end
1280 var propdef = propdefs.first
1281 if propdef.mclassdef.mclass.name == "Object" and t.ctype == "val*" then
1282 defaultpropdef = propdef
1283 continue
1284 end
1285 if not self.compiler.hardening and t == last and defaultpropdef == null then
1286 self.add("default: /* test {t} */")
1287 else
1288 self.add("case {self.compiler.classid(t)}: /* test {t} */")
1289 end
1290 var res2 = self.call(propdef, t, args)
1291 if res != null then self.assign(res, res2.as(not null))
1292 self.add "break;"
1293 end
1294 if defaultpropdef != null then
1295 self.add("default: /* default is Object */")
1296 var res2 = self.call(defaultpropdef, defaultpropdef.mclassdef.bound_mtype, args)
1297 if res != null then self.assign(res, res2.as(not null))
1298 else if self.compiler.hardening then
1299 self.add("default: /* bug */")
1300 self.bugtype(args.first)
1301 end
1302 self.add("\}")
1303 return res
1304 end
1305
1306 # Generate a monomorphic send for the method `m', the type `t' and the arguments `args'
1307 fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable
1308 do
1309 assert t isa MClassType
1310 var propdefs = m.lookup_definitions(self.compiler.mainmodule, t)
1311 if propdefs.length == 0 then
1312 abort
1313 end
1314 if propdefs.length > 1 then
1315 self.debug("NOT YET IMPLEMENTED conflict for {t}.{m}: {propdefs.join(" ")}. choose the first")
1316 end
1317 var propdef = propdefs.first
1318 return self.call(propdef, t, args)
1319 end
1320
1321 fun check_valid_reciever(recvtype: MClassType)
1322 do
1323 if self.compiler.runtime_type_analysis.live_types.has(recvtype) or recvtype.mclass.name == "Object" then return
1324 print "{recvtype} is not a live type"
1325 abort
1326 end
1327
1328 # Generate a static call on a method definition
1329 fun call(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
1330 do
1331 check_valid_reciever(recvtype)
1332 #debug("call {m} on {recvtype} on {args.first}:{args.first.mtype}")
1333 if m.mclassdef.mclass.name == "Object" and recvtype.ctype == "val*" then
1334 recvtype = m.mclassdef.bound_mtype
1335 end
1336 var recv = self.autobox(args.first, recvtype)
1337 recv = self.autoadapt(recv, recvtype)
1338
1339 args = args.to_a
1340 self.varargize(m.msignature.as(not null), args)
1341 if args.length != m.msignature.arity + 1 then # because of self
1342 add("printf(\"NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.\\n\"); exit(1);")
1343 debug("NOT YET IMPLEMENTED: Invalid arity for {m}. {args.length} arguments given.")
1344 return null
1345 end
1346
1347 args.first = recv
1348 var rm = new CustomizedRuntimeFunction(m, recvtype)
1349 return rm.call(self, args)
1350 end
1351
1352 fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
1353 do
1354 var recv = args.first
1355 for i in [0..m.msignature.arity[ do
1356 var t = m.msignature.mparameters[i].mtype
1357 if i == m.msignature.vararg_rank then
1358 t = args[i+1].mtype
1359 end
1360 t = self.resolve_for(t, recv)
1361 args[i+1] = self.autobox(args[i+1], t)
1362 end
1363 end
1364
1365 # Transform varargs, in raw arguments, into a single argument of type Array
1366 # Note: this method modify the given `args`
1367 # If there is no vararg, then `args` is not modified.
1368 fun varargize(msignature: MSignature, args: Array[RuntimeVariable])
1369 do
1370 var recv = args.first
1371 var vararg_rank = msignature.vararg_rank
1372 if vararg_rank >= 0 then
1373 assert args.length >= msignature.arity + 1 # because of self
1374 var rawargs = args
1375 args = new Array[RuntimeVariable]
1376
1377 args.add(rawargs.first) # recv
1378
1379 for i in [0..vararg_rank[ do
1380 args.add(rawargs[i+1])
1381 end
1382
1383 var vararg_lastrank = vararg_rank + rawargs.length-1-msignature.arity
1384 var vararg = new Array[RuntimeVariable]
1385 for i in [vararg_rank..vararg_lastrank] do
1386 vararg.add(rawargs[i+1])
1387 end
1388 # FIXME: its it to late to determine the vararg type, this should have been done during a previous analysis
1389 var elttype = msignature.mparameters[vararg_rank].mtype
1390 elttype = self.resolve_for(elttype, recv)
1391 args.add(self.array_instance(vararg, elttype))
1392
1393 for i in [vararg_lastrank+1..rawargs.length-1[ do
1394 args.add(rawargs[i+1])
1395 end
1396 rawargs.clear
1397 rawargs.add_all(args)
1398 end
1399 end
1400
1401 fun bugtype(recv: RuntimeVariable)
1402 do
1403 if recv.mtype.ctype != "val*" then return
1404 self.add("fprintf(stderr, \"BTD BUG: Dynamic type is %s, static type is %s\\n\", class_names[{recv}->classid], \"{recv.mcasttype}\");")
1405 self.add("exit(1);")
1406 end
1407
1408 # Generate a polymorphic attribute is_set test
1409 fun isset_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable
1410 do
1411 check_recv_notnull(recv)
1412
1413 var types = self.collect_types(recv)
1414
1415 var res = self.new_var(bool_type)
1416
1417 if types.is_empty then
1418 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1419 self.bugtype(recv)
1420 return res
1421 end
1422 self.add("/* isset {a} on {recv.inspect} */")
1423 self.add("switch({recv}->classid) \{")
1424 var last = types.last
1425 for t in types do
1426 if not self.compiler.hardening and t == last then
1427 self.add("default: /*{self.compiler.classid(t)}*/")
1428 else
1429 self.add("case {self.compiler.classid(t)}:")
1430 end
1431 var recv2 = self.autoadapt(recv, t)
1432 var ta = a.intro.static_mtype.as(not null)
1433 ta = self.resolve_for(ta, recv2)
1434 var attr = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
1435 if not ta isa MNullableType then
1436 if ta.ctype == "val*" then
1437 self.add("{res} = ({attr} != NULL);")
1438 else
1439 self.add("{res} = 1; /*NOTYET isset on primitive attributes*/")
1440 end
1441 end
1442 self.add("break;")
1443 end
1444 if self.compiler.hardening then
1445 self.add("default: /* Bug */")
1446 self.bugtype(recv)
1447 end
1448 self.add("\}")
1449
1450 return res
1451 end
1452
1453 # Generate a polymorphic attribute read
1454 fun read_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable
1455 do
1456 check_recv_notnull(recv)
1457
1458 var types = self.collect_types(recv)
1459
1460 var ret = a.intro.static_mtype.as(not null)
1461 ret = self.resolve_for(ret, recv)
1462 var res = self.new_var(ret)
1463
1464 if types.is_empty then
1465 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1466 self.bugtype(recv)
1467 return res
1468 end
1469 self.add("/* read {a} on {recv.inspect} */")
1470 self.add("switch({recv}->classid) \{")
1471 var last = types.last
1472 for t in types do
1473 if not self.compiler.hardening and t == last then
1474 self.add("default: /*{self.compiler.classid(t)}*/")
1475 else
1476 self.add("case {self.compiler.classid(t)}:")
1477 end
1478 var recv2 = self.autoadapt(recv, t)
1479 var ta = a.intro.static_mtype.as(not null)
1480 ta = self.resolve_for(ta, recv2)
1481 var res2 = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
1482 if not ta isa MNullableType and not self.compiler.modelbuilder.toolcontext.opt_no_check_other.value then
1483 if ta.ctype == "val*" then
1484 self.add("if ({res2} == NULL) \{")
1485 self.add_abort("Uninitialized attribute {a.name}")
1486 self.add("\}")
1487 else
1488 self.add("/*NOTYET isset on primitive attributes*/")
1489 end
1490 end
1491 self.assign(res, res2)
1492 self.add("break;")
1493 end
1494 if self.compiler.hardening then
1495 self.add("default: /* Bug */")
1496 self.bugtype(recv)
1497 end
1498 self.add("\}")
1499
1500 return res
1501 end
1502
1503 # Generate a polymorphic attribute write
1504 fun write_attribute(a: MAttribute, recv: RuntimeVariable, value: RuntimeVariable)
1505 do
1506 check_recv_notnull(recv)
1507
1508 var types = self.collect_types(recv)
1509
1510 if types.is_empty then
1511 self.add("/*BUG: no live types for {recv.inspect} . {a}*/")
1512 self.bugtype(recv)
1513 return
1514 end
1515 self.add("/* write {a} on {recv.inspect} */")
1516 self.add("switch({recv}->classid) \{")
1517 var last = types.last
1518 for t in types do
1519 if not self.compiler.hardening and t == last then
1520 self.add("default: /*{self.compiler.classid(t)}*/")
1521 else
1522 self.add("case {self.compiler.classid(t)}:")
1523 end
1524 var recv2 = self.autoadapt(recv, t)
1525 var ta = a.intro.static_mtype.as(not null)
1526 ta = self.resolve_for(ta, recv2)
1527 self.add("((struct {t.c_name}*){recv})->{a.intro.c_name} = {self.autobox(value, ta)};")
1528 self.add("break;")
1529 end
1530 if self.compiler.hardening then
1531 self.add("default: /* Bug*/")
1532 self.bugtype(recv)
1533 end
1534 self.add("\}")
1535 end
1536
1537 # Generate a alloc-instance + init-attributes
1538 fun init_instance(mtype: MClassType): RuntimeVariable
1539 do
1540 mtype = self.anchor(mtype).as(MClassType)
1541 if not self.compiler.runtime_type_analysis.live_types.has(mtype) then
1542 debug "problem: {mtype} was detected dead"
1543 end
1544 var res = self.new_expr("NEW_{mtype.c_name}()", mtype)
1545 res.is_exact = true
1546 return res
1547 end
1548
1549 # Generate a polymorphic subtype test
1550 fun type_test(value: RuntimeVariable, mtype: MType): RuntimeVariable
1551 do
1552 mtype = self.anchor(mtype)
1553 var mclasstype = mtype
1554 if mtype isa MNullableType then mclasstype = mtype.mtype
1555 assert mclasstype isa MClassType
1556 if not self.compiler.runtime_type_analysis.live_cast_types.has(mclasstype) then
1557 debug "problem: {mtype} was detected cast-dead"
1558 abort
1559 end
1560
1561 var types = self.collect_types(value)
1562
1563 var res = self.new_var(bool_type)
1564
1565 self.add("/* isa {mtype} on {value.inspect} */")
1566 if value.mtype.ctype != "val*" then
1567 if value.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
1568 self.add("{res} = 1;")
1569 else
1570 self.add("{res} = 0;")
1571 end
1572 return res
1573 end
1574 if value.mcasttype isa MNullableType or value.mcasttype isa MNullType then
1575 self.add("if ({value} == NULL) \{")
1576 if mtype isa MNullableType then
1577 self.add("{res} = 1; /* isa {mtype} */")
1578 else
1579 self.add("{res} = 0; /* not isa {mtype} */")
1580 end
1581 self.add("\} else ")
1582 end
1583 self.add("switch({value}->classid) \{")
1584 for t in types do
1585 if t.is_subtype(self.compiler.mainmodule, null, mtype) then
1586 self.add("case {self.compiler.classid(t)}: /* {t} */")
1587 end
1588 end
1589 self.add("{res} = 1;")
1590 self.add("break;")
1591 self.add("default:")
1592 self.add("{res} = 0;")
1593 self.add("\}")
1594
1595 return res
1596 end
1597
1598 # Generate the code required to dynamically check if 2 objects share the same runtime type
1599 fun is_same_type_test(value1, value2: RuntimeVariable): RuntimeVariable
1600 do
1601 var res = self.new_var(bool_type)
1602 if value2.mtype.ctype == "val*" then
1603 if value1.mtype.ctype == "val*" then
1604 self.add "{res} = {value1}->classid == {value2}->classid;"
1605 else
1606 self.add "{res} = {self.compiler.classid(value1.mtype.as(MClassType))} == {value2}->classid;"
1607 end
1608 else
1609 if value1.mtype.ctype == "val*" then
1610 self.add "{res} = {value1}->classid == {self.compiler.classid(value2.mtype.as(MClassType))};"
1611 else if value1.mcasttype == value2.mcasttype then
1612 self.add "{res} = 1;"
1613 else
1614 self.add "{res} = 0;"
1615 end
1616 end
1617 return res
1618 end
1619
1620 # Return a "const char*" variable associated to the classname of the dynamic type of an object
1621 # NOTE: we do not return a RuntimeVariable "NativeString" as the class may not exist in the module/program
1622 fun class_name_string(value: RuntimeVariable): String
1623 do
1624 var res = self.get_name("var_class_name")
1625 self.add_decl("const char* {res};")
1626 if value.mtype.ctype == "val*" then
1627 self.add "{res} = class_names[{value}->classid];"
1628 else
1629 self.add "{res} = class_names[{self.compiler.classid(value.mtype.as(MClassType))}];"
1630 end
1631 return res
1632 end
1633
1634 # Generate a Nit "is" for two runtime_variables
1635 fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable
1636 do
1637 var res = self.new_var(bool_type)
1638 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1639 var tmp = value1
1640 value1 = value2
1641 value2 = tmp
1642 end
1643 if value1.mtype.ctype != "val*" then
1644 if value2.mtype == value1.mtype then
1645 self.add("{res} = {value1} == {value2};")
1646 else if value2.mtype.ctype != "val*" then
1647 self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
1648 else
1649 var mtype1 = value1.mtype.as(MClassType)
1650 self.add("{res} = ({value2} != NULL) && ({value2}->classid == {self.compiler.classid(mtype1)});")
1651 self.add("if ({res}) \{")
1652 self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
1653 self.add("\}")
1654 end
1655 else
1656 var s = new Array[String]
1657 for t in self.compiler.live_primitive_types do
1658 if not t.is_subtype(self.compiler.mainmodule, null, value1.mcasttype) then continue
1659 if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
1660 s.add "({value1}->classid == {self.compiler.classid(t)} && ((struct {t.c_name}*){value1})->value == ((struct {t.c_name}*){value2})->value)"
1661 end
1662 if s.is_empty then
1663 self.add("{res} = {value1} == {value2};")
1664 else
1665 self.add("{res} = {value1} == {value2} || ({value1} != NULL && {value2} != NULL && {value1}->classid == {value2}->classid && ({s.join(" || ")}));")
1666 end
1667 end
1668 return res
1669 end
1670
1671 # Generate a check-init-instance
1672 fun check_init_instance(recv: RuntimeVariable, mtype: MClassType)
1673 do
1674 if self.compiler.modelbuilder.toolcontext.opt_no_check_initialization.value then return
1675
1676 mtype = self.anchor(mtype).as(MClassType)
1677 if not self.compiler.runtime_type_analysis.live_types.has(mtype) then
1678 debug "problem: {mtype} was detected dead"
1679 end
1680
1681 self.add("CHECK_NEW_{mtype.c_name}({recv});")
1682 end
1683
1684 # Generate an integer value
1685 fun int_instance(value: Int): RuntimeVariable
1686 do
1687 var res = self.new_var(self.get_class("Int").mclass_type)
1688 self.add("{res} = {value};")
1689 return res
1690 end
1691
1692 # Generate an array value
1693 fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable
1694 do
1695 elttype = self.anchor(elttype)
1696 var arraytype = self.get_class("Array").get_mtype([elttype])
1697 var res = self.init_instance(arraytype)
1698 self.add("\{ /* {res} = array_instance Array[{elttype}] */")
1699 var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
1700 nat.is_exact = true
1701 self.add("{nat} = NEW_{nat.mtype.c_name}({array.length});")
1702 for i in [0..array.length[ do
1703 var r = self.autobox(array[i], elttype)
1704 self.add("((struct {nat.mtype.c_name}*) {nat})->values[{i}] = {r};")
1705 end
1706 var length = self.int_instance(array.length)
1707 self.send(self.get_property("with_native", arraytype), [res, nat, length])
1708 self.check_init_instance(res, arraytype)
1709 self.add("\}")
1710 return res
1711 end
1712
1713 # Generate a string value
1714 fun string_instance(string: String): RuntimeVariable
1715 do
1716 var mtype = self.get_class("String").mclass_type
1717 var name = self.get_name("varonce")
1718 self.add_decl("static {mtype.ctype} {name};")
1719 var res = self.new_var(mtype)
1720 self.add("if ({name}) \{")
1721 self.add("{res} = {name};")
1722 self.add("\} else \{")
1723 var nat = self.new_var(self.get_class("NativeString").mclass_type)
1724 self.add("{nat} = \"{string.escape_to_c}\";")
1725 var res2 = self.init_instance(mtype)
1726 self.add("{res} = {res2};")
1727 var length = self.int_instance(string.length)
1728 self.send(self.get_property("with_native", mtype), [res, nat, length])
1729 self.check_init_instance(res, mtype)
1730 self.add("{name} = {res};")
1731 self.add("\}")
1732 return res
1733 end
1734
1735 # Generate generic abort
1736 # used by aborts, asserts, casts, etc.
1737 fun add_abort(message: String)
1738 do
1739 if self.current_node != null and self.current_node.location.file != null then
1740 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});")
1741 else
1742 self.add("fprintf(stderr, \"Runtime error: %s\\n\", \"{message.escape_to_c}\");")
1743 end
1744 self.add("exit(1);")
1745 end
1746 end
1747
1748 # A frame correspond to a visited property in a GlobalCompilerVisitor
1749 class Frame
1750 # The associated visitor
1751
1752 var visitor: GlobalCompilerVisitor
1753
1754 # The executed property.
1755 # A Method in case of a call, an attribute in case of a default initialization.
1756 var mpropdef: MPropDef
1757
1758 # The static type of the receiver
1759 var receiver: MClassType
1760
1761 # Arguments of the method (the first is the receiver)
1762 var arguments: Array[RuntimeVariable]
1763
1764 # The runtime_variable associated to the return (in a function)
1765 var returnvar: nullable RuntimeVariable writable = null
1766
1767 # The label at the end of the property
1768 var returnlabel: nullable String writable = null
1769 end
1770
1771 redef class MPropDef
1772 private var c_name_cache: nullable String
1773
1774 # The mangled name associated to the property
1775 fun c_name: String
1776 do
1777 var res = self.c_name_cache
1778 if res != null then return res
1779 res = "{self.mclassdef.mmodule.name.to_cmangle}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
1780 self.c_name_cache = res
1781 return res
1782 end
1783 end
1784
1785 redef class MMethodDef
1786 # Can the body be inlined?
1787 fun can_inline(v: GlobalCompilerVisitor): Bool
1788 do
1789 var modelbuilder = v.compiler.modelbuilder
1790 if modelbuilder.mpropdef2npropdef.has_key(self) then
1791 var npropdef = modelbuilder.mpropdef2npropdef[self]
1792 return npropdef.can_inline
1793 else if self.mproperty.name == "init" then
1794 # Automatic free init is always inlined since it is empty or contains only attribtes assigments
1795 return true
1796 else
1797 abort
1798 end
1799 end
1800
1801 # Inline the body in another visitor
1802 fun compile_inside_to_c(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
1803 do
1804 var modelbuilder = v.compiler.modelbuilder
1805 if modelbuilder.mpropdef2npropdef.has_key(self) then
1806 var npropdef = modelbuilder.mpropdef2npropdef[self]
1807 var oldnode = v.current_node
1808 v.current_node = npropdef
1809 self.compile_parameter_check(v, arguments)
1810 npropdef.compile_to_c(v, self, arguments)
1811 v.current_node = oldnode
1812 else if self.mproperty.name == "init" then
1813 var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
1814 var oldnode = v.current_node
1815 v.current_node = nclassdef
1816 self.compile_parameter_check(v, arguments)
1817 nclassdef.compile_to_c(v, self, arguments)
1818 v.current_node = oldnode
1819 else
1820 abort
1821 end
1822 return null
1823 end
1824
1825 # Generate type checks in the C code to check covariant parameters
1826 fun compile_parameter_check(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable])
1827 do
1828 if v.compiler.modelbuilder.toolcontext.opt_no_check_covariance.value then return
1829
1830 for i in [0..msignature.arity[ do
1831 # skip test for vararg since the array is instantiated with the correct polymorphic type
1832 if msignature.vararg_rank == i then continue
1833
1834 # skip if the cast is not required
1835 var origmtype = self.mproperty.intro.msignature.mparameters[i].mtype
1836 if not origmtype.need_anchor then continue
1837
1838 # get the parameter type
1839 var mtype = self.msignature.mparameters[i].mtype
1840
1841 # generate the cast
1842 # note that v decides if and how to implements the cast
1843 v.add("/* Covariant cast for argument {i} ({self.msignature.mparameters[i].name}) {arguments[i+1].inspect} isa {mtype} */")
1844 var cond = v.type_test( arguments[i+1], mtype)
1845 v.add("if (!{cond}) \{")
1846 #var x = v.class_name_string(arguments[i+1])
1847 #var y = v.class_name_string(arguments.first)
1848 #v.add("fprintf(stderr, \"expected {mtype} (self is %s), got %s for {arguments[i+1].inspect}\\n\", {y}, {x});")
1849 v.add_abort("Cast failed")
1850 v.add("\}")
1851 end
1852 end
1853 end
1854
1855 redef class APropdef
1856 fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1857 do
1858 v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
1859 debug("Not yet implemented")
1860 end
1861
1862 fun can_inline: Bool do return true
1863 end
1864
1865 redef class AConcreteMethPropdef
1866 redef fun compile_to_c(v, mpropdef, arguments)
1867 do
1868 for i in [0..mpropdef.msignature.arity[ do
1869 var variable = self.n_signature.n_params[i].variable.as(not null)
1870 v.assign(v.variable(variable), arguments[i+1])
1871 end
1872 # Call the implicit super-init
1873 var auto_super_inits = self.auto_super_inits
1874 if auto_super_inits != null then
1875 var selfarg = [arguments.first]
1876 for auto_super_init in auto_super_inits do
1877 if auto_super_init.intro.msignature.arity == 0 then
1878 v.send(auto_super_init, selfarg)
1879 else
1880 v.send(auto_super_init, arguments)
1881 end
1882 end
1883 end
1884 v.stmt(self.n_block)
1885 end
1886
1887 redef fun can_inline
1888 do
1889 if self.auto_super_inits != null then return false
1890 var nblock = self.n_block
1891 if nblock == null then return true
1892 if (mpropdef.mproperty.name == "==" or mpropdef.mproperty.name == "!=") and mpropdef.mclassdef.mclass.name == "Object" then return true
1893 if nblock isa ABlockExpr and nblock.n_expr.length == 0 then return true
1894 return false
1895 end
1896 end
1897
1898 redef class AInternMethPropdef
1899 redef fun compile_to_c(v, mpropdef, arguments)
1900 do
1901 var pname = mpropdef.mproperty.name
1902 var cname = mpropdef.mclassdef.mclass.name
1903 var ret = mpropdef.msignature.return_mtype
1904 if ret != null then
1905 ret = v.resolve_for(ret, arguments.first)
1906 end
1907 if pname != "==" and pname != "!=" then
1908 v.adapt_signature(mpropdef, arguments)
1909 end
1910 if cname == "Int" then
1911 if pname == "output" then
1912 v.add("printf(\"%ld\\n\", {arguments.first});")
1913 return
1914 else if pname == "object_id" then
1915 v.ret(arguments.first)
1916 return
1917 else if pname == "+" then
1918 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1919 return
1920 else if pname == "-" then
1921 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1922 return
1923 else if pname == "unary -" then
1924 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1925 return
1926 else if pname == "succ" then
1927 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1928 return
1929 else if pname == "prec" then
1930 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1931 return
1932 else if pname == "*" then
1933 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1934 return
1935 else if pname == "/" then
1936 v.ret(v.new_expr("{arguments[0]} / {arguments[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 == "lshift" then
1942 v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
1943 return
1944 else if pname == "rshift" then
1945 v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
1946 return
1947 else if pname == "==" then
1948 v.ret(v.equal_test(arguments[0], arguments[1]))
1949 return
1950 else if pname == "!=" then
1951 var res = v.equal_test(arguments[0], arguments[1])
1952 v.ret(v.new_expr("!{res}", ret.as(not null)))
1953 return
1954 else if pname == "<" then
1955 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1956 return
1957 else if pname == ">" then
1958 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", 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 == "to_f" then
1967 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1968 return
1969 else if pname == "ascii" then
1970 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1971 return
1972 end
1973 else if cname == "Char" then
1974 if pname == "output" then
1975 v.add("printf(\"%c\", {arguments.first});")
1976 return
1977 else if pname == "object_id" then
1978 v.ret(arguments.first)
1979 return
1980 else if pname == "+" then
1981 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1982 return
1983 else if pname == "-" then
1984 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1985 return
1986 else if pname == "==" then
1987 v.ret(v.equal_test(arguments[0], arguments[1]))
1988 return
1989 else if pname == "!=" then
1990 var res = v.equal_test(arguments[0], arguments[1])
1991 v.ret(v.new_expr("!{res}", ret.as(not null)))
1992 return
1993 else if pname == "succ" then
1994 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1995 return
1996 else if pname == "prec" then
1997 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1998 return
1999 else if pname == "<" then
2000 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
2001 return
2002 else if pname == ">" then
2003 v.ret(v.new_expr("{arguments[0]} > {arguments[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 == "to_i" then
2012 v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
2013 return
2014 else if pname == "ascii" then
2015 v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
2016 return
2017 end
2018 else if cname == "Bool" then
2019 if pname == "output" then
2020 v.add("printf({arguments.first}?\"true\\n\":\"false\\n\");")
2021 return
2022 else if pname == "object_id" then
2023 v.ret(arguments.first)
2024 return
2025 else if pname == "==" then
2026 v.ret(v.equal_test(arguments[0], arguments[1]))
2027 return
2028 else if pname == "!=" then
2029 var res = v.equal_test(arguments[0], arguments[1])
2030 v.ret(v.new_expr("!{res}", ret.as(not null)))
2031 return
2032 end
2033 else if cname == "Float" then
2034 if pname == "output" then
2035 v.add("printf(\"%f\\n\", {arguments.first});")
2036 return
2037 else if pname == "object_id" then
2038 v.ret(v.new_expr("(double){arguments.first}", ret.as(not null)))
2039 return
2040 else if pname == "+" then
2041 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
2042 return
2043 else if pname == "-" then
2044 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
2045 return
2046 else if pname == "unary -" then
2047 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
2048 return
2049 else if pname == "succ" then
2050 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
2051 return
2052 else if pname == "prec" then
2053 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
2054 return
2055 else if pname == "*" then
2056 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
2057 return
2058 else if pname == "/" then
2059 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
2060 return
2061 else if pname == "==" then
2062 v.ret(v.equal_test(arguments[0], arguments[1]))
2063 return
2064 else if pname == "!=" then
2065 var res = v.equal_test(arguments[0], arguments[1])
2066 v.ret(v.new_expr("!{res}", ret.as(not null)))
2067 return
2068 else if pname == "<" then
2069 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
2070 return
2071 else if pname == ">" then
2072 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", 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 == "to_i" then
2081 v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
2082 return
2083 end
2084 else if cname == "Char" then
2085 if pname == "output" then
2086 v.add("printf(\"%c\", {arguments.first});")
2087 return
2088 else if pname == "object_id" then
2089 v.ret(arguments.first)
2090 return
2091 else if pname == "==" then
2092 v.ret(v.equal_test(arguments[0], arguments[1]))
2093 return
2094 else if pname == "!=" then
2095 var res = v.equal_test(arguments[0], arguments[1])
2096 v.ret(v.new_expr("!{res}", ret.as(not null)))
2097 return
2098 else if pname == "ascii" then
2099 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
2100 return
2101 end
2102 else if cname == "NativeString" then
2103 if pname == "[]" then
2104 v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
2105 return
2106 else if pname == "[]=" then
2107 v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
2108 return
2109 else if pname == "copy_to" then
2110 v.add("memcpy({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
2111 return
2112 else if pname == "atoi" then
2113 v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
2114 return
2115 end
2116 else if cname == "NativeArray" then
2117 v.native_array_def(pname, ret, arguments)
2118 return
2119 end
2120 if pname == "exit" then
2121 v.add("exit({arguments[1]});")
2122 return
2123 else if pname == "sys" then
2124 v.ret(v.new_expr("glob_sys", ret.as(not null)))
2125 return
2126 else if pname == "calloc_string" then
2127 v.ret(v.new_expr("(char*)GC_MALLOC({arguments[1]})", ret.as(not null)))
2128 return
2129 else if pname == "calloc_array" then
2130 v.calloc_array(ret.as(not null), arguments)
2131 return
2132 else if pname == "object_id" then
2133 v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
2134 return
2135 else if pname == "is_same_type" then
2136 v.ret(v.is_same_type_test(arguments[0], arguments[1]))
2137 return
2138 else if pname == "output_class_name" then
2139 var nat = v.class_name_string(arguments.first)
2140 v.add("printf(\"%s\\n\", {nat});")
2141 return
2142 else if pname == "native_class_name" then
2143 var nat = v.class_name_string(arguments.first)
2144 v.ret(v.new_expr("(char*){nat}", ret.as(not null)))
2145 return
2146 else if pname == "force_garbage_collection" then
2147 v.add("GC_gcollect();")
2148 return
2149 end
2150 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");")
2151 debug("Not implemented {mpropdef}")
2152 end
2153 end
2154
2155 redef class AExternMethPropdef
2156 redef fun compile_to_c(v, mpropdef, arguments)
2157 do
2158 var externname
2159 var nextern = self.n_extern
2160 if nextern == null then
2161 v.add("fprintf(stderr, \"NOT YET IMPLEMENTED nitni for {mpropdef} at {location.to_s}\\n\");")
2162 v.add("exit(1);")
2163 return
2164 end
2165 externname = nextern.text.substring(1, nextern.text.length-2)
2166 if location.file != null then
2167 var file = location.file.filename
2168 v.compiler.add_extern(file)
2169 end
2170 var res: nullable RuntimeVariable = null
2171 var ret = mpropdef.msignature.return_mtype
2172 if ret != null then
2173 ret = v.resolve_for(ret, arguments.first)
2174 res = v.new_var(ret)
2175 end
2176 v.adapt_signature(mpropdef, arguments)
2177
2178 if res == null then
2179 v.add("{externname}({arguments.join(", ")});")
2180 else
2181 v.add("{res} = {externname}({arguments.join(", ")});")
2182 v.ret(res)
2183 end
2184 end
2185 end
2186
2187 redef class AExternInitPropdef
2188 redef fun compile_to_c(v, mpropdef, arguments)
2189 do
2190 var externname
2191 var nextern = self.n_extern
2192 if nextern == null then
2193 debug("{mpropdef} need extern name")
2194 return
2195 end
2196 externname = nextern.text.substring(1, nextern.text.length-2)
2197 if location.file != null then
2198 var file = location.file.filename
2199 v.compiler.add_extern(file)
2200 end
2201 v.adapt_signature(mpropdef, arguments)
2202 var ret = arguments.first.mtype
2203 var res = v.new_var(ret)
2204
2205 arguments.shift
2206
2207 v.add("{res} = {externname}({arguments.join(", ")});")
2208 v.ret(res)
2209 end
2210 end
2211
2212 redef class AAttrPropdef
2213 redef fun compile_to_c(v, mpropdef, arguments)
2214 do
2215 if arguments.length == 1 then
2216 var res = v.read_attribute(self.mpropdef.mproperty, arguments.first)
2217 v.assign(v.frame.returnvar.as(not null), res)
2218 else
2219 v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
2220 end
2221 end
2222
2223 fun init_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
2224 do
2225 var nexpr = self.n_expr
2226 if nexpr != null then
2227 var oldnode = v.current_node
2228 v.current_node = self
2229 var old_frame = v.frame
2230 var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
2231 v.frame = frame
2232 var value = v.expr(nexpr, self.mpropdef.static_mtype)
2233 v.write_attribute(self.mpropdef.mproperty, recv, value)
2234 v.frame = old_frame
2235 v.current_node = oldnode
2236 end
2237 end
2238
2239 fun check_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
2240 do
2241 var nexpr = self.n_expr
2242 if nexpr != null then return
2243
2244 var oldnode = v.current_node
2245 v.current_node = self
2246 var old_frame = v.frame
2247 var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
2248 v.frame = frame
2249 # Force read to check the initialization
2250 v.read_attribute(self.mpropdef.mproperty, recv)
2251 v.frame = old_frame
2252 v.current_node = oldnode
2253 end
2254 end
2255
2256 redef class AClassdef
2257 private fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
2258 do
2259 if mpropdef == self.mfree_init then
2260 var super_inits = self.super_inits
2261 if super_inits != null then
2262 assert arguments.length == 1
2263 for su in super_inits do
2264 v.send(su, arguments)
2265 end
2266 return
2267 end
2268 var recv = arguments.first
2269 var i = 1
2270 # Collect undefined attributes
2271 for npropdef in self.n_propdefs do
2272 if npropdef isa AAttrPropdef and npropdef.n_expr == null then
2273 v.write_attribute(npropdef.mpropdef.mproperty, recv, arguments[i])
2274 i += 1
2275 end
2276 end
2277 else
2278 abort
2279 end
2280 end
2281 end
2282
2283 redef class ADeferredMethPropdef
2284 redef fun compile_to_c(v, mpropdef, arguments)
2285 do
2286 v.add_abort("Deferred method called")
2287 end
2288
2289 redef fun can_inline do return true
2290 end
2291
2292 redef class AExpr
2293 # Try to compile self as an expression
2294 # Do not call this method directly, use `v.expr' instead
2295 private fun expr(v: GlobalCompilerVisitor): nullable RuntimeVariable
2296 do
2297 v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{location.to_s}\\n\");")
2298 var mtype = self.mtype
2299 if mtype == null then
2300 return null
2301 else
2302 var res = v.new_var(mtype)
2303 v.add("/* {res} = NOT YET {class_name} */")
2304 return res
2305 end
2306 end
2307
2308 # Try to compile self as a statement
2309 # Do not call this method directly, use `v.stmt' instead
2310 private fun stmt(v: GlobalCompilerVisitor)
2311 do
2312 var res = expr(v)
2313 if res != null then v.add("{res};")
2314 end
2315
2316 end
2317
2318 redef class ABlockExpr
2319 redef fun stmt(v)
2320 do
2321 for e in self.n_expr do
2322 v.stmt(e)
2323 end
2324 end
2325 end
2326
2327 redef class AVardeclExpr
2328 redef fun stmt(v)
2329 do
2330 var variable = self.variable.as(not null)
2331 var ne = self.n_expr
2332 if ne != null then
2333 var i = v.expr(ne, variable.declared_type)
2334 v.assign(v.variable(variable), i)
2335 end
2336 end
2337 end
2338
2339 redef class AVarExpr
2340 redef fun expr(v)
2341 do
2342 var res = v.variable(self.variable.as(not null))
2343 var mtype = self.mtype.as(not null)
2344 return v.autoadapt(res, mtype)
2345 end
2346 end
2347
2348 redef class AVarAssignExpr
2349 redef fun stmt(v)
2350 do
2351 var variable = self.variable.as(not null)
2352 var i = v.expr(self.n_value, variable.declared_type)
2353 v.assign(v.variable(variable), i)
2354 end
2355 end
2356
2357 redef class AVarReassignExpr
2358 redef fun stmt(v)
2359 do
2360 var variable = self.variable.as(not null)
2361 var vari = v.variable(variable)
2362 var value = v.expr(self.n_value, variable.declared_type)
2363 var res = v.send(reassign_property.mproperty, [vari, value])
2364 assert res != null
2365 v.assign(v.variable(variable), res)
2366 end
2367 end
2368
2369 redef class ASelfExpr
2370 redef fun expr(v)
2371 do
2372 return v.frame.arguments.first
2373 end
2374 end
2375
2376 redef class AContinueExpr
2377 redef fun stmt(v)
2378 do
2379 v.add("goto CONTINUE_{v.escapemark_name(self.escapemark)};")
2380 end
2381 end
2382
2383 redef class ABreakExpr
2384 redef fun stmt(v)
2385 do
2386 v.add("goto BREAK_{v.escapemark_name(self.escapemark)};")
2387 end
2388 end
2389
2390 redef class AReturnExpr
2391 redef fun stmt(v)
2392 do
2393 var nexpr = self.n_expr
2394 if nexpr != null then
2395 var returnvar = v.frame.returnvar.as(not null)
2396 var i = v.expr(nexpr, returnvar.mtype)
2397 v.assign(returnvar, i)
2398 end
2399 v.add("goto {v.frame.returnlabel.as(not null)};")
2400 end
2401 end
2402
2403 redef class AAbortExpr
2404 redef fun stmt(v)
2405 do
2406 v.add_abort("Aborted")
2407 end
2408 end
2409
2410 redef class AIfExpr
2411 redef fun stmt(v)
2412 do
2413 var cond = v.expr_bool(self.n_expr)
2414 v.add("if ({cond})\{")
2415 v.stmt(self.n_then)
2416 v.add("\} else \{")
2417 v.stmt(self.n_else)
2418 v.add("\}")
2419 end
2420 end
2421
2422 redef class AIfexprExpr
2423 redef fun expr(v)
2424 do
2425 var res = v.new_var(self.mtype.as(not null))
2426 var cond = v.expr_bool(self.n_expr)
2427 v.add("if ({cond})\{")
2428 v.assign(res, v.expr(self.n_then, null))
2429 v.add("\} else \{")
2430 v.assign(res, v.expr(self.n_else, null))
2431 v.add("\}")
2432 return res
2433 end
2434 end
2435
2436 redef class ADoExpr
2437 redef fun stmt(v)
2438 do
2439 v.stmt(self.n_block)
2440 var escapemark = self.escapemark
2441 if escapemark != null then
2442 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2443 end
2444 end
2445 end
2446
2447 redef class AWhileExpr
2448 redef fun stmt(v)
2449 do
2450 v.add("for(;;) \{")
2451 var cond = v.expr_bool(self.n_expr)
2452 v.add("if (!{cond}) break;")
2453 v.stmt(self.n_block)
2454 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2455 v.add("\}")
2456 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2457 end
2458 end
2459
2460 redef class ALoopExpr
2461 redef fun stmt(v)
2462 do
2463 v.add("for(;;) \{")
2464 v.stmt(self.n_block)
2465 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2466 v.add("\}")
2467 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2468 end
2469 end
2470
2471 redef class AForExpr
2472 redef fun stmt(v)
2473 do
2474 var cl = v.expr(self.n_expr, null)
2475 var it_meth = self.method_iterator
2476 assert it_meth != null
2477 var it = v.send(it_meth, [cl])
2478 assert it != null
2479 v.add("for(;;) \{")
2480 var isok_meth = self.method_is_ok
2481 assert isok_meth != null
2482 var ok = v.send(isok_meth, [it])
2483 assert ok != null
2484 v.add("if(!{ok}) break;")
2485 if self.variables.length == 1 then
2486 var item_meth = self.method_item
2487 assert item_meth != null
2488 var i = v.send(item_meth, [it])
2489 assert i != null
2490 v.assign(v.variable(variables.first), i)
2491 else if self.variables.length == 2 then
2492 var key_meth = self.method_key
2493 assert key_meth != null
2494 var i = v.send(key_meth, [it])
2495 assert i != null
2496 v.assign(v.variable(variables[0]), i)
2497 var item_meth = self.method_item
2498 assert item_meth != null
2499 i = v.send(item_meth, [it])
2500 assert i != null
2501 v.assign(v.variable(variables[1]), i)
2502 else
2503 abort
2504 end
2505 v.stmt(self.n_block)
2506 v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
2507 var next_meth = self.method_next
2508 assert next_meth != null
2509 v.send(next_meth, [it])
2510 v.add("\}")
2511 v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
2512 end
2513 end
2514
2515 redef class AAssertExpr
2516 redef fun stmt(v)
2517 do
2518 if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return
2519
2520 var cond = v.expr_bool(self.n_expr)
2521 v.add("if (!{cond}) \{")
2522 v.stmt(self.n_else)
2523 var nid = self.n_id
2524 if nid != null then
2525 v.add_abort("Assert '{nid.text}' failed")
2526 else
2527 v.add_abort("Assert failed")
2528 end
2529 v.add("\}")
2530 end
2531 end
2532
2533 redef class AOrExpr
2534 redef fun expr(v)
2535 do
2536 var res = v.new_var(self.mtype.as(not null))
2537 var i1 = v.expr_bool(self.n_expr)
2538 v.add("if ({i1}) \{")
2539 v.add("{res} = 1;")
2540 v.add("\} else \{")
2541 var i2 = v.expr_bool(self.n_expr2)
2542 v.add("{res} = {i2};")
2543 v.add("\}")
2544 return res
2545 end
2546 end
2547
2548 redef class AAndExpr
2549 redef fun expr(v)
2550 do
2551 var res = v.new_var(self.mtype.as(not null))
2552 var i1 = v.expr_bool(self.n_expr)
2553 v.add("if (!{i1}) \{")
2554 v.add("{res} = 0;")
2555 v.add("\} else \{")
2556 var i2 = v.expr_bool(self.n_expr2)
2557 v.add("{res} = {i2};")
2558 v.add("\}")
2559 return res
2560 end
2561 end
2562
2563 redef class ANotExpr
2564 redef fun expr(v)
2565 do
2566 var cond = v.expr_bool(self.n_expr)
2567 return v.new_expr("!{cond}", self.mtype.as(not null))
2568 end
2569 end
2570
2571 redef class AOrElseExpr
2572 redef fun expr(v)
2573 do
2574 var res = v.new_var(self.mtype.as(not null))
2575 var i1 = v.expr(self.n_expr, null)
2576 v.add("if ({i1}!=NULL) \{")
2577 v.assign(res, i1)
2578 v.add("\} else \{")
2579 var i2 = v.expr(self.n_expr2, null)
2580 v.assign(res, i2)
2581 v.add("\}")
2582 return res
2583 end
2584 end
2585
2586 redef class AEeExpr
2587 redef fun expr(v)
2588 do
2589 var value1 = v.expr(self.n_expr, null)
2590 var value2 = v.expr(self.n_expr2, null)
2591 return v.equal_test(value1, value2)
2592 end
2593 end
2594
2595 redef class AIntExpr
2596 redef fun expr(v)
2597 do
2598 return v.new_expr("{self.n_number.text}", self.mtype.as(not null))
2599 end
2600 end
2601
2602 redef class AFloatExpr
2603 redef fun expr(v)
2604 do
2605 return v.new_expr("{self.n_float.text}", self.mtype.as(not null))
2606 end
2607 end
2608
2609 redef class ACharExpr
2610 redef fun expr(v)
2611 do
2612 return v.new_expr("{self.n_char.text}", self.mtype.as(not null))
2613 end
2614 end
2615
2616 redef class AArrayExpr
2617 redef fun expr(v)
2618 do
2619 var mtype = self.mtype.as(MClassType).arguments.first
2620 var array = new Array[RuntimeVariable]
2621 for nexpr in self.n_exprs.n_exprs do
2622 var i = v.expr(nexpr, mtype)
2623 array.add(i)
2624 end
2625 return v.array_instance(array, mtype)
2626 end
2627 end
2628
2629 redef class AStringFormExpr
2630 redef fun expr(v)
2631 do
2632 return v.string_instance(self.value.as(not null))
2633 end
2634 end
2635
2636 redef class ASuperstringExpr
2637 redef fun expr(v)
2638 do
2639 var array = new Array[RuntimeVariable]
2640 for ne in self.n_exprs do
2641 if ne isa AStringFormExpr and ne.value == "" then continue # skip empty sub-strings
2642 var i = v.expr(ne, null)
2643 array.add(i)
2644 end
2645 var a = v.array_instance(array, v.object_type)
2646 var res = v.send(v.get_property("to_s", a.mtype), [a])
2647 return res
2648 end
2649 end
2650
2651 redef class ACrangeExpr
2652 redef fun expr(v)
2653 do
2654 var i1 = v.expr(self.n_expr, null)
2655 var i2 = v.expr(self.n_expr2, null)
2656 var mtype = self.mtype.as(MClassType)
2657 var res = v.init_instance(mtype)
2658 var it = v.send(v.get_property("init", res.mtype), [res, i1, i2])
2659 v.check_init_instance(res, mtype)
2660 return res
2661 end
2662 end
2663
2664 redef class AOrangeExpr
2665 redef fun expr(v)
2666 do
2667 var i1 = v.expr(self.n_expr, null)
2668 var i2 = v.expr(self.n_expr2, null)
2669 var mtype = self.mtype.as(MClassType)
2670 var res = v.init_instance(mtype)
2671 var it = v.send(v.get_property("without_last", res.mtype), [res, i1, i2])
2672 v.check_init_instance(res, mtype)
2673 return res
2674 end
2675 end
2676
2677 redef class ATrueExpr
2678 redef fun expr(v)
2679 do
2680 return v.new_expr("1", self.mtype.as(not null))
2681 end
2682 end
2683
2684 redef class AFalseExpr
2685 redef fun expr(v)
2686 do
2687 return v.new_expr("0", self.mtype.as(not null))
2688 end
2689 end
2690
2691 redef class ANullExpr
2692 redef fun expr(v)
2693 do
2694 var res = v.new_expr("NULL", self.mtype.as(not null))
2695 return res
2696 end
2697 end
2698
2699 redef class AIsaExpr
2700 redef fun expr(v)
2701 do
2702 var i = v.expr(self.n_expr, null)
2703 return v.type_test(i, self.cast_type.as(not null))
2704 end
2705 end
2706
2707 redef class AAsCastExpr
2708 redef fun expr(v)
2709 do
2710 var i = v.expr(self.n_expr, null)
2711 if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
2712
2713 var cond = v.type_test(i, self.mtype.as(not null))
2714 v.add("if (!{cond}) \{")
2715 v.add_abort("Cast failed")
2716 v.add("\}")
2717 return i
2718 end
2719 end
2720
2721 redef class AAsNotnullExpr
2722 redef fun expr(v)
2723 do
2724 var i = v.expr(self.n_expr, null)
2725 if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
2726
2727 v.add("if ({i} == NULL) \{")
2728 v.add_abort("Cast failed")
2729 v.add("\}")
2730 return i
2731 end
2732 end
2733
2734 redef class AParExpr
2735 redef fun expr(v)
2736 do
2737 return v.expr(self.n_expr, null)
2738 end
2739 end
2740
2741 redef class AOnceExpr
2742 redef fun expr(v)
2743 do
2744 var mtype = self.mtype.as(not null)
2745 var name = v.get_name("varonce")
2746 var guard = v.get_name(name + "_guard")
2747 v.add_decl("static {mtype.ctype} {name};")
2748 v.add_decl("static int {guard};")
2749 var res = v.new_var(mtype)
2750 v.add("if ({guard}) \{")
2751 v.add("{res} = {name};")
2752 v.add("\} else \{")
2753 var i = v.expr(self.n_expr, mtype)
2754 v.add("{res} = {i};")
2755 v.add("{name} = {res};")
2756 v.add("{guard} = 1;")
2757 v.add("\}")
2758 return res
2759 end
2760 end
2761
2762 redef class ASendExpr
2763 redef fun expr(v)
2764 do
2765 var recv = v.expr(self.n_expr, null)
2766 var args = [recv]
2767 for a in self.raw_arguments.as(not null) do
2768 args.add(v.expr(a, null))
2769 end
2770 var mproperty = self.mproperty.as(not null)
2771 return v.send(mproperty, args)
2772 end
2773 end
2774
2775 redef class ASendReassignFormExpr
2776 redef fun stmt(v)
2777 do
2778 var recv = v.expr(self.n_expr, null)
2779 var args = [recv]
2780 for a in self.raw_arguments.as(not null) do
2781 args.add(v.expr(a, null))
2782 end
2783 var value = v.expr(self.n_value, null)
2784
2785 var mproperty = self.mproperty.as(not null)
2786 var left = v.send(mproperty, args)
2787 assert left != null
2788
2789 var res = v.send(reassign_property.mproperty, [left, value])
2790 assert res != null
2791
2792 args.add(res)
2793 v.send(self.write_mproperty.as(not null), args)
2794 end
2795 end
2796
2797 redef class ASuperExpr
2798 redef fun expr(v)
2799 do
2800 var recv = v.frame.arguments.first
2801 var args = [recv]
2802 for a in self.n_args.n_exprs do
2803 args.add(v.expr(a, null))
2804 end
2805 if args.length == 1 then
2806 args = v.frame.arguments
2807 end
2808
2809 var mproperty = self.mproperty
2810 if mproperty != null then
2811 if mproperty.intro.msignature.arity == 0 then
2812 args = [recv]
2813 end
2814 # Super init call
2815 var res = v.send(mproperty, args)
2816 return res
2817 end
2818
2819 # stantard call-next-method
2820 var mpropdef = v.frame.mpropdef
2821 # FIXME: we do not want an ugly static call!
2822 var mpropdefs = mpropdef.mproperty.lookup_super_definitions(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
2823 if mpropdefs.length != 1 then
2824 v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
2825 debug("MPRODFEFS for super {mpropdef} for {recv}: {mpropdefs.join(", ")}")
2826 end
2827 mpropdef = mpropdefs.first
2828 assert mpropdef isa MMethodDef
2829 var res = v.call(mpropdef, recv.mtype.as(MClassType), args)
2830 return res
2831 end
2832 end
2833
2834 redef class ANewExpr
2835 redef fun expr(v)
2836 do
2837 var mproperty = self.mproperty.as(not null)
2838 var mtype = self.mtype.as(MClassType)
2839 var recv
2840 var ctype = mtype.ctype
2841 if ctype == "val*" then
2842 recv = v.init_instance(mtype)
2843 else if ctype == "void*" then
2844 recv = v.new_expr("NULL/*special!*/", mtype)
2845 else
2846 debug("cannot new {mtype}")
2847 abort
2848 end
2849 var args = [recv]
2850 for a in self.n_args.n_exprs do
2851 args.add(v.expr(a, null))
2852 end
2853 var res2 = v.send(mproperty, args)
2854 if res2 != null then
2855 #self.debug("got {res2} from {mproperty}. drop {recv}")
2856 return res2
2857 end
2858 v.check_init_instance(recv, mtype)
2859 return recv
2860 end
2861 end
2862
2863 redef class AAttrExpr
2864 redef fun expr(v)
2865 do
2866 var recv = v.expr(self.n_expr, null)
2867 var mproperty = self.mproperty.as(not null)
2868 return v.read_attribute(mproperty, recv)
2869 end
2870 end
2871
2872 redef class AAttrAssignExpr
2873 redef fun stmt(v)
2874 do
2875 var recv = v.expr(self.n_expr, null)
2876 var i = v.expr(self.n_value, null)
2877 var mproperty = self.mproperty.as(not null)
2878 v.write_attribute(mproperty, recv, i)
2879 end
2880 end
2881
2882 redef class AAttrReassignExpr
2883 redef fun stmt(v)
2884 do
2885 var recv = v.expr(self.n_expr, null)
2886 var value = v.expr(self.n_value, null)
2887 var mproperty = self.mproperty.as(not null)
2888 var attr = v.read_attribute(mproperty, recv)
2889 var res = v.send(reassign_property.mproperty, [attr, value])
2890 assert res != null
2891 v.write_attribute(mproperty, recv, res)
2892 end
2893 end
2894
2895 redef class AIssetAttrExpr
2896 redef fun expr(v)
2897 do
2898 var recv = v.expr(self.n_expr, null)
2899 var mproperty = self.mproperty.as(not null)
2900 return v.isset_attribute(mproperty, recv)
2901 end
2902 end
2903
2904 redef class ADebugTypeExpr
2905 redef fun stmt(v)
2906 do
2907 # do nothing
2908 end
2909 end