icode: add I*Value classes
[nit.git] / src / syntax / icode_generation.nit
index b48ede4..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
 
@@ -79,12 +79,16 @@ 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
+
        init(visitor: AbsSyntaxVisitor, r: IRoutine, m: nullable MMMethod)
        do
-               super(visitor.module, r, m)
+               super(visitor.module, r)
                _visitor = visitor
                _return_seq = r.body
                _return_value = r.result
+               _method = m
        end
 
        # Insert implicit super init calls
@@ -336,16 +340,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
@@ -540,16 +551,16 @@ redef class AInternMethPropdef
                        end
                else if c == once "NativeArray".to_symbol then
                        if n == once "object_id".to_symbol then
-                               s = "TAG_Int(UNBOX_NativeArray(@@@))"
+                               s = "TAG_Int(((Nit_NativeArray)@@@)->object_id)"
                        else if n == once "[]".to_symbol then
-                               s = "UNBOX_NativeArray(@@@)[UNTAG_Int(@@@)]"
+                               s = "((Nit_NativeArray)@@@)->val[UNTAG_Int(@@@)]"
                        else if n == once "[]=".to_symbol then
-                               s = "UNBOX_NativeArray(@@@)[UNTAG_Int(@@@)]=@@@;"
+                               s = "((Nit_NativeArray)@@@)->val[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));"
+                               s = "(void)memcpy(((Nit_NativeArray )@@@)->val, ((Nit_NativeArray)@@@)->val, UNTAG_Int(@@@)*sizeof(val_t))"
                        end
                else if c == once "NativeString".to_symbol then
                        if n == once "object_id".to_symbol then
@@ -569,7 +580,7 @@ redef class AInternMethPropdef
                                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)@@@)"
+                       s = "TAG_Int((bigint)((obj_t)@@@)[1].object_id)"
                else if n == once "sys".to_symbol then
                        s = "(G_sys)"
                else if n == once "is_same_type".to_symbol then
@@ -579,10 +590,10 @@ redef class AInternMethPropdef
                        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))))"
+                       s = "NEW_NativeArray(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))))"
+                       s = "BOX_NativeString((char*)raw_alloc((UNTAG_Int(@@@) * sizeof(char))))"
                end
                if s == null then
                        v.visitor.error(self, "Fatal error: unknown intern method {method.full_name}.")
@@ -650,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
@@ -662,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
@@ -674,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
@@ -731,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
@@ -764,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
@@ -821,6 +834,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")
@@ -994,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
 
@@ -1020,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)
@@ -1391,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
@@ -1446,7 +1465,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)