package newTypeSystem;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import ast.Ast.Mdf;
import ast.Ast.NormType;
import ast.Ast.Type;
import ast.Ast.Path;
import ast.Ast.SignalKind;
import ast.Ast;
import ast.ExpCore;
public class TypeManipulation {
public static NormType fwd(NormType t){
// fwd T
// fwd imm P=fwd fwd%imm P=fwdImm P
// fwd mut P=fwd fwd%mut P=fwdMut P
// otherwise fwd T=T
Mdf m=t.getMdf();
if(m==Mdf.Immutable || m==Mdf.ImmutablePFwd){
return t.withMdf(Mdf.ImmutableFwd);
}
if(m==Mdf.Mutable ||m==Mdf.MutablePFwd){
return t.withMdf(Mdf.MutableFwd);
}
return t;
}
public static NormType fwdP(NormType t){
// fwd% T
// fwd% imm P=fwd%Imm P
// fwd% mut P=fwd%Mut P
// otherwise fwd% T=T
Mdf m=t.getMdf();
if(m==Mdf.Immutable){
return t.withMdf(Mdf.ImmutablePFwd);
}
if(m==Mdf.Mutable){
return t.withMdf(Mdf.MutablePFwd);
}
return t;
}
public static boolean fwd_or_fwdP_in(Mdf m){
return m==Mdf.ImmutableFwd
|| m==Mdf.ImmutablePFwd
|| m==Mdf.MutableFwd
|| m==Mdf.MutablePFwd;
}
public static boolean fwd_or_fwdP_in(Collection<? extends Type>ts){
// fwd_or_fwd%_in Ts
// exists T in Ts such that
// T in {fwdImm _,fwdMut_,fwd%Imm _,fwd%Mut _}
for(Type ti:ts){
if(fwd_or_fwdP_in(ti.getNT().getMdf())){return true;}
}
return false;
}
public static boolean fwd_or_fwdP_inMdfs(Collection<Mdf>ms){
for(Mdf mi:ms){
if(fwd_or_fwdP_in(mi)){return true;}
}
return false;
}
public static NormType noFwd(NormType t){
// noFwd T
// noFwd fwdImm P=noFwd fwd%Imm P=imm P
// noFwd fwdMut P=noFwd fwd%Mut P=mut P
// otherwise noFwd T=T
Mdf m=t.getMdf();
if(m==Mdf.ImmutableFwd || m==Mdf.ImmutablePFwd){
return t.withMdf(Mdf.Immutable);
}
if(m==Mdf.MutableFwd ||m==Mdf.MutablePFwd){
return t.withMdf(Mdf.Mutable);
}
return t;
}
public static List<NormType> noFwd(Collection<NormType>ts){
// noFwd T1..Tn= noFwd T1 .. noFwd Tn
List<NormType>res=new ArrayList<>();
for(NormType ti:ts){res.add(noFwd(ti));}
return res;
}
/*public static NormType toImm(NormType t){//used only for fields in coherent
// toImm(T)
// toImm(class P)=class P
// otherwise, toImm(mdf P)=imm P
if(t.getMdf()==Mdf.Class){return t;}
return t.withMdf(Mdf.Immutable);
}*/
public static NormType toImmOrCapsule(NormType t){
// toImmOrCapsule(T)
// toImmOrCapsule(mdf C)=capsule C with mdf in {lent,mut,fwdMut,fwd%Mut}
// toImmOrCapsule(read C)=imm C
// otherwise toImmOrCapsule(T)=T//mdf in {class,imm,fwdImm,fwd%Imm,capsule}
return t.withMdf(toImmOrCapsule(t.getMdf()));
}
public static Mdf toImmOrCapsule(Mdf m){
if (m==Mdf.Lent ||m==Mdf.Mutable ||m==Mdf.MutableFwd ||m==Mdf.MutablePFwd){
return Mdf.Capsule;
}
if(m==Mdf.Readable){return Mdf.Immutable;}
return m;
}
public static NormType _toLent(NormType t){
// toLent(T)
// toLent(mut P)=lent P,
// toLent(fwdMut P) and toLent(fwd%Mut P) undefined;
// otherwise toLent(T)=T
Mdf m=t.getMdf();
if(m==Mdf.MutableFwd || m==Mdf.MutablePFwd){return null;}
if(m==Mdf.Mutable){return t.withMdf(Mdf.Lent);}
return t;
}
public static NormType mutOnlyToLent(NormType t){
// mutOnlyToLent(T)
// mutOnlyToLent(mut P)=lent P,
// otherwise mutOnlyToLent(T)=T
if(t.getMdf()==Mdf.Mutable){return t.withMdf(Mdf.Lent);}
return t;
}
public static NormType capsuleToLent(NormType t){
// capsuleToLent(T)
// capsuleToLent(capsule P)=lent P
// otherwise capsuleToLent(mdf P)=mdf P
if(t.getMdf()==Mdf.Capsule){return t.withMdf(Mdf.Lent);}
return t;
}
public static NormType _toRead(NormType t){
// toRead(T)
// toRead(fwdMut P)=toRead(fwd%Mut P)=undefined
// toRead(fwdImm P)=toRead(fwd%Imm P)=undefined
// toRead(lent P)=toRead(mut P)=toRead(capsule P)=read P
// toRead(lent P)=toRead(mut P)=toRead(capsule P)=read P
// otherwise read(T)=T//mdf in imm,read,class
Mdf m=t.getMdf();
if(m==Mdf.MutableFwd || m==Mdf.MutablePFwd){return null;}
if(m==Mdf.ImmutableFwd || m==Mdf.ImmutablePFwd){return null;}
if(m==Mdf.Lent ||m==Mdf.Mutable||m==Mdf.Capsule){
return t.withMdf(Mdf.Readable);
}
return t;
}
/*public static NormType lentToMut(NormType t){
// lentToMut(T)
// lentToMut(lent C)=mut C
// otherwise lentToMut(T)=T
if(t.getMdf()==Mdf.Lent){return t.withMdf(Mdf.Mutable);}
return t;
}*/
public static NormType mutToCapsule(NormType t){
// mutToCapsule(T)
// mutToCapsule(fwdMut C) and mutToCapsule(fwd%Mut C) undefined
// mutToCapsule(mut C)=capsule C
// otherwise mutToCapsule(T)=T
Mdf _m=mutToCapsule(t.getMdf());
if(_m==null){return null;}
return t.withMdf(_m);
}
public static Mdf mutToCapsule(Mdf m){
assert m!=Mdf.MutableFwd && m!=Mdf.MutablePFwd;
if(m==Mdf.Mutable){return Mdf.Capsule;}
return m;
}
public static NormType mutToCapsuleAndFwdMutToFwdImm(NormType t){
//mutToCapsuleAndFwdMutToFwdImm(T) //called f in the implementation
//f(fwd%Mut P) undefined
//f(mut P)=capsule P
//f(fwdMut P)= fwdImm P
//otherwise f(T)=T
return t.withMdf(mutToCapsuleAndFwdMutToFwdImm(t.getMdf()));
}
public static Mdf mutToCapsuleAndFwdMutToFwdImm(Mdf m){
assert m!=Mdf.MutablePFwd;
if(m==Mdf.Mutable){return Mdf.Capsule;}
if(m==Mdf.MutableFwd){return Mdf.ImmutableFwd;}
return m;
}
public static NormType mutToCapsuleAndFwdToRead(NormType t){
//mutToCapsuleAndFwdMutToRead(T) //called f in the implementation
//f(fwd%Mut P) undefined
//f(mut P)=capsule P
//f(fwdMut P)= read P
//f(fwdImm P)= imm P
//otherwise f(T)=T
return t.withMdf(mutToCapsuleAndFwdToRead(t.getMdf()));
}
public static Mdf mutToCapsuleAndFwdToRead(Mdf m){
assert m!=Mdf.MutablePFwd;
if(m==Mdf.Mutable){return Mdf.Capsule;}
if(m==Mdf.MutableFwd){return Mdf.Readable;}
if(m==Mdf.ImmutableFwd){return Mdf.Immutable;}
return m;
}
public static Mdf _mostGeneralMdf(Ast.SignalKind _throw,ATr<?> out){
//mostGeneralMdf(throw,Tr)
// mostGeneralMdf(error,Tr)=imm
// mostGeneralMdf(return,empty;Ps) undefined
// mostGeneralMdf(return,T1..Tn;Ps)=mostGeneralMdf({T1.mdf .. Tn.mdf})
// otherwise
// mostGeneralMdf(exception,_;Ps)=imm
if(_throw!=SignalKind.Return){return Mdf.Immutable;}
assert !out.returns.isEmpty();
Stream<Ast.Mdf> s = out.returns.stream().map(t->t.getMdf());
return _mostGeneralMdf(s.collect(Collectors.toSet()));
}
public static Mdf _mostGeneralMdf(Set<Mdf> mdfs){
//case by exclusion:
// if mdfs=mdf', then mdf=mdf' //that is the only way mdf=class
if (mdfs.size()==1){return mdfs.iterator().next();}
// if class in mdfs, then undefined
if (mdfs.contains(Mdf.Class)){return null;}
//if mdfs\capsule=mdf', then mdf=mdf'
if (mdfs.contains(Mdf.Capsule) && mdfs.size()==2){
Iterator<Mdf> i = mdfs.iterator();
Mdf m=i.next();
if(m==Mdf.Capsule){m=i.next();}
assert m!=Mdf.Capsule;
return m;
}
// if fwd_or_fwd%_in(mdfs) {
if(TypeManipulation.fwd_or_fwdP_inMdfs(mdfs)){
// if read or lent in mdfs, then undefined
if (mdfs.contains(Mdf.Readable)){return null;}
if (mdfs.contains(Mdf.Lent)){return null;}
// if imm and mut both in noFwd(mdfs) then undefined
boolean mutIn=false;
boolean immIn=false;
for(Mdf m:mdfs){
if(Mdf.muts.contains(m))mutIn=true;
if(Mdf.imms.contains(m))immIn=true;
}
if (mutIn && immIn){return null;}
//we know: more then one, no read/lent, either all imm side or mut side
if(mdfs.contains(Mdf.ImmutableFwd)){return Mdf.ImmutableFwd;}
if(mdfs.contains(Mdf.ImmutablePFwd)){return Mdf.ImmutablePFwd;}
if(mdfs.contains(Mdf.MutableFwd)){return Mdf.MutableFwd;}
assert mdfs.contains(Mdf.MutablePFwd): mdfs;
return Mdf.MutablePFwd;
}
//if read in mdfs, mdf=read
if(mdfs.contains(Mdf.Readable)){return Mdf.Readable;}
if(mdfs.contains(Mdf.Immutable)){return Mdf.Readable;}
return Mdf.Lent;
}
public static boolean catchRethrow(ExpCore.Block.On k){
//liberal use of desugaring in the line under
//catchRethrow(k) iff k=catch throw Any x ((e catch error Any z void void) throw x)
if(!k.getT().equals(Path.Any().toImmNT())){return false;}
if(!(k.getE() instanceof ExpCore.Block)){return false;}
ExpCore.Block b=(ExpCore.Block)k.getE();
if(!(b.getInner() instanceof ExpCore.Signal)){return false;}
return false;
}
}