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