nitsaf: add loop flow set merge
[nit.git] / src / saf / saf_base.nit
index 806b711..26d55ba 100644 (file)
@@ -131,3 +131,99 @@ redef class ANode
                v.outsets[self] = v.current_outset
        end
 end
+
+redef class AIfExpr
+
+       # Merge flow on if .. else constructs.
+       redef fun accept_forward_analysis(v) do
+               v.enter_visit(n_expr)
+               var inset = v.current_inset
+               var outset = v.current_outset
+
+               if n_then != null then v.enter_visit(n_then)
+               var then_outset = v.current_outset
+
+               v.current_inset = inset
+               v.current_outset = outset
+
+               if n_else != null then
+                       v.enter_visit(n_else)
+                       outset = v.merge(then_outset, v.current_outset)
+               else
+                       outset = v.merge(then_outset, v.current_inset)
+               end
+               v.current_inset = inset
+               v.current_outset = outset
+       end
+end
+
+# Represent all kind of `do .. end` blocks.
+#
+# Used to factorize implementations across do blocks, whiles, fors and loops.
+#
+# This factorization makes sense since all these contructs can be flow managed
+# through contine and breack statements.
+#
+# TODO move this up in the module hierarchy
+interface ADoBlockHelper
+       # Lookup fix point for this loop.
+       fun loop_fix_point(v: StaticAnalysis, node: ANode) do
+               var inset = v.current_inset.clone
+               var last: nullable FlowSet = null
+               while v.current_outset != last do
+                       v.enter_visit(node)
+                       v.current_inset = v.merge(inset, v.current_outset)
+                       v.current_outset = v.current_inset.clone
+                       last = v.current_outset.clone
+               end
+               v.current_inset = inset
+               v.current_outset = v.merge(inset, v.current_outset)
+       end
+
+       # Factorize loop forward analysis.
+       fun accept_loop_forward_analysis(v: StaticAnalysis) do
+               var n_block = loop_block
+               if not n_block == null then loop_fix_point(v, n_block)
+       end
+
+       # The block contained by this loop.
+       fun loop_block: nullable ANode is abstract
+end
+
+redef class ADoExpr
+       super ADoBlockHelper
+
+       redef fun loop_block do return self.n_block
+       redef fun accept_forward_analysis(v) do accept_loop_forward_analysis(v)
+end
+
+redef class ALoopExpr
+       super ADoBlockHelper
+
+       redef fun loop_block do return self.n_block
+       redef fun accept_forward_analysis(v) do accept_loop_forward_analysis(v)
+end
+
+redef class AWhileExpr
+       super ADoBlockHelper
+
+       redef fun loop_block do return self.n_block
+
+       redef fun accept_forward_analysis(v) do
+               v.enter_visit(n_expr)
+               accept_loop_forward_analysis(v)
+       end
+end
+
+redef class AForExpr
+       super ADoBlockHelper
+
+       redef fun loop_block do return self.n_block
+
+       redef fun accept_forward_analysis(v) do
+               for n_group in n_groups do
+                       v.enter_visit(n_group.n_expr)
+               end
+               accept_loop_forward_analysis(v)
+       end
+end