package org.scribble.visit.wf.env; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.scribble.sesstype.name.RecVar; import org.scribble.visit.env.Env; public class ReachabilityEnv extends Env<ReachabilityEnv> { private boolean seqable; // For checking bad sequencing of unreachable code: false after a continue; true if choice has an exit (false inherited for all other constructs) private final Set<RecVar> contlabs; // For checking "reachable code" satisfies tail recursion (in the presence of sequencing) public ReachabilityEnv() { this(true, Collections.emptySet()); } protected ReachabilityEnv(boolean seqable, Set<RecVar> contlabs) { this.contlabs = new HashSet<RecVar>(contlabs); this.seqable = seqable; } @Override public ReachabilityEnv copy() { return new ReachabilityEnv(this.seqable, this.contlabs); } @Override public ReachabilityEnv enterContext() { return copy(); } // Should not be used for single block choice @Override public ReachabilityEnv mergeContext(ReachabilityEnv child) { return mergeContexts(Arrays.asList(child)); } // Should not be used for Choice @Override public ReachabilityEnv mergeContexts(List<ReachabilityEnv> children) { return merge(false, children); } public ReachabilityEnv mergeForChoice(List<ReachabilityEnv> children) { return merge(true, children); } // Does merge depend on choice/par etc? private ReachabilityEnv merge(boolean isChoice, List<ReachabilityEnv> children) { ReachabilityEnv copy = copy(); copy.seqable = (isChoice) ? children.stream().filter((e) -> e.seqable).count() > 0 : children.stream().filter((e) -> !e.seqable).count() == 0; children.stream().forEach((e) -> copy.contlabs.addAll(e.contlabs)); return copy; } // i.e. control flow has the potential to exit from this context public boolean isSequenceable() { return this.seqable && this.contlabs.isEmpty(); } public ReachabilityEnv addContinueLabel(RecVar recvar) { ReachabilityEnv copy = copy(); copy.seqable = false; copy.contlabs.add(recvar); return copy; } public ReachabilityEnv removeContinueLabel(RecVar recvar) { ReachabilityEnv copy = copy(); copy.contlabs.remove(recvar); return copy; } }