package reduction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import platformSpecific.javaTranslation.Resources;
import programReduction.Program;
import sugarVisitors.ToFormattedText;
import tools.Assertions;
import tools.Map;
import tools.Match;
import coreVisitors.*;
import facade.Configuration;
import facade.ErrorFormatter;
import facade.L42;
import facade.PData;
import facade.Parser;
import ast.Ast;
import ast.Ast.Doc;
import ast.Ast.Mdf;
import ast.Ast.MethodSelector;
import ast.Ast.Path;
import ast.Ast.Stage;
import ast.Ast.Type;
import ast.Ast.NormType;
//import ast.Ast.*;//NO too much clashes
import ast.ErrorMessage;
import ast.ExpCore;
import ast.ExpCore.Block;
import ast.ExpCore.Block.Dec;
import ast.ExpCore.ClassB;
import ast.ExpCore.WalkBy;
import ast.ExpCore.ClassB.Member;
import ast.Redex.LoopR;
import ast.Redex.Using;
import auxiliaryGrammar.Ctx;
import auxiliaryGrammar.Functions;
import ast.ExpCore.*;
import ast.ExpCore.Block.*;
import ast.ExpCore.ClassB.*;
import ast.Redex;
import ast.Redex.*;
abstract public class Executor {
abstract protected ExpCore executeAtomicStep(PData p1, ExpCore e1,Ast.C nestedName);
abstract protected ClassB meta1(Program p, ClassB cb, NestedClass m);
abstract protected void log(String s);
static public ExpCore last1=null;
static public ExpCore last2=null;
public static void dbgRecordNext(ExpCore e){
last2=last1;
last1=e;
}
public static ExpCore stepStar(Executor executer,ExpCore e){
final Program emptyP=Program.emptyLibraryProgram();
int iteration=0;
dbgRecordNext(e);
executer.log("--------------------"+(iteration+=1));
//TestHelper.dbgCompact(e);
try{while(true){
assert coreVisitors.CheckNoVarDeclaredTwice.of((ClassB) e);
e=NormalizeBlocks.of(e);
e=executer.step(new PData(emptyP),e);
dbgRecordNext(e);
assert coreVisitors.CheckNoVarDeclaredTwice.of((ClassB) e);
executer.log("--------------------"+(iteration+=1));
//TestHelper.dbgCompact(e);
}}
//catch(ErrorMessage.NormalForm mess){ return mess.getE();}
catch(ErrorMessage.CtxExtractImpossible mess){
assert e instanceof ClassB;
if(!L42.trustPluginsAndFinalProgram){
ClassB ct=(ClassB)e;
Program p1=emptyP.evilPush(ct);
assert false;//I think this is all old code?
//Configuration.typeSystem.checkCt( emptyP, ct);
/*if(!p1.checkComplete()){//also check is star
throw new ErrorMessage.MalformedFinalResult(ct,
"Some class can not be completely typed as is still incomplete or refers to incomplete classes"
+ErrorFormatter.reportPlaceOfMetaError(p1,ct)
);
}*/
}
return e;}
}
final public ExpCore step(PData p,ExpCore e){
throw Assertions.codeNotReachable();//the whole reduction will soon disappear
/*try{
Ctx<Redex> ctx=ExtractCtxVal.of(p.p, e);
log("---REDEX--: "+ctx.hole.getClass().getSimpleName());
return Match.<ExpCore>of(ctx.hole)
.add(Redex.Garbage.class, r->garbage(ctx.ctx,r))
.add(Redex.CaptureOrNot.class, r->captureOrNot(p.p,ctx.ctx,r))
.add(Redex.BlockElim.class, r->blockElim(ctx.ctx,r))
.add(Redex.Subst.class, r->subst(ctx.ctx,r))
.add(Redex.MethCall.class, r->methCall(p.p,ctx.ctx,r))
.add(Redex.Ph.class, r->ph(p.p,ctx.ctx,r))
.add(Redex.NoThrowRemoveOn.class, r->removeCatch(ctx.ctx,r))
.add(Redex.LoopR.class, r->loopR(ctx.ctx,r))
.add(Redex.UsingOut.class, r->usingOut(p.p,ctx.ctx,r))
.add(Redex.Using.class, r->using(p.p,ctx.ctx,r))
.add(Redex.Meta.class, r->meta(p.p,ctx.ctx,r))
.end();}
catch(ErrorMessage.CtxExtractImpossible rethrow){
throw rethrow;//to debug
}*/
}
public static ExpCore subst(ExpCore ctxVal,Redex.Subst r){
Block e1=r.getThat();
int i=r.getSubstIndex();
ExpCore val=e1.getDecs().get(i).getInner();
String x=e1.getDecs().get(i).getX();
ArrayList<Block.Dec> decs = new ArrayList<Block.Dec>(e1.getDecs());
decs.remove(i);
Block e2=new Block(e1.getDoc(),decs,e1.getInner(),e1.getOns(),e1.getP());
ExpCore result=ReplaceX.of(e2,val,x);
return ReplaceCtx.of(ctxVal,result);
}
protected ClassB meta1Prop(Program p, ClassB cb, NestedClass m) {
log("---meta1Prop--");
//get cb-->ct
//get p'
Program p1=p.evilPush(cb);
//extract e
ExpCore e=m.getInner();
//extract cb
Ctx<ClassB> ctxC=ExtractCtxCompiled.of(e);
//run cb1-->cb2
ClassB cb2=(ClassB)step(new PData(p1), ctxC.hole);
ExpCore e2=ReplaceCtx.of(ctxC.ctx,cb2);
//compose cb with new member
return cb.withMember(m.withInner(e2));
}
protected ClassB metaMethod(Program p, ClassB cb, Member m) {
log("---meta2--");
//get cb-->ct
//get p'
Program p1=p.evilPush(cb);
//extract e
ExpCore e=m.getInner();
//extract cb
Ctx<ClassB> ctxC=ExtractCtxCompiled.of(e);
//run cb1-->cb2
ClassB cb2=(ClassB)step(new PData(p1), ctxC.hole);
ExpCore e2=ReplaceCtx.of(ctxC.ctx,cb2);
//compose cb with new member
return cb.withMember(m.withInner(e2));
}
/*
private static ExpCore using(Program p, ExpCore ctxVal, Using r) {
return ReplaceCtx.of(ctxVal,r.getToReplace());
}
private static ExpCore usingOut(Program p, ExpCore ctxVal, UsingOut r) {
ExpCore inner=r.getThat().getInner();
return ReplaceCtx.of(ctxVal,inner);
}
private static ExpCore loopR(ExpCore ctxVal, LoopR r) {
HashSet<String> usedAround = new HashSet<String>(HB.of(ctxVal, false));
HashSet<String> usedSomewhere = new HashSet<String>(HB.of(r.getThat().getInner(), false));
HashSet<String> forbidden = new HashSet<String>(usedSomewhere);
forbidden.addAll(usedAround);
String x=Functions.freshName(Path.Void(), forbidden);
ExpCore newInner=r.getThat().getInner();
HashMap<String,String> renames=new HashMap<String,String>();
for(String s:usedSomewhere){
String s2=Functions.freshName(s,forbidden);
renames.put(s, s2);
}
newInner=RenameVars.of(newInner,renames);
assert checkSuccessRename(usedSomewhere, newInner);
Block.Dec xDec=new Block.Dec(NormType.immVoid,x,newInner);
Ast.Position pos=null; if(r.getThat().getInner() instanceof Ast.HasPos){pos=((Ast.HasPos)r.getThat().getInner()).getP();}
Block result=new Block(Doc.empty(),Collections.singletonList(xDec),r.getThat(),Collections.emptyList(),pos);
return ReplaceCtx.of(ctxVal, result);
}
//NO! the ctc could no be extracted//.end(new ErrorMessage.NormalForm(e,p.getInnerData()));}
private ExpCore meta(Program p, ExpCore ctx, Meta r) {
ClassB cb=r.getThat();
assert !IsCompiled.of(cb);
Member m=Functions.firstIncomplete(cb);
if(m instanceof NestedClass && IsCompiled.of(((NestedClass)m).getInner())){
return ReplaceCtx.of(ctx, meta1(p,cb,(NestedClass)m));
}
if(m instanceof NestedClass){//&& not is compiled
return ReplaceCtx.of(ctx, meta1Prop(p,cb,(NestedClass)m));
}
return ReplaceCtx.of(ctx, metaMethod(p,cb,m));
}
private static ExpCore removeCatch(ExpCore ctxVal, NoThrowRemoveOn r) {
return ReplaceCtx.of(ctxVal,r.getThat().withOns(Collections.emptyList()));
}
private ExpCore methCall(Program p, ExpCore ctxVal, MethCall r) {
MCall mc = r.getThat();
Path pathR=Functions.classOf(p, ctxVal, mc.getInner());
MethodWithType mwt = p.method(pathR,mc.getS(),mc,false);
if(mwt.get_inner().isPresent()){
return normalMeth(pathR,mwt,ctxVal,mc);
}
HashSet<String> usedNames = new HashSet<String>(HB.of(ctxVal, false));
usedNames.add("this");
usedNames.addAll(HB.of(mc, false));
if (!IsValue.isAtom(mc.getInner())){
return ReplaceCtx.of(ctxVal,primCallRec( mc, pathR, mwt, usedNames));
}
for(int i=0;i<mc.getEs().size();i++){
if(!IsValue.isAtom(mc.getEs().get(i))){
return ReplaceCtx.of(ctxVal,primCallArg(p,mc,i,mwt,usedNames));
}
}
//case new
if(mwt.getMt().getMdf()==ast.Ast.Mdf.Class){
return ReplaceCtx.of(ctxVal,rNew(mc,mwt,usedNames));
}
//assert IsValue.of(Resources.getP(),mc.getReceiver());
// assert new IsValue().validDvs(ctxVal.coreVisitors.Dec.of(ctxVal, ((ExpCore.X)mc.getReceiver()).getInner(),false));
//case getter-exposer
if(mwt.getMs().getNames().isEmpty()){
return fieldA(ctxVal, mc, mwt, usedNames);
}
//case setter
return fieldU(ctxVal, mc);
}
private ExpCore fieldU(ExpCore ctxVal, MCall mc) {
log("---meth FieldU--");
String x=((ExpCore.X)mc.getInner()).getInner();
Ctx<Block> _ctx=ExtractCtxUpToX.of(x,ctxVal);
//ctxVal[mc] --> ctxVal_0[ctxVal_1[mc]]
//ctxVal_1 is Block, have dvs containing x mut or lent
ExpCore ctxVal0=_ctx.ctx;
Block ctxVal1=_ctx.hole;
Block.Dec xDec=ctxVal1.getDecs().get(ctxVal1.domDecs().indexOf(x));
Mdf xMdf=xDec.getT().getNT().getMdf();
if(xMdf!=Mdf.Mutable && xMdf!=Mdf.Lent){
throw new ErrorMessage.IllegalAttemptedModification(ctxVal1,xDec,mc);
}
ExpCore newVal=mc.getEs().get(0);
assert IsValue.isAtom(newVal);
Block ctxVal2=ctxVal1;
if(newVal instanceof Block.X){
ctxVal2=Move.of(ctxVal1, ((Block.X)newVal).toString());
}
ctxVal2=(Block)ReplaceCtx.of(ctxVal2,new ExpCore._void());
ctxVal2=ctxVal2.withDecs(Functions.replace(ctxVal2.getDecs(), mc));
return ReplaceCtx.of(ctxVal0,ctxVal2);
}
private ExpCore fieldA(ExpCore ctxVal, MCall mc, MethodWithType mwt,HashSet<String> usedNames) {
//case get-exposer
ExpCore decRec=coreVisitors.Dec.of(ctxVal, ((ExpCore.X)mc.getInner()).getInner(),false);
if(decRec instanceof Block){
coreVisitors.Dec.of(ctxVal, ((ExpCore.X)mc.getInner()).getInner(),true);
//this may throw errors on purpose
//fieldABlock
Set<String> around = new HashSet<String>(HB.of(ctxVal, false));
return ReplaceCtx.of(ctxVal,fieldABlock(around,mc, mwt, usedNames, (Block)decRec));
}
//fieldAObj
log("---meth fieldA obj--");
String fName=mc.getS().nameToS();
if(fName.startsWith("#")){fName=fName.substring(1);}
MCall decRec2=(MCall)decRec;
//assert IsValue.of(Resources.getP(),decRec2);
for(int i=0;i<decRec2.getS().getNames().size();i++){
if(!decRec2.getS().getNames().get(i).equals(fName)){continue;}
return ReplaceCtx.of(ctxVal, decRec2.getEs().get(i));
}
throw Assertions.codeNotReachable();
}
private Block fieldABlock(Set<String> around,MCall mc, MethodWithType mwt,HashSet<String> usedNames, Block decRec) {
log("---meth fieldABlock--");
HashSet<String> inside = new HashSet<String>(HB.of(decRec, false));
HashSet<String> forbidden=new HashSet<String>(around);
forbidden.addAll(inside);
forbidden.addAll(usedNames);
HashMap<String,String> renames=new HashMap<String,String>();
for(String s:inside){
if(!around.contains(s)){continue;}
String s2=Functions.freshName(s,forbidden);
renames.put(s, s2);
}
decRec=(Block)RenameVars.of(decRec,renames);
assert checkSuccessRename(around, decRec);
Path path1=((NormType)mwt.getMt().getReturnType()).getPath();
Type tz=path1.toImmNT();
String z=Functions.freshName(path1, forbidden);
MCall mcz=mc.withInner(decRec.getInner());
ExpCore ez=decRec.withInner(mcz);
Block result=new Block(Doc.empty(),Collections.singletonList(new Block.Dec(tz,z,ez)),new ExpCore.X(z),Collections.emptyList(),mc.getP());
return result;
}
private ExpCore rNew(MCall mc, MethodWithType mwt,HashSet<String> usedNames) {
log("---method rNew--");
NormType t0=(NormType)mwt.getMt().getReturnType();
String x0=Functions.freshName(t0.getPath(), usedNames);
return new Block(Doc.empty(),Collections.singletonList(new Block.Dec(t0,x0,mc)),
new ExpCore.X(x0),Collections.emptyList(),mc.getP());
}
private ExpCore primCallArg(Program p,MCall mc, int i, MethodWithType mwt, HashSet<String> usedNames) {
//String xRole=ms.getXs().get(i);
log("---primCallArg--");
NormType ti=mwt.getMt().getTs().get(i).match(n->n, hType->Norm.resolve(p,hType));
Path pi=ti.getPath();
ti=Functions.toComplete(ti);
String xi=Functions.freshName(pi,usedNames);
ExpCore ei=mc.getEs().get(i);
ArrayList<ExpCore> es = new ArrayList<ExpCore>(mc.getEs());
es.set(i, new ExpCore.X(xi));
return new Block(Doc.empty(),Collections.singletonList(new Block.Dec(ti,xi,ei)),
mc.withEs(es),Collections.emptyList(),mc.getP());
}
private ExpCore primCallRec(MCall mc, Path pathR,MethodWithType mwt, HashSet<String> usedNames) {
NormType t1=Functions.toComplete(new NormType(mwt.getMt().getMdf(),pathR,Doc.empty()));
log("---primCallRec--");
String x1=Functions.freshName(pathR,usedNames);
ExpCore e1=mc.getInner();
return new Block(Doc.empty(),Collections.singletonList(new Block.Dec(t1,x1,e1)),
mc.withInner(new ExpCore.X(x1)),Collections.emptyList(),mc.getP());
}
private ExpCore normalMeth(Path pathR,MethodWithType mwt, ExpCore ctxVal, MCall mc) {
log("---normalMeth--");
HashSet<String> around = new HashSet<String>(HB.of(ctxVal, false));//TODO: it may be true in a more permissive scoping
around.add("this");
HashSet<String> aroundAndParameters = new HashSet<String>(around);
aroundAndParameters.addAll(HB.of(mc.getInner(), false));
for(ExpCore ei:mc.getEs()){
aroundAndParameters.addAll(HB.of(ei, false));
}
HashSet<String> inside = new HashSet<String>(HB.of(mwt.getInner(), false));
inside.addAll(mwt.getMs().getNames());
inside.add("this");
HashSet<String> forbidden=new HashSet<String>(aroundAndParameters);
forbidden.addAll(inside);
HashMap<String,String> renames=new HashMap<String,String>();
for(String s:inside){
if(!aroundAndParameters.contains(s)){continue;}
String s2=Functions.freshName(s,forbidden);
renames.put(s, s2);
}
ExpCore e=RenameVars.of(mwt.getInner(),renames);
assert checkSuccessRename(aroundAndParameters, e);
for(String pari:mwt.getMs().getNames()){
if(!renames.containsKey(pari)){
renames.put(pari, pari);
}
}
ArrayList<Block.Dec> decs=new ArrayList<Block.Dec>();
decs.add( new Block.Dec(
Functions.toComplete(new NormType(mwt.getMt().getMdf(),pathR,Doc.empty())),
renames.get("this"),
mc.getInner()));
for(int i=0;i<mc.getEs().size();i++){
decs.add(new Block.Dec(
mwt.getMt().getTs().get(i),
renames.get(mwt.getMs().getNames().get(i)),
mc.getEs().get(i)));
}
Block e2=new Block(mc.getDoc(),decs,e,Collections.emptyList(),mc.getP());
//System.out.println(aroundAndParameters+"\n"+ToFormattedText.of(e2)+"\n@@\n@@\n"+ToFormattedText.of(mc));
assert checkSuccessRename(around, e2);
ExpCore result= ReplaceCtx.of(ctxVal,e2);
assert !(result instanceof ExpCore.ClassB) || WellFormedness.checkCoreVariables((ExpCore.ClassB)result);
return result;
}
private static boolean checkSuccessRename(Set<String> around, ExpCore e) {
HashSet<String> eIn = new HashSet<String>(HB.of(e, false));
for(String s:eIn){
assert !around.contains(s):s;
}
return true;
}
private static ExpCore garbage(ExpCore ctxVal,Redex.Garbage r){
return ReplaceCtx.of(ctxVal,r.getThatLessGarbage());
}
private static ExpCore captureOrNot(Program p,ExpCore ctxVal,Redex.CaptureOrNot r){
Block e1=r.getThat();
Signal s=r.getThrowExtracted();
int i=r.getThrowIndex();
ArrayList<Block.Dec> decsUpToI = new ArrayList<Block.Dec>();
for(int ii=0;ii<i;ii++){
decsUpToI.add(e1.getDecs().get(ii));
}
//case notCapture zero ons not here
//case capture
//-subtype
Path c=Functions.classOf(p, ctxVal,decsUpToI, s.getInner());
List<On> catch_ = e1.getOns();
assert !catch_.isEmpty();
On on=catch_.get(0);
NormType onT=Norm.of(p, on.getT());
//TODO: -hope garbage remove dvx' properly
ArrayList<Block.Dec> decs = new ArrayList<Block.Dec>(decsUpToI);
if(s.getKind()==on.getKind() && Functions.isSubtype(p, c, onT.getPath())){
decs.add(new Block.Dec(
onT,on.getX(),s.getInner()));
Block e2=new Block(e1.getDoc(),decs,on.getInner(),Collections.emptyList(),e1.getP());
return ReplaceCtx.of(ctxVal,e2);
}
//case notCapture
decs.add(e1.getDecs().get(i).withInner(s));
return ReplaceCtx.of(ctxVal,rOnMiss(decs,e1));
}
private static ExpCore rOnMiss(ArrayList<Block.Dec> ds,Block b) {
Block result=removeOneOn(b);
return result.withDecs(ds);
}
private static Block removeOneOn(Block e1){
List<On> k = e1.getOns();
assert !k.isEmpty();
return e1.withOns(k.subList(1, k.size()));
}
private ExpCore blockElim(ExpCore ctxVal,Redex.BlockElim r){
log("-- block elim --");
//System.out.println("Block elim over"+r.getElimIndex()+ToFormattedText.of(r.getThat()));
Block e1=r.getThat();
int ii=r.getElimIndex();
ArrayList<Block.Dec> decs = new ArrayList<Block.Dec>(e1.getDecs());
Block eInner=(Block)decs.get(ii).getInner();
assert eInner.getOns().isEmpty();
decs.set(ii,decs.get(ii).withInner(eInner.getInner()));
decs.addAll(ii, eInner.getDecs());
//Note: we lose the docs on eInner, is it ok?
Block result=e1.withDecs(decs);
return ReplaceCtx.of(ctxVal,result);
}
private static ExpCore ph(Program p,ExpCore ctxVal,Redex.Ph r){
Block b=r.getThat();
ArrayList<Block.Dec> decs = new ArrayList<Block.Dec>(b.getDecs());
Dec deci = decs.get(r.getPhIndex());
NormType ti=deci.getT().getNT();
Path path=Functions.classOf(p, ctxVal, deci.getInner());
ti=Functions.toComplete(ti).withPath(path);
decs.set(r.getPhIndex(),deci.withT(ti));
return ReplaceCtx.of(ctxVal,b.withDecs(decs));
}
*/
}