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