import scope
redef class ToolContext
+ # Run `APropdef::do_flow` on each propdef
var flow_phase: Phase = new FlowPhase(self, [scope_phase])
end
redef fun process_npropdef(npropdef) do npropdef.do_flow(toolcontext)
end
-# The visitor that derermine flowcontext for nodes
+# The visitor that determine flowcontext for nodes
private class FlowVisitor
super Visitor
- var current_flow_context: FlowContext
+ var current_flow_context = new FlowContext
var toolcontext: ToolContext
- init(toolcontext: ToolContext)
+ init
do
- self.toolcontext = toolcontext
- current_flow_context = new FlowContext
flows.add(current_flow_context)
current_flow_context.is_start = true
end
- var first: nullable ANode
+ var first: nullable ANode = null
redef fun visit(node)
do
return node.after_flow_context.as(not null)
end
- var flows: Array[FlowContext] = new Array[FlowContext]
+ var flows = new Array[FlowContext]
fun printflow
do
- var file = new OFStream.open("flow.dot")
- file.write("digraph \{\n")
+ var file = new FileWriter.open("flow.dot")
+ file.write("digraph \{\nnode[shape=box];")
for f in flows do
var s = ""
if f.node isa AExpr then
end
file.write "F{f.object_id} [label=\"{f.object_id}\\n{f.node.location}\\n{f.node.class_name}\\n{f.name}{s}\"];\n"
for p in f.previous do
- file.write "F{p.object_id} -> F{f.object_id};\n"
+ s = ""
+ if f.when_true == p then s = "[label=TRUE, style=dotted]"
+ if f.when_false == p then s = "[label=FALSE, style=dotted]"
+ if f.when_true == p and f.when_false == p then s = "[label=TRUE_FALSE, style=dotted]"
+ file.write "F{p.object_id} -> F{f.object_id}{s};\n"
end
- if f.when_true != f then
- file.write "F{f.object_id} -> F{f.when_true.object_id}[label=TRUE, style=dotted];\n"
- end
- if f.when_false != f then
- file.write "F{f.object_id} -> F{f.when_false.object_id}[label=FALSE,style=dotted];\n"
+ for p in f.loops do
+ file.write "F{p.object_id} -> F{f.object_id}[label=LOOP, style=dashed, constraint=false];\n"
end
end
file.write("\}\n")
fun merge_continues_to(before_loop: FlowContext, escapemark: nullable EscapeMark)
do
if escapemark == null then return
- for b in escapemark.continues do
+ for b in escapemark.escapes do
var before = b.before_flow_context
if before == null then continue # Forward error
before_loop.add_loop(before)
fun merge_breaks(escapemark: nullable EscapeMark)
do
if escapemark == null then return
- for b in escapemark.breaks do
+ for b in escapemark.escapes do
var before = b.before_flow_context
if before == null then continue # Forward error
self.make_merge_flow(self.current_flow_context, before)
# A same `FlowContext` can be shared by more than one `ANode`.
class FlowContext
# The reachable previous flow
- var previous: Array[FlowContext] = new Array[FlowContext]
+ var previous = new Array[FlowContext]
# Additional reachable flow that loop up to self.
- # Loops apears in `loop`, `while`, `for`, and with `continue`
- var loops: Array[FlowContext] = new Array[FlowContext]
+ # Loops appears in `loop`, `while`, `for`, and with `continue`
+ var loops = new Array[FlowContext]
private var is_marked_unreachable: Bool = false
# Is the flow dead?
fun is_unreachable: Bool
do
- # Are we explicitely marked unreachable?
+ # Are we explicitly marked unreachable?
if self.is_marked_unreachable then return true
# Are we the starting flow context?
return false
end
- # Flag to avoid repeaed errors
+ # Flag to avoid repeated errors
var is_already_unreachable: Bool = false
# Mark that self is the starting flow context.
# Such a context is reachable even if there is no previous flow
var is_start: Bool = false
- # The node that introduce the flow (for debuging)
+ # The node that introduce the flow (for debugging)
var node: nullable ANode = null
- # Additional information for the flor (for debuging)
+ # Additional information for the flow (for debugging)
var name: String = ""
# The sub-flow to use if the associated expr is true
# The starting flow
- var before_flow_context: nullable FlowContext
+ var before_flow_context: nullable FlowContext is noautoinit
# The ending flow
- var after_flow_context: nullable FlowContext
+ var after_flow_context: nullable FlowContext is noautoinit
redef fun accept_flow_visitor(v)
do
end
end
-redef class AContinueExpr
- # The flow just before it become unreachable
- fun before_flow_context: nullable FlowContext
- do
- var after = self.after_flow_context
- if after == null then return null
- return after.previous.first
- end
- redef fun accept_flow_visitor(v)
- do
- super
- v.make_unreachable_flow
- end
-end
-
-redef class ABreakExpr
+redef class AEscapeExpr
# The flow just before it become unreachable
fun before_flow_context: nullable FlowContext
do
redef class ADoExpr
redef fun accept_flow_visitor(v)
do
- super
- v.merge_breaks(self.escapemark)
+ # FlowContext before the block
+ var before_block = v.make_sub_flow
+
+ # Visit the bloc, then merge the breaks
+ v.enter_visit(self.n_block)
+ v.merge_breaks(self.break_mark)
+ var after_block = v.current_flow_context
+
+ # Visit the catch if there is one
+ if self.n_catch != null then
+ var before_catch = v.make_sub_flow
+ v.make_merge_flow(before_block, after_block)
+ v.enter_visit(self.n_catch)
+ var after_catch = v.current_flow_context
+ v.make_merge_flow(before_catch, after_catch)
+ end
end
end
var after_block = v.current_flow_context
before_loop.add_loop(after_block)
- v.merge_continues_to(after_block, self.escapemark)
+ v.merge_continues_to(before_loop, self.continue_mark)
v.current_flow_context = after_expr.when_false
- v.merge_breaks(self.escapemark)
+ v.merge_breaks(self.break_mark)
end
end
var after_block = v.current_flow_context
before_loop.add_loop(after_block)
- v.merge_continues_to(after_block, self.escapemark)
+ v.merge_continues_to(before_loop, self.continue_mark)
v.make_unreachable_flow
- v.merge_breaks(self.escapemark)
+ v.merge_breaks(self.break_mark)
end
end
redef class AForExpr
redef fun accept_flow_visitor(v)
do
- v.enter_visit(self.n_expr)
+ for g in n_groups do
+ v.enter_visit(g.n_expr)
+ end
var before_loop = v.make_sub_flow
var after_block = v.current_flow_context
before_loop.add_loop(after_block)
- v.merge_continues_to(after_block, self.escapemark)
+ v.merge_continues_to(before_loop, self.continue_mark)
v.make_merge_flow(v.current_flow_context, before_loop)
- v.merge_breaks(self.escapemark)
+ v.merge_breaks(self.break_mark)
+ end
+end
+
+redef class AWithExpr
+ redef fun accept_flow_visitor(v)
+ do
+ super
+ v.merge_breaks(self.break_mark)
end
end
end
end
-redef class AProxyExpr
+redef class AParExpr
+ redef fun accept_flow_visitor(v)
+ do
+ var after_expr = v.visit_expr(self.n_expr)
+ v.current_flow_context = after_expr
+ end
+end
+
+redef class AOnceExpr
redef fun accept_flow_visitor(v)
do
var after_expr = v.visit_expr(self.n_expr)