From 226e7222076ee031c49ed7911e579e56ce579e96 Mon Sep 17 00:00:00 2001 From: Jean Privat Date: Tue, 6 Oct 2015 21:33:19 -0400 Subject: [PATCH] transform: rewrite the AFor transformation to handle multi-iterators Signed-off-by: Jean Privat --- src/transform.nit | 108 ++++++++++++++++++++++++++++------------------------- 1 file changed, 58 insertions(+), 50 deletions(-) diff --git a/src/transform.nit b/src/transform.nit index 838b9bc..de99e26 100644 --- a/src/transform.nit +++ b/src/transform.nit @@ -213,89 +213,97 @@ redef class AForExpr var escapemark = self.break_mark assert escapemark != null + # Main block that will contain the whole for and will replace `self` var nblock = v.builder.make_block + # Part before the loop + var before = v.builder.make_block + nblock.add before + + # The loop + var nloop = v.builder.make_loop + nloop.break_mark = escapemark + nblock.add nloop + + # Part before the body inside the loop + var begin = v.builder.make_block + nloop.add begin + + # The `do` block with then user code + var ndo = v.builder.make_do + ndo.break_mark = escapemark.continue_mark + nloop.add ndo + + ndo.add self.n_block.as(not null) + + # Fill up each part + for g in n_groups do + g.transform_in(v, before, begin, nloop, nblock, escapemark) + end + + replace_with(nblock) + end +end + +redef class AForGroup + private fun transform_in(v: TransformVisitor, before, begin, next, finish: AExpr, escapemark: EscapeMark) + do 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 + # Before: evaluate bounds var variable = variables.first - nblock.add v.builder.make_var_assign(variable, nexpr.n_expr) + before.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 + before.add to + # Begin: check variable 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) + begin.add nif + nif.n_else.add v.builder.make_break(escapemark) + # Next: increment one 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) + next.add v.builder.make_var_assign(variable, succ) return end - nblock.add nexpr - + # Before: evaluate expr, make the iterator + before.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 + before.add iter + # Begin: check iterator `is_ok` 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 + begin.add nif + nif.n_else.add v.builder.make_break(escapemark) - 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 + # Begin: assign automatic variables + if 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 + begin.add v.builder.make_var_assign(variables.first, item) + else if 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) + begin.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) + begin.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) + # Next: call next + next.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 + # Finish: call finish + var method_finish = method_finish if method_finish != null then - nblock.add v.builder.make_call(iter.make_var_read, method_finish, null) + finish.add v.builder.make_call(iter.make_var_read, method_finish, null) end - - replace_with(nblock) end end -- 1.7.9.5