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