transform: move up shortcut-range from abstract_compiler to transform
[nit.git] / src / transform.nit
index 50ea215..6c8208a 100644 (file)
@@ -23,6 +23,15 @@ intrude import semantize::scope
 
 redef class ToolContext
        var transform_phase: Phase = new TransformPhase(self, [typing_phase, auto_super_init_phase])
+
+       # --no-shortcut-range
+       var opt_no_shortcut_range: OptionBool = new OptionBool("Always insantiate a range and its iterator on 'for' loops", "--no-shortcut-range")
+
+       redef init
+       do
+               super
+               self.option_context.add_option(self.opt_no_shortcut_range)
+       end
 end
 
 private class TransformPhase
@@ -180,6 +189,41 @@ redef class AForExpr
 
                var nexpr = n_expr
 
+               # Shortcut on explicit range
+               # Avoid the instantiation of the range and the iterator
+               if self.variables.length == 1 and nexpr isa ARangeExpr and not v.phase.toolcontext.opt_no_shortcut_range.value then
+                       var variable = variables.first
+                       nblock.add v.builder.make_var_assign(variable, nexpr.n_expr)
+                       var to = nexpr.n_expr2
+                       nblock.add to
+
+                       var nloop = v.builder.make_loop
+                       nloop.break_mark = escapemark
+                       nblock.add nloop
+
+                       var is_ok = v.builder.make_call(v.builder.make_var_read(variable, variable.declared_type.as(not null)), method_lt.as(not null), [to.make_var_read])
+
+                       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
+
+                       ndo.add self.n_block.as(not null)
+
+                       var one = v.builder.make_int(1)
+                       var succ = v.builder.make_call(v.builder.make_var_read(variable, variable.declared_type.as(not null)), method_successor.as(not null), [one])
+                       nthen.add v.builder.make_var_assign(variable, succ)
+
+                       var nbreak = v.builder.make_break(escapemark)
+                       nif.n_else.add nbreak
+
+                       replace_with(nblock)
+                       return
+               end
+
                nblock.add nexpr
 
                var iter = v.builder.make_call(nexpr.make_var_read, method_iterator.as(not null), null)