package de.ovgu.cide.language.jdt;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import org.eclipse.jdt.core.dom.CharacterLiteral;
import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
import org.eclipse.jdt.core.dom.ChildPropertyDescriptor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
import org.eclipse.jdt.core.dom.EnumDeclaration;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.NumberLiteral;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SimplePropertyDescriptor;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
import org.eclipse.jdt.core.dom.TextElement;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import cide.gast.ASTNode;
import cide.gast.ASTTextNode;
import cide.gast.ASTVisitor;
import cide.gast.IASTNode;
import cide.gast.IToken;
import cide.gast.Property;
import cide.gast.PropertyOne;
import cide.gast.PropertyZeroOrMore;
import cide.gast.PropertyZeroOrOne;
import cide.gast.SimpleToken;
import de.ovgu.cide.configuration.jdt.ASTColorInheritance;
import de.ovgu.cide.language.jdt.UnifiedASTNode.Kind;
/**
* input: Eclipse AST; output: CIDE AST
*
* this is not an on the fly adapter, but it copies the entire data structure.
* (as no way back to the eclipse ast is needed this is ok) only the pretty
* printer must be written from scratch.
*
* e_ stands of eclipse object; c_ stands for CIDE object
*
*
* @author ckaestne
*
*/
public class ASTBridge {
public IASTNode getAST(CompilationUnit e_root) {
return bridgeASTNode(e_root);
}
/**
* to bridge a single node from the outside the root is still required to
* get the parents right. note, unless resolveAllSiblings is true, the
* returned structure is not complete. parent nodes have only a single
* property required to get here. only their ids are preserved to enable
* color lookups, but not navigation
*
* @param e_root
* @param e_node
* @return
*/
public IASTNode getASTNode(CompilationUnit e_root,
org.eclipse.jdt.core.dom.ASTNode e_node, boolean resolveAllSiblings) {
// fake inheritance by adding fake parent nodes with correct ID but
// without other children
if (!resolveAllSiblings) {
ASTNode result = bridgeASTNode(e_node);
bridgeFakeParentNodes(result, e_node);
return result;
}
// bridge the entire AST but retrieve the correct node
ASTNode c_root = bridgeASTNode(e_root);
BridgedASTFinder astFinder = new BridgedASTFinder(ASTID.id(e_node));
c_root.accept(astFinder);
return astFinder.node;
}
private static class BridgedASTFinder extends ASTVisitor {
BridgedASTFinder(String id) {
this.id = id;
}
final String id;
IASTNode node = null;
@Override
public boolean visit(IASTNode node) {
if (node.getId().equals(id)) {
this.node = node;
return false;
}
return super.visit(node);
}
}
private void bridgeFakeParentNodes(ASTNode c_node,
org.eclipse.jdt.core.dom.ASTNode e_node) {
while (e_node.getParent() != null) {
org.eclipse.jdt.core.dom.ASTNode e_parent = e_node.getParent();
IToken c_firstToken = new PosToken(e_parent.getStartPosition());
IToken c_lastToken = new PosToken(e_parent.getStartPosition()
+ e_node.getLength());
StructuralPropertyDescriptor e_prop = e_node.getLocationInParent();
List<Property> c_props = new ArrayList<Property>();
// fake a property with a single child
c_props.add(new PropertyZeroOrOne<ASTNode>(e_prop.getId(), c_node));
c_node = new UnifiedASTNode(getDisplayName(e_parent), ASTID
.id(e_parent), c_props, c_firstToken, c_lastToken, null,
getKind(e_parent));
e_node = e_parent;
}
}
private static final Map<org.eclipse.jdt.core.dom.ASTNode, cide.gast.ASTNode> bridgeCache = Collections
.synchronizedMap(new WeakHashMap<org.eclipse.jdt.core.dom.ASTNode, cide.gast.ASTNode>());
private ASTNode bridgeASTNode(org.eclipse.jdt.core.dom.ASTNode e_node) {
ASTNode result = bridgeCache.get(e_node);
if (result != null)
return result;
IToken c_firstToken = new PosToken(e_node.getStartPosition());
IToken c_lastToken = new PosToken(e_node.getStartPosition()
+ e_node.getLength());
IASTNode[] wrappee = null;
List<StructuralPropertyDescriptor> e_props = e_node
.structuralPropertiesForType();
List<Property> c_props = new ArrayList<Property>();
for (StructuralPropertyDescriptor e_prop : e_props) {
if (e_prop.isSimpleProperty()) {
Property prop = bridgeSimpleProperty(e_node,
(SimplePropertyDescriptor) e_prop);
if (prop != null) {
if (ASTColorInheritance.notInheritedProperties
.contains(e_prop))
wrappee = join(wrappee, prop.getChildren());
c_props.add(prop);
}
} else if (e_prop.isChildListProperty()) {
Property prop = bridgeChildListProperty(e_node,
(ChildListPropertyDescriptor) e_prop);
if (ASTColorInheritance.notInheritedProperties.contains(e_prop))
wrappee = join(wrappee, prop.getChildren());
c_props.add(prop);
} else if (e_prop.isChildProperty()) {
Property prop = bridgeChildProperty(e_node,
(ChildPropertyDescriptor) e_prop);
if (prop != null) {
if (ASTColorInheritance.notInheritedProperties
.contains(e_prop))
wrappee = join(wrappee, prop.getChildren());
c_props.add(prop);
}
}
}
result = new UnifiedASTNode(getDisplayName(e_node), ASTID.id(e_node),
c_props, c_firstToken, c_lastToken, wrappee, getKind(e_node));
bridgeCache.put(e_node, result);
return result;
}
private Kind getKind(org.eclipse.jdt.core.dom.ASTNode e_node) {
if (e_node instanceof Statement)
return Kind.STATEMENT;
if (e_node instanceof TypeDeclaration)
return Kind.TYPE;
if (e_node instanceof MethodDeclaration)
return Kind.METHOD;
if (e_node instanceof FieldDeclaration)
return Kind.FIELD;
return Kind.OTHER;
}
/** helper method to concatenate two arrays */
private IASTNode[] join(IASTNode[] existing, IASTNode[] newarray) {
if (existing == null || existing.length == 0)
return newarray;
if (newarray == null || newarray.length == 0)
return existing;
ArrayList<IASTNode> result = new ArrayList<IASTNode>(existing.length
+ newarray.length);
result.addAll(Arrays.asList(existing));
result.addAll(Arrays.asList(newarray));
return result.toArray(new IASTNode[existing.length + newarray.length]);
}
private Property bridgeChildProperty(
org.eclipse.jdt.core.dom.ASTNode e_node,
ChildPropertyDescriptor prop) {
if (prop.isMandatory())
return bridgeOneChildProperty(e_node, prop);
else
return bridgeOptionalChildProperty(e_node, prop);
}
private Property bridgeOneChildProperty(
org.eclipse.jdt.core.dom.ASTNode e_node,
StructuralPropertyDescriptor prop) {
Object o = e_node.getStructuralProperty(prop);
ASTNode child;
assert o != null;
if (o instanceof org.eclipse.jdt.core.dom.ASTNode)
child = bridgeASTNode((org.eclipse.jdt.core.dom.ASTNode) o);
else if (e_node instanceof Modifier ||e_node instanceof PrimitiveType|| e_node instanceof SimpleName|| e_node instanceof NumberLiteral|| e_node instanceof CharacterLiteral || e_node instanceof StringLiteral || e_node instanceof TextElement)
child = new ASTTextNode(o.toString(), new SimpleToken(e_node
.getStartPosition(), e_node.getLength()));
else
return null;
return new PropertyOne<ASTNode>(prop.getId(), child);
}
private Property bridgeOptionalChildProperty(
org.eclipse.jdt.core.dom.ASTNode e_node,
StructuralPropertyDescriptor prop) {
Object o = e_node.getStructuralProperty(prop);
ASTNode child;
if (o == null)
child = null;
else if (o instanceof org.eclipse.jdt.core.dom.ASTNode)
child = bridgeASTNode((org.eclipse.jdt.core.dom.ASTNode) o);
else
child = new ASTTextNode(o.toString(), new SimpleToken(e_node
.getStartPosition(), e_node.getLength()));
return new PropertyZeroOrOne<ASTNode>(prop.getId(), child);
}
private Property bridgeChildListProperty(
org.eclipse.jdt.core.dom.ASTNode e_node,
ChildListPropertyDescriptor prop) {
Object e_object = e_node.getStructuralProperty(prop);
assert e_object instanceof List<?>;
List<?> e_childList = (List<?>) e_object;
ArrayList<ASTNode> c_children = new ArrayList<ASTNode>();
for (Object e_child : e_childList) {
assert e_child instanceof org.eclipse.jdt.core.dom.ASTNode;
c_children
.add(bridgeASTNode((org.eclipse.jdt.core.dom.ASTNode) e_child));
}
return new PropertyZeroOrMore<ASTNode>(prop.getId(), c_children);
}
// private int aFlags = JavaElementLabelProvider.SHOW_SMALL_ICONS | JavaElementLabelProvider.SHOW_PARAMETERS;
// private JavaElementLabelProvider aProvider = new JavaElementLabelProvider( aFlags );
private String getDisplayName(org.eclipse.jdt.core.dom.ASTNode node) {
//ALEX
if (node instanceof ImportDeclaration)
return "ImpDec: " + ((ImportDeclaration) node).getName().getFullyQualifiedName();
if (node instanceof SimpleType)
return "SimTyp: " + ((SimpleType) node).getName().getFullyQualifiedName();
if (node instanceof PrimitiveType)
return "PrimTyp: " + ((PrimitiveType) node).toString();
if (node instanceof TypeDeclaration)
return "TypDec: " + ((TypeDeclaration) node).getName().getFullyQualifiedName();
if (node instanceof EnumDeclaration)
return "EnmDec: " + ((EnumDeclaration) node).getName().getFullyQualifiedName();
if (node instanceof MethodDeclaration)
return "MetDec: " + ((MethodDeclaration) node).getName().getFullyQualifiedName();
if (node instanceof VariableDeclarationFragment)
return "VaDeFa: " + ((VariableDeclarationFragment) node).getName().getFullyQualifiedName();
if (node instanceof EnumConstantDeclaration)
return "EnCoDe: " + ((EnumConstantDeclaration) node).getName().getFullyQualifiedName();
if (node instanceof SingleVariableDeclaration)
return "SiVaDe: " + ((SingleVariableDeclaration) node).getName().getFullyQualifiedName();
if (node instanceof SimpleName)
return "SimNam: " + ((SimpleName) node).getFullyQualifiedName();
//ALEX
return org.eclipse.jdt.core.dom.ASTNode.nodeClassForType(
node.getNodeType()).getSimpleName();
}
private Property bridgeSimpleProperty(
org.eclipse.jdt.core.dom.ASTNode e_node,
SimplePropertyDescriptor prop) {
if (prop.isMandatory())
return bridgeOneChildProperty(e_node, prop);
else
return bridgeOptionalChildProperty(e_node, prop);
}
public static IASTNode bridge(org.eclipse.jdt.core.dom.ASTNode node) {
return new ASTBridge().getASTNode((CompilationUnit) node.getRoot(),
node, false);
}
}