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
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
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
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
# 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
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
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