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