X-Git-Url: http://nitlanguage.org diff --git a/src/syntax/icode_generation.nit b/src/syntax/icode_generation.nit index 08466d9..af61111 100644 --- a/src/syntax/icode_generation.nit +++ b/src/syntax/icode_generation.nit @@ -354,6 +354,11 @@ redef class AClosureDecl 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 @@ -658,7 +663,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 @@ -670,7 +675,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 @@ -682,7 +687,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 @@ -739,7 +744,7 @@ 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 @@ -772,51 +777,53 @@ end redef class AForExpr 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) + 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 - # Process insite the loop (condition is true) - v.stmt(iif) - v.seq = iif.then_seq - escapable.continue_seq = iif.then_seq + # Build closure + var iclos = meth.signature.closures.first.signature.generate_empty_iclosuredef(v) + var old_seq = v.seq - # 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) + var seq = new ISeq + v.stmt(seq) + v.seq = seq + escapable.break_seq = seq + escapable.break_value = null - # Body evaluation + v.seq = iclos.body + escapable.continue_seq = iclos.body + escapable.continue_value = null + v.stmt(new IMove(v.variable(variable), iclos.params.first)) v.generate_stmt(n_block) - # Exit contition (condition is false) - v.seq = iif.else_seq - v.stmt(new IEscape(iloop)) - - # 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])) + # Call closure + v.seq = seq + v.add_call(meth, args, [iclos]) - v.seq = seq_old + v.seq = old_seq return null end end @@ -1400,6 +1407,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