transform: transforms `while` and `for`
[nit.git] / src / transform.nit
index af19ef6..50ea215 100644 (file)
@@ -17,8 +17,9 @@
 module transform
 
 import astbuilder
-import auto_super_init
 import astvalidation
+import semantize
+intrude import semantize::scope
 
 redef class ToolContext
        var transform_phase: Phase = new TransformPhase(self, [typing_phase, auto_super_init_phase])
@@ -88,13 +89,14 @@ redef class AVardeclExpr
        #
        # Declarations are only useful for scope rules
        # Once names are associated with real objects, ther declaration become useless
-       # Therefore, if there is no initial value, then just detach it
+       # Therefore, if there is no initial value, then just ignore it
        # Else, replace it with a simple assignment
        redef fun accept_transform_visitor(v)
        do
                var nexpr = n_expr
                if nexpr == null then
-                       detach
+                       # do nothing
+                       # note: not detached because the collection is currently under iteration
                else
                        var nvar = v.builder.make_var_assign(self.variable.as(not null), nexpr)
                        replace_with(nvar)
@@ -128,6 +130,13 @@ redef class AOrExpr
        end
 end
 
+redef class AImpliesExpr
+       redef fun accept_transform_visitor(v)
+       do
+               # TODO
+       end
+end
+
 redef class AAndExpr
        # `x and y` is replaced with `if x then y else x`
        redef fun accept_transform_visitor(v)
@@ -143,14 +152,78 @@ end
 redef class AWhileExpr
        redef fun accept_transform_visitor(v)
        do
-               # TODO
+               var nloop = v.builder.make_loop
+               var nif = v.builder.make_if(n_expr, null)
+               nloop.add nif
+
+               var nblock = n_block
+               if nblock != null then nif.n_then.add nblock
+
+               var escapemark = self.break_mark.as(not null)
+               var nbreak = v.builder.make_break(escapemark)
+               nif.n_else.add nbreak
+
+               nloop.break_mark = self.break_mark
+               nloop.continue_mark = self.continue_mark
+
+               replace_with(nloop)
        end
 end
 
 redef class AForExpr
        redef fun accept_transform_visitor(v)
        do
-               # TODO
+               var escapemark = self.break_mark
+               assert escapemark != null
+
+               var nblock = v.builder.make_block
+
+               var nexpr = n_expr
+
+               nblock.add nexpr
+
+               var iter = v.builder.make_call(nexpr.make_var_read, method_iterator.as(not null), null)
+               nblock.add iter
+
+               var nloop = v.builder.make_loop
+               nloop.break_mark = escapemark
+               nblock.add nloop
+
+               var is_ok = v.builder.make_call(iter.make_var_read, method_is_ok.as(not null), null)
+
+               var nif = v.builder.make_if(is_ok, null)
+               nloop.add nif
+
+               var nthen = nif.n_then
+               var ndo = v.builder.make_do
+               ndo.break_mark = escapemark.continue_mark
+               nthen.add ndo
+
+               if self.variables.length == 1 then
+                       var item = v.builder.make_call(iter.make_var_read, method_item.as(not null), null)
+                       ndo.add v.builder.make_var_assign(variables.first, item)
+               else if self.variables.length == 2 then
+                       var key = v.builder.make_call(iter.make_var_read, method_key.as(not null), null)
+                       ndo.add v.builder.make_var_assign(variables[0], key)
+                       var item = v.builder.make_call(iter.make_var_read, method_item.as(not null), null)
+                       ndo.add v.builder.make_var_assign(variables[1], item)
+               else
+                       abort
+               end
+
+               ndo.add self.n_block.as(not null)
+
+               nthen.add v.builder.make_call(iter.make_var_read, method_next.as(not null), null)
+
+               var nbreak = v.builder.make_break(escapemark)
+               nif.n_else.add nbreak
+
+               var method_finish = self.method_finish
+               if method_finish != null then
+                       nblock.add v.builder.make_call(iter.make_var_read, method_finish, null)
+               end
+
+               replace_with(nblock)
        end
 end
 
@@ -163,16 +236,13 @@ redef class AArrayExpr
        #     t
        redef fun accept_transform_visitor(v)
        do
-               var mtype = self.mtype.as(MClassType)
                var nblock = v.builder.make_block
 
-               var meth = v.get_method(self, "with_capacity", mtype.mclass)
-               var nnew = v.builder.make_new(mtype, meth, [v.builder.make_int(n_exprs.n_exprs.length)])
+               var nnew = v.builder.make_new(with_capacity_callsite.as(not null), [v.builder.make_int(n_exprs.n_exprs.length)])
                nblock.add nnew
 
-               var madd = v.get_method(self, "push", mtype.mclass)
                for nexpr in self.n_exprs.n_exprs do
