icode: generate closure for 'for'
[nit.git] / src / syntax / icode_generation.nit
index f545cb5..7bb32be 100644 (file)
@@ -58,7 +58,9 @@ special ICodeBuilder
                if _variables.has_key(v) then
                        return _variables[v]
                else
-                       var reg = new_register(v.stype.as(not null))
+                       var t = v.stype
+                       if t == null then t = visitor.type_object.as_nullable
+                       var reg = new_register(t)
                        _variables[v] = reg
                        return reg
                end
@@ -345,11 +347,18 @@ redef class AClosureDecl
                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
@@ -654,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
@@ -666,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
@@ -678,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
@@ -735,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
@@ -770,49 +779,30 @@ redef class AForExpr
        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)
+               # Get iterate
+               var meth_iterate = v.visitor.get_method(expr_type, once "iterate".to_symbol)
 
-               # 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_iterate.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_iterate, [v.generate_expr(n_expr)], [iclos])
 
-               v.seq = seq_old
+               v.seq = old_seq
                return null
        end
 end
@@ -825,6 +815,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")
@@ -1395,6 +1386,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