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