X-Git-Url: http://nitlanguage.org diff --git a/src/syntax/icode_generation.nit b/src/syntax/icode_generation.nit index b87f91c..260d1e5 100644 --- a/src/syntax/icode_generation.nit +++ b/src/syntax/icode_generation.nit @@ -24,7 +24,7 @@ private import primitive_info # An AST2ICode context stores the currently built icode informations class A2IContext -special ICodeBuilder + super ICodeBuilder redef fun stmt(s: ICode) do if _current_node != null then @@ -39,7 +39,7 @@ special ICodeBuilder fun add_new_array(stype: MMType, length: Int): IRegister do var prop = visitor.get_method(stype, once "with_capacity".to_symbol) - var ni = expr(new INative("TAG_Int({length})", null), visitor.type_int) + var ni = expr(new IIntValue(length.to_s), visitor.type_int) return expr(new INew(stype, prop, [ni]), stype) end @@ -79,12 +79,19 @@ special ICodeBuilder # Register where a functionnal nit return must store its value readable writable var _return_value: nullable IRegister + # The method associated to the iroutine (if any) + readable var _method: nullable MMMethod + + # The register of self (if any) + var selfreg: nullable IRegister writable + init(visitor: AbsSyntaxVisitor, r: IRoutine, m: nullable MMMethod) do - super(visitor.module, r, m) + super(visitor.mmmodule, r) _visitor = visitor _return_seq = r.body _return_value = r.result + _method = m end # Insert implicit super init calls @@ -115,17 +122,17 @@ special ICodeBuilder end var l = n.super_init_calls.length while i < l do - var p = n.super_init_calls[i] - if p == stop_prop then break + var sp = n.super_init_calls[i] + if sp == stop_prop then break var cargs = new Array[IRegister] - if p.signature.arity == 0 then + if sp.signature.arity == 0 then cargs.add(iroutine.params.first) else for va in iroutine.params do cargs.add(va) end end - stmt(new ICall(p, cargs)) + stmt(new ICall(sp, cargs)) i += 1 end end @@ -275,7 +282,7 @@ redef class MMImplicitInit end class A2IVisitor -special AbsSyntaxVisitor + super AbsSyntaxVisitor writable var _icode_ctx: nullable A2IContext fun icode_ctx: A2IContext do return _icode_ctx.as(not null) redef fun visit(n) do n.accept_icode_generation(self) @@ -314,7 +321,7 @@ redef class AMethPropdef end redef class ASignature - fun fill_iroutine_parameters(v: A2IContext, orig_sig: MMSignature, params: IndexedCollection[IRegister], closdecls: nullable IndexedCollection[IClosureDecl]) + fun fill_iroutine_parameters(v: A2IContext, orig_sig: MMSignature, params: Sequence[IRegister], closdecls: nullable Sequence[IClosureDecl]) do for ap in n_params do var reg = v.variable(ap.variable) @@ -336,16 +343,23 @@ redef class AClosureDecl redef fun accept_icode_generation(vv) do var v = vv.icode_ctx - var iclos = variable.closure.signature.generate_empty_iclosuredef + var iclos = variable.closure.signature.generate_empty_iclosuredef(v) var old_seq = v.seq v.seq = iclos.body escapable.continue_seq = iclos.body escapable.continue_value = iclos.result + escapable.break_seq = v.return_seq + escapable.break_value = v.return_value n_signature.fill_iroutine_parameters(v, variable.closure.signature, iclos.params, null) if n_expr != null then v.generate_stmt(n_expr) v.iroutine.closure_decls[position].default = iclos + + # Add a final break in case of break block witout value + if variable.closure.is_break and v.return_value == null then + v.add_escape(v.return_seq.as(not null)) + end end v.seq = old_seq end @@ -357,6 +371,7 @@ redef class AConcreteMethPropdef var params = v.iroutine.params.to_a var selfreg = v.variable(self_var) v.stmt(new IMove(selfreg, params[0])) + v.selfreg = selfreg params.shift var orig_meth: MMLocalProperty = method.global.intro @@ -372,6 +387,7 @@ redef class AConcreteMethPropdef if n_block != null then v.generate_stmt(n_block) end + v.selfreg = null end end @@ -386,25 +402,11 @@ redef class AExternMethPropdef redef fun fill_iroutine(v, method) do var params = v.iroutine.params - var ename = "{method.module.name}_{method.local_class.name}_{method.local_class.name}_{method.name}_{method.signature.arity}" - if n_extern != null then - ename = n_extern.text - ename = ename.substring(1, ename.length-2) - end - var sig = method.signature - assert params.length == sig.arity + 1 - var args = new Array[String] - args.add(sig.recv.unboxtype("@@@")) - for i in [0..sig.arity[ do - args.add(sig[i].unboxtype("@@@")) - end - var s = "{ename}({args.join(", ")})" - var rtype = sig.return_type + var rtype = method.signature.return_type if rtype != null then - s = rtype.boxtype(s) - v.add_return_value(v.expr(new INative(s, params), rtype)) + v.add_return_value(v.expr(new INative(method, params), rtype)) else - v.stmt(new INative(s, params)) + v.stmt(new INative(method, params)) end end end @@ -412,187 +414,12 @@ end redef class AInternMethPropdef redef fun fill_iroutine(v, method) do - var p = v.iroutine.params.to_a - var c = method.local_class.name - var n = method.name - var s: nullable String = null - if c == once "Int".to_symbol then - if n == once "object_id".to_symbol then - s = "@@@" - else if n == once "unary -".to_symbol then - s = "TAG_Int(-UNTAG_Int(@@@))" - else if n == once "output".to_symbol then - s = "printf(\"%ld\\n\", UNTAG_Int(@@@));" - else if n == once "ascii".to_symbol then - s = "TAG_Char(UNTAG_Int(@@@))" - else if n == once "succ".to_symbol then - s = "TAG_Int(UNTAG_Int(@@@)+1)" - else if n == once "prec".to_symbol then - s = "TAG_Int(UNTAG_Int(@@@)-1)" - else if n == once "to_f".to_symbol then - s = "BOX_Float((float)UNTAG_Int(@@@))" - else if n == once "+".to_symbol then - s = "TAG_Int(UNTAG_Int(@@@)+UNTAG_Int(@@@))" - else if n == once "-".to_symbol then - s = "TAG_Int(UNTAG_Int(@@@)-UNTAG_Int(@@@))" - else if n == once "*".to_symbol then - s = "TAG_Int(UNTAG_Int(@@@)*UNTAG_Int(@@@))" - else if n == once "/".to_symbol then - s = "TAG_Int(UNTAG_Int(@@@)/UNTAG_Int(@@@))" - else if n == once "%".to_symbol then - s = "TAG_Int(UNTAG_Int(@@@)%UNTAG_Int(@@@))" - else if n == once "<".to_symbol then - s = "TAG_Bool(UNTAG_Int(@@@)".to_symbol then - s = "TAG_Bool(UNTAG_Int(@@@)>UNTAG_Int(@@@))" - else if n == once "<=".to_symbol then - s = "TAG_Bool(UNTAG_Int(@@@)<=UNTAG_Int(@@@))" - else if n == once ">=".to_symbol then - s = "TAG_Bool(UNTAG_Int(@@@)>=UNTAG_Int(@@@))" - else if n == once "lshift".to_symbol then - s = "TAG_Int(UNTAG_Int(@@@)<".to_symbol then - s = "TAG_Bool(UNBOX_Float(@@@)>UNBOX_Float(@@@))" - else if n == once "<=".to_symbol then - s = "TAG_Bool(UNBOX_Float(@@@)<=UNBOX_Float(@@@))" - else if n == once ">=".to_symbol then - s = "TAG_Bool(UNBOX_Float(@@@)>=UNBOX_Float(@@@))" - end - else if c == once "Char".to_symbol then - if n == once "object_id".to_symbol then - s = "TAG_Int(UNTAG_Char(@@@))" - else if n == once "unary -".to_symbol then - s = "TAG_Char(-UNTAG_Char(@@@))" - else if n == once "output".to_symbol then - s = "printf(\"%c\", (unsigned char)UNTAG_Char(@@@));" - else if n == once "ascii".to_symbol then - s = "TAG_Int((unsigned char)UNTAG_Char(@@@))" - else if n == once "succ".to_symbol then - s = "TAG_Char(UNTAG_Char(@@@)+1)" - else if n == once "prec".to_symbol then - s = "TAG_Char(UNTAG_Char(@@@)-1)" - else if n == once "to_i".to_symbol then - s = "TAG_Int(UNTAG_Char(@@@)-'0')" - else if n == once "+".to_symbol then - s = "TAG_Char(UNTAG_Char(@@@)+UNTAG_Char(@@@))" - else if n == once "-".to_symbol then - s = "TAG_Char(UNTAG_Char(@@@)-UNTAG_Char(@@@))" - else if n == once "*".to_symbol then - s = "TAG_Char(UNTAG_Char(@@@)*UNTAG_Char(@@@))" - else if n == once "/".to_symbol then - s = "TAG_Char(UNTAG_Char(@@@)/UNTAG_Char(@@@))" - else if n == once "%".to_symbol then - s = "TAG_Char(UNTAG_Char(@@@)%UNTAG_Char(@@@))" - else if n == once "<".to_symbol then - s = "TAG_Bool(UNTAG_Char(@@@)".to_symbol then - s = "TAG_Bool(UNTAG_Char(@@@)>UNTAG_Char(@@@))" - else if n == once "<=".to_symbol then - s = "TAG_Bool(UNTAG_Char(@@@)<=UNTAG_Char(@@@))" - else if n == once ">=".to_symbol then - s = "TAG_Bool(UNTAG_Char(@@@)>=UNTAG_Char(@@@))" - else if n == once "==".to_symbol then - s = "TAG_Bool((@@@)==(@@@))" - else if n == once "!=".to_symbol then - s = "TAG_Bool((@@@)!=(@@@))" - end - else if c == once "Bool".to_symbol then - if n == once "object_id".to_symbol then - s = "TAG_Int(UNTAG_Bool(@@@))" - else if n == once "unary -".to_symbol then - s = "TAG_Bool(-UNTAG_Bool(@@@))" - else if n == once "output".to_symbol then - s = "(void)printf(UNTAG_Bool(@@@)?\"true\\n\":\"false\\n\");" - else if n == once "ascii".to_symbol then - s = "TAG_Bool(UNTAG_Bool(@@@))" - else if n == once "to_i".to_symbol then - s = "TAG_Int(UNTAG_Bool(@@@))" - else if n == once "==".to_symbol then - s = "TAG_Bool((@@@)==(@@@))" - else if n == once "!=".to_symbol then - s = "TAG_Bool((@@@)!=(@@@))" - end - else if c == once "NativeArray".to_symbol then - if n == once "object_id".to_symbol then - s = "TAG_Int(UNBOX_NativeArray(@@@))" - else if n == once "[]".to_symbol then - s = "UNBOX_NativeArray(@@@)[UNTAG_Int(@@@)]" - else if n == once "[]=".to_symbol then - s = "UNBOX_NativeArray(@@@)[UNTAG_Int(@@@)]=@@@;" - else if n == once "copy_to".to_symbol then - var t = p[0] - p[0] = p[1] - p[1] = t - s = "(void)memcpy(UNBOX_NativeArray(@@@), UNBOX_NativeArray(@@@), UNTAG_Int(@@@)*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(@@@))" - else if n == once "atoi".to_symbol then - s = "TAG_Int(atoi(UNBOX_NativeString(@@@)))" - else if n == once "[]".to_symbol then - s = "TAG_Char(UNBOX_NativeString(@@@)[UNTAG_Int(@@@)])" - else if n == once "[]=".to_symbol then - s = "UNBOX_NativeString(@@@)[UNTAG_Int(@@@)]=UNTAG_Char(@@@);" - else if n == once "copy_to".to_symbol then - var t = p[0] - p[0] = p[1] - p[1] = p[4] - p[4] = p[2] - p[2] = t - s = "(void)memcpy(UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNBOX_NativeString(@@@)+UNTAG_Int(@@@), UNTAG_Int(@@@));" - end - else if n == once "object_id".to_symbol then - s = "TAG_Int((bigint)@@@)" - 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(@@@)==VAL2VFT(@@@)))" - else if n == once "exit".to_symbol then - p[0] = p[1] - s = "exit(UNTAG_Int(@@@));" - else if n == once "calloc_array".to_symbol then - p[0] = p[1] - s = "BOX_NativeArray((val_t*)malloc((UNTAG_Int(@@@) * sizeof(val_t))))" - else if n == once "calloc_string".to_symbol then - p[0] = p[1] - s = "BOX_NativeString((char*)malloc((UNTAG_Int(@@@) * sizeof(char))))" - end - if s == null then - v.visitor.error(self, "Fatal error: unknown intern method {method.full_name}.") - s = "NIT_NULL" - end + var params = v.iroutine.params var rtype = method.signature.return_type if rtype != null then - v.add_return_value(v.expr(new INative(s, p), rtype)) + v.add_return_value(v.expr(new INative(method, params), rtype)) else - v.stmt(new INative(s, p)) + v.stmt(new INative(method, params)) end end end @@ -650,7 +477,7 @@ redef class AReturnExpr if ne != null then v.add_assignment(v.return_value.as(not null), v.generate_expr(ne)) end - v.stmt(new IEscape(v.return_seq.as(not null))) + v.add_escape(v.return_seq.as(not null)) return null end end @@ -662,7 +489,7 @@ redef class ABreakExpr if ne != null then v.add_assignment(escapable.break_value.as(not null), v.generate_expr(ne)) end - v.stmt(new IEscape(escapable.break_seq.as(not null))) + v.add_escape(escapable.break_seq.as(not null)) return null end end @@ -674,7 +501,7 @@ redef class AContinueExpr if ne != null then v.add_assignment(escapable.continue_value.as(not null), v.generate_expr(ne)) end - v.stmt(new IEscape(escapable.continue_seq.as(not null))) + v.add_escape(escapable.continue_seq.as(not null)) return null end end @@ -731,61 +558,88 @@ redef class AWhileExpr # Process escape (condition is false) v.seq = iif.else_seq - v.stmt(new IEscape(iloop)) + v.add_escape(iloop) v.seq = seq_old return null end end -redef class AForExpr +redef class ALoopExpr redef fun generate_icode(v) do - var expr_type = n_expr.stype - - # Get iterator - var meth_iterator = v.visitor.get_method(expr_type, once "iterator".to_symbol) - - var iter_type = meth_iterator.signature_for(expr_type).return_type.as(not null) - var ireg_iter = v.expr(new ICall(meth_iterator, [v.generate_expr(n_expr)]), iter_type) - - # Enter loop var seq_old = v.seq var iloop = new ILoop v.stmt(iloop) escapable.break_seq = iloop v.seq = iloop - # Condition evaluation - var meth_is_ok = v.visitor.get_method(iter_type, once ("is_ok".to_symbol)) - var ireg_isok = v.expr(new ICall(meth_is_ok, [ireg_iter]), v.visitor.type_bool) - var iif = new IIf(ireg_isok) + # Process inside + if n_block != null then + var seq = new ISeq + v.stmt(seq) + v.seq = seq + escapable.continue_seq = seq + v.generate_stmt(n_block) + end - # Process insite the loop (condition is true) - v.stmt(iif) - v.seq = iif.then_seq - escapable.continue_seq = iif.then_seq + v.seq = seq_old + return null + end +end - # Automatic variable assignment - var meth_item = v.visitor.get_method(iter_type, once ("item".to_symbol)) - var va_stype = variable.stype.as(not null) - var ireg_item = v.expr(new ICall(meth_item, [ireg_iter]), va_stype) - var ireg_va = v.variable(variable) - v.add_assignment(ireg_va, ireg_item) +redef class AForExpr + redef fun generate_icode(v) + do + var ne = n_expr + var expr_type = ne.stype + var tint = v.visitor.type_int + var meth # The method that call the closure + var args # The arguments of meth + + if ne isa ARangeExpr and expr_type == v.visitor.type_range(tint) then + # Shortcut. No Range[Int] object allocated. + # 'for x in [y..z] do' become 'y.enumerate_to(z) !each(x) do' + # 'for x in [y..z[ do' become 'y.enumerate_before(z) !each(x) do' + # And both methods may be inlined + args = [v.generate_expr(ne.n_expr), v.generate_expr(ne.n_expr2)] + if ne isa ACrangeExpr then + meth = v.visitor.get_method(tint, once "enumerate_to".to_symbol) + else + assert ne isa AOrangeExpr + meth = v.visitor.get_method(tint, once "enumerate_before".to_symbol) + end + else + # Standard way. + # 'for x in e do' become 'e.iterate !each(x) do' + # Some iterate methods may be inlined (eg. the Array one) + meth = v.visitor.get_method(expr_type, once "iterate".to_symbol) + args = [v.generate_expr(n_expr)] + end - # Body evaluation - v.generate_stmt(n_block) + # Build closure + var iclos = meth.signature.closures.first.signature.generate_empty_iclosuredef(v) + var old_seq = v.seq - # Exit contition (condition is false) - v.seq = iif.else_seq - v.stmt(new IEscape(iloop)) + var seq = new ISeq + v.stmt(seq) + v.seq = seq + escapable.break_seq = seq + escapable.break_value = null - # Next step - var meth_next = v.visitor.get_method(iter_type, once ("next".to_symbol)) - v.seq = iloop - v.stmt(new ICall(meth_next, [ireg_iter])) + v.seq = iclos.body + escapable.continue_seq = iclos.body + escapable.continue_value = null + for i in [0..variables.length[ do + v.stmt(new IMove(v.variable(variables[i]), iclos.params[i])) + end + v.generate_stmt(n_block) - v.seq = seq_old + # Call closure + v.seq = seq + v.add_call(meth, args, [iclos]) + + v.seq = old_seq return null end end @@ -798,6 +652,7 @@ redef class AAssertExpr v.stmt(iif) var seq_old = v.seq v.seq = iif.else_seq + v.generate_stmt(n_else) var id = n_id if id == null then v.add_abort("Assert failed") @@ -928,11 +783,41 @@ redef class ANotExpr end end +redef class AOrElseExpr + redef fun generate_icode(v) + do + # Compute left operand + var e = v.generate_expr(n_expr) + + # Prepare result + var reg = v.new_register(stype) + + # Compare left and null + var n = v.lit_null_reg + var c = v.expr(new IIs(e, n), v.mmmodule.type_bool) + var iif = new IIf(c) + v.stmt(iif) + var old_seq = v.seq + + # if equal, result = right opr + v.seq = iif.then_seq + v.add_assignment(reg, v.generate_expr(n_expr2)) + + # else, result = left operand + v.seq = iif.else_seq + v.add_assignment(reg, e) + + v.seq = old_seq + + return reg + end +end + redef class AIsaExpr redef fun generate_icode(v) do var e = v.generate_expr(n_expr) - return v.expr(new ITypeCheck(e, n_type.stype), stype) + return v.expr(new ITypeCheck(v.selfreg.as(not null), e, n_type.stype), stype) end end @@ -971,21 +856,21 @@ end redef class AIntExpr redef fun generate_icode(v) do - return v.expr(new INative("TAG_Int({n_number.text})", null), stype) + return v.expr(new IIntValue(n_number.text), stype) end end redef class AFloatExpr redef fun generate_icode(v) do - return v.expr(new INative("BOX_Float({n_float.text})", null), stype) + return v.expr(new IFloatValue(n_float.text), stype) end end redef class ACharExpr redef fun generate_icode(v) do - return v.expr(new INative("TAG_Char({n_char.text})", null), stype) + return v.expr(new ICharValue(n_char.text), stype) end end @@ -997,8 +882,8 @@ redef class AStringFormExpr var ionce = new IOnce var reg = v.expr(ionce, stype) v.seq = ionce.body - var ns = v.expr(new INative("BOX_NativeString(\"{_cstring}\")", null), v.visitor.type_nativestring) - var ni = v.expr(new INative("TAG_Int({_cstring_length})", null), v.visitor.type_int) + var ns = v.expr(new IStringValue(_cstring.as(not null)), v.visitor.type_nativestring) + var ni = v.expr(new IIntValue(_cstring_length.to_s), v.visitor.type_int) var prop = v.visitor.get_method(stype, once "with_native".to_symbol) var e = v.expr(new INew(stype, prop, [ns, ni]), stype) v.add_assignment(reg, e) @@ -1137,7 +1022,7 @@ redef class ASuperExpr return null end else - var p = prop + p = prop var rtype = p.signature.return_type if rtype == null then v.stmt(new ISuper(p, args)) @@ -1368,6 +1253,11 @@ redef class AClosureDef v.generate_stmt(n_expr) + # Add a final break in case of break block witout value + if closure.is_break and escapable.break_value == null then + v.add_escape(escapable.break_seq.as(not null)) + end + v.seq = seq_old _iclosure_def = iclos return iclos @@ -1423,7 +1313,7 @@ redef class AClosureCallExpr v.add_assignment(r, r2) end v.seq = iif.else_seq - var r3 = closdecl_default.inline_in_seq(iif.else_seq, args) + var r3 = v.inline_routine(closdecl_default, args, null) if r != null then assert r3 != null v.add_assignment(r, r3)