package coreVisitors;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import ast.Ast;
import ast.ExpCore;
import ast.Ast.*;
import ast.ErrorMessage;
import ast.ExpCore.ClassB.MethodWithType;
import ast.ExpCore.Loop;
import ast.Redex;
import ast.Redex.Garbage;
import ast.ExpCore.*;
import auxiliaryGrammar.Functions;
import programReduction.Program;
//no, non e' un visitor, e deve ritornare un Optional Redex!
public class IsRedex{
//Program p;
//IsRedex(Program p){this.p=p;}
public static Redex of(Program p,ExpCore e){
if( e instanceof Using){return visit(p,(Using)e);}
if( e instanceof MCall){return visit(p,(MCall)e);}
if( e instanceof Block){return visit(p,(Block)e);}
if( e instanceof ClassB){return visit(p,(ClassB)e);}
if( e instanceof Loop){return visit(p,(Loop)e);}
return Redex.invalid();
}
private static Redex visit(Program p, Loop e) {
return new Redex.LoopR(e);
}
public static Redex visit(Program p,Using s) {
for(ExpCore e:s.getEs()){
if(!IsValue.of(p, e)){return Redex.invalid();}
}
//after the first approximation//TODO: really slow
List<ExpCore> newEs = esNestedGarbage(s.getEs());
if(newEs!=null){return new Garbage(s.withEs(newEs));}
try{
ExpCore newE=platformSpecific.fakeInternet.OnLineCode.pluginAction(p, s);
return new Redex.Using(s,newE);
}
catch(ErrorMessage.PluginActionUndefined pau){
ExpCore inner=s.getInner();
//if(IsValue.of(p,inner))//TODO: boh, should just return the expression, since is small step?
{return new Redex.UsingOut(s);}
//ExpCore throw_ = ExtractThrow.of(p,inner);
//if(throw_ instanceof ExpCore.Signal){return new Redex.UsingOut(s);}
//return Redex.invalid();
}
}
public static Redex visit(Program p,ClassB s) {
if(IsCompiled.of(s)){return Redex.invalid();}
return new Redex.Meta(s);
}
public static Redex visit(Program p,MCall s) {
if(!IsValue.of(p,s.getInner())){return Redex.invalid();}
for(ExpCore ei:s.getEs()){
if(!IsValue.of(p,ei)){return Redex.invalid();}
}
//after the first approximation//TODO: it is really slow, can we use this idea to redo the whole ctxExtract?, note, it is only needed for garbage
Garbage g=IsValue.nestedGarbage(s.getInner());
if (g!=null){return new Garbage(s.withInner(g.getThatLessGarbage()));}
List<ExpCore> newEs = esNestedGarbage(s.getEs());
if(newEs!=null){return new Garbage(s.withEs(newEs));}
return new Redex.MethCall(s);
/*MethodWithType mwt=p.method(path, ms);
if(!IsValue.isAtom(s.getReceiver())){
return Optional.of(new Redex.PrimCallRec(s));
}
for(int i=0;i<s.getEs().size();i++){
if(!IsValue.isAtom(s.getEs().get(i))){
return Optional.of(new Redex.PrimCallArg(s,i));
}}
return Optional.of(new Redex.);*/
}
public static List<ExpCore> esNestedGarbage(List<ExpCore> es) {
{int i=-1;for(ExpCore ei:es){i+=1;
Garbage gi=IsValue.nestedGarbage(ei);
if(gi==null){continue;}
List<ExpCore> newEs = new ArrayList<>(es);
newEs.set(i,gi.getThatLessGarbage());
return newEs;
}}
return null;
}
public static Redex visit(Program p,Block s) {
for(int i=0;i<s.getDecs().size();i++){
ExpCore ei=s.getDecs().get(i).getInner();
NormType ti=s.getDecs().get(i).getT().getNT();
//Here I was reasoning on missing nested garbage
//Redex ri=redexDec(p, s, i, ei, ti);
//if(!(ri instanceof Redex.NoRedex)){return ri;}
if(new IsValue(p).validDv(s.getDecs().get(i))){continue;}
//otherwise, i is the first non dv
//return ri;
return redexDec(p, s, i, ei, ti);
}//end of for members
Block s2=Functions.garbage(s, s.getDecs().size());
if(!s2.equals(s)){return new Redex.Garbage(s2);}
if(!s.getOns().isEmpty()){
return new Redex.NoThrowRemoveOn(s);
}
return Redex.invalid();
}
private static Redex redexDec(Program p, Block s, int i, ExpCore ei, NormType ti) {
Block s2=Functions.garbage(s, i);
if(!s2.equals(s)){return new Redex.Garbage(s2);}
if(new IsValue(p).validDecForPh(s.getDecs().get(i))){
if(!Functions.isComplete(ti) || Functions.isInterface(p,ti.getPath())){return new Redex.Ph(s,i);}
if(ti.getMdf()==Mdf.Capsule){return new Redex.Subst(s,i);}
}
if(!IsValue.of(p,ei)){
//no or throw
if(s.getOns().isEmpty()){return Redex.invalid();}
ExpCore throw_ = ExtractThrow.of(p,ei);
if(throw_ instanceof WalkBy){return Redex.invalid();}
return new Redex.CaptureOrNot(s, i,(Signal)throw_);
}
if(IsValue.isAtom(ei)){return new Redex.Subst(s, i);}
if(ei instanceof Block &&(
ti.getMdf()==Mdf.Mutable
||ti.getMdf()==Mdf.Lent
||ti.getMdf()==Mdf.Readable)){
return new Redex.BlockElim(s, i);
}
return Redex.invalid();
}
}