package programReduction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import ast.Ast.Position;
import ast.Ast;
import ast.Ast.C;
import ast.Ast.Path;
import ast.Ast.Type;
import ast.ErrorMessage;
import ast.ErrorMessage.IncompleteClassIsRequired;
import ast.ErrorMessage.PathMetaOrNonExistant;
import ast.ExpCore;
import ast.ExpCore.Block;
import ast.ExpCore.ClassB;
import ast.ExpCore.MCall;
import ast.ExpCore.ClassB.Member;
import ast.ExpCore.ClassB.MethodImplemented;
import ast.ExpCore.ClassB.MethodWithType;
import ast.ExpCore.ClassB.NestedClass;
import ast.ExpCore.ClassB.Phase;
import coreVisitors.CollectClassBs0;
import coreVisitors.CollectPaths0;
import coreVisitors.FindPathUsage;
import coreVisitors.IsCompiled;
import coreVisitors.PropagatorVisitor;
import sugarVisitors.CollapsePositions;
import tools.Assertions;
class PathsPaths{
public PathsPaths(Paths left, Paths right) {
this.left = left;this.right = right;
}
final Paths left; final Paths right;}
public class UsedPaths {
static PathsPaths usedPathsECatchErrors(Program p, ExpCore e){
try{return usedPathsE(p,e);}
catch(PathMetaOrNonExistant pne){
if (pne.getWherePathWasWritten()==null){
assert pne.getListOfNodeNames()!=null;
Position pos=FindPathUsage._locate(p,e,Path.outer(1,pne.getListOfNodeNames()));
pne=pne.withWherePathWasWritten(pos);
}
throw pne.withPos(CollapsePositions.of(e));
}
catch(IncompleteClassIsRequired icir){
throw icir.withE(e).withPos(CollapsePositions.of(e));
}
}
static PathsPaths usedPathsE(Program p, ExpCore e){
//- usedPathsE(p,eC)= <reorganize(Ps); usedPathsFix(p,paths, empty)>
//assert that the result includes paths in usedPathsFix(p,paths, empty)
//Ps,Ps'={P|P inside eC}//arbitrary split of the set; heuristic will apply in the implementation.
List<Ast.Path> psBoth=CollectPaths0.of(e);//collect all paths
List<Ast.Path> ps1;
try{ps1=collectNotAnyPaths(p,e);}
catch(ErrorMessage.PathMetaOrNonExistant pne){
throw Assertions.codeNotReachable();
}
//L1..Ln={L| L inside eC}//in path not prime// not repeat check stage
List<ClassB> l1n = CollectClassBs0.of(e);
//paths'=usedPathsFix(p,reorganize(Ps'), empty,Coherent)
Paths paths1 = Paths.reorganize(ps1);
paths1 = usedPathsFix(p,paths1,Collections.emptyList(),Phase.Coherent);
assert paths1.checkAllDefined(p);
//paths0=reorganize(Ps,Ps') U paths' U (deepImplements(L1)U..U deepImplements(Ln)).pop()
//paths=usedPathsFix(p,paths0, empty,Typed)
Paths paths0= Paths.reorganize(psBoth).union(paths1);
Paths acc=Paths.empty();
for(ClassB li:l1n){
acc=acc.union(deepImplements(li));
}
paths0=paths0.union(acc.pop());
Paths paths=usedPathsFix(p,paths0,Collections.emptyList(),Phase.Typed);
assert paths.checkAllDefined(p);
PathsPaths result= new PathsPaths(paths.setMinus(paths1),paths1);
System.out.println("UsedPaths:\npaths:"+result.left+"\npaths':"+result.right+"\n-----------------\n");
return result;
}
static private Paths usedPathsFix(Program p, Paths paths, List<List<Ast.C>> css,Phase phase0) {
//- usedPathsFix(p,empty,empty) =empty
if (paths.isEmpty()){
assert css.isEmpty();
return Paths.empty();
}
//- usedPathsFix(p,paths,Css)= usedPathsFix(p.pop(),paths.pop(),empty).push(Css)
//paths.top()\Css==empty
List<List<Ast.C>> topLessCss = new ArrayList<>(paths.top());
topLessCss.removeAll(css);
if(topLessCss.isEmpty()){
Paths popPaths=paths.pop();
if(popPaths.isEmpty()){
return Paths.empty().push(css);
}
assert !(p instanceof FlatProgram):
popPaths;
return usedPathsFix(p.pop(),popPaths,Collections.emptyList(),phase0).push(css);
}
//-usedPathsFix(p,paths,Css)= usedPathsFix(p, paths U paths0,minimize(paths0.top() U Css)) // U on paths does minimize() internally
//paths.top()\Css!=empty
//paths0=usedPathsL(p.top(),paths.top()\Css)
Paths paths0=usedPathsL(p,p.top(),topLessCss,phase0);
List<List<Ast.C>> css1=new ArrayList<>(paths.top());
css1.addAll(css);
return usedPathsFix(p,paths.union(paths0),Paths.minimize(css1),phase0);
}
//- usedPathsL(L, Cs1..Csn)=usedInnerL(L(Cs1),Cs1) U ... U usedInnerL(L(Csn),Csn)
static private Paths usedPathsL(Program pForError,ClassB l, List<List<Ast.C>> css,Phase phase0) {
Paths result=Paths.empty();
for(List<Ast.C> csi : css){
assert !csi.isEmpty();
ClassB li;try{li=l.getClassB(csi);}
catch(ErrorMessage.PathMetaOrNonExistant pne){
/*Position p=FindPathUsage._locate(pForError,l,Path.outer(1,
csi));*/
throw pne.withListOfNodeNames(csi).withCb(l);//.withWherePathWasWritten(p);
}
ClassB liTop=li;
if (csi.size()!=0){liTop=l.getClassB(Collections.singletonList(csi.get(0)));}
assert IsCompiled.of(liTop);
//checked after for newPaths: when the offending value is produced, so we have more context for error message
// throw new ErrorMessage.PathMetaOrNonExistant(true, Collections.singletonList(csi.get(0)), l, null,null);
Paths newPaths=usedInnerL(li,csi,phase0);
try{newPaths.checkAllDefined(pForError);}
catch(ErrorMessage.PathMetaOrNonExistant pne){
Position p=FindPathUsage._locate(pForError,li,Path.outer(csi.size()+1/*TODO we need to fix this crap for real*/,
pne.getListOfNodeNames()));
throw pne.withWherePathWasWritten(p);
}
result=result.union(newPaths);
}
return result;
}
//- usedInnerL(LC,Cs)=paths.prefix(Cs)
static private Paths usedInnerL(ClassB lc, List<Ast.C> cs,Phase phase0) {
//LC={_ implements Ps, M1..Mn}//in implementation, error if not compiled
if(!IsCompiled.of(lc)){
throw new ErrorMessage.IncompleteClassIsRequired(
"library not compiled yet is required to be typed",
null,Path.outer(0, cs), Collections.emptyList(),Ast.Position.noInfo
);
}
Paths paths=Paths.reorganize(lc.getSuperPaths());
for(ClassB.Member mi: lc.getMs()){
paths=paths.union(usedInnerM(mi,phase0));
}
//paths=reorganize(Ps) U usedInnerM(M1) U... U usedInnerM(Mn))
return paths.prefix(cs);}
static private Paths usedInnerM(Member m,Phase phase0) {
if(m instanceof NestedClass){
NestedClass nc=(NestedClass)m;
return usedInnerL((ClassB)nc.getInner(),Collections.emptyList(),phase0).pop();
}
List<Path> result1;
List<ClassB> l1n = Collections.emptyList();
if(m instanceof MethodWithType){
MethodWithType mwt=(MethodWithType)m;
result1=CollectPaths0.of(mwt);
if(phase0==Phase.Typed && mwt.get_inner().isPresent()){
l1n = CollectClassBs0.of(m.getInner());
}
}
else{
assert m instanceof MethodImplemented;
result1=CollectPaths0.of(m.getInner());
}
Paths result2=Paths.reorganize(result1);
Paths acc=Paths.empty();
for(ClassB li: l1n){acc=acc.union(usedInnerL(li,Collections.emptyList(),phase0));}
return result2.union(acc.pop());
}
static private Paths deepImplements(ClassB l){
Paths res=Paths.reorganize(l.getSuperPaths());
Paths acc=Paths.empty();
for(Member mi:l.getMs()){
ExpCore e;try{e=mi.getInner();}
catch(NoSuchElementException nsee){continue;}
for(ClassB cbij:CollectClassBs0.of(e)){
acc=acc.union(deepImplements(cbij));
}
}
return res.union(acc.pop());
}
static private List<Ast.Path> collectNotAnyPaths(Program p,ExpCore e) {
class HeuristicForNotAnyPathsSplit extends PropagatorVisitor{
public Void visit(ClassB s) {return null;}
protected List<Path> paths=new ArrayList<Path>();
private void add(Path p){this.paths.add(p);}
//non determinism heuristic:
//**if P.m(_) inside e, P not Any
public Void visit(MCall s) {
Path p=justPath(s.getInner());
if (p!=null){add(p);}
return super.visit(s);
}
//**if ( _ T x=P _ _) inside e and T!=class Any, P not Any.
//**if (mdf P x=_ _) inside e, P not Any
protected void liftDec(Block.Dec s) {
Path pt=s.getT().match(nt->nt.getPath(), hType->hType.getPath());
if(!pt.isPrimitive()){add(pt);}
Path p=justPath(s.getInner());
if (p!=null){add(p);}
super.liftDec(s);
}
private Path justPath(ExpCore e){
if(e instanceof ExpCore.EPath){
if(!((ExpCore.EPath)e).getInner().isPrimitive()){
return ((ExpCore.EPath)e).getInner();
}
}
if(e instanceof ExpCore.Block){return justPath(((ExpCore.Block)e).getInner());}
return null;
}
//**if p(Pi).Cache=Typed, Pi is not Any
@Override protected void liftP(Path s) {
if(s.isPrimitive()){return;}
try{if(p.extractClassB(s).getPhase()==Phase.Typed){
super.liftP(s); return;
}}
catch(ErrorMessage.PathMetaOrNonExistant pne){/*we do not rise this error while computing the heuristic*/}
}
//**if using P _ _ inside e, P not Any
public Void visit(ExpCore.Using s) {
if (!s.getPath().isPrimitive()){add(s.getPath());}
return super.visit(s);
}
//**if catch T inside e, T.P not Any
protected void liftO(ExpCore.Block.On on){
Path pOn=on.getT().match(
normType->normType.getPath(),
hType->hType.getPath());
if (!pOn.isPrimitive()){add(pOn);}
super.liftO(on);
}
List<Path> result(ExpCore e){
e.accept(this);
return this.paths;
}
}
return new HeuristicForNotAnyPathsSplit().result(e);
}
}