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