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