nitg: self type in implicit init is exact
[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 redef init
42 do
43 super
44 self.option_context.add_option(self.opt_output, self.opt_no_cc, self.opt_hardening)
45 end
46 end
47
48 redef class ModelBuilder
49 fun run_global_compiler(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis)
50 do
51 var time0 = get_time
52 self.toolcontext.info("*** COMPILING TO C ***", 1)
53
54 var compiler = new GlobalCompiler(mainmodule, runtime_type_analysis, self)
55 var v = new GlobalCompilerVisitor(compiler)
56
57 v.add_decl("#include <stdlib.h>")
58 v.add_decl("#include <stdio.h>")
59 v.add_decl("#include <string.h>")
60
61 # TODO: Better way to activate the GC
62 #v.add_decl("#include <gc/gc.h>")
63 v.add_decl("#define GC_MALLOC(x) calloc(1, (x))")
64
65 # Declare structure for each live type
66
67 v.add_decl("typedef struct \{int classid;\} val;")
68 for t in runtime_type_analysis.live_types do
69 compiler.declare_runtimeclass(v, t)
70 end
71
72 v.add_decl("extern int glob_argc;")
73 v.add_decl("extern char **glob_argv;")
74 v.add_decl("extern val *glob_sys;")
75
76 # Class names (for the class_name and output_class_name methods)
77
78 v.add_decl("extern const char const * class_names[];")
79 v.add("const char const * class_names[] = \{")
80 for t in runtime_type_analysis.live_types do
81 v.add("\"{t}\", /* {compiler.classid(t)} */")
82 end
83 v.add("\};")
84 compiler.header = v
85
86 # Init instance code (allocate and init-arguments)
87
88 for t in runtime_type_analysis.live_types do
89 if t.ctype != "val*" then continue
90 compiler.generate_init_instance(t)
91 end
92
93 # The main function of the C
94
95 v = new GlobalCompilerVisitor(compiler)
96 v.add_decl("int glob_argc;")
97 v.add_decl("char **glob_argv;")
98 v.add_decl("val *glob_sys;")
99 v.add_decl("int main(int argc, char** argv) \{")
100 v.add("glob_argc = argc; glob_argv = argv;")
101 var main_type = mainmodule.sys_type
102 if main_type == null then return # Nothing to compile
103 var glob_sys = v.init_instance(main_type)
104 v.add("glob_sys = {glob_sys};")
105 var main_init = mainmodule.try_get_primitive_method("init", main_type)
106 if main_init != null then
107 v.send(main_init, [glob_sys])
108 end
109 var main_method = mainmodule.try_get_primitive_method("main", main_type)
110 if main_method != null then
111 v.send(main_method, [glob_sys])
112 end
113 v.add("\}")
114
115 # Compile until all runtime_functions are visited
116
117 while not compiler.todos.is_empty do
118 var m = compiler.todos.shift
119 self.toolcontext.info("Compile {m.mmethoddef} for {m.recv} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3)
120 m.mmethoddef.compile_to_c(compiler, self, m.recv)
121 end
122 self.toolcontext.info("Total methods to compile to C: {compiler.visitors.length}", 2)
123
124 # Generate the .h and .c files
125
126 var outname = self.toolcontext.opt_output.value
127 if outname == null then
128 outname = "{mainmodule.name}.bin"
129 end
130
131 var hfilename = ".nit_compile/{mainmodule.name}.1.h"
132 var h = new OFStream.open(hfilename)
133 for l in compiler.header.decl_lines do
134 h.write l
135 h.write "\n"
136 end
137 h.close
138
139 var cfiles = new Array[String]
140
141 var file: nullable OFStream = null
142 var count = 0
143
144 ".nit_compile".mkdir
145 var i = 0
146 for vis in compiler.visitors do
147 count += vis.lines.length
148 if file == null or count > 10000 then
149 i += 1
150 if file != null then file.close
151 var cfilename = ".nit_compile/{mainmodule.name}.{i}.c"
152 cfiles.add(cfilename)
153 file = new OFStream.open(cfilename)
154 file.write "#include \"{mainmodule.name}.1.h\"\n"
155 count = vis.lines.length
156 end
157 if vis != compiler.header then
158 for l in vis.decl_lines do
159 file.write l
160 file.write "\n"
161 end
162 end
163 for l in vis.lines do
164 file.write l
165 file.write "\n"
166 end
167 end
168 if file != null then file.close
169
170 self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
171
172 # Generate the Makefile
173
174 var makename = ".nit_compile/{mainmodule.name}.mk"
175 var makefile = new OFStream.open(makename)
176
177 makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc\n\n")
178 makefile.write("all: {outname}\n\n")
179
180 var ofiles = new Array[String]
181 for f in cfiles do
182 var o = f.strip_extension(".c") + ".o"
183 makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) -I .nit_compile -I ../clib -c -o {o} {f}\n\n")
184 ofiles.add(o)
185 end
186
187 makefile.write("{outname}: {ofiles.join(" ")} {compiler.extern_bodies.join(" ")}\n\t$(CC) -Wl,--warn-unresolved-symbols $(CFLAGS) $(LDFLAGS) $(LDLIBS) -I .nit_compile -I ../clib -o {outname} {ofiles.join(" ")} {compiler.extern_bodies.join(" ")}\n\n")
188 makefile.close
189 self.toolcontext.info("Generated makefile: {makename}", 2)
190
191 var time1 = get_time
192 self.toolcontext.info("*** END COMPILING TO C: {time1-time0} ***", 2)
193
194 # Execute the Makefile
195
196 if self.toolcontext.opt_no_cc.value then return
197
198 time0 = time1
199 self.toolcontext.info("*** COMPILING C ***", 1)
200 self.toolcontext.info("make -f {makename} -j 4", 2)
201
202 var res
203 if self.toolcontext.verbose_level >= 3 then
204 res = sys.system("make -f {makename} -j 4 2>&1")
205 else
206 res = sys.system("make -f {makename} -j 4 2>&1 >/dev/null")
207 end
208 if res != 0 then
209 toolcontext.error(null, "make failed! Error code: {res}.")
210 end
211
212 time1 = get_time
213 self.toolcontext.info("*** END COMPILING C: {time1-time0} ***", 2)
214 end
215 end
216
217 # Singleton that store the knowledge about the compilation process
218 private class GlobalCompiler
219 # The main module of the program
220 var mainmodule: MModule
221
222 # The result of the RTA (used to know live types and methods)
223 var runtime_type_analysis: RapidTypeAnalysis
224
225 # The modeulbuilder used to know the model and the AST
226 var modelbuilder: ModelBuilder
227
228 # Is hardening asked (see --hardening)
229 fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value
230
231 init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis, modelbuilder: ModelBuilder)
232 do
233 self.mainmodule = mainmodule
234 self.runtime_type_analysis = runtime_type_analysis
235 self.modelbuilder = modelbuilder
236 self.live_primitive_types = new Array[MClassType]
237 for t in runtime_type_analysis.live_types do
238 if t.ctype != "val*" then
239 self.live_primitive_types.add(t)
240 end
241 end
242 end
243
244 # Subset of runtime_type_analysis.live_types that contains only primitive types
245 var live_primitive_types: Array[MClassType]
246
247 # runtime_functions that need to be compiled
248 private var todos: List[RuntimeFunction] = new List[RuntimeFunction]
249
250 # runtime_functions already seen (todo or done)
251 private var seen: HashSet[RuntimeFunction] = new HashSet[RuntimeFunction]
252 fun todo(m: RuntimeFunction)
253 do
254 if seen.has(m) then return
255 todos.add(m)
256 seen.add(m)
257 end
258
259 # Where global declaration are stored (the main .h)
260 #
261 # FIXME: should not be a vistor but just somewhere to store lines
262 # FIXME: should not have a global .h since its does no helps recompilation
263 var header: nullable GlobalCompilerVisitor = null
264
265 # The list of all associated visitors
266 # Used to generate .c files
267 private var visitors: List[GlobalCompilerVisitor] = new List[GlobalCompilerVisitor]
268
269 # List of additional .c files required to compile (native interface)
270 var extern_bodies = new ArraySet[String]
271
272 # Return the C symbol associated to a live type runtime
273 # REQUIRE: self.runtime_type_analysis.live_types.has(mtype)
274 fun classid(mtype: MClassType): String
275 do
276 if self.classids.has_key(mtype) then
277 return self.classids[mtype]
278 end
279 print "No classid for {mtype}"
280 abort
281 end
282
283 # Cache for classid (computed by declare_runtimeclass)
284 private var classids: HashMap[MClassType, String] = new HashMap[MClassType, String]
285
286 # Declare C structures and identifiers for a runtime class
287 fun declare_runtimeclass(v: GlobalCompilerVisitor, mtype: MClassType)
288 do
289 assert self.runtime_type_analysis.live_types.has(mtype)
290 v.add_decl("/* runtime class {mtype} */")
291 var idnum = classids.length
292 var idname = "ID_" + mtype.c_name
293 self.classids[mtype] = idname
294 v.add_decl("#define {idname} {idnum} /* {mtype} */")
295 v.add_decl("struct {mtype.c_name} \{")
296 v.add_decl("int classid; /* must be {idname} */")
297 if mtype.ctype != "val*" then
298 v.add_decl("{mtype.ctype} value;")
299 end
300 for cd in mtype.collect_mclassdefs(self.mainmodule) do
301 for p in cd.intro_mproperties do
302 if not p isa MAttribute then continue
303 var t = p.intro.static_mtype.as(not null)
304 t = t.anchor_to(self.mainmodule, mtype)
305 v.add_decl("{t.ctype} {p.intro.c_name}; /* {p}: {t} */")
306 end
307 end
308 v.add_decl("\};")
309 end
310
311 # Generate the init-instance of a live type (allocate + init-instance)
312 fun generate_init_instance(mtype: MClassType)
313 do
314 assert self.runtime_type_analysis.live_types.has(mtype)
315 assert mtype.ctype == "val*"
316 var v = new GlobalCompilerVisitor(self)
317
318 self.header.add_decl("{mtype.ctype} NEW_{mtype.c_name}(void);")
319 v.add_decl("/* allocate {mtype} */")
320 v.add_decl("{mtype.ctype} NEW_{mtype.c_name}(void) \{")
321 var res = v.new_var(mtype)
322 res.is_exact = true
323 v.add("{res} = GC_MALLOC(sizeof(struct {mtype.c_name}));")
324 v.add("{res}->classid = {self.classid(mtype)};")
325
326 for cd in mtype.collect_mclassdefs(self.mainmodule)
327 do
328 var n = self.modelbuilder.mclassdef2nclassdef[cd]
329 for npropdef in n.n_propdefs do
330 if npropdef isa AAttrPropdef then
331 npropdef.init_expr(v, res)
332 end
333 end
334 end
335 v.add("return {res};")
336 v.add("\}")
337 end
338
339 # look for a needed .h and .c file for a given .nit source-file
340 # FIXME: bad API, parameter should be a MModule, not its source-file
341 fun add_extern(file: String)
342 do
343 file = file.strip_extension(".nit")
344 var tryfile = file + ".nit.h"
345 if tryfile.file_exists then
346 self.header.add_decl("#include \"{"..".join_path(tryfile)}\"")
347 end
348 tryfile = file + "_nit.h"
349 if tryfile.file_exists then
350 self.header.add_decl("#include \"{"..".join_path(tryfile)}\"")
351 end
352 tryfile = file + ".nit.c"
353 if tryfile.file_exists then
354 self.extern_bodies.add(tryfile)
355 end
356 tryfile = file + "_nit.c"
357 if tryfile.file_exists then
358 self.extern_bodies.add(tryfile)
359 end
360 #(new OFStream.open("{file.basename("")}._nitni.h")).close
361 end
362 end
363
364 redef class String
365 # Mangle a string to be a unique valid C identifier
366 fun to_cmangle: String
367 do
368 var res = new Buffer
369 var underscore = false
370 for c in self do
371 if (c >= 'a' and c <= 'z') or (c >='A' and c <= 'Z') then
372 res.add(c)
373 underscore = false
374 continue
375 end
376 if underscore then
377 res.append('_'.ascii.to_s)
378 res.add('d')
379 end
380 if c >= '0' and c <= '9' then
381 res.add(c)
382 underscore = false
383 else if c == '_' then
384 res.add(c)
385 underscore = true
386 else
387 res.add('_')
388 res.append(c.ascii.to_s)
389 res.add('d')
390 underscore = false
391 end
392 end
393 return res.to_s
394 end
395
396 # Escape " \ ' and non printable characters for literal C strings or characters
397 fun escape_to_c: String
398 do
399 var b = new Buffer
400 for c in self do
401 if c == '\n' then
402 b.append("\\n")
403 else if c == '\0' then
404 b.append("\\0")
405 else if c == '"' then
406 b.append("\\\"")
407 else if c == '\'' then
408 b.append("\\\'")
409 else if c == '\\' then
410 b.append("\\\\")
411 else if c.ascii < 32 then
412 b.append("\\{c.ascii.to_base(8, false)}")
413 else
414 b.add(c)
415 end
416 end
417 return b.to_s
418 end
419 end
420
421 redef class MType
422 # Return the C type associated to a given Nit static type
423 fun ctype: String
424 do
425 return "val*"
426 end
427
428 # Return the name of the C structure associated to a Nit live type
429 # FIXME: move to GlobalCompiler so we can check that self is a live type
430 fun c_name: String is abstract
431 private var c_name_cache: nullable String
432 end
433
434 redef class MClassType
435 redef fun c_name
436 do
437 var res = self.c_name_cache
438 if res != null then return res
439 res = "{mclass.intro_mmodule.name.to_cmangle}__{mclass.name.to_cmangle}"
440 self.c_name_cache = res
441 return res
442 end
443
444 redef fun ctype: String
445 do
446 if mclass.name == "Int" then
447 return "long"
448 else if mclass.name == "Bool" then
449 return "short int"
450 else if mclass.name == "Char" then
451 return "char"
452 else if mclass.name == "Float" then
453 return "double"
454 else if mclass.name == "NativeString" then
455 return "char*"
456 else if mclass.name == "NativeArray" then
457 assert self isa MGenericType
458 return "{self.arguments.first.ctype}*"
459 else if mclass.kind == extern_kind then
460 return "void*"
461 else
462 return "val*"
463 end
464 end
465 end
466
467 redef class MGenericType
468 redef fun c_name
469 do
470 var res = self.c_name_cache
471 if res != null then return res
472 res = super
473 for t in self.arguments do
474 res = res + t.c_name
475 end
476 self.c_name_cache = res
477 return res
478 end
479 end
480
481 redef class MNullableType
482 redef fun c_name
483 do
484 var res = self.c_name_cache
485 if res != null then return res
486 res = "nullable_{self.mtype.c_name}"
487 self.c_name_cache = res
488 return res
489 end
490 end
491
492 # A C function associated to a Nit method
493 # Because of customization, a given Nit method can be compiler more that once
494 private class RuntimeFunction
495 # The associated Nit method
496 var mmethoddef: MMethodDef
497
498 # The considered reciever
499 # (usually is a live type but no strong guarantee)
500 var recv: MClassType
501
502 # The mangled c name of the runtime_function
503 fun c_name: String
504 do
505 var res = self.c_name_cache
506 if res != null then return res
507 if self.mmethoddef.mclassdef.bound_mtype == self.recv then
508 res = self.mmethoddef.c_name
509 else
510 res = "{mmethoddef.c_name}__{recv.c_name}"
511 end
512 self.c_name_cache = res
513 return res
514 end
515
516 private var c_name_cache: nullable String = null
517
518 redef fun ==(o)
519 # used in the compiler worklist
520 do
521 if not o isa RuntimeFunction then return false
522 if self.mmethoddef != o.mmethoddef then return false
523 if self.recv != o.recv then return false
524 return true
525 end
526
527 redef fun hash
528 # used in the compiler work-list
529 do
530 var res = self.mmethoddef.hash + self.recv.hash
531 return res
532 end
533
534 redef fun to_s
535 do
536 if self.mmethoddef.mclassdef.bound_mtype == self.recv then
537 return self.mmethoddef.to_s
538 else
539 return "{self.mmethoddef}@{self.recv}"
540 end
541 end
542
543 # Implements a call of the runtime_function
544 # May inline the body
545 fun call(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
546 do
547 var ret = self.mmethoddef.msignature.return_mtype
548 if self.mmethoddef.mproperty.is_new then
549 ret = arguments.first.mtype
550 end
551 if ret != null then
552 ret = v.resolve_for(ret, arguments.first)
553 end
554 if self.mmethoddef.can_inline(v) then
555 var frame = new Frame(v, self.mmethoddef, self.recv, arguments)
556 frame.returnlabel = v.get_name("RET_LABEL")
557 if ret != null then
558 frame.returnvar = v.new_var(ret)
559 end
560 var old_frame = v.frame
561 v.frame = frame
562 v.add("\{ /* Inline {self} ({arguments.join(",")}) */")
563 self.mmethoddef.compile_inside_to_c(v, arguments)
564 v.add("{frame.returnlabel.as(not null)}:(void)0;")
565 v.add("\}")
566 v.frame = old_frame
567 return frame.returnvar
568 end
569 v.adapt_signature(self.mmethoddef, arguments)
570 v.compiler.todo(self)
571 if ret == null then
572 v.add("{self.c_name}({arguments.join(",")});")
573 return null
574 else
575 var res = v.new_var(ret)
576 v.add("{res} = {self.c_name}({arguments.join(",")});")
577 return res
578 end
579 end
580 end
581
582 # A runtime variable hold a runtime value in C
583 # Runtime variables are associated to local variables and intermediate results
584 private class RuntimeVariable
585 # The name of the variable in the C code
586 var name: String
587
588 # The static type of the variable (as declard in C)
589 var mtype: MType
590
591 # The current casted type of the variable (as known in Nit)
592 var mcasttype: MType
593
594 # If the variable exaclty a mcasttype?
595 # false (usual value) means that the variable is a mcasttype or a subtype.
596 var is_exact: Bool = false
597
598 redef fun to_s do return name
599
600 redef fun inspect do return "<{inspect_head} {name}:{mtype}({mcasttype})>"
601 end
602
603 # Visit the AST to generate the C code.
604 # Because of inlining, a visitor can visit more than one property.
605 private class GlobalCompilerVisitor
606 # The associated compiler
607 var compiler: GlobalCompiler
608
609 init(compiler: GlobalCompiler)
610 do
611 self.compiler = compiler
612 compiler.visitors.add(self)
613 end
614
615 # Alias for self.compiler.mainmodule.object_type
616 fun object_type: MClassType do return self.compiler.mainmodule.object_type
617
618 # Alias for self.compiler.mainmodule.bool_type
619 fun bool_type: MClassType do return self.compiler.mainmodule.bool_type
620
621 # Force to get the primitive class named `name' or abort
622 fun get_class(name: String): MClass
623 do
624 return self.compiler.mainmodule.get_primitive_class(name)
625 end
626
627 # Force to get the primitive property named `name' in the instance `recv' or abort
628 fun get_property(name: String, recv: MType): MMethod
629 do
630 return self.compiler.mainmodule.force_get_primitive_method(name, recv)
631 end
632
633 # The current Frame
634 var frame: nullable Frame
635
636 # Anchor a type to the main module and the current receiver
637 fun anchor(mtype: MType): MType
638 do
639 if not mtype.need_anchor then return mtype
640 #debug("anchor {mtype} to {self.reciever.as(not null)}:{self.reciever.mtype}")
641 return mtype.anchor_to(self.compiler.mainmodule, self.frame.receiver)
642 end
643
644 # Add a line in the main part of the generated C
645 fun add(s: String)
646 do
647 self.lines.add(s)
648 end
649
650 # Add a line in the
651 # (used for local or global declaration)
652 fun add_decl(s: String)
653 do
654 self.decl_lines.add(s)
655 end
656
657 private var lines: List[String] = new List[String]
658 private var decl_lines: List[String] = new List[String]
659
660 # The current visited AST node
661 var current_node: nullable AExpr = null
662
663 # Compile an expression an return its
664 fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable
665 do
666 var old = self.current_node
667 self.current_node = nexpr
668 var res = nexpr.expr(self).as(not null)
669 if mtype != null then
670 mtype = self.anchor(mtype)
671 res = self.autobox(res, mtype)
672 end
673 self.current_node = old
674 return res
675 end
676
677 # Unsafely cast a value to a new type
678 # ENSURE: return.name == value.name
679 fun autoadapt(value: RuntimeVariable, mtype: MType): RuntimeVariable
680 do
681 mtype = self.anchor(mtype)
682 if value.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
683 return value
684 end
685
686 var valmtype = value.mtype
687 if valmtype isa MNullableType and valmtype.mtype.is_subtype(self.compiler.mainmodule, null, mtype) then
688 var res = new RuntimeVariable(value.name, value.mtype, valmtype.mtype)
689 return res
690 else
691 var res = new RuntimeVariable(value.name, value.mtype, mtype)
692 return res
693 end
694 end
695
696 # Box or unbox a value to another type iff a C type conversion is needed
697 # ENSURE: result.mtype.ctype == mtype.ctype
698 fun autobox(value: RuntimeVariable, mtype: MType): RuntimeVariable
699 do
700 if value.mtype.ctype == mtype.ctype then
701 return value
702 else if value.mtype.ctype == "val*" then
703 return self.new_expr("((struct {mtype.c_name}*){value})->value /* autounbox from {value.mtype} to {mtype} */", mtype)
704 else if mtype.ctype == "val*" then
705 var valtype = value.mtype.as(MClassType)
706 var res = self.new_var(mtype)
707 if not compiler.runtime_type_analysis.live_types.has(valtype) then
708 self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
709 self.add("printf(\"Dead code executed!\\n\"); exit(1);")
710 return res
711 end
712 self.add("{res} = GC_MALLOC(sizeof(struct {valtype.c_name})); /* autobox from {value.mtype} to {mtype} */")
713 self.add("{res}->classid = {self.compiler.classid(valtype)};")
714 self.add("((struct {valtype.c_name}*){res})->value = {value};")
715 return res
716 else
717 # Bad things will append!
718 var res = self.new_var(mtype)
719 self.add("/* {res} left unintialized (cannot convert {value.mtype} to {mtype}) */")
720 self.add("printf(\"Cast error: Cannot cast %s to %s.\\n\", \"{value.mtype}\", \"{mtype}\"); exit(1);")
721 return res
722 end
723 end
724
725 # Correctly assign a left and a right value
726 # Boxing and unboxing is performed if required
727 fun assign(left, right: RuntimeVariable)
728 do
729 right = self.autobox(right, left.mtype)
730 self.add("{left} = {right};")
731 end
732
733
734 # Alias for `self.expr(nexpr, self.bool_type)'
735 fun expr_bool(nexpr: AExpr): RuntimeVariable
736 do
737 return expr(nexpr, bool_type)
738 end
739
740 # Compile statement
741 fun stmt(nexpr: nullable AExpr)
742 do
743 if nexpr == null then return
744 var old = self.current_node
745 self.current_node = nexpr
746 nexpr.stmt(self)
747 self.current_node = old
748 end
749
750 # Safely show a debug message on the current node and repeat the message in the C code
751 fun debug(message: String)
752 do
753 var node = self.current_node
754 if node == null then
755 print "?: {message}"
756 else
757 node.debug(message)
758 end
759 self.add("/* DEBUG: {message} */")
760 end
761
762 # Return a new uninitialized local runtime_variable
763 fun new_var(mtype: MType): RuntimeVariable
764 do
765 if mtype isa MNullType then
766 mtype = self.object_type
767 else
768 mtype = self.anchor(mtype)
769 end
770 var name = self.get_name("var")
771 var res = new RuntimeVariable(name, mtype, mtype)
772 self.add_decl("{mtype.ctype} {name} /* : {mtype} */;")
773 return res
774 end
775
776 # Return a new local runtime_variable initialized with the C expression `cexpr'.
777 fun new_expr(cexpr: String, mtype: MType): RuntimeVariable
778 do
779 var res = new_var(mtype)
780 self.add("{res} = {cexpr};")
781 return res
782 end
783
784 # Return the local runtime_variable associated to a Nit local variable
785 fun variable(variable: Variable): RuntimeVariable
786 do
787 if self.variables.has_key(variable) then
788 return self.variables[variable]
789 else
790 var name = self.get_name("var_{variable.name}")
791 var mtype = variable.declared_type.as(not null)
792 mtype = self.anchor(mtype)
793 var res = new RuntimeVariable(name, mtype, mtype)
794 self.add_decl("{mtype.ctype} {name} /* var {variable}: {mtype} */;")
795 self.variables[variable] = res
796 return res
797 end
798 end
799
800 private var variables: HashMap[Variable, RuntimeVariable] = new HashMap[Variable, RuntimeVariable]
801
802 # Return a new name based on `s' and unique in the visitor
803 fun get_name(s: String): String
804 do
805 if not self.names.has(s) then
806 self.names.add(s)
807 return s
808 end
809 var i = self.last + 1
810 loop
811 var s2 = s + i.to_s
812 if not self.names.has(s2) then
813 self.last = i
814 self.names.add(s2)
815 return s2
816 end
817 i = i + 1
818 end
819 end
820
821 private var last: Int = 0
822
823 private var names: HashSet[String] = new HashSet[String]
824
825 # Generate a return with the value `s'
826 fun ret(s: RuntimeVariable)
827 do
828 self.assign(self.frame.returnvar.as(not null), s)
829 self.add("goto {self.frame.returnlabel.as(not null)};")
830 end
831
832 # The runtime types that are acceptable for a given receiver.
833 fun collect_types(recv: RuntimeVariable): Array[MClassType]
834 do
835 var mtype = recv.mcasttype
836 if recv.is_exact then
837 assert mtype isa MClassType
838 assert self.compiler.runtime_type_analysis.live_types.has(mtype)
839 var types = [mtype]
840 return types
841 end
842 var cache = self.collect_types_cache
843 if cache.has_key(mtype) then
844 return cache[mtype]
845 end
846 var types = new Array[MClassType]
847 var mainmodule = self.compiler.mainmodule
848 for t in self.compiler.runtime_type_analysis.live_types do
849 if not t.is_subtype(mainmodule, null, mtype) then continue
850 types.add(t)
851 end
852 cache[mtype] = types
853 return types
854 end
855
856 private var collect_types_cache: HashMap[MType, Array[MClassType]] = new HashMap[MType, Array[MClassType]]
857
858 fun resolve_for(mtype: MType, recv: RuntimeVariable): MType
859 do
860 if not mtype.need_anchor then return mtype
861 #debug("resolve for {mtype} to {recv}:{recv.mcasttype}(declared as {recv.mtype}) (in {self.reciever.to_s}:{self.reciever.mtype})")
862 var res = mtype.resolve_for(recv.mcasttype, self.frame.receiver, self.compiler.mainmodule, true)
863 return res
864 end
865
866 # Generate a polymorphic send for the method `m' and the arguments `args'
867 fun send(m: MMethod, args: Array[RuntimeVariable]): nullable RuntimeVariable
868 do
869 var types = self.collect_types(args.first)
870
871 var res: nullable RuntimeVariable
872 var ret = m.intro.msignature.return_mtype
873 if m.is_new then
874 ret = args.first.mtype
875 res = self.new_var(ret)
876 else if ret == null then
877 res = null
878 else
879 ret = self.resolve_for(ret, args.first)
880 res = self.new_var(ret)
881 end
882
883 if types.is_empty then
884 self.add("/*BUG: no live types for {args.first.mtype} . {m}*/")
885 return res
886 end
887 self.add("/* send {m} on {args.first}: {args.first.mcasttype} (declared {args.first.mtype}) */")
888 if args.first.mtype.ctype != "val*" then
889 var propdefs = m.lookup_definitions(self.compiler.mainmodule, args.first.mtype)
890 if propdefs.length == 0 then
891 self.add("/* skip {args.first.mcasttype}, no method {m} */")
892 return res
893 end
894 assert propdefs.length == 1
895 var propdef = propdefs.first
896 var res2 = self.call(propdef, args.first.mtype.as(MClassType), args)
897 if res != null then self.assign(res, res2.as(not null))
898 return res
899 end
900 if args.first.mcasttype isa MNullableType then
901 self.add("if ({args.first} == NULL) \{ /* Special null case */")
902 if m.name == "==" then
903 assert res != null
904 if args[1].mcasttype.ctype == "val*" then
905 self.add("{res} = ({args[1]} == NULL);")
906 else
907 self.add("{res} = 0; /* {args[1]}: {args[1].mcasttype} cannot be null */")
908 end
909 else if m.name == "!=" then
910 assert res != null
911 if args[1].mcasttype.ctype == "val*" then
912 self.add("{res} = ({args[1]} != NULL);")
913 else
914 self.add("{res} = 1; /* {args[1]}: {args[1].mcasttype} cannot be null */")
915 end
916 else
917 self.add_abort("Reciever is null")
918 end
919 self.add "\} else"
920 end
921 self.add("switch({args.first}->classid) \{")
922 var last = types.last
923 var defaultpropdef: nullable MMethodDef = null
924 for t in types do
925 var propdefs = m.lookup_definitions(self.compiler.mainmodule, t)
926 if propdefs.length == 0 then
927 self.add("/* skip {t}, no method {m} */")
928 continue
929 end
930 var propdef = propdefs.first
931 if propdef.mclassdef.mclass.name == "Object" and t.ctype == "val*" then
932 defaultpropdef = propdef
933 continue
934 end
935 if not self.compiler.hardening and t == last and defaultpropdef == null then
936 self.add("default: /* test {t} */")
937 else
938 self.add("case {self.compiler.classid(t)}: /* test {t} */")
939 end
940 var res2 = self.call(propdef, t, args)
941 if res != null then self.assign(res, res2.as(not null))
942 self.add "break;"
943 end
944 if defaultpropdef != null then
945 self.add("default: /* default is Object */")
946 var res2 = self.call(defaultpropdef, defaultpropdef.mclassdef.bound_mtype, args)
947 if res != null then self.assign(res, res2.as(not null))
948 else if self.compiler.hardening then
949 self.add("default: /* bug */")
950 self.bugtype(args.first)
951 end
952 self.add("\}")
953 return res
954 end
955
956 fun check_valid_reciever(recvtype: MClassType)
957 do
958 if self.compiler.runtime_type_analysis.live_types.has(recvtype) or recvtype.mclass.name == "Object" then return
959 print "{recvtype} is not a live type"
960 abort
961 end
962
963 fun call(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
964 do
965 check_valid_reciever(recvtype)
966 #debug("call {m} on {recvtype} on {args.first}:{args.first.mtype}")
967 if m.mclassdef.mclass.name == "Object" and recvtype.ctype == "val*" then
968 recvtype = m.mclassdef.bound_mtype
969 end
970 var recv = self.autobox(args.first, recvtype)
971 recv = self.autoadapt(recv, recvtype)
972
973 var vararg_rank = m.msignature.vararg_rank
974 if vararg_rank >= 0 then
975 assert args.length >= m.msignature.arity + 1 # because of self
976 var rawargs = args
977 args = new Array[RuntimeVariable]
978
979 args.add(rawargs.first) # recv
980
981 for i in [0..vararg_rank[ do
982 args.add(rawargs[i+1])
983 end
984
985 var vararg_lastrank = vararg_rank + rawargs.length-1-m.msignature.arity
986 var vararg = new Array[RuntimeVariable]
987 for i in [vararg_rank..vararg_lastrank] do
988 vararg.add(rawargs[i+1])
989 end
990 # FIXME: its it to late to determine the vararg type, this should have been done during a previous analysis
991 var elttype = m.msignature.parameter_mtypes[vararg_rank]
992 elttype = self.resolve_for(elttype, recv)
993 args.add(self.array_instance(vararg, elttype))
994
995 for i in [vararg_lastrank+1..rawargs.length-1[ do
996 args.add(rawargs[i+1])
997 end
998 else
999 args = args.to_a
1000 end
1001 assert args.length == m.msignature.arity + 1 # because of self
1002
1003 args.first = recv
1004 var rm = new RuntimeFunction(m, recvtype)
1005 return rm.call(self, args)
1006 end
1007
1008 fun adapt_signature(m: MMethodDef, args: Array[RuntimeVariable])
1009 do
1010 var recv = args.first
1011 for i in [0..m.msignature.arity[ do
1012 var t = m.msignature.parameter_mtypes[i]
1013 if i == m.msignature.vararg_rank then
1014 t = args[i+1].mtype
1015 end
1016 t = self.resolve_for(t, recv)
1017 args[i+1] = self.autobox(args[i+1], t)
1018 end
1019 end
1020
1021 fun bugtype(recv: RuntimeVariable)
1022 do
1023 if recv.mtype.ctype != "val*" then return
1024 self.add("fprintf(stderr, \"BTD BUG: Dynamic type is %s, static type is %s\\n\", class_names[{recv}->classid], \"{recv.mcasttype}\");")
1025 end
1026
1027 # Generate a polymorphic attribute read
1028 fun read_attribute(a: MAttribute, recv: RuntimeVariable): RuntimeVariable
1029 do
1030 var types = self.collect_types(recv)
1031
1032 var ret = a.intro.static_mtype.as(not null)
1033 ret = self.resolve_for(ret, recv)
1034 var res = self.new_var(ret)
1035
1036 if types.is_empty then
1037 self.add("/*BUG: no live types for {recv.mtype} . {a}*/")
1038 return res
1039 end
1040 self.add("/* read {a} on {recv.mcasttype} */")
1041 self.add("switch({recv}->classid) \{")
1042 var last = types.last
1043 for t in types do
1044 if not self.compiler.hardening and t == last then
1045 self.add("default: /*{self.compiler.classid(t)}*/")
1046 else
1047 self.add("case {self.compiler.classid(t)}:")
1048 end
1049 var recv2 = self.autoadapt(recv, t)
1050 var ta = a.intro.static_mtype.as(not null)
1051 ta = self.resolve_for(ta, recv2)
1052 var res2 = self.new_expr("((struct {t.c_name}*){recv})->{a.intro.c_name}", ta)
1053 if not ta isa MNullableType then
1054 if ta.ctype == "val*" then
1055 self.add("if ({res2} == NULL) \{")
1056 self.add_abort("Uninitialized attribute {a.name}")
1057 self.add("\}")
1058 else
1059 self.add("/*NOTYET isset on primitive attributes*/")
1060 end
1061 end
1062 self.assign(res, res2)
1063 self.add("break;")
1064 end
1065 if self.compiler.hardening then
1066 self.add("default: /* Bug */")
1067 self.bugtype(recv)
1068 end
1069 self.add("\}")
1070
1071 return res
1072 end
1073
1074 # Generate a polymorphic attribute write
1075 fun write_attribute(a: MAttribute, recv: RuntimeVariable, value: RuntimeVariable)
1076 do
1077 var types = self.collect_types(recv)
1078
1079 if types.is_empty then
1080 self.add("/*BUG: no live types for {recv.mtype} . {a}*/")
1081 return
1082 end
1083 self.add("/* write {a} on {recv.mcasttype} */")
1084 self.add("switch({recv}->classid) \{")
1085 var last = types.last
1086 for t in types do
1087 if not self.compiler.hardening and t == last then
1088 self.add("default: /*{self.compiler.classid(t)}*/")
1089 else
1090 self.add("case {self.compiler.classid(t)}:")
1091 end
1092 var recv2 = self.autoadapt(recv, t)
1093 var ta = a.intro.static_mtype.as(not null)
1094 ta = self.resolve_for(ta, recv2)
1095 self.add("((struct {t.c_name}*){recv})->{a.intro.c_name} = {self.autobox(value, ta)};")
1096 self.add("break;")
1097 end
1098 if self.compiler.hardening then
1099 self.add("default: /* Bug*/")
1100 self.bugtype(recv)
1101 end
1102 self.add("\}")
1103 end
1104
1105 # Generate a alloc-instance + init-attributes
1106 fun init_instance(mtype: MClassType): RuntimeVariable
1107 do
1108 mtype = self.anchor(mtype).as(MClassType)
1109 if not self.compiler.runtime_type_analysis.live_types.has(mtype) then
1110 debug "problem: {mtype} was detected dead"
1111 end
1112 var res = self.new_expr("NEW_{mtype.c_name}()", mtype)
1113 res.is_exact = true
1114 return res
1115 end
1116
1117 # Generate a polymorphic subtype test
1118 fun type_test(value: RuntimeVariable, mtype: MType): RuntimeVariable
1119 do
1120 mtype = self.anchor(mtype)
1121 var types = self.collect_types(value)
1122
1123 var res = self.new_var(bool_type)
1124
1125 self.add("/* isa {mtype} on {value.mcasttype} */")
1126 if value.mcasttype isa MNullableType then
1127 self.add("if ({value} == NULL) \{")
1128 if mtype isa MNullableType then
1129 self.add("{res} = 1; /* isa {mtype} */")
1130 else
1131 self.add("{res} = 0; /* not isa {mtype} */")
1132 end
1133 self.add("\} else ")
1134 end
1135 self.add("switch({value}->classid) \{")
1136 for t in types do
1137 if t.is_subtype(self.compiler.mainmodule, null, mtype) then
1138 self.add("case {self.compiler.classid(t)}: /* {t} */")
1139 end
1140 end
1141 self.add("{res} = 1;")
1142 self.add("break;")
1143 self.add("default:")
1144 self.add("{res} = 0;")
1145 self.add("\}")
1146
1147 return res
1148 end
1149
1150 # Generate a Nit "is" for two runtime_variables
1151 fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable
1152 do
1153 var res = self.new_var(bool_type)
1154 if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
1155 var tmp = value1
1156 value1 = value2
1157 value2 = tmp
1158 end
1159 if value1.mtype.ctype != "val*" then
1160 if value2.mtype.ctype == value1.mtype.ctype then
1161 self.add("{res} = {value1} == {value2};")
1162 else if value2.mtype.ctype != "val*" then
1163 self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
1164 else
1165 var mtype1 = value1.mtype.as(MClassType)
1166 self.add("{res} = ({value2} != NULL) && ({value2}->classid == {self.compiler.classid(mtype1)});")
1167 self.add("if ({res}) \{")
1168 self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
1169 self.add("\}")
1170 end
1171 else
1172 var s = new Array[String]
1173 for t in self.compiler.live_primitive_types do
1174 if not t.is_subtype(self.compiler.mainmodule, null, value1.mcasttype) then continue
1175 if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
1176 s.add "({value1}->classid == {self.compiler.classid(t)} && ((struct {t.c_name}*){value1})->value == ((struct {t.c_name}*){value2})->value)"
1177 end
1178 if s.is_empty then
1179 self.add("{res} = {value1} == {value2};")
1180 else
1181 self.add("{res} = {value1} == {value2} || ({value1} != NULL && {value2} != NULL && {value1}->classid == {value2}->classid && ({s.join(" || ")}));")
1182 end
1183 end
1184 return res
1185 end
1186
1187 # Generate a check-init-instance
1188 # TODO: is an empty stub currently
1189 fun check_init_instance(recv: RuntimeVariable)
1190 do
1191 end
1192
1193 # Generate an integer value
1194 fun int_instance(value: Int): RuntimeVariable
1195 do
1196 var res = self.new_var(self.get_class("Int").mclass_type)
1197 self.add("{res} = {value};")
1198 return res
1199 end
1200
1201 # Generate an array value
1202 fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable
1203 do
1204 elttype = self.anchor(elttype)
1205 var res = self.init_instance(self.get_class("Array").get_mtype([elttype]))
1206 self.add("\{ /* {res} = array_instance Array[{elttype}] */")
1207 var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
1208 nat.is_exact = true
1209 self.add("{nat} = GC_MALLOC({array.length} * sizeof({elttype.ctype}));")
1210 for i in [0..array.length[ do
1211 var r = self.autobox(array[i], elttype)
1212 self.add("{nat}[{i}] = {r};")
1213 end
1214 var length = self.int_instance(array.length)
1215 self.send(self.get_property("with_native", res.mtype), [res, nat, length])
1216 self.check_init_instance(res)
1217 self.add("\}")
1218 return res
1219 end
1220
1221 # Generate a string value
1222 fun string_instance(string: String): RuntimeVariable
1223 do
1224 var mtype = self.get_class("String").mclass_type
1225 var name = self.get_name("varonce")
1226 self.add_decl("static {mtype.ctype} {name};")
1227 var res = self.new_var(mtype)
1228 self.add("if ({name}) \{")
1229 self.add("{res} = {name};")
1230 self.add("\} else \{")
1231 var nat = self.new_var(self.get_class("NativeString").mclass_type)
1232 self.add("{nat} = \"{string.escape_to_c}\";")
1233 var res2 = self.init_instance(mtype)
1234 self.add("{res} = {res2};")
1235 var length = self.int_instance(string.length)
1236 self.send(self.get_property("with_native", res.mtype), [res, nat, length])
1237 self.check_init_instance(res)
1238 self.add("{name} = {res};")
1239 self.add("\}")
1240 return res
1241 end
1242
1243 # Generate generic abort
1244 # used by aborts, asserts, casts, etc.
1245 fun add_abort(message: String)
1246 do
1247 if self.current_node != null and self.current_node.location.file != null then
1248 self.add("fprintf(stderr, \"%s (%s:%d)\\n\", \"{message.escape_to_c}\", \"{self.current_node.location.file.filename.escape_to_c}\", {current_node.location.line_start});")
1249 else
1250 self.add("fprintf(stderr, \"%s\\n\", \"{message.escape_to_c}\");")
1251 end
1252 self.add("exit(1);")
1253 end
1254 end
1255
1256 # A frame correspond to a visited property in a GlobalCompilerVisitor
1257 private class Frame
1258 # The associated visitor
1259
1260 var visitor: GlobalCompilerVisitor
1261
1262 # The executed property.
1263 # A Method in case of a call, an attribute in case of a default initialization.
1264 var mpropdef: MPropDef
1265
1266 # The static type of the receiver
1267 var receiver: MClassType
1268
1269 # Arguments of the method (the first is the receiver)
1270 var arguments: Array[RuntimeVariable]
1271
1272 # The runtime_variable associated to the return (in a function)
1273 var returnvar: nullable RuntimeVariable = null
1274
1275 # The label at the end of the property
1276 var returnlabel: nullable String = null
1277 end
1278
1279 redef class MPropDef
1280 private var c_name_cache: nullable String
1281
1282 # The mangled name associated to the property
1283 fun c_name: String
1284 do
1285 var res = self.c_name_cache
1286 if res != null then return res
1287 res = "{self.mclassdef.mmodule.name.to_cmangle}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
1288 self.c_name_cache = res
1289 return res
1290 end
1291 end
1292
1293 redef class MMethodDef
1294 # Can the body be inlined?
1295 private fun can_inline(v: GlobalCompilerVisitor): Bool
1296 do
1297 var modelbuilder = v.compiler.modelbuilder
1298 if modelbuilder.mpropdef2npropdef.has_key(self) then
1299 var npropdef = modelbuilder.mpropdef2npropdef[self]
1300 return npropdef.can_inline
1301 else if self.mproperty.name == "init" then
1302 # Automatic free init is always inlined since it is empty or contains only attribtes assigments
1303 return true
1304 else
1305 abort
1306 end
1307 end
1308
1309 # Inline the body in another visitor
1310 private fun compile_inside_to_c(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
1311 do
1312 var modelbuilder = v.compiler.modelbuilder
1313 if modelbuilder.mpropdef2npropdef.has_key(self) then
1314 var npropdef = modelbuilder.mpropdef2npropdef[self]
1315 npropdef.compile_to_c(v, self, arguments)
1316 else if self.mproperty.name == "init" then
1317 var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
1318 nclassdef.compile_to_c(v, self, arguments)
1319 else
1320 abort
1321 end
1322 return null
1323 end
1324
1325 # Compile the body in a new visitor
1326 private fun compile_to_c(compiler: GlobalCompiler, modelbuilder: ModelBuilder, recv: MClassType)
1327 do
1328 if not recv.is_subtype(compiler.mainmodule, null, self.mclassdef.bound_mtype) then
1329 print("problem: why do we compile {self} for {recv}?")
1330 abort
1331 end
1332
1333 var v = new GlobalCompilerVisitor(compiler)
1334 var selfvar = new RuntimeVariable("self", recv, recv)
1335 if compiler.runtime_type_analysis.live_types.has(recv) then
1336 selfvar.is_exact = true
1337 end
1338 var arguments = new Array[RuntimeVariable]
1339 var frame = new Frame(v, self, recv, arguments)
1340 v.frame = frame
1341
1342 var sig = new Buffer
1343 var comment = new Buffer
1344 var ret = self.msignature.return_mtype
1345 if ret != null then
1346 ret = v.resolve_for(ret, selfvar)
1347 sig.append("{ret.ctype} ")
1348 else if self.mproperty.is_new then
1349 ret = recv
1350 sig.append("{ret.ctype} ")
1351 else
1352 sig.append("void ")
1353 end
1354 sig.append(self.c_name)
1355 if recv != self.mclassdef.bound_mtype then
1356 sig.append("__{recv.c_name}")
1357 end
1358 sig.append("({recv.ctype} self")
1359 comment.append("(self: {recv}")
1360 arguments.add(selfvar)
1361 for i in [0..self.msignature.arity[ do
1362 var mtype = self.msignature.parameter_mtypes[i]
1363 if i == self.msignature.vararg_rank then
1364 mtype = v.get_class("Array").get_mtype([mtype])
1365 end
1366 mtype = v.resolve_for(mtype, selfvar)
1367 comment.append(", {mtype}")
1368 sig.append(", {mtype.ctype} p{i}")
1369 var argvar = new RuntimeVariable("p{i}", mtype, mtype)
1370 arguments.add(argvar)
1371 end
1372 sig.append(")")
1373 comment.append(")")
1374 if ret != null then
1375 comment.append(": {ret}")
1376 end
1377 compiler.header.add_decl("{sig};")
1378
1379 v.add_decl("/* method {self} for {comment} */")
1380 v.add_decl("{sig} \{")
1381 #v.add("printf(\"method {self} for {comment}\\n\");")
1382 if ret != null then
1383 frame.returnvar = v.new_var(ret)
1384 end
1385 frame.returnlabel = v.get_name("RET_LABEL")
1386
1387 if modelbuilder.mpropdef2npropdef.has_key(self) then
1388 var npropdef = modelbuilder.mpropdef2npropdef[self]
1389 npropdef.compile_to_c(v, self, arguments)
1390 else if self.mproperty.name == "init" then
1391 var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
1392 nclassdef.compile_to_c(v, self, arguments)
1393 else
1394 abort
1395 end
1396
1397 v.add("{frame.returnlabel.as(not null)}:;")
1398 if ret != null then
1399 v.add("return {frame.returnvar.as(not null)};")
1400 end
1401 v.add("\}")
1402 end
1403 end
1404
1405 redef class APropdef
1406 private fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1407 do
1408 v.add("printf(\"Not implemented {class_name} {mpropdef} at {location.to_s}\\n\");")
1409 debug("Not yet implemented")
1410 end
1411
1412 private fun can_inline: Bool do return true
1413 end
1414
1415 redef class AConcreteMethPropdef
1416 redef fun compile_to_c(v, mpropdef, arguments)
1417 do
1418 for i in [0..mpropdef.msignature.arity[ do
1419 var variable = self.n_signature.n_params[i].variable.as(not null)
1420 v.assign(v.variable(variable), arguments[i+1])
1421 end
1422 # Call the implicit super-init
1423 var auto_super_inits = self.auto_super_inits
1424 if auto_super_inits != null then
1425 var selfarg = [arguments.first]
1426 for auto_super_init in auto_super_inits do
1427 if auto_super_init.intro.msignature.arity == 0 then
1428 v.send(auto_super_init, selfarg)
1429 else
1430 v.send(auto_super_init, arguments)
1431 end
1432 end
1433 end
1434
1435 v.stmt(self.n_block)
1436 end
1437
1438 redef fun can_inline
1439 do
1440 if self.auto_super_inits != null then return false
1441 var nblock = self.n_block
1442 if nblock == null then return true
1443 if (mpropdef.mproperty.name == "==" or mpropdef.mproperty.name == "!=") and mpropdef.mclassdef.mclass.name == "Object" then return true
1444 if nblock isa ABlockExpr and nblock.n_expr.length == 0 then return true
1445 return false
1446 end
1447 end
1448
1449 redef class AInternMethPropdef
1450 redef fun compile_to_c(v, mpropdef, arguments)
1451 do
1452 var pname = mpropdef.mproperty.name
1453 var cname = mpropdef.mclassdef.mclass.name
1454 var ret = mpropdef.msignature.return_mtype
1455 if ret != null then
1456 ret = v.resolve_for(ret, arguments.first)
1457 end
1458 if pname != "==" and pname != "!=" then
1459 v.adapt_signature(mpropdef, arguments)
1460 end
1461 if cname == "Int" then
1462 if pname == "output" then
1463 v.add("printf(\"%ld\\n\", {arguments.first});")
1464 return
1465 else if pname == "object_id" then
1466 v.ret(arguments.first)
1467 return
1468 else if pname == "+" then
1469 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1470 return
1471 else if pname == "-" then
1472 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1473 return
1474 else if pname == "unary -" then
1475 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1476 return
1477 else if pname == "succ" then
1478 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1479 return
1480 else if pname == "prec" then
1481 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1482 return
1483 else if pname == "*" then
1484 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1485 return
1486 else if pname == "/" then
1487 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1488 return
1489 else if pname == "%" then
1490 v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
1491 return
1492 else if pname == "lshift" then
1493 v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
1494 return
1495 else if pname == "rshift" then
1496 v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
1497 return
1498 else if pname == "==" then
1499 v.ret(v.equal_test(arguments[0], arguments[1]))
1500 return
1501 else if pname == "!=" then
1502 var res = v.equal_test(arguments[0], arguments[1])
1503 v.ret(v.new_expr("!{res}", ret.as(not null)))
1504 return
1505 else if pname == "<" then
1506 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1507 return
1508 else if pname == ">" then
1509 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1510 return
1511 else if pname == "<=" then
1512 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1513 return
1514 else if pname == ">=" then
1515 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1516 return
1517 else if pname == "to_f" then
1518 v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
1519 return
1520 else if pname == "ascii" then
1521 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1522 return
1523 end
1524 else if cname == "Char" then
1525 if pname == "output" then
1526 v.add("printf(\"%c\", {arguments.first});")
1527 return
1528 else if pname == "object_id" then
1529 v.ret(arguments.first)
1530 return
1531 else if pname == "==" then
1532 v.ret(v.equal_test(arguments[0], arguments[1]))
1533 return
1534 else if pname == "!=" then
1535 var res = v.equal_test(arguments[0], arguments[1])
1536 v.ret(v.new_expr("!{res}", ret.as(not null)))
1537 return
1538 else if pname == "succ" then
1539 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1540 return
1541 else if pname == "prec" then
1542 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1543 return
1544 else if pname == "<" then
1545 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1546 return
1547 else if pname == ">" then
1548 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1549 return
1550 else if pname == "<=" then
1551 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1552 return
1553 else if pname == ">=" then
1554 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1555 return
1556 else if pname == "to_i" then
1557 v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
1558 return
1559 else if pname == "ascii" then
1560 v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
1561 return
1562 end
1563 else if cname == "Bool" then
1564 if pname == "output" then
1565 v.add("printf({arguments.first}?\"true\\n\":\"false\\n\");")
1566 return
1567 else if pname == "object_id" then
1568 v.ret(arguments.first)
1569 return
1570 else if pname == "==" then
1571 v.ret(v.equal_test(arguments[0], arguments[1]))
1572 return
1573 else if pname == "!=" then
1574 var res = v.equal_test(arguments[0], arguments[1])
1575 v.ret(v.new_expr("!{res}", ret.as(not null)))
1576 return
1577 end
1578 else if cname == "Float" then
1579 if pname == "output" then
1580 v.add("printf(\"%f\\n\", {arguments.first});")
1581 return
1582 else if pname == "object_id" then
1583 v.ret(v.new_expr("(double){arguments.first}", ret.as(not null)))
1584 return
1585 else if pname == "+" then
1586 v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
1587 return
1588 else if pname == "-" then
1589 v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
1590 return
1591 else if pname == "unary -" then
1592 v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
1593 return
1594 else if pname == "succ" then
1595 v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
1596 return
1597 else if pname == "prec" then
1598 v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
1599 return
1600 else if pname == "*" then
1601 v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
1602 return
1603 else if pname == "/" then
1604 v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
1605 return
1606 else if pname == "==" then
1607 v.ret(v.equal_test(arguments[0], arguments[1]))
1608 return
1609 else if pname == "!=" then
1610 var res = v.equal_test(arguments[0], arguments[1])
1611 v.ret(v.new_expr("!{res}", ret.as(not null)))
1612 return
1613 else if pname == "<" then
1614 v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
1615 return
1616 else if pname == ">" then
1617 v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
1618 return
1619 else if pname == "<=" then
1620 v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
1621 return
1622 else if pname == ">=" then
1623 v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
1624 return
1625 else if pname == "to_i" then
1626 v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
1627 return
1628 end
1629 else if cname == "Char" then
1630 if pname == "output" then
1631 v.add("printf(\"%c\", {arguments.first});")
1632 return
1633 else if pname == "object_id" then
1634 v.ret(arguments.first)
1635 return
1636 else if pname == "==" then
1637 v.ret(v.equal_test(arguments[0], arguments[1]))
1638 return
1639 else if pname == "!=" then
1640 var res = v.equal_test(arguments[0], arguments[1])
1641 v.ret(v.new_expr("!{res}", ret.as(not null)))
1642 return
1643 else if pname == "ascii" then
1644 v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
1645 return
1646 end
1647 else if cname == "NativeString" then
1648 if pname == "[]" then
1649 v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
1650 return
1651 else if pname == "[]=" then
1652 v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
1653 return
1654 else if pname == "copy_to" then
1655 v.add("memcpy({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
1656 return
1657 else if pname == "atoi" then
1658 v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
1659 return
1660 end
1661 else if cname == "NativeArray" then
1662 var elttype = arguments.first.mtype
1663 if pname == "[]" then
1664 v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
1665 return
1666 else if pname == "[]=" then
1667 v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
1668 return
1669 else if pname == "copy_to" then
1670 v.add("memcpy({arguments[1]},{arguments[0]},{arguments[2]}*sizeof({elttype.ctype}));")
1671 return
1672 end
1673 end
1674 if pname == "exit" then
1675 v.add("exit({arguments[1]});")
1676 return
1677 else if pname == "sys" then
1678 v.ret(v.new_expr("glob_sys", ret.as(not null)))
1679 return
1680 else if pname == "calloc_string" then
1681 v.ret(v.new_expr("(char*)GC_MALLOC({arguments[1]})", ret.as(not null)))
1682 return
1683 else if pname == "calloc_array" then
1684 var elttype = arguments.first.mtype.supertype_to(v.compiler.mainmodule,arguments.first.mtype.as(MClassType),v.get_class("ArrayCapable")).as(MGenericType).arguments.first
1685 v.ret(v.new_expr("({elttype.ctype}*)GC_MALLOC({arguments[1]} * sizeof({elttype.ctype}))", ret.as(not null)))
1686 return
1687 else if pname == "object_id" then
1688 v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
1689 return
1690 else if pname == "is_same_type" then
1691 if arguments[0].mtype.ctype == "val*" then
1692 v.ret(v.new_expr("{arguments[0]}->classid == {arguments[1]}->classid", ret.as(not null)))
1693 else
1694 v.ret(v.new_expr("{v.compiler.classid(arguments[0].mtype.as(MClassType))} == {arguments[1]}->classid", ret.as(not null)))
1695 end
1696 return
1697 else if pname == "output_class_name" then
1698 if arguments[0].mtype.ctype == "val*" then
1699 v.add("printf(\"%s\\n\", class_names[{arguments.first}->classid]);")
1700 else
1701 v.add("printf(\"%s\\n\", class_names[{v.compiler.classid(arguments.first.mtype.as(MClassType))}]);")
1702 end
1703 return
1704 else if pname == "native_class_name" then
1705 if arguments[0].mtype.ctype == "val*" then
1706 v.ret(v.new_expr("(char*)(void*)class_names[{arguments.first}->classid]", ret.as(not null)))
1707 else
1708 v.ret(v.new_expr("(char*)(void*)class_names[{v.compiler.classid(arguments.first.mtype.as(MClassType))}]", ret.as(not null)))
1709 end
1710 return
1711 end
1712 v.add("printf(\"Not implemented {class_name}:{mpropdef} at {location.to_s}\\n\");")
1713 debug("Not implemented {mpropdef}")
1714 end
1715 end
1716
1717 redef class AExternMethPropdef
1718 redef fun compile_to_c(v, mpropdef, arguments)
1719 do
1720 var externname
1721 var nextern = self.n_extern
1722 if nextern == null then
1723 debug("{mpropdef} need extern name")
1724 return
1725 end
1726 externname = nextern.text.substring(1, nextern.text.length-2)
1727 if location.file != null then
1728 var file = location.file.filename
1729 v.compiler.add_extern(file)
1730 end
1731 var res: nullable RuntimeVariable = null
1732 var ret = mpropdef.msignature.return_mtype
1733 if ret != null then
1734 ret = v.resolve_for(ret, arguments.first)
1735 res = v.new_var(ret)
1736 end
1737
1738 if res == null then
1739 v.add("{externname}({arguments.join(", ")});")
1740 else
1741 v.add("{res} = {externname}({arguments.join(", ")});")
1742 v.ret(res)
1743 end
1744 end
1745 end
1746
1747 redef class AExternInitPropdef
1748 redef fun compile_to_c(v, mpropdef, arguments)
1749 do
1750 var externname
1751 var nextern = self.n_extern
1752 if nextern == null then
1753 debug("{mpropdef} need extern name")
1754 return
1755 end
1756 externname = nextern.text.substring(1, nextern.text.length-2)
1757 if location.file != null then
1758 var file = location.file.filename
1759 v.compiler.add_extern(file)
1760 end
1761 var ret = arguments.first.mtype
1762 var res = v.new_var(ret)
1763
1764 arguments.shift
1765
1766 v.add("{res} = {externname}({arguments.join(", ")});")
1767 v.ret(res)
1768 end
1769 end
1770
1771 redef class AAttrPropdef
1772 redef fun compile_to_c(v, mpropdef, arguments)
1773 do
1774 if arguments.length == 1 then
1775 var res = v.read_attribute(self.mpropdef.mproperty, arguments.first)
1776 v.assign(v.frame.returnvar.as(not null), res)
1777 else
1778 v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
1779 end
1780 end
1781
1782 private fun init_expr(v: GlobalCompilerVisitor, recv: RuntimeVariable)
1783 do
1784 var nexpr = self.n_expr
1785 if nexpr != null then
1786 var old_frame = v.frame
1787 var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
1788 v.frame = frame
1789 var value = v.expr(nexpr, self.mpropdef.static_mtype)
1790 v.write_attribute(self.mpropdef.mproperty, recv, value)
1791 v.frame = old_frame
1792 end
1793 end
1794 end
1795
1796 redef class AClassdef
1797 private fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
1798 do
1799 if mpropdef == self.mfree_init then
1800 var super_inits = self.super_inits
1801 if super_inits != null then
1802 assert arguments.length == 1
1803 for su in super_inits do
1804 v.send(su, arguments)
1805 end
1806 return
1807 end
1808 var recv = arguments.first
1809 var i = 1
1810 # Collect undefined attributes
1811 for npropdef in self.n_propdefs do
1812 if npropdef isa AAttrPropdef and npropdef.n_expr == null then
1813 v.write_attribute(npropdef.mpropdef.mproperty, recv, arguments[i])
1814 i += 1
1815 end
1816 end
1817 else
1818 abort
1819 end
1820 end
1821 end
1822
1823 redef class ADeferredMethPropdef
1824 redef fun compile_to_c(v, mpropdef, arguments)
1825 do
1826 v.add("printf(\"Not implemented {class_name} {mpropdef} at {location.to_s}\\n\");")
1827 v.add("exit(1);")
1828 end
1829
1830 redef fun can_inline do return true
1831 end
1832
1833 redef class AExpr
1834 # Try to compile self as an expression
1835 # Do not call this method directly, use `v.expr' instead
1836 private fun expr(v: GlobalCompilerVisitor): nullable RuntimeVariable
1837 do
1838 debug("Unimplemented expr {class_name}")
1839 v.add("printf(\"Not implemented {class_name}:{location.to_s}\\n\");")
1840 var mtype = self.mtype
1841 if mtype == null then
1842 return null
1843 else
1844 var res = v.new_var(mtype)
1845 v.add("/* {res} = NOT YET {class_name} */")
1846 return res
1847 end
1848 end
1849
1850 # Try to compile self as a statement
1851 # Do not call this method directly, use `v.stmt' instead
1852 private fun stmt(v: GlobalCompilerVisitor)
1853 do
1854 var res = expr(v)
1855 if res != null then v.add("{res};")
1856 end
1857
1858 end
1859
1860 redef class ABlockExpr
1861 redef fun stmt(v)
1862 do
1863 for e in self.n_expr do
1864 v.stmt(e)
1865 end
1866 end
1867 end
1868
1869 redef class AVardeclExpr
1870 redef fun stmt(v)
1871 do
1872 var variable = self.variable.as(not null)
1873 var ne = self.n_expr
1874 if ne != null then
1875 var i = v.expr(ne, variable.declared_type)
1876 v.assign(v.variable(variable), i)
1877 end
1878 end
1879 end
1880
1881 redef class AVarExpr
1882 redef fun expr(v)
1883 do
1884 var res = v.variable(self.variable.as(not null))
1885 var mtype = self.mtype.as(not null)
1886 return v.autoadapt(res, mtype)
1887 end
1888 end
1889
1890 redef class AVarAssignExpr
1891 redef fun stmt(v)
1892 do
1893 var variable = self.variable.as(not null)
1894 var i = v.expr(self.n_value, variable.declared_type)
1895 v.assign(v.variable(variable), i)
1896 end
1897 end
1898
1899 redef class AVarReassignExpr
1900 redef fun stmt(v)
1901 do
1902 var variable = self.variable.as(not null)
1903 var vari = v.variable(variable)
1904 var value = v.expr(self.n_value, variable.declared_type)
1905 var res = v.send(reassign_property.mproperty, [vari, value])
1906 assert res != null
1907 v.assign(v.variable(variable), res)
1908 end
1909 end
1910
1911 redef class ASelfExpr
1912 redef fun expr(v)
1913 do
1914 return v.frame.arguments.first
1915 end
1916 end
1917
1918 redef class AContinueExpr
1919 redef fun stmt(v)
1920 do
1921 v.add("goto CONTINUE_{self.escapemark.object_id};")
1922 end
1923 end
1924
1925 redef class ABreakExpr
1926 redef fun stmt(v)
1927 do
1928 v.add("goto BREAK_{self.escapemark.object_id};")
1929 end
1930 end
1931
1932 redef class AReturnExpr
1933 redef fun stmt(v)
1934 do
1935 var nexpr = self.n_expr
1936 if nexpr != null then
1937 var returnvar = v.frame.returnvar.as(not null)
1938 var i = v.expr(nexpr, returnvar.mtype)
1939 v.assign(returnvar, i)
1940 end
1941 v.add("goto {v.frame.returnlabel.as(not null)};")
1942 end
1943 end
1944
1945 redef class AAbortExpr
1946 redef fun stmt(v)
1947 do
1948 v.add_abort("Aborted")
1949 end
1950 end
1951
1952 redef class AIfExpr
1953 redef fun stmt(v)
1954 do
1955 var cond = v.expr_bool(self.n_expr)
1956 v.add("if ({cond})\{")
1957 v.stmt(self.n_then)
1958 v.add("\} else \{")
1959 v.stmt(self.n_else)
1960 v.add("\}")
1961 end
1962 end
1963
1964 redef class AIfexprExpr
1965 redef fun expr(v)
1966 do
1967 var res = v.new_var(self.mtype.as(not null))
1968 var cond = v.expr_bool(self.n_expr)
1969 v.add("if ({cond})\{")
1970 v.assign(res, v.expr(self.n_then, null))
1971 v.add("\} else \{")
1972 v.assign(res, v.expr(self.n_else, null))
1973 v.add("\}")
1974 return res
1975 end
1976 end
1977
1978 redef class ADoExpr
1979 redef fun stmt(v)
1980 do
1981 v.stmt(self.n_block)
1982 var escapemark = self.escapemark
1983 if escapemark != null then
1984 v.add("BREAK_{escapemark.object_id}: (void)0;")
1985 end
1986 end
1987 end
1988
1989 redef class AWhileExpr
1990 redef fun stmt(v)
1991 do
1992 v.add("for(;;) \{")
1993 var cond = v.expr_bool(self.n_expr)
1994 v.add("if (!{cond}) break;")
1995 v.stmt(self.n_block)
1996 v.add("CONTINUE_{escapemark.object_id}: (void)0;")
1997 v.add("\}")
1998 v.add("BREAK_{escapemark.object_id}: (void)0;")
1999 end
2000 end
2001
2002 redef class ALoopExpr
2003 redef fun stmt(v)
2004 do
2005 v.add("for(;;) \{")
2006 v.stmt(self.n_block)
2007 v.add("CONTINUE_{escapemark.object_id}: (void)0;")
2008 v.add("\}")
2009 v.add("BREAK_{escapemark.object_id}: (void)0;")
2010 end
2011 end
2012
2013 redef class AForExpr
2014 redef fun stmt(v)
2015 do
2016 var cl = v.expr(self.n_expr, null)
2017 var it = v.send(v.get_property("iterator", cl.mtype), [cl])
2018 assert it != null
2019 v.add("for(;;) \{")
2020 var ok = v.send(v.get_property("is_ok", it.mtype), [it])
2021 assert ok != null
2022 v.add("if(!{ok}) break;")
2023 var i = v.send(v.get_property("item", it.mtype), [it])
2024 assert i != null
2025 v.assign(v.variable(variables.first), i)
2026 v.stmt(self.n_block)
2027 v.add("CONTINUE_{escapemark.object_id}: (void)0;")
2028 v.send(v.get_property("next", it.mtype), [it])
2029 v.add("\}")
2030 v.add("BREAK_{escapemark.object_id}: (void)0;")
2031 end
2032 end
2033
2034 redef class AAssertExpr
2035 redef fun stmt(v)
2036 do
2037 var cond = v.expr_bool(self.n_expr)
2038 v.add("if (!{cond}) \{")
2039 v.stmt(self.n_else)
2040 var nid = self.n_id
2041 if nid != null then
2042 v.add_abort("Assert '{nid.text}' failed")
2043 else
2044 v.add_abort("Assert failed")
2045 end
2046 v.add("\}")
2047 end
2048 end
2049
2050 redef class AOrExpr
2051 redef fun expr(v)
2052 do
2053 var res = v.new_var(self.mtype.as(not null))
2054 var i1 = v.expr_bool(self.n_expr)
2055 v.add("if ({i1}) \{")
2056 v.add("{res} = 1;")
2057 v.add("\} else \{")
2058 var i2 = v.expr_bool(self.n_expr2)
2059 v.add("{res} = {i2};")
2060 v.add("\}")
2061 return res
2062 end
2063 end
2064
2065 redef class AAndExpr
2066 redef fun expr(v)
2067 do
2068 var res = v.new_var(self.mtype.as(not null))
2069 var i1 = v.expr_bool(self.n_expr)
2070 v.add("if (!{i1}) \{")
2071 v.add("{res} = 0;")
2072 v.add("\} else \{")
2073 var i2 = v.expr_bool(self.n_expr2)
2074 v.add("{res} = {i2};")
2075 v.add("\}")
2076 return res
2077 end
2078 end
2079
2080 redef class ANotExpr
2081 redef fun expr(v)
2082 do
2083 var cond = v.expr_bool(self.n_expr)
2084 return v.new_expr("!{cond}", self.mtype.as(not null))
2085 end
2086 end
2087
2088 redef class AOrElseExpr
2089 redef fun expr(v)
2090 do
2091 var res = v.new_var(self.mtype.as(not null))
2092 var i1 = v.expr(self.n_expr, null)
2093 v.add("if ({i1}!=NULL) \{")
2094 v.assign(res, i1)
2095 v.add("\} else \{")
2096 var i2 = v.expr(self.n_expr2, null)
2097 v.assign(res, i2)
2098 v.add("\}")
2099 return res
2100 end
2101 end
2102
2103 redef class AEeExpr
2104 redef fun expr(v)
2105 do
2106 var value1 = v.expr(self.n_expr, null)
2107 var value2 = v.expr(self.n_expr2, null)
2108 return v.equal_test(value1, value2)
2109 end
2110 end
2111
2112 redef class AIntExpr
2113 redef fun expr(v)
2114 do
2115 return v.new_expr("{self.n_number.text}", self.mtype.as(not null))
2116 end
2117 end
2118
2119 redef class AFloatExpr
2120 redef fun expr(v)
2121 do
2122 return v.new_expr("{self.n_float.text}", self.mtype.as(not null))
2123 end
2124 end
2125
2126 redef class ACharExpr
2127 redef fun expr(v)
2128 do
2129 return v.new_expr("{self.n_char.text}", self.mtype.as(not null))
2130 end
2131 end
2132
2133 redef class AArrayExpr
2134 redef fun expr(v)
2135 do
2136 var mtype = self.mtype.as(MGenericType).arguments.first
2137 var array = new Array[RuntimeVariable]
2138 for nexpr in self.n_exprs.n_exprs do
2139 var i = v.expr(nexpr, mtype)
2140 array.add(i)
2141 end
2142 return v.array_instance(array, mtype)
2143 end
2144 end
2145
2146 redef class AStringFormExpr
2147 redef fun expr(v)
2148 do
2149 return v.string_instance(self.value.as(not null))
2150 end
2151 end
2152
2153 redef class ASuperstringExpr
2154 redef fun expr(v)
2155 do
2156 var array = new Array[RuntimeVariable]
2157 for ne in self.n_exprs do
2158 var i = v.expr(ne, null)
2159 array.add(i)
2160 end
2161 var a = v.array_instance(array, v.object_type)
2162 var res = v.send(v.get_property("to_s", a.mtype), [a])
2163 return res
2164 end
2165 end
2166
2167 redef class ACrangeExpr
2168 redef fun expr(v)
2169 do
2170 var i1 = v.expr(self.n_expr, null)
2171 var i2 = v.expr(self.n_expr2, null)
2172 var res = v.init_instance(self.mtype.as(MClassType))
2173 var it = v.send(v.get_property("init", res.mtype), [res, i1, i2])
2174 v.check_init_instance(res)
2175 return res
2176 end
2177 end
2178
2179 redef class AOrangeExpr
2180 redef fun expr(v)
2181 do
2182 var i1 = v.expr(self.n_expr, null)
2183 var i2 = v.expr(self.n_expr2, null)
2184 var res = v.init_instance(self.mtype.as(MClassType))
2185 var it = v.send(v.get_property("without_last", res.mtype), [res, i1, i2])
2186 v.check_init_instance(res)
2187 return res
2188 end
2189 end
2190
2191 redef class ATrueExpr
2192 redef fun expr(v)
2193 do
2194 return v.new_expr("1", self.mtype.as(not null))
2195 end
2196 end
2197
2198 redef class AFalseExpr
2199 redef fun expr(v)
2200 do
2201 return v.new_expr("0", self.mtype.as(not null))
2202 end
2203 end
2204
2205 redef class ANullExpr
2206 redef fun expr(v)
2207 do
2208 var res = v.new_expr("NULL", self.mtype.as(not null))
2209 return res
2210 end
2211 end
2212
2213 redef class AIsaExpr
2214 redef fun expr(v)
2215 do
2216 var i = v.expr(self.n_expr, null)
2217 return v.type_test(i, self.cast_type.as(not null))
2218 end
2219 end
2220
2221 redef class AAsCastExpr
2222 redef fun expr(v)
2223 do
2224 var i = v.expr(self.n_expr, null)
2225 var cond = v.type_test(i, self.mtype.as(not null))
2226 v.add("if (!{cond}) \{")
2227 v.add_abort("Cast failed")
2228 v.add("\}")
2229 return i
2230 end
2231 end
2232
2233 redef class AAsNotnullExpr
2234 redef fun expr(v)
2235 do
2236 var i = v.expr(self.n_expr, null)
2237 v.add("if ({i} == NULL) \{")
2238 v.add_abort("Cast failed")
2239 v.add("\}")
2240 return i
2241 end
2242 end
2243
2244 redef class AParExpr
2245 redef fun expr(v)
2246 do
2247 return v.expr(self.n_expr, null)
2248 end
2249 end
2250
2251 redef class AOnceExpr
2252 redef fun expr(v)
2253 do
2254 var mtype = self.mtype.as(not null)
2255 var name = v.get_name("varonce")
2256 var guard = v.get_name(name + "_guard")
2257 v.add_decl("static {mtype.ctype} {name};")
2258 v.add_decl("static int {guard};")
2259 var res = v.new_var(mtype)
2260 v.add("if ({guard}) \{")
2261 v.add("{res} = {name};")
2262 v.add("\} else \{")
2263 var i = v.expr(self.n_expr, mtype)
2264 v.add("{res} = {i};")
2265 v.add("{name} = {res};")
2266 v.add("{guard} = 1;")
2267 v.add("\}")
2268 return res
2269 end
2270 end
2271
2272 redef class ASendExpr
2273 redef fun expr(v)
2274 do
2275 var recv = v.expr(self.n_expr, null)
2276 var args = [recv]
2277 for a in compute_raw_arguments do
2278 args.add(v.expr(a, null))
2279 end
2280 var mproperty = self.mproperty.as(not null)
2281 return v.send(mproperty, args)
2282 end
2283 end
2284
2285 redef class ASendReassignFormExpr
2286 redef fun stmt(v)
2287 do
2288 var recv = v.expr(self.n_expr, null)
2289 var args = [recv]
2290 for a in compute_raw_arguments do
2291 args.add(v.expr(a, null))
2292 end
2293 var value = v.expr(self.n_value, null)
2294
2295 var mproperty = self.mproperty.as(not null)
2296 var left = v.send(mproperty, args)
2297 assert left != null
2298
2299 var res = v.send(reassign_property.mproperty, [left, value])
2300 assert res != null
2301
2302 args.add(res)
2303 v.send(self.write_mproperty.as(not null), args)
2304 end
2305 end
2306
2307 redef class ASuperExpr
2308 redef fun expr(v)
2309 do
2310 var recv = v.frame.arguments.first
2311 var args = [recv]
2312 for a in self.n_args.n_exprs do
2313 args.add(v.expr(a, null))
2314 end
2315 if args.length == 1 then
2316 args = v.frame.arguments
2317 end
2318
2319 var mproperty = self.mproperty
2320 if mproperty != null then
2321 if mproperty.intro.msignature.arity == 0 then
2322 args = [recv]
2323 end
2324 # Super init call
2325 var res = v.send(mproperty, args)
2326 return res
2327 end
2328
2329 # stantard call-next-method
2330 var mpropdef = v.frame.mpropdef
2331 # FIXME: we do not want an ugly static call!
2332 var mpropdefs = mpropdef.mproperty.lookup_super_definitions(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
2333 if mpropdefs.length != 1 then
2334 debug("MPRODFEFS for super {mpropdef} for {recv}: {mpropdefs.join(", ")}")
2335 end
2336 mpropdef = mpropdefs.first
2337 assert mpropdef isa MMethodDef
2338 var res = v.call(mpropdef, recv.mtype.as(MClassType), args)
2339 return res
2340 end
2341 end
2342
2343 redef class ANewExpr
2344 redef fun expr(v)
2345 do
2346 var mproperty = self.mproperty.as(not null)
2347 var mtype = self.mtype.as(MClassType)
2348 var recv
2349 var ctype = mtype.ctype
2350 if ctype == "val*" then
2351 recv = v.init_instance(mtype)
2352 else if ctype == "void*" then
2353 recv = v.new_expr("NULL/*special!*/", mtype)
2354 else
2355 debug("cannot new {mtype}")
2356 abort
2357 end
2358 var args = [recv]
2359 for a in self.n_args.n_exprs do
2360 args.add(v.expr(a, null))
2361 end
2362 var res2 = v.send(mproperty, args)
2363 if res2 != null then
2364 #self.debug("got {res2} from {mproperty}. drop {recv}")
2365 return res2
2366 end
2367 v.check_init_instance(recv)
2368 return recv
2369 end
2370 end
2371
2372 redef class AAttrExpr
2373 redef fun expr(v)
2374 do
2375 var recv = v.expr(self.n_expr, null)
2376 var mproperty = self.mproperty.as(not null)
2377 return v.read_attribute(mproperty, recv)
2378 end
2379 end
2380
2381 redef class AAttrAssignExpr
2382 redef fun stmt(v)
2383 do
2384 var recv = v.expr(self.n_expr, null)
2385 var i = v.expr(self.n_value, null)
2386 var mproperty = self.mproperty.as(not null)
2387 v.write_attribute(mproperty, recv, i)
2388 end
2389 end
2390
2391 redef class AAttrReassignExpr
2392 redef fun stmt(v)
2393 do
2394 var recv = v.expr(self.n_expr, null)
2395 var value = v.expr(self.n_value, null)
2396 var mproperty = self.mproperty.as(not null)
2397 var attr = v.read_attribute(mproperty, recv)
2398 var res = v.send(reassign_property.mproperty, [attr, value])
2399 assert res != null
2400 v.write_attribute(mproperty, recv, res)
2401 end
2402 end
2403
2404 redef class AIssetAttrExpr
2405 end
2406
2407 redef class ADebugTypeExpr
2408 redef fun stmt(v)
2409 do
2410 # do nothing
2411 end
2412 end