-                       var nadd = v.builder.make_call(nnew.make_var_read, madd, [nexpr])
+                       var nadd = v.builder.make_call(nnew.make_var_read, push_callsite.as(not null), [nexpr])
                        nblock.add nadd
                end
                var nres = nnew.make_var_read
@@ -182,45 +252,12 @@ redef class AArrayExpr
        end
 end
 
-redef class ASuperstringExpr
-       # `"x{y}z"` is replaced with
-       #
-       #     var t = new Array[Object].with_capacity(3)
-       #     t.add("x")
-       #     t.add(y)
-       #     t.add("z")
-       #     t.to_s
-       redef fun accept_transform_visitor(v)
-       do
-               var nblock = v.builder.make_block
-
-               var arraytype = v.get_class(self, "Array").get_mtype([v.get_class(self, "Object").mclass_type])
-               var meth = v.get_method(self, "with_capacity", arraytype.mclass)
-               var nnew = v.builder.make_new(arraytype, meth, [v.builder.make_int(n_exprs.length)])
-               nblock.add nnew
-
-               var madd = v.get_method(self, "add", arraytype.mclass)
-               for nexpr in self.n_exprs do
-                       var nadd = v.builder.make_call(nnew.make_var_read, madd, [nexpr])
-                       nblock.add nadd
-               end
-
-               var mtos = v.get_method(self, "to_s", arraytype.mclass)
-               var ntos = v.builder.make_call(nnew.make_var_read, mtos, null)
-               nblock.add ntos
-
-               replace_with(nblock)
-       end
-end
-
 redef class ACrangeExpr
        # `[x..y]` is replaced with `new Range[X](x,y)`
        redef fun accept_transform_visitor(v)
        do
-               var mtype = self.mtype.as(MClassType)
-               var meth = v.get_method(self, "init", mtype.mclass)
-
-               replace_with(v.builder.make_new(mtype, meth, [n_expr, n_expr2]))
+               if parent isa AForExpr then return # to permit shortcut ranges
+               replace_with(v.builder.make_new(init_callsite.as(not null), [n_expr, n_expr2]))
        end
 end
 
@@ -228,10 +265,8 @@ redef class AOrangeExpr
        # `[x..y[` is replaced with `new Range[X].without_last(x,y)`
        redef fun accept_transform_visitor(v)
        do
-               var mtype = self.mtype.as(MClassType)
-               var meth = v.get_method(self, "without_last", mtype.mclass)
-
-               replace_with(v.builder.make_new(mtype, meth, [n_expr, n_expr2]))
+               if parent isa AForExpr then return # to permit shortcut ranges
+               replace_with(v.builder.make_new(init_callsite.as(not null), [n_expr, n_expr2]))
        end
 end
 
@@ -258,18 +293,18 @@ redef class ASendReassignFormExpr
 
                var read_args = new Array[AExpr]
                var write_args = new Array[AExpr]
-               for a in raw_arguments.as(not null) do
+               for a in raw_arguments do
                        nblock.add(a)
                        read_args.add(a.make_var_read)
                        write_args.add(a.make_var_read)
                end
 
-               var nread = v.builder.make_call(n_expr.make_var_read, callsite.mproperty, read_args)
+               var nread = v.builder.make_call(n_expr.make_var_read, callsite.as(not null), read_args)
 
-               var nnewvalue = v.builder.make_call(nread, reassign_callsite.mproperty, [n_value])
+               var nnewvalue = v.builder.make_call(nread, reassign_callsite.as(not null), [n_value])
 
                write_args.add(nnewvalue)
-               var nwrite = v.builder.make_call(n_expr.make_var_read, write_callsite.mproperty, write_args)
+               var nwrite = v.builder.make_call(n_expr.make_var_read, write_callsite.as(not null), write_args)
                nblock.add(nwrite)
 
                replace_with(nblock)
@@ -282,8 +317,9 @@ redef class AVarReassignExpr
        do
                var variable = self.variable.as(not null)
 
-               var nread = v.builder.make_var_read(variable)
-               var nnewvalue = v.builder.make_call(nread, reassign_callsite.mproperty, [n_value])
+               var nread = v.builder.make_var_read(variable, read_type.as(not null))
+
+               var nnewvalue = v.builder.make_call(nread, reassign_callsite.as(not null), [n_value])
                var nwrite = v.builder.make_var_assign(variable, nnewvalue)
 
                replace_with(nwrite)
@@ -299,7 +335,7 @@ redef class AAttrReassignExpr
                var attribute = self.mproperty.as(not null)
 
                var nread = v.builder.make_attr_read(n_expr.make_var_read, attribute)
-               var nnewvalue = v.builder.make_call(nread, reassign_callsite.mproperty, [n_value])
+               var nnewvalue = v.builder.make_call(nread, reassign_callsite.as(not null), [n_value])
                var nwrite = v.builder.make_attr_assign(n_expr.make_var_read, attribute, nnewvalue)
                nblock.add(nwrite)