package sugarVisitors; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Optional; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.stream.IntStream; import org.antlr.v4.codegen.model.chunk.TokenRef; import coreVisitors.InjectionOnSugar; import tools.Assertions; import tools.StringBuilders; import ast.Ast; import ast.Ast.ConcreteHeader; import ast.Ast.Doc; import ast.Ast.FieldDec; import ast.Ast.MethodSelector; import ast.Ast.MethodSelectorX; import ast.Ast.Parameters; import ast.Ast.Path; import ast.Ast.Position; import ast.Ast.Stage; import ast.Ast.Type; import ast.Ast.VarDec; import ast.ExpCore.ClassB.Phase; import ast.ExpCore; import ast.Expression; import ast.Expression.BinOp; import ast.Expression.ClassB; import ast.Expression.ClassB.Member; import ast.Expression.ClassB.MethodWithType; import ast.Expression.ClassB.NestedClass; import ast.Expression.ClassReuse; import ast.Expression.CurlyBlock; import ast.Expression.DocE; import ast.Expression.DotDotDot; import ast.Expression.FCall; import ast.Expression.ContextId; 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.Literal; import ast.Expression.UnOp; import ast.Expression.Using; import ast.Expression.WalkBy; import ast.Expression.While; import ast.Expression.With; import ast.Expression.X; import ast.Expression._void; import auxiliaryGrammar.Functions; public class ToFormattedText implements Visitor<Void>{ private StringBuilder result=new StringBuilder(); private String currentIndent=""; private ToFormattedText(){} public static String of(Expression e){ ToFormattedText tft=new ToFormattedText(); e.accept(tft); return tft.result.toString(); } public static String of(Type t){ ToFormattedText tft=new ToFormattedText(); tft.formatType(t); return tft.result.toString(); } public static String of(Path path){ ToFormattedText tft=new ToFormattedText(); tft.liftP(path); return tft.result.toString(); } public static String of(Doc doc){ ToFormattedText tft=new ToFormattedText(); tft.formatDoc(doc); return tft.result.toString(); } public static String of(ExpCore e){ return of(e.accept(new InjectionOnSugar())); } public static String of(ExpCore.ClassB.Member m){ List<ExpCore.ClassB.Member> ms=new ArrayList<>(); ms.add(m); ExpCore e=ExpCore.ClassB.membersClass(ms,m.getP(),Phase.None); Expression.ClassB es=(ClassB) e.accept(new InjectionOnSugar()); ToFormattedText tft=new ToFormattedText(); tft.formatMembers(es.getMs());//for the injection return tft.result.toString(); } public static String of(Expression.ClassB.Member m){ List<Expression.ClassB.Member> ms=new ArrayList<>(); ms.add(m); ToFormattedText tft=new ToFormattedText(); tft.formatMembers(ms); return tft.result.toString(); } //String atomIndent=" "; protected Void c(String s){result.append(s);return null;} @SuppressWarnings("unused") private Void c(StringBuilder s){result.append(s);return null;} private Void sp(){result.append(" ");return null;} private Void separeFromChar(){ char last=result.charAt(result.length()-1); if(Character.isLetter(last) || Character.isDigit(last)){ result.append(" ");}return null; } private Void nl(){result.append("\n");result.append(currentIndent);return null;} private Void indent(){currentIndent+=" ";return null;} private Void deIndent(){currentIndent=currentIndent.substring(2);return null;} @Override public Void visit(Signal arg0) { c(arg0.getKind().content); separeFromChar(); return arg0.getInner().accept(this); } @Override public Void visit(Loop arg0) { c("loop "); return arg0.getInner().accept(this); } @Override public Void visit(If arg0) { c("if "); arg0.getCond().accept(this); sp(); arg0.getThen().accept(this); if(!arg0.get_else().isPresent())return null; c("else "); arg0.get_else().get().accept(this); return null; } @Override public Void visit(While arg0) { c("while "); arg0.getCond().accept(this); sp(); arg0.getThen().accept(this); return null; } @Override public Void visit(With s) { c("with");//ok no space if (!s.getXs().isEmpty()){c(" ");} StringBuilders.formatSequence(this.result,s.getXs().iterator(),", ",x->c(x)); if (!s.getIs().isEmpty()){c(" ");} StringBuilders.formatSequence(this.result,s.getIs().iterator(),", ",is->{ if(is.isVar()){c("var ");} formatType(is.getT()); separeFromChar(); c(is.getX()); c(" in "); is.getInner().accept(this); }); if (!s.getDecs().isEmpty()){c(" ");} StringBuilders.formatSequence(this.result,s.getDecs().iterator(),", ",xe->{ if(xe.isVar()){c("var ");} formatType(xe.getT()); separeFromChar(); c(xe.getX()); c("= "); xe.getInner().accept(this); }); c(" (");nl(); for(With.On on:s.getOns()){ c("on "); StringBuilders.formatSequence(this.result,on.getTs().iterator(),", ",t->formatType(t)); sp(); on.getInner().accept(this); nl(); } if(s.getDefaultE().isPresent()){ separeFromChar(); if(!s.getOns().isEmpty()){c("default");separeFromChar();} s.getDefaultE().get().accept(this); } return c(")");//throw Assertions.codeNotReachable(); } @Override public Void visit(X arg0) { return c(arg0.getInner()); } @Override public Void visit(BinOp arg0) { arg0.getLeft().accept(this); sp(); c(arg0.getOp().inner); sp(); return arg0.getRight().accept(this); } @Override public Void visit(DocE arg0) { arg0.getInner().accept(this); return formatDoc(arg0.getDoc()); } @Override public Void visit(UnOp arg0) { c(arg0.getOp().inner); return arg0.getInner().accept(this); } @Override public Void visit(MCall arg0) { if(arg0.getReceiver() instanceof Expression.Signal){c("(");} arg0.getReceiver().accept(this); if(arg0.getReceiver() instanceof Expression.Signal){c(")");} c("."); assert !arg0.getName().isEmpty(); c(arg0.getName()); c("("); formatDoc(arg0.getDoc()); formatParameters(arg0.getPs()); return c(")"); } @Override public Void visit(FCall arg0) { arg0.getReceiver().accept(this); c("("); formatDoc(arg0.getDoc()); formatParameters(arg0.getPs()); return c(")"); } private void formatParameters(Parameters ps) { assert ps.getEs().size()==ps.getXs().size(); if(ps.getE().isPresent()){ps.getE().get().accept(this); if(!ps.getEs().isEmpty()){c(", ");} } StringBuilders.formatSequence(this.result,ps.getXs().iterator(),ps.getEs().iterator(),", ", (x,e)->{ c(x); c(":"); e.accept(this); }); } @Override public Void visit(SquareCall arg0) { arg0.getReceiver().accept(this); return formatSquarePart(arg0); } private Void formatSquarePart(SquareCall arg0) { c("["); arg0.getDoc(); indent(); StringBuilders.formatSequence(result, arg0.getPss().iterator(), arg0.getDocs().iterator(), "\n",(ps,doc)->{ formatParameters(ps); c(";"); formatDoc(doc); }); c("]"); return deIndent(); } @Override public Void visit(SquareWithCall arg0) { arg0.getReceiver().accept(this); c("["); arg0.getWith().accept(this); return c("]"); } @Override public Void visit(Expression.UseSquare arg0) { Expression inner=arg0.getInner(); if (inner instanceof Expression.With){ c("use ["); inner.accept(this); return c("]"); } assert inner instanceof Expression.SquareCall; c("use"); return formatSquarePart((Expression.SquareCall)inner); } @Override public Void visit(RoundBlock arg0) { c("("); formatDoc(arg0.getDoc()); generateContent(arg0.getContents()); arg0.getInner().accept(this); if(!arg0.getContents().isEmpty()){ nl();c(")");deIndent();} else c(")"); return null; } private void generateContent(List<Expression.BlockContent> contents) { if(!contents.isEmpty()){ indent();nl();} for(Expression.BlockContent bc :contents){ for(VarDec vd: bc.getDecs()){ vd.match( (v)->{ if(v.isVar()){c("var ");} formatType(v.getT()); separeFromChar(); c(v.getX()); c("="); return v.getInner().accept(this); }, (v)->{ return v.getInner().accept(this); }, (v)->{ c(v.getInner().getName().toString()); c(":"); formatDoc(v.getInner().getDoc()); return v.getInner().getInner().accept(this); }); nl(); } if(!bc.get_catch().isEmpty()){nl();} for(Expression.Catch k : bc.get_catch()){ generateCatch(k); } } } private void generateCatch(Expression.Catch catch1) { catch1.match( k1->{ c("catch "); c(k1.getKind().content); sp(); formatType(k1.getT()); sp(); c(k1.getX()); sp(); k1.getInner().accept(this); nl(); return null;}, kM->{ c("catch "); c(kM.getKind().content); sp(); for(Type t:kM.getTs()){ formatType(t); } sp(); kM.getInner().accept(this); return null; }, kP->{ sp(); c(kP.getKind().content); c(" on "); for(Type t:kP.getTs()){ formatType(t); } sp(); kP.getInner().accept(this); return null; } ); nl(); } @Override public Void visit(CurlyBlock arg0) { c("{"); formatDoc(arg0.getDoc()); generateContent(arg0.getContents()); if(!arg0.getContents().isEmpty()){ c("}");deIndent();} else c("}"); return null; } @Override public Void visit(Using arg0) { c("use "); this.liftP(arg0.getPath()); sp(); c("check "); c(arg0.getName()); c("("); formatDoc(arg0.getDocs()); formatParameters(arg0.getPs()); c(") "); return arg0.getInner().accept(this); } @Override public Void visit(ClassB cb) { c(" {"); formatH(cb); cb.getFields().forEach(this::formatField); formatMembers(cb.getMs()); c("}"); separeFromChar(); return null; } private void formatMembers(List<Member> ms) { for( Member m:ms){ m.match( nestedClass->{nl(); c(nestedClass.getName().toString()); c(":"); formatDoc(nestedClass.getDoc()); return nestedClass.getInner().accept(this); }, methImpl->{nl(); c("method "); formatMs(methImpl.getS()); return methImpl.getInner().accept(this); }, methT->{nl(); formatMts(methT); if(methT.getInner().isPresent()){ methT.getInner().get().accept(this); } return null; }); } } /*private Expression forceBlock(Expression e) { if (e instanceof Expression.RoundBlock){return e;} if (e instanceof Expression.CurlyBlock){return e;} return new Expression.RoundBlock("",e,Collections.emptyList()); }*/ private void formatMts(MethodWithType methT) { if(methT.getMt().isRefine()){c("refine ");} c(methT.getMt().getMdf().inner); separeFromChar(); c("method "); if(!methT.getDoc().isEmpty()){formatDoc(methT.getDoc());} else{nl();} formatType(methT.getMt().getReturnType()); separeFromChar(); c(methT.getMs().nameToS()); c("("); StringBuilders.formatSequence(this.result,methT.getMt().getTs().iterator(), methT.getMs().getNames().iterator(),", ", (ti,xi)->{ formatType(ti.withDoc(Doc.empty())); separeFromChar(); c(xi); formatDoc(ti.getDoc()); }); c(") "); if(methT.getMt().getExceptions().isEmpty()){return;} c("exception "); StringBuilders.formatSequence(this.result,methT.getMt().getExceptions().iterator(),", ", p->formatType(p)); sp(); } private void formatMs(MethodSelector s) { c(s.nameToS()); c("("); for( String ss:s.getNames()){ c(ss); sp(); } c(") "); } private void formatH(ClassB arg0) { formatDoc(arg0.getDoc1()); arg0.getH().match( h->{//concrete header c(h.getMdf().inner); sp(); c(h.getName()); c("("); StringBuilders.formatSequence(result,h.getFs().iterator(), ", ",this::formatField); return c(")");}, //trait h->{return null;}, //inteface h->{return c("interface ");}); if(!arg0.getSupertypes().isEmpty()){ c("implements "); StringBuilders.formatSequence(this.result,arg0.getSupertypes().iterator(),", ", p->formatType(p)); } } private void formatField(FieldDec v) { sp(); if(v.isVar()){c("var ");} formatType(v.getT()); sp(); c(v.getName()); formatDoc(v.getDoc()); sp(); } private Void formatDoc(Doc d) {return c(d.toCodeFormattedString());} private Void formatType(Optional<Type> t) { if(t.isPresent()){ return formatType(t.get()); } return null; } private Void formatType(Type t) { return t.match( tN->{ if(ast.Ast.Mdf.Immutable!=tN.getMdf()){ c(tN.getMdf().inner);sp();} liftP(tN.getPath()); return null; }, tH->{ liftP(tH.getPath()); for( MethodSelectorX s:tH.getSelectors()){ c("::"); formatMs(s.getMs()); if(!s.getX().isEmpty()){ c("::"); c(s.getX()); } } return null; }); } @Override public Void visit(DotDotDot arg0) { return c(" ... "); } @Override public Void visit(_void arg0) { return c("void"); } @Override public Void visit(Literal arg0) { if(!arg0.isNumber()){ arg0.getReceiver().accept(this); c("\""); if(!arg0.getInner().contains("\n")){ c(arg0.getInner()); return c("\""); } String[] splitted = arg0.getInner().split("\n", -1); for(String s:splitted){c("'");c(s);nl();} return c("\""); } c(arg0.getInner()); return arg0.getReceiver().accept(this); } @Override public Void visit(Expression.EPath path) { return liftP(path.getInner()); } protected Void liftP(Path path) { if(Path.Any()==path){return c("Any");} if(Path.Library()==path){return c("Library");} if(Path.Void()==path){return c("Void");} if(path.isCore()){ c("This"+path.outerNumber()); for(Ast.C ci:path.getCBar()){ c("."+ci); } return null; } StringBuilders.formatSequence(this.result, path.sugarNames().iterator(),".",s->c(s.toString())); return null; } @Override public Void visit(WalkBy s) { return c("##walkBy"); } @Override public Void visit(ClassReuse s) { c("{"); formatDoc(s.getInner().getDoc1()); c(s.getUrl()); if(s.getInner().getMs().isEmpty()){return c("}");} indent(); nl(); formatMembers(s.getInner().getMs()); nl(); c("}"); return deIndent(); } public static String ofCompact(Expression e) { return ofCompact(e,true); } public static String ofCompact(Expression e,boolean inline) { ToFormattedText tft=new ToFormattedText(){ public Void visit(ClassB cb){ //String res=""; String wb=""; for(Member m:cb.getMs()){ if(m instanceof NestedClass){ NestedClass nc=(NestedClass)m; if(nc.getInner() instanceof WalkBy){wb=nc.getName()+":##";} } } return c("{.."+wb+"..}"); } }; e.accept(tft); String res=tft.result.toString(); if(inline){res=res.replace("\n", " ");} //if(res.length()>80){ res=res.substring(0, 34)+" ... "+res.substring(res.length()-34); } return res; } @Override public Void visit(ContextId s) { return c(s.getInner()); } }