package is.L42.connected.withSafeOperators; import ast.Ast.Doc; import ast.Ast.Mdf; import ast.Ast.MethodSelector; import ast.Ast.MethodType; import ast.Ast.Path; import ast.Ast.Position; import ast.Ast.Type; import ast.Ast; import ast.ExpCore; import ast.ExpCore.*; import ast.ExpCore.ClassB.Member; import ast.ExpCore.ClassB.MethodImplemented; import ast.ExpCore.ClassB.MethodWithType; import ast.ExpCore.ClassB.NestedClass; import ast.Util.PathMwt; import auxiliaryGrammar.Functions; import programReduction.Program; import coreVisitors.From; import tools.Assertions; import java.util.*; import java.util.stream.Collectors; public class SumMethods { public static ClassB sumMethods(ClassB lib, List<Ast.C> path, MethodSelector m1,MethodSelector m2,MethodSelector mRes,String name){ ClassB pathCb = pathCb(lib, path); Member mem1=Errors42.checkExistsPathMethod(lib, path, Optional.of(m1)); Member mem2=Errors42.checkExistsPathMethod(lib, path, Optional.of(m2)); MethodType mt1=((MethodWithType)pathCb._getMember(m1)).getMt(); MethodType mt2=((MethodWithType)pathCb._getMember(m2)).getMt(); int index=m2.getNames().indexOf(name); if(index==-1){ throw Errors42.errorParameterMismatch(path, mem1,mem2, false,false,false); } checkParSize(index,path, m1, m2, mRes, mem1, mem2, mt1, mt2); MethodType mtU=mtU(index,mt1,mt2); if(mtU==null){throw Errors42.errorParameterMismatch(path, mem1,mem2, isReplacedParOk(index,mt1,mt2),false,true);} ExpCore eU=eU(index,mem2.getP(),mt1,mt2,m1,m2, mRes); MethodWithType mwtU=new MethodWithType(Doc.empty(),mRes,mtU,Optional.of(eU),mem2.getP() ); checkConflict(path, mRes, pathCb, mwtU); boolean replOk=isReplacedParOk(index,mt1,mt2); if(!replOk){throw Errors42.errorParameterMismatch(path, mem1,mem2, false,true,true);} return finalResult(lib, path, mwtU); } private static ClassB finalResult(ClassB lib, List<Ast.C> path, MethodWithType mwtU) { if(path.isEmpty()){ return lib.withMember(mwtU); }//if may be omitted? return lib.onClassNavigateToPathAndDo(path,cbi->cbi.withMember(mwtU)); } private static void checkParSize(int index,List<Ast.C> path, MethodSelector m1, MethodSelector m2, MethodSelector mRes, Member mem1, Member mem2, MethodType mt1, MethodType mt2) { if(m1.getNames().size()+m2.getNames().size()-1!=mRes.getNames().size()){ throw Errors42.errorParameterMismatch(path, mem1,mem2, isReplacedParOk(index,mt1,mt2),mdfU(mt1.getMdf(),mt2.getMdf())!=null,false); } } private static ClassB pathCb(ClassB lib, List<Ast.C> path) { ClassB pathCb=lib; if(!path.isEmpty()){ pathCb=(ClassB)((NestedClass)Errors42.checkExistsPathMethod(lib, path, Optional.empty())).getInner(); } return pathCb; } private static void checkConflict(List<Ast.C> path, MethodSelector mRes, ClassB pathCb, MethodWithType mwtU) { /*for(PathMwt e:pathCb.getStage().getInherited()){ if(e.getMwt().getMs().equals(mRes)){//method declared in an interface and not implemented MethodWithType mtConflict=e.getMwt(); mtConflict=From.from(mtConflict, From.fromP(e.getOriginal(),Path.outer(0,path))); Errors42.checkMethodClash(path, mwtU,mtConflict,false); } }*/ //unneded for normalized classb Optional<Member> optConflict = Functions.getIfInDom(pathCb.getMs(),mRes); if(optConflict.isPresent()){ if(optConflict.get() instanceof MethodImplemented){ throw Errors42.errorMethodClash(path,mwtU, optConflict.get(), true,Collections.emptyList(),true,true,false); } MethodWithType mwtC=(MethodWithType)optConflict.get(); Errors42.checkMethodClash(path, mwtU,mwtC,false); } } static MethodType mtU(int index,MethodType mt1,MethodType mt2){ Mdf mdfU=mdfU(mt1.getMdf(),mt2.getMdf()); if(mdfU==null){return null;} Type removed=mt2.getTs().get(index); boolean isRemovedPh=removed.match(nt->!Functions.isComplete(nt), hType->false); List<Type> totTypes; if(isRemovedPh){ totTypes=new ArrayList<>(mt1.getTs()); } else{ totTypes=mt1.getTs().stream().map(t->t.match(nt->Functions.toComplete(nt), hType->hType)).collect(Collectors.toList()); } totTypes.addAll(mt2.getTs()); int toRemove=mt1.getTs().size()+index; totTypes.remove(toRemove); List<Type> exU = new ArrayList<>(mt1.getExceptions()); exU.addAll(mt2.getExceptions()); MethodType mtU =new MethodType(false, mdfU,totTypes,mt2.getReturnType(),exU); return mtU; } static boolean isReplacedParOk(int index,MethodType mt1,MethodType mt2){ if(mt2.getTs().isEmpty()){return false;} Type p1 = mt2.getTs().get(index); Type r = mt1.getReturnType(); return p1.equals(r); } static ExpCore eU(int index,Position pos,MethodType mt1,MethodType mt2,MethodSelector m1,MethodSelector m2,MethodSelector mRes){ ExpCore r1=(mt1.getMdf()==Mdf.Class)?ExpCore.EPath.wrap(Path.outer(0)):new ExpCore.X(pos,"this"); ExpCore r2=(mt2.getMdf()==Mdf.Class)?ExpCore.EPath.wrap(Path.outer(0)):new ExpCore.X(pos,"this"); //this/outer0 . m2(this/outer0 .m1(ps1),ps2) List<ExpCore> ps1=new ArrayList<>(); for(String x:mRes.getNames().subList(0,m1.getNames().size())){ps1.add(new ExpCore.X(pos,x));} ExpCore eInner=new ExpCore.MCall(r1, m1,Doc.empty(), ps1, pos); ArrayList<ExpCore> ps2=new ArrayList<>(); for(int i=1;i<m2.getNames().size();i++){ String x=mRes.getNames().get(m1.getNames().size()+i-1); ps2.add(new ExpCore.X(pos,x)); } ps2.add(index,eInner); ExpCore eU=new ExpCore.MCall(r2, m2, Doc.empty(),ps2 , pos); return eU; } private static Mdf mdfU(Mdf mdf1, Mdf mdf2) { if(mdf1==Mdf.Capsule && mdf2==Mdf.Capsule){return null;} if(mdf1==mdf2){return mdf1;} if(mdf1==Mdf.Class){return mdf2;} if(mdf2==Mdf.Class){return mdf1;} if(mdf1==Mdf.Capsule|| mdf2==Mdf.Capsule){return null;} if(mdf1==Mdf.Immutable|| mdf2==Mdf.Immutable){ if(mdf1==Mdf.Readable ||mdf2==Mdf.Readable){return Mdf.Immutable;} return null; } //not immutable if(mdf1==Mdf.Mutable|| mdf2==Mdf.Mutable){return Mdf.Mutable;} return Mdf.Lent; } }