nitcc: tests script return non-zero on failure (print is not enough)
[nit.git] / src / saf / saf_base.nit
index 48f5cbf..fcc409e 100644 (file)
@@ -56,6 +56,13 @@ abstract class StaticAnalysis
        # implementation of this method is the responsability the subclass.
        fun new_initial_flow: FLOW is abstract
 
+       # Initial flow set to use within methods.
+       #
+       # Returns `new_initial_flow` by default.
+       # Redefine this method to inject things in the inset like parameters from
+       # the signature.
+       fun new_initial_method_flow(v: AMethPropdef): FLOW do return new_initial_flow
+
        # The merge operation on sets for confluence.
        #
        # Depends on the analysis performed.
@@ -156,3 +163,84 @@ redef class AIfExpr
                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
+
+redef class AMethPropdef
+       redef fun accept_forward_analysis(v) do
+               v.current_inset = v.new_initial_method_flow(self)
+               v.current_outset = v.current_inset.clone
+               v.insets[self] = v.current_inset
+               visit_all(v)
+               v.outsets[self] = v.current_outset
+       end
+end