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