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