icode: add I*Value classes
[nit.git] / src / syntax / icode_generation.nit
index fab9e98..0d60974 100644 (file)
@@ -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
 
@@ -345,11 +345,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 +661,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 +673,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 +685,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 +742,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
@@ -768,51 +775,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
@@ -999,21 +1008,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
 
@@ -1025,8 +1034,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)
@@ -1396,6 +1405,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