package com.google.code.joto.ast.beanstmt; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import com.google.code.joto.ast.beanstmt.impl.BeanASTToStringFormatter; import com.google.code.joto.util.attr.DefaultAttributeSupport; import com.google.code.joto.util.attr.IAttributeSupport; import com.google.code.joto.util.attr.IAttributeSupportDelegate; /** * AST for java code relative to javabean handling.<BR/> * very simplified AST sub-part of the java langage! * <p/> * * Typically, it allows writing code like * <pre> * MyClass bean = new MyClass(); * bean.setField1(123); * bean.addElt(new MyClassElement()); * </pre> * * Such code can be created programmatically by * <pre> * // line 1: "MyClass bean = new MyClass();" * VarDeclStmt beanVarDecl = new VarDeclStmt(MyClass.class, "bean", new NewObjectExpr(MyClass.class)); * * // line 2: "bean.setField1(123);" * BeanExpr expr2 = new MethodApplyExpr(new SimpleNameExpr("bean"), "setField1", singletonList(new LiteralExpr(123))); * ExprStmt stmt2 = new ExprStmt(expr2); * * // line 3: "bean.addElt(new MyClassElement());" * BeanExpr expr3 = new MethodApplyExpr(new SimpleNameExpr("bean"), "addElt", new NewObjectExpr(MyClassElement.class)); * ExprStmt stmt3 = new ExprStmt(expr3); * </pre> * */ public abstract class BeanAST implements IAttributeSupportDelegate { private IAttributeSupport attributeSupport; public BeanAST() { } public abstract void visit(BeanASTVisitor v); public abstract <R,A> R visit(BeanASTVisitor2<R,A> v, A arg); public IAttributeSupport getAttributeSupport() { if (attributeSupport == null) { attributeSupport = new DefaultAttributeSupport(); } return attributeSupport; } @Override public String toString() { String javaText = BeanASTToStringFormatter.getInstance().objectToString(this); return javaText; } // ------------------------------------------------------------------------- /** * */ public static abstract class BeanStmt extends BeanAST { } /** * */ public static abstract class BeanExpr extends BeanAST { } /** * */ public static class ExprStmt extends BeanStmt { private BeanExpr beanExpr; public ExprStmt(BeanExpr beanExpr) { this.beanExpr = beanExpr; } public void visit(BeanASTVisitor v) { v.caseExprStmt(this); } public <R,A> R visit(BeanASTVisitor2<R,A> v, A arg) { return v.caseExprStmt(this, arg); } public BeanExpr getExpr() { return beanExpr; } } /** * */ public static class AssignExpr extends BeanExpr { private BeanExpr lhs; private BeanExpr rhs; public AssignExpr(BeanExpr lhs, BeanExpr rhs) { this.lhs = lhs; this.rhs = rhs; } public void visit(BeanASTVisitor v) { v.caseAssign(this); } public <R,A> R visit(BeanASTVisitor2<R,A> v, A arg) { return v.caseAssign(this, arg); } public BeanExpr getLhs() { return lhs; } public BeanExpr getRhs() { return rhs; } public void setRhs(BeanExpr rhs) { this.rhs = rhs; } public void setLhs(BeanExpr lhs) { this.lhs = lhs; } } /** * */ public static class MethodApplyExpr extends BeanExpr { BeanExpr lhsExpr; String methodName; List<BeanExpr> args = new ArrayList<BeanExpr>(); public MethodApplyExpr(BeanExpr lhsExpr, String methodName, List<BeanExpr> args) { this.lhsExpr = lhsExpr; this.methodName = methodName; this.args = args; } public MethodApplyExpr(BeanExpr lhsExpr, String methodName, BeanExpr... optArgs) { this.lhsExpr = lhsExpr; this.methodName = methodName; if (optArgs != null) { args.addAll(Arrays.asList(optArgs)); } } public void visit(BeanASTVisitor v) { v.caseMethodApplyExpr(this); } public <R,A> R visit(BeanASTVisitor2<R,A> v, A arg) { return v.caseMethodApplyExpr(this, arg); } public BeanExpr getLhsExpr() { return lhsExpr; } public String getMethodName() { return methodName; } public List<BeanExpr> getArgs() { return args; } } /** * */ public static class LiteralExpr extends BeanExpr { Object value; public LiteralExpr(Object value) { super(); this.value = value; } public void visit(BeanASTVisitor v) { v.caseLitteralExpr(this); } public <R,A> R visit(BeanASTVisitor2<R,A> v, A arg) { return v.caseLitteralExpr(this, arg); } public Object getValue() { return value; } } /** * */ public static class NewObjectExpr extends BeanExpr { Class<?> newClss; List<BeanExpr> args = new ArrayList<BeanExpr>(); public NewObjectExpr(Class<?> clss) { this(clss, (List<BeanExpr>) null); } public NewObjectExpr(Class<?> clss, BeanExpr... args) { this(clss, Arrays.asList(args)); } public NewObjectExpr(Class<?> clss, List<BeanExpr> args) { super(); this.newClss = clss; if (args != null) { this.args.addAll(args); } } public void visit(BeanASTVisitor v) { v.caseNewObject(this); } public <R,A> R visit(BeanASTVisitor2<R,A> v, A arg) { return v.caseNewObject(this, arg); } public Class<?> getNewClss() { return newClss; } public List<BeanExpr> getArgs() { return args; } } /** * */ public static class NewArrayExpr extends BeanExpr { private Class<?> newArrayClass; private int length; private BeanExpr[] initExprs; public NewArrayExpr(Class<?> newArrayClass, int length) { super(); this.newArrayClass = newArrayClass; this.length = length; } public NewArrayExpr(Class<?> newArrayClass, int length, BeanExpr[] initExprs) { super(); this.newArrayClass = newArrayClass; this.length = length; this.initExprs = initExprs; } public void visit(BeanASTVisitor v) { v.caseNewArray(this); } public <R,A> R visit(BeanASTVisitor2<R,A> v, A arg) { return v.caseNewArray(this, arg); } public Class<?> getNewArrayClass() { return newArrayClass; } public int getLength() { return length; } public BeanExpr[] getInitExprs() { return initExprs; } } /** * */ public static class IndexedArrayExpr extends BeanExpr { private BeanExpr lhs; private BeanExpr index; public IndexedArrayExpr(BeanExpr lhs, BeanExpr index) { super(); this.lhs = lhs; this.index = index; } @Override public void visit(BeanASTVisitor v) { v.caseIndexedArray(this); } @Override public <R, A> R visit(BeanASTVisitor2<R, A> v, A arg) { return v.caseIndexedArray(this, arg); } public BeanExpr getLhs() { return lhs; } public void setLhs(BeanExpr lhs) { this.lhs = lhs; } public BeanExpr getIndex() { return index; } public void setIndex(BeanExpr index) { this.index = index; } } /** * */ public static class ClassExpr extends BeanExpr { String lhsClassName; public ClassExpr(String lhsClassName) { super(); this.lhsClassName = lhsClassName; } public void visit(BeanASTVisitor v) { v.caseClassExpr(this); } public <R,A> R visit(BeanASTVisitor2<R,A> v, A arg) { return v.caseClassExpr(this, arg); } public String getLhsClassName() { return lhsClassName; } } /** * */ public static class FieldExpr extends BeanExpr { private BeanExpr lhs; private String fieldName; public FieldExpr(BeanExpr lhs, String fieldName) { super(); this.lhs = lhs; this.fieldName = fieldName; } public void visit(BeanASTVisitor v) { v.caseFieldExpr(this); } public <R,A> R visit(BeanASTVisitor2<R,A> v, A arg) { return v.caseFieldExpr(this, arg); } public BeanExpr getLhs() { return lhs; } public void setLhs(BeanExpr p) { this.lhs = p; } public void setFieldName(String p) { this.fieldName = p; } public String getFieldName() { return fieldName; } } /** * */ public static class SimpleNameExpr extends BeanExpr { private String name; // TODO can be null + should be more general: use "Symbol" (either LocalVarDecl, ParameterDecl, Field, or Class...) private VarDeclStmt resolvedDecl; public SimpleNameExpr(String p) { super(); this.name = p; } public SimpleNameExpr(VarDeclStmt resolvedDecl) { super(); this.resolvedDecl = resolvedDecl; this.name = resolvedDecl.getVarName(); } public void visit(BeanASTVisitor v) { v.caseSimpleName(this); } public <R,A> R visit(BeanASTVisitor2<R,A> v, A arg) { return v.caseSimpleName(this, arg); } public String getName() { return name; } public VarDeclStmt getResolvedDecl() { return resolvedDecl; } } // ------------------------------------------------------------------------- /** * */ public static class VarDeclStmt extends BeanStmt { private Class<?> declaredType; private String varName; private BeanExpr initExpr; public VarDeclStmt(Class<?> declaredType, String varName, BeanExpr initExpr) { this.declaredType = declaredType; this.varName = varName; this.initExpr = initExpr; } public void visit(BeanASTVisitor v) { v.caseVarDecl(this); } public <R,A> R visit(BeanASTVisitor2<R,A> v, A arg) { return v.caseVarDecl(this, arg); } public Class<?> getDeclaredType() { return declaredType; } public void setDeclaredType(Class<?> declaredType) { this.declaredType = declaredType; } public String getVarName() { return varName; } public void setVarName(String p) { this.varName = p; } public BeanExpr getInitExpr() { return initExpr; } public void setInitExpr(BeanExpr p) { this.initExpr = p; } } /** * */ public static class BlockStmt extends BeanStmt { private List<BeanStmt> stmts = new ArrayList<BeanStmt>(); public BlockStmt() { } public void visit(BeanASTVisitor v) { v.caseBlock(this); } public <R,A> R visit(BeanASTVisitor2<R,A> v, A arg) { return v.caseBlock(this, arg); } public void doVisitChildStmts(BeanASTVisitor v) { for(BeanStmt stmt : stmts) { stmt.visit(v); } } public <R,A> R doVisitChildStmts(BeanASTVisitor2<R,A> v, A arg) { for(BeanStmt stmt : stmts) { stmt.visit(v, arg); } return null; } public List<BeanStmt> getStmts() { return stmts; } public void addStmt(BeanStmt p) { stmts.add(p); } public void addExprStmt(BeanExpr p) { addStmt(new ExprStmt(p)); } } }