package coreVisitors;
import java.util.HashSet;
import ast.Ast.Mdf;
import ast.Ast.Path;
import ast.ErrorMessage;
import ast.ExpCore;
import ast.ExpCore.Block;
import ast.ExpCore.Block.On;
import ast.ExpCore.ClassB;
import ast.ExpCore.Loop;
import ast.ExpCore.MCall;
import ast.ExpCore.Signal;
import ast.ExpCore.Using;
import ast.ExpCore.WalkBy;
import ast.ExpCore.X;
import ast.ExpCore._void;
public class HB implements Visitor<ExpCore> {
HashSet<String> xs=new HashSet<String>();
HashSet<String> xsRes=new HashSet<String>();
boolean onlyAroundHole;
HB(boolean onlyAroundHole){this.onlyAroundHole=onlyAroundHole;}
public static HashSet<String> of(ExpCore ctxVal, boolean onlyAroundHole){
HB hb=new HB(onlyAroundHole);
ctxVal.accept(hb);
return hb.xsRes;
}
//return null if not walkBy,
//return walkby on walkby but not dec for x,
//return dec for x otherwise
public ExpCore visit(Signal s) {
return s.getInner().accept(this);
}
public ExpCore visit(Loop s) {
return s.getInner().accept(this);
}
@Override
public ExpCore visit(Using s) {
ExpCore result=null;
for(ExpCore ei:s.getEs()){
result=acc(result,ei.accept(this));
}
return acc(result,s.getInner().accept(this));
}
@Override
public ExpCore visit(MCall s) {
ExpCore result=s.getInner().accept(this);
for(ExpCore ei:s.getEs()){
result=acc(result,ei.accept(this));
}
return result;
}
@Override
public ExpCore visit(Block s) {
ExpCore result=null;
for(Block.Dec di:s.getDecs()){
result=acc(result,di.getInner().accept(this));
}
result=acc(result,s.getInner().accept(this));
if(result==null &&onlyAroundHole){return null;}
assert !onlyAroundHole || result instanceof WalkBy:onlyAroundHole+" "+result;
for(Block.Dec dec:s.getDecs()){
if(xs.contains(dec.getX())){throw new ErrorMessage.VariableDeclaredMultipleTimes(dec.getX(),s.getP());}
this.xs.add(dec.getX());
this.xsRes.add(dec.getX());
}
try{
if(!onlyAroundHole && !s.getOns().isEmpty()){
for(On on:s.getOns()){
if(xs.contains(on.getX())){throw new ErrorMessage.VariableDeclaredMultipleTimes(on.getX(),s.getP());}
xs.add(on.getX());
xsRes.add(on.getX());
on.getInner().accept(this);
xs.remove(on.getX());
}
}
return result;
}finally{
for(Block.Dec dec:s.getDecs()){
this.xs.remove(dec.getX());
}
}
}
public ExpCore visit(ExpCore.EPath s) {return null;}
public ExpCore visit(X s) {return null;}
public ExpCore visit(_void s) {return null;}
public ExpCore visit(WalkBy s) {return s;}
public ExpCore visit(ClassB s) {return null;}
private ExpCore acc(ExpCore c1,ExpCore c2){
if(c2==null){return c1;}
return c2;
}
}