package synthesijer.ast.opt;
import java.util.Hashtable;
import synthesijer.SynthesijerUtils;
import synthesijer.ast.Expr;
import synthesijer.ast.Method;
import synthesijer.ast.Module;
import synthesijer.ast.Op;
import synthesijer.ast.Scope;
import synthesijer.ast.SimpleEvaluator;
import synthesijer.ast.Type;
import synthesijer.ast.expr.ArrayAccess;
import synthesijer.ast.expr.AssignExpr;
import synthesijer.ast.expr.AssignOp;
import synthesijer.ast.expr.BinaryExpr;
import synthesijer.ast.expr.CondExpr;
import synthesijer.ast.expr.FieldAccess;
import synthesijer.ast.expr.Ident;
import synthesijer.ast.expr.Literal;
import synthesijer.ast.expr.MethodInvocation;
import synthesijer.ast.expr.NewArray;
import synthesijer.ast.expr.NewClassExpr;
import synthesijer.ast.expr.ParenExpr;
import synthesijer.ast.expr.TypeCast;
import synthesijer.ast.expr.UnaryExpr;
import synthesijer.ast.statement.VariableDecl;
import synthesijer.ast.type.PrimitiveTypeKind;
import synthesijer.ast.type.StringType;
public class StaticEvaluator {
private Hashtable<String, Expr> identTable = new Hashtable<>();
public Module conv(Module m){
Module newM = new Module(m.getParentScope(), m.getName(), m.getImportTable(), m.getExtending(), m.getImplementingList());
newM.setSynthesijerHDL(m.isSynthesijerHDL());
for(VariableDecl v: m.getVariableDecls()){
VariableDecl newV = conv(newM, v);
newM.addVariableDecl(newV);
}
// update
for(VariableDecl v: newM.getVariableDecls()){
if(identTable.containsKey(v.getVariable().getName())){
Expr e = identTable.get(v.getVariable().getName());
v.setInitExpr(e);
}
}
// methods are copied as is
for(Method method: m.getMethods()){
newM.addMethod(method);
}
return newM;
}
private VariableDecl conv(Scope parent, VariableDecl v){
Expr newInitExpr = conv(parent, v.getInitExpr());
VariableDecl newV = new VariableDecl(parent, v.getName(), v.getType(), newInitExpr);
newV.setGlobalConstant(v.isGlobalConstant());
newV.setPublic(v.isPublic());
newV.setVolatile(v.isVolatile());
newV.setMethodParam(v.isMethodParam());
if(newInitExpr != null){
identTable.put(v.getVariable().getName(), newInitExpr);
}
//System.out.println(identTable);
return newV;
}
/*
* convert expressions
*/
public Expr conv(Scope scope, Expr expr){
if(expr == null){
return null;
}else if(expr instanceof ArrayAccess){
return conv(scope, (ArrayAccess)expr);
}else if(expr instanceof AssignExpr){
return conv(scope, (AssignExpr)expr);
}else if(expr instanceof AssignOp){
return conv(scope, (AssignOp)expr);
}else if(expr instanceof BinaryExpr){
return conv(scope, (BinaryExpr)expr);
}else if(expr instanceof CondExpr){
return conv(scope, (CondExpr)expr);
}else if(expr instanceof FieldAccess){
return conv(scope, (FieldAccess)expr);
}else if(expr instanceof Ident){
return conv(scope, (Ident)expr);
}else if(expr instanceof Literal){
return conv(scope, (Literal)expr);
}else if(expr instanceof MethodInvocation){
return conv(scope, (MethodInvocation)expr);
}else if(expr instanceof NewArray){
return conv(scope, (NewArray)expr);
}else if(expr instanceof NewClassExpr){
return conv(scope, (NewClassExpr)expr);
}else if(expr instanceof ParenExpr){
return conv(scope, (ParenExpr)expr);
}else if(expr instanceof TypeCast){
return conv(scope, (TypeCast)expr);
}else if(expr instanceof UnaryExpr){
return conv(scope, (UnaryExpr)expr);
}else{
throw new RuntimeException("[Internal Error] no convesion rule for " + expr);
}
}
private Expr conv(Scope scope, ArrayAccess expr){
ArrayAccess newE = new ArrayAccess(scope);
newE.setIndex(conv(scope, expr.getIndex()));
newE.setIndexed(conv(scope, expr.getIndexed()));
return newE;
}
private Expr conv(Scope scope, AssignExpr expr){
Expr rhs = conv(scope, expr.getRhs());
Expr lhs = conv(scope, expr.getRhs());
if(lhs instanceof Ident){
identTable.put(((Ident)lhs).getSymbol(), rhs);
}
return rhs;
}
private Expr conv(Scope scope, AssignOp expr){
Expr rhs = conv(scope, expr.getRhs());
Expr lhs = conv(scope, expr.getLhs());
Expr ret = null;
if(lhs instanceof Literal && rhs instanceof Literal){
Literal a = (Literal)lhs;
Literal b = (Literal)rhs;
try{
Literal newL = SimpleEvaluator.eval(expr.getOp(), a.getType(), a.getValueAsStr(), b.getType(), b.getValueAsStr());
ret = newL;
}catch(Exception e){
System.out.println("eval failuer:" + expr);
}
}else{
AssignOp newE = new AssignOp(scope);
newE.setRhs(rhs);
newE.setLhs(lhs);
newE.setOp(expr.getOp());
ret = newE;
}
if(lhs instanceof Ident){
identTable.put(((Ident)lhs).getSymbol(), rhs);
}
return ret;
}
private boolean isConstant(Expr e){
if(e instanceof Literal) return true;
else if(e instanceof Ident){
return isConstant(identTable.get(((Ident)e).getSymbol()));
}else{
return false;
}
}
private Literal getLiteral(Expr e){
if(e instanceof Literal) return (Literal)e;
else{
return getLiteral(identTable.get(((Ident)e).getSymbol()));
}
}
private Expr conv(Scope scope, BinaryExpr expr){
Expr rhs = conv(scope, expr.getRhs());
Expr lhs = conv(scope, expr.getLhs());
if(isConstant(lhs) && isConstant(rhs)){
Literal a = getLiteral(lhs);
Literal b = getLiteral(rhs);
try{
Literal newL = SimpleEvaluator.eval(expr.getOp(), a.getType(), a.getValueAsStr(), b.getType(), b.getValueAsStr());
return newL;
}catch(Exception e){
System.out.println("eval failuer:" + expr);
}
}
BinaryExpr newE = new BinaryExpr(scope);
newE.setRhs(rhs);
newE.setLhs(lhs);
newE.setOp(expr.getOp());
return newE;
}
private Expr conv(Scope scope, CondExpr expr){
Expr cond = conv(scope, expr.getCond());
Expr truePart = conv(scope, expr.getTruePart());
Expr falsePart = conv(scope, expr.getFalsePart());
if(cond instanceof Literal && ((Literal) cond).isBoolean()){
if(Boolean.parseBoolean(((Literal)cond).getValueAsStr())){
return truePart;
}else{
return falsePart;
}
}else{
CondExpr newE = new CondExpr(scope);
newE.setCond(cond);
newE.setTruePart(truePart);
newE.setFalsePart(falsePart);
return newE;
}
}
private Expr conv(Scope scope, FieldAccess expr){
FieldAccess newE = new FieldAccess(scope);
Expr ident = conv(scope, expr.getIdent());
if(!(ident instanceof Ident)){
throw new RuntimeException("FieildAccess should be Ident: " + ident);
}
newE.setIdent((Ident)(conv(scope, expr.getIdent())));
newE.setSelected(conv(scope, expr.getSelected()));
return newE;
}
private Expr conv(Scope scope, Ident expr){
Ident newE = new Ident(scope);
newE.setIdent(expr.getSymbol());
return newE;
}
private Expr conv(Scope scope, Literal expr){
Type t = expr.getType();
Literal newE = new Literal(scope);
if(t == PrimitiveTypeKind.UNDEFINED){
// nothing to do
}else if(t == PrimitiveTypeKind.BOOLEAN){
newE.setValue(Boolean.parseBoolean(expr.getValueAsStr()));
}else if(t == PrimitiveTypeKind.BYTE){
newE.setValue(Byte.parseByte(expr.getValueAsStr()));
}else if(t == PrimitiveTypeKind.CHAR){
newE.setValue((char)(Integer.parseInt(expr.getValueAsStr())));
}else if(t == PrimitiveTypeKind.SHORT){
newE.setValue(Short.parseShort(expr.getValueAsStr()));
}else if(t == PrimitiveTypeKind.INT){
newE.setValue(Integer.parseInt(expr.getValueAsStr()));
}else if(t == PrimitiveTypeKind.LONG){
newE.setValue(Long.parseLong(expr.getValueAsStr()));
}else if(t == PrimitiveTypeKind.DOUBLE){
newE.setValue(Double.parseDouble(expr.getValueAsStr()));
}else if(t == PrimitiveTypeKind.FLOAT){
newE.setValue(Float.parseFloat(expr.getValueAsStr()));
}else if(t == PrimitiveTypeKind.NULL){
newE.setNull();
}else if(t instanceof StringType){
newE.setValue(expr.getValueAsStr());
}else{
SynthesijerUtils.warn("unsupported type for Literal: " + t);
}
return newE;
}
private Expr conv(Scope scope, MethodInvocation expr){
MethodInvocation newE = new MethodInvocation(scope);
newE.setMethod(conv(scope, expr.getMethod()));
for(Expr e: expr.getParameters()){
newE.addParameter(conv(scope, e));
}
return newE;
}
private Expr conv(Scope scope, NewArray expr){
NewArray newE = new NewArray(scope);
for(Expr e: expr.getDimExpr()){
newE.addDimExpr(conv(scope, e));
}
for(Expr e: expr.getElems()){
newE.addElem(conv(scope, e));
}
return newE;
}
private Expr conv(Scope scope, NewClassExpr expr){
NewClassExpr newE = new NewClassExpr(scope);
for(Expr e: expr.getParameters()){
newE.addParam(conv(scope, e));
}
newE.setClassName(expr.getClassName());
return newE;
}
private Expr conv(Scope scope, ParenExpr expr){
Expr e = conv(scope, expr.getExpr());
if(e instanceof Literal){
return e;
}else if(isConstant(e)){
Expr newE = conv(scope, e);
return newE;
}else{
ParenExpr newE = new ParenExpr(scope);
newE.setExpr(e);
return newE;
}
}
private Expr conv(Scope scope, TypeCast expr){
Expr e = conv(scope, expr.getExpr());
Type t = expr.getType();
if(e instanceof Literal){
((Literal)e).castType(t);
return e;
}else{
TypeCast newE = new TypeCast(scope);
newE.setExpr(conv(scope, expr.getExpr()));
newE.setTargetType(expr.getType());
return newE;
}
}
private Expr conv(Scope scope, UnaryExpr expr){
//System.out.println(identTable);
Expr arg = conv(scope, expr.getArg());
if(isConstant(arg)){
Literal l = getLiteral(arg);
try{
Literal newL = SimpleEvaluator.eval(expr.getOp(), l.getType(), l.getValueAsStr());
if(expr.getOp() == Op.INC || expr.getOp() == Op.DEC){
identTable.put(((Ident)arg).getSymbol(), newL); // update
}
if(expr.isPostfix()){
return l.copy(scope); // as is
}else{
return newL; // updated value
}
}catch(Exception e){
System.out.println("eval failuer:" + expr);
}
}else{
//System.out.println(expr);
}
UnaryExpr newE = new UnaryExpr(scope);
newE.setArg(arg);
newE.setOp(expr.getOp());
newE.setPostfix(expr.isPostfix());
//System.out.println(newE);
return newE;
}
}