package auxiliaryGrammar; import java.util.ArrayList; import java.util.Collections; import java.util.List; import ast.Ast; import ast.Ast.Doc; import ast.Ast.MethodSelector; import ast.Ast.Path; import ast.Ast.Position; import ast.ExpCore.ClassB; import ast.ExpCore.ClassB.Member; public class Locator { public static enum Kind { Node, Nested, Method }; final List<ClassB.Member> ms = new ArrayList<>(); final List<Integer> indexes = new ArrayList<>(); ClassB initialCb=null; final List<ClassB> cbs = new ArrayList<>(); Object annotation = null; public void setAnnotation(Object o){annotation=o;} public Object getAnnotation(){return annotation;} public List<ClassB> getCbs(){ return this.cbs; } public Member getLastMember(){ return this.ms.get(this.ms.size()-1); } public ClassB getLastCb(){ if (this.cbs.isEmpty()){ assert this.initialCb!=null; return this.initialCb; } return this.cbs.get(this.cbs.size()-1); } public String getLastName(){ Member m=this.ms.get(this.ms.size()-1); return m.match(nc->nc.getName().toString(), mi->mi.getS().nameToS(), mt->mt.getMs().nameToS()); } public Kind kind() { int size = this.size(); if (cbs.get(size - 1) != null) { return Kind.Node; } if (ms.get(size - 1) instanceof ClassB.NestedClass) { return Kind.Nested; } return Kind.Method; } public int size() { int size = ms.size(); assert size == indexes.size(); assert size == cbs.size(); assert size==0 ||!cbs.subList(0, size - 1).contains(null) : cbs; return size; } public Locator copy() { Locator result = new Locator(); result.ms.addAll(this.ms); result.indexes.addAll(this.indexes); result.cbs.addAll(this.cbs); return result; } public boolean moveInPath(Path path) { if (!this.cutUpTo(path.outerNumber())) { return false; } this.addCs(path.getCBar()); return true; } public boolean auxMoveInPath(Path path) {//avoid putting 0 in the end if (!this.cutUpTo(path.outerNumber())) { return false; } this.auxAddCs(path.getCBar()); return true; } public void addCsAndMember(List<Ast.C> cs,Member m) { auxAddCs(cs); this.cbs.add(null); this.indexes.add(0); this.ms.add(m); } public void addCs(List<Ast.C> cs) { auxAddCs(cs); assert !cbs.contains(null) : cbs; int size=this.size(); if(cs.size()!=0){ this.cbs.set(size - 1, null); this.indexes.set(size-1, 0); } } private void auxAddCs(List<Ast.C> cs) { int size=this.size(); if(size>0 && this.cbs.get(size-1)==null){ this.indexes.set(size-1,1); this.cbs.set(size-1,LocatorSupport.dumbCb); } for (Ast.C s : cs) { this.ms.add(new ClassB.NestedClass(ast.Ast.Doc.empty(), s, new ast.ExpCore.WalkBy(), null)); this.indexes.add(1); this.cbs.add(LocatorSupport.dumbCb); } } public void toFormerNodeLocator(){ int size=this.size(); if(size==0){return;} if(this.cbs.get(size-1)!=null){return;} assert this.cbs.get(size-1)==null; this.cbs.remove(size-1); this.indexes.remove(size-1); this.ms.remove(size-1); } public boolean cutUpTo(int outerNumber) { assert outerNumber >= 0; if (outerNumber == 0) { return true; } int size = this.size(); if (size == 0) { return false; } int cutIndex = size - 1; if (this.cbs.get(cutIndex) == null) {//kind ==node cutIndex -= 1; } cutIndex -= outerNumber-1; if (cutIndex < 0) { return false; } this.ms.subList(cutIndex, size).clear(); this.indexes.subList(cutIndex, size).clear(); this.cbs.subList(cutIndex, size).clear(); return true; } static class LocatorSupport { private static final ClassB dumbCb = ClassB.membersClass(Collections.emptyList(),Position.noInfo,null); } public boolean prefixOf(Locator nl) { int size = nl.size(); if (this.size() < size) { return false; } for (int i = 0; i < size; i++) { int indexC = this.indexes.get(i); int indexPos = nl.indexes.get(i); assert i!=size-1 || indexPos==0: ""+i+" "+size+" "+indexPos; if (i!=size-1 && indexC != indexPos) { return false; } Member ci = this.ms.get(i); Member nli = nl.ms.get(i); if (ci == nli) { continue; } if (ci.getClass() != nli.getClass()) { return false; } if (!(ci instanceof ClassB.NestedClass)) { return false; } Ast.C nci = ((ClassB.NestedClass) ci).getName(); Ast.C nnli = ((ClassB.NestedClass) nli).getName(); if (!nci.equals(nnli)) { return false; } //is ok to not check classBs? } return true; } public String toStringNoAnnotation() { return coreVisitors.PathAnnotateClass.computeComment(this.ms, this.indexes); } public String toString() { return toStringNoAnnotation()+ annotation; } public boolean equals(Object _that){ if(this.getClass()!=_that.getClass()){return false;} Locator that=(Locator)_that; return this.toStringNoAnnotation().equals(that.toStringNoAnnotation()); } public int hashCode(){return this.toString().hashCode();} public List<Ast.C> getClassNamesPath(){ int size=this.size(); //assert path.get(path.size()-1)==null; List<Ast.C> sPath=new ArrayList<>(); for(Member m:this.ms){ m.match(nc->sPath.add(nc.getName()), mi->sPath.add(null), mt->sPath.add(null)); } if(size>0 && cbs.get(size-1)==null){ sPath.remove(sPath.size()-1); } return sPath; } public void pushMember(ClassB.Member m) { assert !cbs.contains(null) : cbs; ms.add(m); indexes.add(0); cbs.add(null); } public void enterClassB(ClassB cb){ int size=this.size(); if(size==0){ assert this.initialCb==null; this.initialCb=cb; return; } assert this.cbs.get(size-1)==null; this.cbs.set(size-1,cb); this.indexes.set(size-1,this.indexes.get(size-1)+1); assert !cbs.contains(null) : cbs; } public void exitClassB(){ int size=this.size(); if(size==0){ assert this.initialCb!=null; this.initialCb=null; return; } assert !cbs.contains(null) : cbs; //assert this.cbs.get(size-1)!=null; this.cbs.set(size-1,null); } }