package sugarVisitors;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import tools.Map;
import ast.Ast;
import ast.Expression;
import ast.Ast.Doc;
import ast.Ast.Mdf;
import ast.Ast.NormType;
import ast.Ast.Op;
import ast.Ast.Parameters;
import ast.Ast.Path;
import ast.Ast.Position;
import ast.Ast.SignalKind;
import ast.Ast.Type;
import ast.Expression.Catch;
import ast.Expression.Catch1;
import ast.Expression.With.On;
import ast.Expression.BlockContent;
import ast.Ast.VarDec;
import ast.Ast.VarDecE;
import ast.Ast.VarDecXE;
import ast.Expression.BinOp;
import ast.Expression.ClassB;
import ast.Expression.If;
import ast.Expression.Loop;
import ast.Expression.MCall;
import ast.Expression.RoundBlock;
import ast.Expression.Signal;
import ast.Expression.SquareCall;
import ast.Expression.SquareWithCall;
import ast.Expression.With;
import ast.Expression.X;
import ast.Expression._void;
import ast.Expression.ClassB.MethodImplemented;
import ast.Expression.ClassB.MethodWithType;
import ast.Expression.ClassB.NestedClass;
import auxiliaryGrammar.Functions;
class DesugarW extends CloneVisitor{
Set<String> usedVars=new HashSet<String>();
public static Expression of(Set<String> usedVars,Expression e){
DesugarW d=new DesugarW();
d.usedVars=usedVars;
Expression result= e.accept(d);
return result;
}
public Expression visit(ClassB s) {
Set<String> oldUsedVars = this.usedVars;
try{ return (ClassB)super.visit(s);}
finally{ this.usedVars=oldUsedVars; }// it reset but not replace, membes replace
}
public NestedClass visit(NestedClass nc){
this.usedVars=new HashSet<String>();
usedVars.addAll(CollectDeclaredVars.of(nc.getInner()));
return super.visit(nc);
}
public MethodImplemented visit(MethodImplemented mi){
this.usedVars=new HashSet<String>();
for(String name:mi.getS().getNames()){ usedVars.add(name); }
usedVars.add("this");
usedVars.addAll(CollectDeclaredVars.of(mi.getInner()));
return super.visit(mi);
}
public MethodWithType visit(MethodWithType mt){
this.usedVars=new HashSet<String>();
if(!mt.getInner().isPresent()){return super.visit(mt);}
for(String name:mt.getMs().getNames()){this.usedVars.add(name);}
usedVars.add("this");
usedVars.addAll(CollectDeclaredVars.of(mt.getInner().get()));
return super.visit(mt);
}
public Expression visit(With e){
Position pos=e.getP();
e=with_A_applyDefault(e);//case a
if(e.getIs().isEmpty() && e.getDecs().isEmpty()){//case c
return with_C_resolveXsBaseCase(pos,e.getXs(),e.getOns(),e.getDefaultE().get()).accept(this);
}
if(e.getIs().isEmpty()){return with_B_noI_makeBlock(e).accept(this);} //case b
//assert !e.getIs().isEmpty();
if(e.getXs().isEmpty() && e.getDecs().isEmpty() && e.getOns().isEmpty()){//case e
Expression b=e.getDefaultE().get();
b=b.accept(this);//NOTE WELL: needed to avoid xs that can not be replaced in with xs... this is also the reason we need DesugarW in the first place.
return with_E_handleIs(pos,e.getIs(),b).accept(this);
}
return with_D_replace_XID_with_InestedDwithX(e).accept(this);//case d
}
private static With with_A_applyDefault(With e) {//a (case a in 6 pages)
if (e.getDefaultE().isPresent()){return e;}
return e.withDefaultE(Optional.of(Expression._void.instance));
}
public Expression visit(SquareWithCall s) {
//we can assumethe receivers are normalized after DesugarContext
assert s.getReceiver() instanceof Ast.Atom: s;
//(b=r.builder() b.a() b.b() b.c() .... b)
List<VarDec> vd=new ArrayList<>();
Expression k=Desugar.getMCall(s.getP(),s.getReceiver(),"#seqBuilder",Desugar.getPs());
String x=Functions.freshName("b", usedVars);
X b=new X(s.getP(),x);
vd.add(new VarDecXE(false, Optional.empty(), x, k));
Expression ew=s.getWith().accept(this);
ew=ew.accept(new CloneVisitor(){
@Override public Expression visit(Expression.UseSquare u){
SquareCall sq=(SquareCall)u.getInner();
List<VarDec> vd=new ArrayList<>();//inner, hide external one to prevent use (was a bug before)
for(Parameters ps:sq.getPss()){
vd.add(new VarDecE(Desugar.getMCall(s.getP(),b,"#add",ps)));
}
return Desugar.getBlock(s.getP(),vd,Expression._void.instance);
}});
vd.add(new VarDecE(ew));
Expression inner=Desugar.getBlock(s.getP(), vd, b);
Parameters ps=new Parameters(Optional.empty(), Collections.singletonList("seqBuilder"),Collections.singletonList(inner));
return Desugar.getMCall(s.getP(),s.getReceiver(),"#from",ps);
}
private void oldWith_noUseKw(SquareWithCall s, X xX, List<VarDec> decs) {
List<With.On> ons = s.getWith().getOns();
List<With.On> onsPrime = new ArrayList<>();
for(With.On on:ons){
onsPrime.add(on.withInner(withSquareAdd(s.getP(),xX,on.getInner())));
}
Optional<Expression> def = s.getWith().getDefaultE();
Optional<Expression> defPrime =Map.of(e->withSquareAdd(s.getP(),xX,e), def);
With w=s.getWith().withOns(onsPrime).withDefaultE(defPrime);
decs.add(new VarDecE(w));
}
private VarDecXE castT(Position pos,Type t, String y, String x) {
assert t instanceof NormType;
NormType nt=t.getNT();
String z=Functions.freshName("casted", usedVars);
List<Catch> ks=new ArrayList<>();
Type t2=new NormType(nt.getMdf(),Path.Any(),Doc.empty());
ks.add(new Expression.Catch1(pos,SignalKind.Return,t,z,//case return captured
new X(pos,z)));//return it
ks.add(new Expression.Catch1(pos,SignalKind.Return,t2,z,//else
new Signal(SignalKind.Exception,Expression._void.instance)));// exception void
RoundBlock block=Desugar.getBlock(pos,
new Signal(SignalKind.Return,new X(pos,x)),
ks,Desugar.errorMsg("CastT-Should be unreachable code"));
return new VarDecXE(false,Optional.of(t),y,block);
}
private static Expression renameT(Expression e, Expression.X x, Type t, Expression.X y) {
assert t instanceof NormType;
NormType nt=(NormType)t;
if(nt.getPath().equals(Path.Any())){return e;}
return XInE.of(x,y,e);
}
private static Expression innerWithXs(With e) {//right side of case b and part of right side of case d
Expression inner=e.getDefaultE().get();
List<String> xs=new ArrayList<String>(e.getXs());
for(VarDecXE d:e.getDecs()){xs.add(d.getX());}
for(VarDecXE d:e.getIs()){xs.add(d.getX());}
inner=new With(e.getP(),xs, Collections.emptyList(),Collections.emptyList(), e.getOns(),e.getDefaultE());
return inner;
}
private static Expression with_B_noI_makeBlock(With e) {
if(e.getDecs().isEmpty()){
assert !e.getXs().isEmpty();
return e;
}
return Desugar.getBlock(e.getP(),e.getDecs(),innerWithXs(e));
}
private Expression with_C_resolveXsBaseCase(Position pos,List<String> xs,List<With.On> ons, Expression def) {//case c
if(ons.isEmpty()){return def;}//case cc
With.On on0 = ons.get(0);
List<With.On> ons2 = ons.subList(1, ons.size());
assert !on0.getTs().isEmpty();
return with_C_A(pos, xs, on0, with_C_resolveXsBaseCase(pos,xs, ons2, def));
}
private Expression with_C_A(Position pos, List<String> xs, With.On on0,Expression continuation) {
List<String> ys=new ArrayList<String>();
for(String x:xs){ys.add(Functions.freshName(x, usedVars));}
//(
List<VarDec> decs=new ArrayList<>();
//TODO:?? now is very strange and requires the mdf to propagate it to the locally introduced var?
//casts: every cast is a block content e+catch
{int i=-1;for(Type ti:on0.getTs()){i+=1;
String xi=xs.get(i);
String yi=ys.get(i);
decs.add(castT(pos,ti,yi,xi));}}
//catch exception Void recursive call
Catch k=Desugar.getK(pos,
SignalKind.Exception, "",
NormType.immVoid,
continuation);
//main expression with 'T' renaming
Expression e0=on0.getInner();
{int i=-1;for(Type ti:on0.getTs()){i+=1;
String xi=xs.get(i);
String yi=ys.get(i);
e0=renameT(e0,new Expression.X(pos,xi), ti, new Expression.X(pos,yi));
}}
BlockContent content=new BlockContent(decs,Collections.singletonList(k));
List<BlockContent> contents=new ArrayList<BlockContent>();
contents.add(content);
contents.add(Desugar.getBlockContent(e0));
//void)
return new RoundBlock(pos,Doc.empty(),Expression._void.instance,contents);
}
/*private static Expression with_C_B(Position p,Expression cond, Expression then, Expression _else) {
return new Expression.If(p,cond,then,Optional.of(_else));
}*/
private static Expression with_D_replace_XID_with_InestedDwithX(With e) {//case d
assert e.getDefaultE().isPresent();
assert !e.getIs().isEmpty();
return new With(e.getP(),Collections.emptyList(),e.getIs(),Collections.emptyList(),Collections.emptyList(),
Optional.of(Desugar.getBlock(e.getP(),e.getDecs(),innerWithXs(e))));
}
private Expression with_E_handleIs(Position pos,List<VarDecXE> is, Expression b) {//case e in 6 pages
//xs is dom(Is)
List<String>xs=new ArrayList<>();
for(VarDecXE i:is){xs.add(i.getX());}
//di ki is block content =nexti(xs)
List<BlockContent>bc=new ArrayList<>();
for(int i=0;i<xs.size();i++){bc.add(withNext(pos,i,xs));}
//inner =di ki s b[xs:=xs.#inner()]
for(String xi:xs){
b=XInE.of(new X(pos,xi),Desugar.getMCall(pos,new X(pos,xi),"#inner", Desugar.getPs()),b);
}
RoundBlock inner=new RoundBlock(pos,Doc.empty(),b,bc);
Catch k=Desugar.getK(pos,SignalKind.Exception, "",
NormType.immVoid,
Expression._void.instance);
inner=Desugar.getBlock(pos,new Loop(inner), Collections.singletonList(k), Expression._void.instance);
Expression result=withDeclareIts(is,inner);
//accept
return result;
}
private RoundBlock withDeclareIts(List<VarDecXE> is, RoundBlock inner) {
if(is.isEmpty()){return inner;}
VarDecXE i0 = is.get(0);
List<VarDecXE> is2 = is.subList(1, is.size());
List<VarDec> decs=new ArrayList<VarDec>();
decs.add(i0.withVar(false));
RoundBlock conclusive = withDeclareItsNestedBlock(inner, i0, is2);
return Desugar.getBlock(inner.getP(),decs,conclusive);
}
private RoundBlock withDeclareItsNestedBlock(RoundBlock inner, VarDecXE i0, List<VarDecXE> is2) {
RoundBlock recursive=withDeclareIts(is2,inner);
/*Expression eClose=Desugar.getMCall(inner.getP(),new X(inner.getP(),i0.getX()),"#close",Desugar.getPs());
Catch k1 = withDesugarGetDefaultCatch(inner.getP(),SignalKind.Exception,eClose);
Catch k2 = withDesugarGetDefaultCatch(inner.getP(),SignalKind.Return,eClose);
RoundBlock conclusive1=Desugar.getBlock(inner.getP(),recursive, Collections.singletonList(k1), Expression._void.instance);
RoundBlock conclusive2=Desugar.getBlock(inner.getP(),conclusive1, Collections.singletonList(k2), eClose);
return conclusive2;*/
return recursive;
}
private Catch withDesugarGetDefaultCatch(Position pos,SignalKind kind,Expression eClose) {
String propagated1=Functions.freshName("propagated",usedVars);
Expression blockPropagate1=Desugar.getBlock(pos,eClose,new Signal(kind,new X(pos,propagated1)));
Type t=NormType.immAny;
Expression.Catch1 k1=new Expression.Catch1(pos,kind, t,propagated1,blockPropagate1);
return new DesugarCatchDefault.CatchToComplete(k1);
}
private static RoundBlock withE1CatchExceptionOnVoidE2elseE3(Position pos,Expression e1,Expression e2,Expression e3) {
Expression.Catch k=Desugar.getK(pos,SignalKind.Exception, "", NormType.immVoid,e2);
List<Expression.BlockContent> cs=new ArrayList<>();
cs.add(Desugar.getBlockContent(e1,k));
return new RoundBlock(pos,Doc.empty(),e3,cs);
}
private static Expression.BlockContent withNext(Position pos,int index,List<String> xs) {
Expression eStart=Desugar.getMCall(pos,new X(pos,xs.get(index)),"#next",Desugar.getPs());
List<VarDec> decs=new ArrayList<>();
for(String x:xs.subList(index+1, xs.size())){
Expression ei=Desugar.getMCall(pos,new X(pos,x),"#next",Desugar.getPs());
ei=withE1CatchExceptionOnVoidE2elseE3(pos,ei,Expression._void.instance,Expression._void.instance);
decs.add(new VarDecE(ei));
}
for(String x:xs){
Expression ei=Desugar.getMCall(pos,new X(pos,x),"#checkEnd",Desugar.getPs());
ei=withE1CatchExceptionOnVoidE2elseE3(pos,ei,Expression._void.instance,Expression._void.instance);
decs.add(new VarDecE(ei));
}
Expression eCatch=Desugar.getBlock(pos,decs, new Signal(SignalKind.Exception,Expression._void.instance));
Expression.Catch k=Desugar.getK(pos,SignalKind.Exception, "", NormType.immVoid,eCatch);
return Desugar.getBlockContent(eStart,k);
}
private static Expression withSquareAdd(Position pos,X x,Expression inner) {
Expression result=new BinOp(pos,x,Op.ColonEqual,new MCall(x,"#add",Doc.empty(),Desugar.getPs(inner),pos));
return result;
}
}