package ast;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.Value;
import lombok.experimental.Wither;
import ast.Expression;
import ast.Ast.*;
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;
public interface ExpCore {
<T> T accept(coreVisitors.Visitor<T> v);
default String toS(){return sugarVisitors.ToFormattedText.of(this);}
@Value @EqualsAndHashCode(exclude = "p") @ToString(exclude = "p") @Wither public static class MCall implements ExpCore,HasPos, WithInner<MCall>{
ExpCore inner;
MethodSelector s;
Doc doc;
List<ExpCore> es;
Position p;
public MCall withEsi(int i,ExpCore ei){
List<ExpCore> es2=new ArrayList<>(es);
es2.set(i,ei);
return this.withEs(es2);
}
@Override public <T> T accept(coreVisitors.Visitor<T> v) {
return v.visit(this);
}
}
@Value @EqualsAndHashCode(exclude = "p")
public static class X implements ExpCore, Ast.Atom, HasPos {
Position p;
String inner;
public String toString() {
return this.inner;
}
@Override public <T> T accept(coreVisitors.Visitor<T> v) {
return v.visit(this);
}
}
@Value @EqualsAndHashCode(exclude = "p") @ToString(exclude = "p") @Wither public static class Block implements ExpCore,HasPos,WithInner<Block> {
Doc doc;
List<Dec> decs;
ExpCore inner;
List<On> ons;
Position p;
public ExpCore getE(){return inner;}
public Block withE(ExpCore e){return this.withInner(e);}
public Block withDeci(int i,Dec di){
List<Dec> decs2=new ArrayList<>(decs);
decs2.set(i,di);
return this.withDecs(decs2);
}
public Block withDeci(int i,On oi){
List<On> ons2=new ArrayList<>(ons);
ons2.set(i,oi);
return this.withOns(ons2);
}
@Override public <T> T accept(coreVisitors.Visitor<T> v) {
return v.visit(this);
}
@Value @Wither public static class Dec implements WithInner<Dec>{
Type t;
String x;
ExpCore inner;
}
public List<String> domDecs() {
List<String> dom = new java.util.ArrayList<String>();
for (Dec d : this.decs) {
dom.add(d.x);
}
return dom;
}
@Value @Wither @EqualsAndHashCode(exclude = "p") @ToString(exclude = "p") public static class On implements HasPos, WithInner<On>{
SignalKind kind;
String x;
Type t;
ExpCore inner;
Position p;
public ExpCore getE(){return inner;}
public On withE(ExpCore e){return this.withInner(e);}
}
}
@Value @Wither @EqualsAndHashCode(exclude = {"p","phase","uniqueId"}) /*@ToString(exclude ="p")*/ public static class ClassB implements ExpCore, Ast.Atom,HasPos {
public ClassB(Doc doc1, boolean isInterface, List<Type> supertypes, List<Member> ms,Position p, Phase phase, int uniqueId) {
this.doc1 = doc1;
this.isInterface = isInterface;
this.supertypes = supertypes;
this.ms = ms;
this.p=p;
this.phase=phase;
this.uniqueId=uniqueId;
assert isConsistent();
}//lombock fails me here :-(
Doc doc1;
boolean isInterface;
List<Ast.Type> supertypes;
List<Member> ms;
Position p;
Phase phase;
int uniqueId;
// In the future, we may remove members and add mwts and ns, now we add delegation constructors/getters
public ClassB(Doc doc1, boolean isInterface, List<Type> supertypes, List<ClassB.MethodWithType> mwts, List<ClassB.NestedClass> ns,Position p, Phase phase, int uniqueId) {
this(doc1,isInterface,supertypes,java.util.stream.Stream.concat(mwts.stream(),ns.stream()).collect(Collectors.toList()),p,phase,uniqueId);
}
public List<ClassB.MethodWithType> mwts(){
return ms.stream().filter(e->e instanceof ClassB.MethodWithType)
.map(e->(ClassB.MethodWithType)e)
.collect(Collectors.toList());
}
public List<ClassB.NestedClass> ns(){
return ms.stream().filter(e->e instanceof ClassB.NestedClass)
.map(e->(ClassB.NestedClass)e)
.collect(Collectors.toList());
}
public String toString() {return sugarVisitors.ToFormattedText.of(this);}
public boolean isConsistent() { return _Aux.isConsistent(this);}
public ClassB withMember(Member m) {return _Aux.withMember(this, m);}
public Member _getMember(ast.Ast.MethodSelector ms) {return _Aux._getMember(this, ms);}
public ClassB onClassNavigateToPathAndDo(List<Ast.C>cs,Function<ClassB,ClassB>op){return _Aux.onClassNavigateToPathAndDo(this, cs, op);}
public ClassB onNestedNavigateToPathAndDo(List<Ast.C>cs,Function<ClassB.NestedClass,Optional<ClassB.NestedClass>>op){return _Aux.onNestedNavigateToPathAndDo(this, cs, op);}
public ExpCore.ClassB.NestedClass getNested(List<Ast.C>cs){return _Aux.getNested(this, cs);}
public List<ExpCore.ClassB.NestedClass> getNestedList(List<Ast.C>cs){return _Aux.getNestedList(this, cs);}
public ExpCore.ClassB getClassB(List<Ast.C>cs){return _Aux.getClassB(this, cs);}
public static ExpCore.ClassB docClass(Doc d){return new ClassB(d,false,Collections.emptyList(),Collections.emptyList(),Position.noInfo,Phase.Typed,0);}
public static ExpCore.ClassB membersClass(List<Member> ms,Position pos,Phase phase){return new ClassB(Doc.empty(),false,Collections.emptyList(),ms,pos,phase,0);}
public List<Path> getSuperPaths(){
return this.getSupertypes().stream()
.map(t->t.getNT().getPath())
.collect(Collectors.toList());
}
@Override public <T> T accept(coreVisitors.Visitor<T> v) {return v.visit(this);}
public static enum Phase{None,Norm,Typed,Coherent;
public Phase acc(Phase that){
if(this.subtypeEq(that)){return that;}
return this;
}
public boolean subtypeEq(Phase that){
return this.ordinal()>=that.ordinal();
}
}
public interface Member extends HasPos, WithInner<Member> {
<T> T match(Function<NestedClass, T> nc, Function<MethodImplemented, T> mi, Function<MethodWithType, T> mt);
}
@Value @Wither @EqualsAndHashCode(exclude = "p") @ToString(exclude = "p")public static class NestedClass implements Member {
@NonNull Doc doc;
@NonNull Ast.C name;
@NonNull ExpCore inner;
Position p;
public ExpCore getE(){return inner;}
public NestedClass withE(ExpCore e) {return this.withInner(e);}
public <T> T match(Function<NestedClass, T> nc, Function<MethodImplemented, T> mi, Function<MethodWithType, T> mt) {
return nc.apply(this);
}
}
@Value @Wither @EqualsAndHashCode(exclude = {"p"/*,"mt"*/}) @ToString(exclude = {"p"/*,"mt"*/})public static class MethodImplemented implements Member {
@NonNull Doc doc;
@NonNull MethodSelector s;
@NonNull ExpCore inner;
Position p;
public ExpCore getE(){return inner;}
public MethodImplemented withE(ExpCore e) {return this.withInner(e);}
public <T> T match(Function<NestedClass, T> nc, Function<MethodImplemented, T> mi, Function<MethodWithType, T> mt) {
return mi.apply(this);
}
}
@Value @Wither @EqualsAndHashCode(exclude = "p") @ToString(exclude = "p") public static class MethodWithType implements Member {
@NonNull Doc doc;
@NonNull MethodSelector ms;
@NonNull MethodType mt;
@NonNull Optional<ExpCore> _inner;
Position p;
public ExpCore getInner(){return _inner.get();}//and boom if there is not
public MethodWithType withInner(ExpCore e) {return this.with_inner(Optional.of(e));}
public <T> T match(Function<NestedClass, T> nc, Function<MethodImplemented, T> mi, Function<MethodWithType, T> mt) {
return mt.apply(this);
}
}
}
@Value public static class _void implements ExpCore, Ast.Atom {
@Override public <T> T accept(coreVisitors.Visitor<T> v) {
return v.visit(this);
}
}
@Value @Wither @EqualsAndHashCode(exclude = "p")
public static class EPath implements ExpCore,HasPos,Atom{
Position p;
Ast.Path inner;
public String toString(){return this.getInner().toString();}
public <T> T accept(coreVisitors.Visitor<T> v) {
return v.visit(this);
}
public static EPath wrap(Ast.Path p){
return new EPath(Position.noInfo,p);
}
}
@Value public static class WalkBy implements ExpCore {
@Override public <T> T accept(coreVisitors.Visitor<T> v) {
return v.visit(this);
}
}
@Value @Wither public static class Using implements ExpCore, WithInner<Using> {
Path path;
MethodSelector s;
Doc doc;
List<ExpCore> es;
ExpCore inner;
public Using(Path path,MethodSelector s,Doc doc,List<ExpCore> es,ExpCore inner){
this.path=path;this.s=s;this.doc=doc;this.es=es;this.inner=inner;
assert s.getNames().size()==es.size();
}
public Using withEsi(int i,ExpCore ei){
List<ExpCore> es2=new ArrayList<>(es);
es2.set(i,ei);
return this.withEs(es2);
}
@Override public <T> T accept(coreVisitors.Visitor<T> v) {
return v.visit(this);
}
}
@Value @Wither
@EqualsAndHashCode(exclude = {"typeOut","typeIn"}) @ToString(exclude = {"typeOut","typeIn"})
public static class Signal implements ExpCore, WithInner<Signal>{
SignalKind kind;
ExpCore inner;
NormType typeOut;
NormType typeIn;
@Override public <T> T accept(coreVisitors.Visitor<T> v) {
return v.visit(this);
}
}
@Value @Wither public static class Loop implements ExpCore, WithInner<Loop> {
ExpCore inner;
@Override public <T> T accept(coreVisitors.Visitor<T> v) {
return v.visit(this);
}
}
interface WithInner<T>{
ExpCore getInner(); T withInner(ExpCore e);
}
}
class _Aux{
static ClassB wrapCast(ExpCore e){
try{return (ClassB)e;}
catch(ClassCastException cce){
throw new ErrorMessage.PathMetaOrNonExistant(true,null,null,null,null);
}
}
static void checkIndex(int index){
if (index==-1){
throw new ErrorMessage.PathMetaOrNonExistant(false,null,null,null,null);
}
}
static ClassB onNestedNavigateToPathAndDo(ClassB cb,List<Ast.C>cs,Function<NestedClass,Optional<NestedClass>>op){
assert !cs.isEmpty();
assert cb!=null;
List<Member> newMs=new ArrayList<>(cb.getMs());
Ast.C nName=cs.get(0);
int index=getIndex(newMs, nName);
checkIndex(index);
NestedClass nc=(NestedClass)newMs.get(index);
if(cs.size()>1){
nc=nc.withInner(onNestedNavigateToPathAndDo(wrapCast(nc.getInner()),cs.subList(1,cs.size()),op));
newMs.set(index, nc);
return cb.withMs(newMs);
}
assert cs.size()==1;
Optional<NestedClass> optNc = op.apply(nc);
if(optNc.isPresent()){
newMs.set(index,optNc.get());
}
else{newMs.remove(index);}
return cb.withMs(newMs);
}
static ClassB onClassNavigateToPathAndDo(ClassB cb,List<Ast.C>cs,Function<ClassB,ClassB>op){
if(cs.isEmpty()){return op.apply(cb);}
List<Member> newMs=new ArrayList<>(cb.getMs());
Ast.C nName=cs.get(0);
int index=getIndex(newMs, nName);
checkIndex(index);
NestedClass nc=(NestedClass)newMs.get(index);
if(cs.size()>1){
nc=nc.withInner(onClassNavigateToPathAndDo(wrapCast(nc.getInner()),cs.subList(1,cs.size()),op));
newMs.set(index, nc);
return cb.withMs(newMs);
}
assert cs.size()==1;
ClassB newCb = op.apply(wrapCast(nc.getInner()));
newMs.set(index, nc.withInner(newCb));
return cb.withMs(newMs);
}
static int getIndex(List<ExpCore.ClassB.Member> map, ast.Ast.MethodSelector elem){
int i=-1;for(ExpCore.ClassB.Member m: map){i++;
if(m.match(nc->false,mi->mi.getS().equals(elem) ,mt->mt.getMs().equals(elem))){return i;}
}
return -1;
}
static int getIndex(List<ExpCore.ClassB.Member> map, Ast.C elem){
int i=-1;for(ExpCore.ClassB.Member m: map){i++;
if(m.match(nc->nc.getName().equals(elem), mi->false, mt->false)){return i;}
}
return -1;
}
static int getIndex(List<ExpCore.ClassB.Member> map, ExpCore.ClassB.Member elem){
return elem.match(nc->getIndex(map,nc.getName()), mi->getIndex(map,mi.getS()),mt->getIndex(map,mt.getMs()));
}
static ExpCore.ClassB.NestedClass getNested(ExpCore.ClassB cb, List<Ast.C>cs){
assert !cs.isEmpty();
Ast.C nName=cs.get(0);
int index=getIndex(cb.getMs(), nName);
checkIndex(index);
NestedClass nc=(NestedClass)cb.getMs().get(index);
if(cs.size()==1){return nc;}
return getNested(wrapCast(nc.getInner()),cs.subList(1, cs.size()));
}
static List<ExpCore.ClassB.NestedClass> getNestedList(ExpCore.ClassB cb, List<Ast.C>cs){
assert !cs.isEmpty();
List<ExpCore.ClassB.NestedClass> result=new ArrayList<>();
getNestedList(cb,cs,result);
return result;
}
static void getNestedList(ExpCore.ClassB cb, List<Ast.C>cs,List<ExpCore.ClassB.NestedClass> result){
Ast.C nName=cs.get(0);
int index=getIndex(cb.getMs(), nName);
checkIndex(index);
NestedClass nc=(NestedClass)cb.getMs().get(index);
result.add(nc);
if(cs.size()!=1){
getNestedList(wrapCast(nc.getInner()),cs.subList(1, cs.size()),result);
}
}
static ExpCore.ClassB getClassB(ExpCore.ClassB cb, List<Ast.C>cs){
if(cs.isEmpty()){return cb;}
return wrapCast(getNested(cb,cs).getInner());
}
static ClassB withMember(ClassB cb,Member m) {
assert cb.isConsistent();
List<Member> newMs = new java.util.ArrayList<>(cb.getMs());
int index=_Aux.getIndex(newMs,m);
if(index==-1){newMs.add(m);}
else {newMs.set(index, m);}
ClassB result = cb.withMs(newMs);
return result;
}
static ClassB.Member _getMember(ClassB cb,ast.Ast.MethodSelector ms) {
assert cb.isConsistent();
int index=_Aux.getIndex(cb.getMs(),ms);
if(index==-1){return null;}
return cb.getMs().get(index);
}
static boolean isConsistent(ClassB cb) {
int countWalkBy = 0;
HashSet<String> keys = new HashSet<String>();
for (Member m : cb.getMs()) {
if (m instanceof MethodWithType) {
MethodWithType mwt = (MethodWithType) m;
String key = mwt.getMs().toString();
assert !keys.contains(key);
keys.add(key);
//assert mwt.getMt().getTDocs().size() == mwt.getMt().getTs().size();
}
if (m instanceof NestedClass) {
NestedClass nc = (NestedClass) m;
String key = nc.getName().toString();
assert !keys.contains(key);
keys.add(key);
if (nc.getInner() instanceof ExpCore.WalkBy) {
countWalkBy += 1;
}
}
if (m instanceof MethodImplemented) {
MethodImplemented mi = (MethodImplemented) m;
String key = mi.getS().toString();
assert !keys.contains(key);
keys.add(key);
}
}
//TODO: re enable with new TS/reduction
//assert (cb.getPhase()==ast.ExpCore.ClassB.Phase.None && cb.getUniqueId().isEmpty())
// || ((cb.getPhase()!=ast.ExpCore.ClassB.Phase.None && !cb.getUniqueId().isEmpty()) );
assert countWalkBy <= 1 : cb;
return true;
}
}