X-Git-Url: http://nitlanguage.org diff --git a/src/compiling/compiling_icode.nit b/src/compiling/compiling_icode.nit index 5374ac8..3238811 100644 --- a/src/compiling/compiling_icode.nit +++ b/src/compiling/compiling_icode.nit @@ -94,7 +94,7 @@ class I2CCompilerVisitor end # The rank (number) of each closure - readable var _closures: HashMap[IClosureDecl, Int] = new HashMap[IClosureDecl, Int] + readable var _closures: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String] # The functionnal type of each closure readable var _clostypes: HashMap[IClosureDecl, String] = new HashMap[IClosureDecl, String] @@ -159,14 +159,28 @@ class I2CCompilerVisitor visitor.add_decl(s) end - fun add_instr(s: String) + # Prepare a new instuction (indent, comment) + # Caller must ensure to add a new line to finish its instr + fun new_instr: Writer do + var w = visitor.writer var l = _next_location if l != null then - visitor.add_instr("/* ", l.file, ":", l.line_start.to_s, " */") + visitor.add_indent(w) + w.add("/* ") + w.add(l.file) + w.add(":") + w.add(l.line_start.to_s) + w.add(" */\n") _next_location = null end - visitor.add_instr(s) + visitor.add_indent(w) + return w + end + + fun add_instr(s: String) + do + new_instr.add(s).add("\n") end fun indent @@ -252,10 +266,10 @@ redef class IRoutine else p = cparams.join(", ") end - if human_name != null then v.add_decl("#define LOCATE_", cname, " \"", human_name, "\"") - v.add_decl(r, " ", cname, "(", p, ");") - v.add_decl("typedef ", r, " (*", cname, "_t)(", p, ");") - v.add_instr(r, " ", cname, "(", p, ")\{") + if human_name != null then v.add_decl("static const char * const LOCATE_{cname} = \"{human_name}\";") + v.add_decl("{r} {cname}({p});") + v.add_decl("typedef {r} (*{cname}_t)({p});") + v.add_instr("{r} {cname}({p})\{") v.indent return cargs end @@ -275,7 +289,7 @@ redef class IRoutine v.add_decl("struct \{struct stack_frame_t me;\} fra;") end v.add_instr("fra.me.prev = stack_frame_head; stack_frame_head = &fra.me;") - v.add_instr("fra.me.file = LOCATE_{v.visitor.module.name};") + v.add_instr("fra.me.file = LOCATE_{v.visitor.mmmodule.name};") v.add_instr("fra.me.line = {ll};") v.add_instr("fra.me.meth = LOCATE_{v.basecname};") v.add_instr("fra.me.has_broke = 0;") @@ -303,7 +317,7 @@ redef class IRoutine for i in [0..iclosdecls.length[ do var iclosdecl = iclosdecls[i] v.add_instr("CREG[{i}] = {args[params.length+i]};") - v.closures[iclosdecl] = i + v.closures[iclosdecl] = i.to_s var cs = iclosdecl.closure.signature # Closure signature var subparams = new Array[String] # Parameters of the closure subparams.add("struct stack_frame_t *") @@ -346,11 +360,7 @@ end redef class ICode # Full compilation of the icode - fun compile_to_c(v: I2CCompilerVisitor) - do - v.add_location(location) - store_result(v, inner_compile_to_c(v)) - end + fun compile_to_c(v: I2CCompilerVisitor) is abstract # Is a result really needed private fun need_result: Bool @@ -360,28 +370,46 @@ redef class ICode end # Store s in the result value of self - private fun store_result(v: I2CCompilerVisitor, s: nullable String) + private fun store_result(v: I2CCompilerVisitor, w: nullable Writer) do var r = result if r != null and r.slot_index != null then - assert s != null - v.add_assignment(v.register(r), s) - else if s != null and not is_pure then + assert w != null + var w2 = v.new_instr + w2.add(v.register(r)) + w2.add(" = ") + w2.append(w) + w2.add(";\n") + else if w != null and not is_pure then # ICode with side effects must be evaluated # even if the result is not wanted - v.add_instr(s + ";") + var w2 = v.new_instr + w2.append(w) + w2.add(";\n") end end - # Compilation of without the result assigment - # Return the right value is case of expression - # Return the full expression (witout ;) in case of statement - private fun inner_compile_to_c(v: I2CCompilerVisitor): nullable String is abstract + # Prepare a writer if the expression icode need to be compiled + # * Result assigment is automatic if needed + private fun new_result(v: I2CCompilerVisitor): Writer + do + assert need_result or not is_pure + var w2 = v.new_instr + var r = result + if r != null and r.slot_index != null then + w2.add(v.register(r)) + w2.add(" = ") + end + var w = w2.sub + w2.add(";\n") + return w + end end redef class ISeq - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do + v.add_location(location) v.local_labels.add(self) var mark = iescape_mark if mark != null then v.marks_to_seq[mark] = self @@ -389,33 +417,36 @@ redef class ISeq ic.compile_to_c(v) end v.add_label(self) - return null end end redef class IIf - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do - v.add_instr("if (UNTAG_Bool({v.register(expr)})) \{") + v.add_location(location) + var w = v.new_instr + w.add("if (UNTAG_Bool(") + w.add(v.register(expr)) + w.add(")) \{\n") if not then_seq.icodes.is_empty then v.indent - then_seq.inner_compile_to_c(v) + then_seq.compile_to_c(v) v.unindent end if not else_seq.icodes.is_empty then - v.add_instr("} else \{") + v.add_instr("\} else \{") v.indent - else_seq.inner_compile_to_c(v) + else_seq.compile_to_c(v) v.unindent end - v.add_instr("}") - return null + v.add_instr("\}") end end redef class ILoop - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do + v.add_location(location) v.local_labels.add(self) var mark = iescape_mark if mark != null then v.marks_to_seq[mark] = self @@ -425,17 +456,16 @@ redef class ILoop ic.compile_to_c(v) end v.unindent - v.add_instr("}") + v.add_instr("\}") v.add_label(self) - return null end end redef class IEscape - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do + v.add_location(location) v.add_goto(v.marks_to_seq[iescape_mark]) - return null end end @@ -475,8 +505,8 @@ redef class IAbsCall end # Compile the real call - var s = compile_call_to_c(v, args) - var r: nullable String = s + var call = compile_call_to_c(v, args) + var res: nullable Writer = call # Intercept escapes if closctx != null then @@ -485,15 +515,21 @@ redef class IAbsCall # Is there possible escapes? if not els.is_empty then # Call in a tmp variable to avoid 'break' overwrite + var w = v.new_instr if need_result then - r = "tmp" - v.add_assignment(r, s) + w.add("tmp") + w.add(" = ") + w.append(call) + w.add(";\n") + res = new Writer + res.add("tmp") else - r = null - v.add_instr(s + ";") + res = null + w.append(call) + w.add(";\n") end # What are the expected escape indexes - v.add_instr("switch ({closctx}->has_broke) \{") + v.new_instr.add("switch (").add(closctx).add("->has_broke) \{\n") v.indent # No escape occured, continue as usual v.add_instr("case 0: break;") @@ -505,7 +541,7 @@ redef class IAbsCall if lls.has(seq) then # Local escape occured # Clear the has_broke information and go to the target - v.add_instr("case {iels.item}: {closctx}->has_broke = 0; goto {v.lab(seq)};") + v.new_instr.add("case ").add(iels.item.to_s).add(": ").add(closctx).add("->has_broke = 0; goto ").add(v.lab(seq)).add(";\n") else # Forward escape occured: register the escape label assert v.closure @@ -518,32 +554,36 @@ redef class IAbsCall if forward_escape then # Do not need to copy 'has_broke' value since it is shared by the next one. # So just exit the C function. - v.add_instr("default: goto {v.lab(v.return_label.as(not null))};") + v.new_instr.add("default: goto ").add(v.lab(v.return_label.as(not null))).add(";\n") end v.unindent v.add_instr("\}") end end - store_result(v, r) + if res != null then + var w = new_result(v) + w.append(res) + end end - redef fun inner_compile_to_c(v) do abort - # The single invocation witout fancy stuffs - private fun compile_call_to_c(v: I2CCompilerVisitor, args: Array[String]): String is abstract + private fun compile_call_to_c(v: I2CCompilerVisitor, args: Array[String]): Writer is abstract end redef class ICall redef fun compile_call_to_c(v, args) do + var w = new Writer var prop = property if prop.global.is_init then args.add("init_table") - if prop.name == (once ("add".to_symbol)) and prop.local_class.name == (once ("Array".to_symbol)) then - return "{prop.cname}({args.join(", ")})" - else - return "{prop.global.meth_call}({args[0]})({args.join(", ")})" - end + w.add(prop.global.meth_call) + w.add("(") + w.add(args.first) + w.add(")(") + w.add_all(args, ", ") + w.add(")") + return w end end @@ -552,35 +592,66 @@ redef class ISuper do var prop = property if prop.global.is_init then args.add("init_table") - return "{prop.super_meth_call}({args[0]})({args.join(", ")})" + var w = new Writer + w.add(prop.super_meth_call) + w.add("(") + w.add(args.first) + w.add(")(") + w.add_all(args, ", ") + w.add(")") + return w end end redef class INew redef fun compile_call_to_c(v, args) do - return "NEW_{stype.local_class}_{property.global.intro.cname}({args.join(", ")})" + var w = new Writer + w.add("NEW_") + w.add(stype.local_class.to_s) + w.add("_") + w.add(property.global.intro.cname) + w.add("(") + w.add_all(args, ", ") + w.add(")") + return w end end redef class IAllocateInstance - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do - return "NEW_{stype.local_class.name}()" + v.add_location(location) + var w = new_result(v) + w.add("NEW_") + w.add(stype.local_class.name.to_s) + w.add("()") end end redef class ICheckInstance - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do - return "CHECKNEW_{stype.local_class.name}({v.register(expr)})" + v.add_location(location) + var w = new_result(v) + w.add("CHECKNEW_") + w.add(stype.local_class.name.to_s) + w.add("(") + w.add(v.register(expr)) + w.add(")") end end redef class IInitAttributes - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do - return "INIT_ATTRIBUTES__{stype.local_class.name}({v.register(expr)})" + v.add_location(location) + var w = v.new_instr + w.add("INIT_ATTRIBUTES__") + w.add(stype.local_class.name.to_s) + w.add("(") + w.add(v.register(expr)) + w.add(");\n") end end @@ -589,150 +660,485 @@ redef class IStaticCall do var prop = property if prop.global.is_init then args.add("init_table") - return "{property.cname}({args.join(", ")})" + var w = new Writer + w.add(property.cname) + w.add("(") + w.add_all(args, ", ") + w.add(")") + return w end end redef class INative - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do - if exprs.is_empty then - return code + v.add_location(location) + if method.is_intern then + compile_intern_method_to_c(v) else - var res = new Buffer - var i = 0 - var c = code.split_with("@@@") - for s in c do - res.append(s) - if i < exprs.length and i < c.length-1 then - res.append(v.register(exprs[i])) - end - i += 1 + compile_extern_method_to_c(v) + end + end + + fun compile_extern_method_to_c(v: I2CCompilerVisitor) + do + var ename = method.extern_name.as(not null)#"{method.module.name}_{method.local_class.name}_{method.local_class.name}_{method.name}_{method.signature.arity}" + var sig = method.signature + assert exprs.length == sig.arity + 1 + + var regs = v.registers(exprs) + + var args = new Array[String] + args.add(sig.recv.unboxtype(regs[0])) + for i in [0..sig.arity[ do + args.add(sig[i].unboxtype(regs[i+1])) + end + var s = "{ename}({args.join(", ")})" + + if need_result then s = sig.return_type.boxtype(s) + var w = new_result(v) + w.add(s) + end + + fun compile_intern_method_to_c(v: I2CCompilerVisitor) + do + var sig = method.signature + assert exprs.length == sig.arity + 1 + var c = method.local_class.name + var n = method.name + var regs = v.registers(exprs) + var s: nullable String = null + if c == once "Int".to_symbol then + if n == once "object_id".to_symbol then + s = regs[0] + else if n == once "unary -".to_symbol then + s = "TAG_Int(-UNTAG_Int({regs[0]}))" + else if n == once "output".to_symbol then + s = "printf(\"%ld\\n\", UNTAG_Int({regs[0]}));" + else if n == once "ascii".to_symbol then + s = "TAG_Char(UNTAG_Int({regs[0]}))" + else if n == once "succ".to_symbol then + s = "TAG_Int(UNTAG_Int({regs[0]})+1)" + else if n == once "prec".to_symbol then + s = "TAG_Int(UNTAG_Int({regs[0]})-1)" + else if n == once "to_f".to_symbol then + s = "BOX_Float((float)UNTAG_Int({regs[0]}))" + else if n == once "+".to_symbol then + s = "TAG_Int(UNTAG_Int({regs[0]})+UNTAG_Int({regs[1]}))" + else if n == once "-".to_symbol then + s = "TAG_Int(UNTAG_Int({regs[0]})-UNTAG_Int({regs[1]}))" + else if n == once "*".to_symbol then + s = "TAG_Int(UNTAG_Int({regs[0]})*UNTAG_Int({regs[1]}))" + else if n == once "/".to_symbol then + s = "TAG_Int(UNTAG_Int({regs[0]})/UNTAG_Int({regs[1]}))" + else if n == once "%".to_symbol then + s = "TAG_Int(UNTAG_Int({regs[0]})%UNTAG_Int({regs[1]}))" + else if n == once "<".to_symbol then + s = "TAG_Bool(UNTAG_Int({regs[0]})".to_symbol then + s = "TAG_Bool(UNTAG_Int({regs[0]})>UNTAG_Int({regs[1]}))" + else if n == once "<=".to_symbol then + s = "TAG_Bool(UNTAG_Int({regs[0]})<=UNTAG_Int({regs[1]}))" + else if n == once ">=".to_symbol then + s = "TAG_Bool(UNTAG_Int({regs[0]})>=UNTAG_Int({regs[1]}))" + else if n == once "lshift".to_symbol then + s = "TAG_Int(UNTAG_Int({regs[0]})<".to_symbol then + s = "TAG_Bool(UNBOX_Float({regs[0]})>UNBOX_Float({regs[1]}))" + else if n == once "<=".to_symbol then + s = "TAG_Bool(UNBOX_Float({regs[0]})<=UNBOX_Float({regs[1]}))" + else if n == once ">=".to_symbol then + s = "TAG_Bool(UNBOX_Float({regs[0]})>=UNBOX_Float({regs[1]}))" + end + else if c == once "Char".to_symbol then + if n == once "object_id".to_symbol then + s = "TAG_Int(UNTAG_Char({regs[0]}))" + else if n == once "unary -".to_symbol then + s = "TAG_Char(-UNTAG_Char({regs[0]}))" + else if n == once "output".to_symbol then + s = "printf(\"%c\", (unsigned char)UNTAG_Char({regs[0]}));" + else if n == once "ascii".to_symbol then + s = "TAG_Int((unsigned char)UNTAG_Char({regs[0]}))" + else if n == once "succ".to_symbol then + s = "TAG_Char(UNTAG_Char({regs[0]})+1)" + else if n == once "prec".to_symbol then + s = "TAG_Char(UNTAG_Char({regs[0]})-1)" + else if n == once "to_i".to_symbol then + s = "TAG_Int(UNTAG_Char({regs[0]})-'0')" + else if n == once "+".to_symbol then + s = "TAG_Char(UNTAG_Char({regs[0]})+UNTAG_Char({regs[1]}))" + else if n == once "-".to_symbol then + s = "TAG_Char(UNTAG_Char({regs[0]})-UNTAG_Char({regs[1]}))" + else if n == once "*".to_symbol then + s = "TAG_Char(UNTAG_Char({regs[0]})*UNTAG_Char({regs[1]}))" + else if n == once "/".to_symbol then + s = "TAG_Char(UNTAG_Char({regs[0]})/UNTAG_Char({regs[1]}))" + else if n == once "%".to_symbol then + s = "TAG_Char(UNTAG_Char({regs[0]})%UNTAG_Char({regs[1]}))" + else if n == once "<".to_symbol then + s = "TAG_Bool(UNTAG_Char({regs[0]})".to_symbol then + s = "TAG_Bool(UNTAG_Char({regs[0]})>UNTAG_Char({regs[1]}))" + else if n == once "<=".to_symbol then + s = "TAG_Bool(UNTAG_Char({regs[0]})<=UNTAG_Char({regs[1]}))" + else if n == once ">=".to_symbol then + s = "TAG_Bool(UNTAG_Char({regs[0]})>=UNTAG_Char({regs[1]}))" + else if n == once "==".to_symbol then + s = "TAG_Bool(({regs[0]})==({regs[1]}))" + else if n == once "!=".to_symbol then + s = "TAG_Bool(({regs[0]})!=({regs[1]}))" + end + else if c == once "Bool".to_symbol then + if n == once "object_id".to_symbol then + s = "TAG_Int(UNTAG_Bool({regs[0]}))" + else if n == once "unary -".to_symbol then + s = "TAG_Bool(-UNTAG_Bool({regs[0]}))" + else if n == once "output".to_symbol then + s = "(void)printf(UNTAG_Bool({regs[0]})?\"true\\n\":\"false\\n\");" + else if n == once "ascii".to_symbol then + s = "TAG_Bool(UNTAG_Bool({regs[0]}))" + else if n == once "to_i".to_symbol then + s = "TAG_Int(UNTAG_Bool({regs[0]}))" + else if n == once "==".to_symbol then + s = "TAG_Bool(({regs[0]})==({regs[1]}))" + else if n == once "!=".to_symbol then + s = "TAG_Bool(({regs[0]})!=({regs[1]}))" end - return res.to_s + else if c == once "NativeArray".to_symbol then + if n == once "object_id".to_symbol then + s = "TAG_Int(((Nit_NativeArray){regs[0]})->object_id)" + else if n == once "[]".to_symbol then + s = "((Nit_NativeArray){regs[0]})->val[UNTAG_Int({regs[1]})]" + else if n == once "[]=".to_symbol then + s = "((Nit_NativeArray){regs[0]})->val[UNTAG_Int({regs[1]})]={regs[2]}" + else if n == once "copy_to".to_symbol then + s = "(void)memcpy(((Nit_NativeArray ){regs[1]})->val, ((Nit_NativeArray){regs[0]})->val, UNTAG_Int({regs[2]})*sizeof(val_t))" + end + else if c == once "NativeString".to_symbol then + if n == once "object_id".to_symbol then + s = "TAG_Int(UNBOX_NativeString({regs[0]}))" + else if n == once "atoi".to_symbol then + s = "TAG_Int(atoi(UNBOX_NativeString({regs[0]})))" + else if n == once "[]".to_symbol then + s = "TAG_Char(UNBOX_NativeString({regs[0]})[UNTAG_Int({regs[1]})])" + else if n == once "[]=".to_symbol then + s = "UNBOX_NativeString({regs[0]})[UNTAG_Int({regs[1]})]=UNTAG_Char({regs[2]});" + else if n == once "copy_to".to_symbol then + s = "(void)memcpy(UNBOX_NativeString({regs[1]})+UNTAG_Int({regs[4]}), UNBOX_NativeString({regs[0]})+UNTAG_Int({regs[3]}), UNTAG_Int({regs[2]}));" + end + else if n == once "object_id".to_symbol then + s = "TAG_Int((bigint)((obj_t){regs[0]})[1].object_id)" + else if n == once "sys".to_symbol then + s = "(G_sys)" + else if n == once "is_same_type".to_symbol then + s = "TAG_Bool((VAL2VFT({regs[0]})==VAL2VFT({regs[1]})))" + else if n == once "exit".to_symbol then + s = "exit(UNTAG_Int({regs[1]}));" + else if n == once "calloc_array".to_symbol then + s = "NEW_NativeArray(UNTAG_Int({regs[1]}), sizeof(val_t))" + else if n == once "calloc_string".to_symbol then + s = "BOX_NativeString((char*)raw_alloc((UNTAG_Int({regs[1]}) * sizeof(char))))" + end + if s == null then + var ll = location + if ll != null then v.add_instr("fprintf(stderr, \"{ll.to_s}: \");") + v.add_instr("fprintf(stderr, \"Fatal error: unknown intern method {method.full_name}.\\n\");") + v.add_instr("nit_exit(1);") + s = "NIT_NULL" end + if result == null then + v.new_instr.add(s).add(";\n") + else if need_result then + var w = new_result(v) + w.add(s) + end + end +end + +redef class IIntValue + redef fun compile_to_c(v) + do + v.add_location(location) + var w = new_result(v) + w.add("TAG_Int(").add(value.to_s).add(")") + end +end + +redef class IBoolValue + redef fun compile_to_c(v) + do + v.add_location(location) + var w = new_result(v) + w.add("TAG_Bool(") + if value then w.add("true") else w.add("false") + w.add(")") + end +end + +redef class ICharValue + redef fun compile_to_c(v) + do + v.add_location(location) + var w = new_result(v) + w.add("TAG_Char(").add(value).add(")") + end +end + +redef class IFloatValue + redef fun compile_to_c(v) + do + v.add_location(location) + var w = new_result(v) + w.add("BOX_Float(").add(value).add(")") + end +end + +redef class IStringValue + redef fun compile_to_c(v) + do + v.add_location(location) + var w = new_result(v) + w.add("BOX_NativeString(\"").add(value).add("\")") end end redef class IAbort - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do - var s = new Buffer.from("fprintf(stderr") - for t in texts do - s.append(", \"{t}\"") + v.add_location(location) + var w = v.new_instr + w.add("nit_abort(\"") + w.add(texts[0]) + if texts.length > 1 then + w.add("\", \"") + w.add(texts[1]) + w.add("\"") + else + w.add("\", NULL") end - s.append(");") - v.add_instr(s.to_s) - + w.add(", LOCATE_") + w.add(module_location.name.to_s) var ll = location - s = new Buffer.from("fprintf(stderr, \" (%s") - if ll != null then - s.append(":%d") - end - s.append(")\\n\", LOCATE_{module_location.name}") if ll != null then - s.append(", {ll.line_start}") + w.add(", ") + w.add(ll.line_start.to_s) + else + w.add(", 0") end - s.append(");") - v.add_instr(s.to_s) - - v.add_instr("nit_exit(1);") - return null + w.add(");\n") end end redef class IMove - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do - return v.register(expr) + if not need_result then return + var e = v.register(expr) + var r = v.register(result.as(not null)) + if e == r then return + v.add_location(location) + var w = v.new_instr + w.add(r) + w.add(" = ") + w.add(e) + w.add(";\n") end end redef class IAttrRead - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do - return "{property.global.attr_access}({v.register(expr)})" + if not need_result then return + v.add_location(location) + var w = new_result(v) + w.add(property.global.attr_access) + w.add("(") + w.add(v.register(expr)) + w.add(")") end end redef class IAttrIsset - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do - return "TAG_Bool({property.global.attr_access}({v.register(expr)})!=NIT_NULL)" + if not need_result then return + v.add_location(location) + var w = new_result(v) + w.add("TAG_Bool(") + w.add(property.global.attr_access) + w.add("(") + w.add(v.register(expr)) + w.add(")!=NIT_NULL)") end end redef class IAttrWrite - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do - v.add_instr("{property.global.attr_access}({v.register(expr1)}) = {v.register(expr2)};") - return null + v.add_location(location) + var w = v.new_instr + w.add(property.global.attr_access) + w.add("(") + w.add(v.register(expr1)) + w.add(") = ") + w.add(v.register(expr2)) + w.add(";\n") end end redef class ITypeCheck - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do - # FIXME handle formaltypes - var g = stype.local_class.global - var recv = v.register(expr) - var s = "" - if expr.stype.is_nullable then + if not need_result then return + v.add_location(location) + var recv = v.register(expr2) + var w = new_result(v) + w.add("TAG_Bool(") + if expr2.stype.is_nullable then if stype.is_nullable then - s = "({recv}==NIT_NULL) || " - else if stype.as_nullable == expr.stype then - return "TAG_Bool({recv}!=NIT_NULL)" + w.add("(") + w.add(recv) + w.add("==NIT_NULL) || ") + else if stype.as_nullable == expr2.stype then + w.add(recv) + w.add("!=NIT_NULL)") + return else - s = "({recv}!=NIT_NULL) && " + w.add("(") + w.add(recv) + w.add("!=NIT_NULL) && ") end end - return "TAG_Bool({s}VAL_ISA({recv}, {g.color_id}, {g.id_id})) /*cast {stype}*/" + # FIXME handle formaltypes + var t = stype + if t isa MMVirtualType then + var slf = v.register(expr1) + var g = t.property.global + w.add("VAL_ISA(") + w.add(recv) + w.add(", ") + w.add(g.vt_class_color) + w.add("(") + w.add(slf) + w.add(")") + w.add(", ") + w.add(g.vt_class_id) + w.add("(") + w.add(slf) + w.add(")") + w.add(")) /*cast ") + w.add(t.to_s) + w.add("*/") + else + var g = t.local_class.global + w.add("VAL_ISA(") + w.add(recv) + w.add(", ") + w.add(g.color_id) + w.add(", ") + w.add(g.id_id) + w.add(")) /*cast ") + w.add(t.to_s) + w.add("*/") + end end end redef class IIs - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do + if not need_result then return + v.add_location(location) + var w = new_result(v) + w.add("TAG_Bool(") var t1 = expr1.stype var t2 = expr2.stype if t1 isa MMTypeNone then if t2 isa MMTypeNone then - return "TAG_Bool(1)" + w.add("1)") + return else if t2.is_nullable then - return "TAG_Bool({v.register(expr2)}==NIT_NULL)" + w.add(v.register(expr2)) + w.add("==NIT_NULL)") + return else - return "TAG_Bool(0)" + w.add("0)") + return end else if t1.is_nullable then if t2 isa MMTypeNone then - return "TAG_Bool({v.register(expr1)}==NIT_NULL)" + w.add(v.register(expr1)) + w.add("==NIT_NULL)") + return else if t2.is_nullable then - return "TAG_Bool(IS_EQUAL_NN({v.register(expr1)},{v.register(expr2)}))" + w.add("IS_EQUAL_NN(") else - return "TAG_Bool(IS_EQUAL_ON({v.register(expr2)},{v.register(expr1)}))" + w.add("IS_EQUAL_ON(") + w.add(v.register(expr2)) + w.add(",") + w.add(v.register(expr1)) + w.add("))") + return end else if t2 isa MMTypeNone then - return "TAG_Bool(0)" + w.add("0)") + return else if t2.is_nullable then - return "TAG_Bool(IS_EQUAL_ON({v.register(expr1)},{v.register(expr2)}))" + w.add("IS_EQUAL_ON(") else - return "TAG_Bool(IS_EQUAL_OO({v.register(expr1)},{v.register(expr2)}))" + w.add("IS_EQUAL_OO(") end end + w.add(v.register(expr1)) + w.add(",") + w.add(v.register(expr2)) + w.add("))") end end redef class INot - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do - return "TAG_Bool(!UNTAG_Bool({v.register(expr)}))" + if not need_result then return + v.add_location(location) + var w = new_result(v) + w.add("TAG_Bool(!UNTAG_Bool(") + w.add(v.register(expr)) + w.add("))") end end redef class IOnce - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do + v.add_location(location) var i = v.new_number var res = result.as(not null) if res.stype.is_nullable then @@ -745,13 +1151,14 @@ redef class IOnce end v.indent body.compile_to_c(v) - var e = v.register(result.as(not null)) + var e = v.register(res) v.add_instr("once_value_{i} = {e};") v.add_instr("register_static_object(&once_value_{i});") if res.stype.is_nullable then v.add_instr("once_bool_{i} = true;") v.unindent - v.add_instr("} else {e} = once_value_{i};") - return e + v.add_instr("\} else {e} = once_value_{i};") + var w = new_result(v) + w.add(e) end end @@ -771,7 +1178,9 @@ redef class IClosCall args.append(v.registers(exprs)) var s = "(({v.clostypes[closure_decl]})({ivar}))({args.join(", ")})" - store_result(v, s) + var w = new Writer + w.add(s) + store_result(v, w) # Intercept escape v.add_instr("if ({args.first}->has_broke) \{") @@ -784,20 +1193,25 @@ redef class IClosCall v.unindent v.add_instr("\}") end - - redef fun inner_compile_to_c(v) do abort end redef class IHasClos - redef fun inner_compile_to_c(v) + redef fun compile_to_c(v) do - var ivar: String + if not need_result then return + v.add_location(location) + var w = new_result(v) + w.add("TAG_Bool(") if v.closure then - ivar = "closctx->closure_funs[{v.closures[closure_decl]}]" + w.add("closctx->closure_funs[") + w.add(v.closures[closure_decl]) + w.add("]") else - ivar = "CREG[{v.closures[closure_decl]}]" + w.add("CREG[") + w.add(v.closures[closure_decl]) + w.add("]") end - return "TAG_Bool({ivar} != NULL)" + w.add(" != NULL)") end end @@ -817,28 +1231,28 @@ redef class IClosureDef v.local_labels = new HashSet[ISeq] # We are now in a new C context - var ctx_old = cv.ctx - cv.ctx = new CContext - cv.out_contexts.add(cv.ctx) + var decl_writer_old = cv.decl_writer + var writer_old = cv.writer + cv.writer = cv.top_writer.sub + cv.decl_writer = cv.header_writer.sub # Generate the C function var cname = "OC_{v.basecname}_{v.new_number}" var args = compile_signature_to_c(v.visitor, cname, null, "struct stack_frame_t *closctx", null) - var ctx_old2 = cv.ctx - cv.ctx = new CContext + cv.decl_writer = cv.writer.sub + var s = compile_inside_to_c(v, args) if s == null then v.add_instr("return;") else v.add_instr("return {s};") end - ctx_old2.append(cv.ctx) - cv.ctx = ctx_old2 v.unindent - v.add_instr("}") + v.add_instr("\}") # Restore things - cv.ctx = ctx_old + cv.writer = writer_old + cv.decl_writer = decl_writer_old v.closure = cfc_old v.local_labels = lls_old return "((fun_t){cname})"