Skip to content
Snippets Groups Projects
Commit 914d9048 authored by Johannes Mey's avatar Johannes Mey
Browse files

add initial name resolution and creation, improve parser

parent 337debd5
No related branches found
No related tags found
No related merge requests found
......@@ -20,7 +20,7 @@ aspect JastAddAPIExtension {
throw new RuntimeException("unable to remove child, because it was not contained in its parent!");
}
public int ASTNode.containedChildren() {
public int ASTNode.numContainedChildren() {
int result = 0;
for (ASTNode child: this.astChildren()) {
if (child instanceof JastAddList) {
......@@ -36,6 +36,18 @@ aspect JastAddAPIExtension {
return result;
}
public java.util.List<ASTNode> ASTNode.containedChildren() {
java.util.List<ASTNode> result = new java.util.ArrayList<>();
for (ASTNode child: this.astChildren()) {
if (child instanceof JastAddList || child instanceof Opt) {
result.addAll(child.containedChildren());
} else {
result.add(child);
}
}
return Collections.unmodifiableList(result);
}
public ASTNode ASTNode.root() {
if (getParent() == null) {
return this;
......@@ -45,3 +57,127 @@ aspect JastAddAPIExtension {
}
}
aspect JavaListInterface {
public class JastAddList {
private class JavaListDecorator extends java.util.AbstractList<T> {
@Override
public T set(int index, T element) {
T oldElement = JastAddList.this.getChild(index);
JastAddList.this.setChild(element, index);
return oldElement;
}
@Override
public boolean add(T element) {
JastAddList.this.addChild(element);
return true;
}
@Override
public T remove(int index) {
T removedChild = JastAddList.this.getChild(index);
JastAddList.this.removeChild(index);
return removedChild;
}
@Override
public T get(int i) {
return JastAddList.this.getChild(i);
}
@Override
public int size() {
return JastAddList.this.getNumChild();
}
}
public java.util.List asJavaList() {
return new JavaListDecorator();
}
}
// // unfortunately, it is not possible to implement the java.util.List or java.util.Collection
// // interfaces, because $List.add() returns the list and not a boolean
// JastAddList implements java.util.List<T>;
public int JastAddList.size() {
return getNumChild();
}
public boolean JastAddList.isEmpty() {
return (getNumChild() == 0);
}
public boolean JastAddList.contains(Object o) {
if (o == null) {
for (int i = 1; i < getNumChild(); i++) {
if (getChild(i) == null) {
return true;
}
}
} else {
for (int i = 0; i < getNumChild(); i++) {
if (getChild(i) == o) {
return true;
}
}
}
return false;
}
public boolean JastAddList.addAll(java.util.Collection<? extends T> collection) {
for (T t: collection) {
addChild(t);
}
return !collection.isEmpty();
}
public Object[] JastAddList.toArray() {
Object[] array = new Object[getNumChild()];
for (int i = 0; i < getNumChild(); i++) {
array[i] = getChild(i);
}
return array;
}
public <T1> T1[] JastAddList.toArray(T1[] t1s) {
T1[] array = t1s.length >= getNumChild() ? t1s : (T1[])((Object[]) java.lang.reflect.Array.newInstance(t1s.getClass().getComponentType(), getNumChild()));
for (int i = 0; i < getNumChild(); i++) {
array[i] = (T1) getChild(i);
}
return array;
}
public boolean JastAddList.remove(Object o) {
if (o == null) {
for (int i = 1; i < getNumChild(); i++) {
if (getChild(i) == null) {
removeChild(i);
return true;
}
}
} else {
for (int i = 0; i < getNumChild(); i++) {
if (getChild(i) == o) {
removeChild(i);
return true;
}
}
}
return false;
}
public boolean JastAddList.containsAll(java.util.Collection<?> collection) {
for (Object o: collection) {
if (!this.contains(o)) {
return false;
}
}
return true;
}
}
aspect XMIPathConstruction {
syn String EModelElement.xmiReference() = xmiPath() + localName();
eq EDataType.xmiReference() {
switch (getName()) {
case "EInt":
return "ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt";
case "EString":
return "ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString";
default:
throw new RuntimeException("Unable to create reference to EDataType " + getName());
}
}
inh String EModelElement.xmiPath();
eq EModelElement.getChild(int i).xmiPath() {
if (getParent() != null) {
return xmiPath() + localName();
} else {
return "#/";
}
}
syn String EModelElement.localName() = localRelativeName();
eq ENamedElement.localName() {
if (getName() == null || getName() == "") {
if (getParent() != null) {
return localRelativeName();
} else {
throw new RuntimeException("Unable to create reference to root node (that is not a EDataType)!");
}
} else {
return "/" + getName();
}
}
inh String EModelElement.localRelativeName();
eq EPackage.getEClassifier(int i).localRelativeName() = "/@eNamedElements." + i;
eq EPackage.getESubPackage(int i).localRelativeName() = "/@eSubPackages." + i;
eq EModelElement.getEAnnotation(int i).localRelativeName() = "//@eAnnotations." + i;
eq EAnnotation.getDetail(int i).localRelativeName() = "/@details." + i;
eq EClassifier.getETypeParameter(int i).localRelativeName() = "/@eTypeParameters." + i;
eq ETypedElement.getEGenericType().localRelativeName() = "/@eGenericType";
eq EClass.getEStructuralFeature(int i).localRelativeName() = "//@eStructuralFeatures." + i;
eq EClass.getEOperation(int i).localRelativeName() = "/@eOperations." + i;
eq EClass.getEGenericSuperType(int i).localRelativeName() = "//@eGenericSuperTypes." + i;
eq EEnum.getELiteral(int i).localRelativeName() = "/@eLiterals." + i;
eq EOperation.getGenericException(int i).localRelativeName() = "/@eGenericExceptions." + i;
eq EOperation.getETypeParameter(int i).localRelativeName() = "/@eTypeParameters." + i;
eq EOperation.getEParameter(int i).localRelativeName() = "/@eParameters." + i;
eq ETypeParameter.getEBound(int i).localRelativeName() = "/@eBounds." + i;
eq EGenericType.getEUpperBound().localRelativeName() = "/@eUpperBound";
eq EGenericType.getELowerBound().localRelativeName() = "/@eLowerBound";
eq EGenericType.getETypeArgument(int i).localRelativeName() = "/@eTypeArguments." + i;
}
aspect XMIPathResolution {
refine RefResolverStubs eq ETypedElement.resolveETypeByToken(String id) {
return (EClassifier) resolve(id);
}
refine RefResolverStubs eq EReference.resolveEOppositeByToken(String id) {
return (EReference) resolve(id);
}
refine RefResolverStubs eq EClass.resolveESuperTypesByToken(String id, int position) {
return (EClass) resolve(id);
}
private static EDataType EDataType.eInt;
public static final EDataType EDataType.eInt() {
if (eInt == null) {
eInt = new EDataType();
eInt.setInstanceClassName("int");
eInt.setName("EInt");
}
return eInt;
}
private static EDataType EDataType.eString;
public static final EDataType EDataType.eString() {
if (eString == null) {
eString = new EDataType();
eString.setInstanceClassName("String");
eString.setName("EString");
}
return eString;
}
syn ASTNode ASTNode.resolve(String uriString) {
// built-in data types
if (uriString.startsWith("ecore:EDataType ")) {
switch (uriString.substring(16)) {
case "http://www.eclipse.org/emf/2002/Ecore#//EInt":
return EDataType.eInt();
case "http://www.eclipse.org/emf/2002/Ecore#//EString":
return EDataType.eString();
default:
throw new RuntimeException("Unable to resolve built-in data type '" + uriString + "'");
}
}
// TODO EMF uses its own implementation of URI with some extension with regard to the "device"
// like "c:" and for files within archives
String[] uriParts = uriString.split("#", 2);
String fragment = uriParts.length == 2 ? uriParts[1] : uriParts[0];
// TODO we ignore everything before the fragment
return resolvePath(fragment);
}
syn ASTNode ASTNode.resolvePath(String path) {
int length = path.length();
if (length > 0) {
if (path.charAt(0) == '/') {
path = path.substring(1);
ASTNode result = resolvePath(path.split("/"));
return result;
} else if (path.charAt(length - 1) == '?') {
int index = path.lastIndexOf('?', length - 2);
if (index > 0) {
path = path.substring(0, index);
}
} else {
throw new RuntimeException("[ASTNode.resolvePath(String path)][2] Unable to resolve path'" + path + "'");
}
} else {
throw new RuntimeException("Unable to resolve empty path");
}
throw new RuntimeException("[ASTNode.resolvePath(String path)][1] Unable to resolve path'" + path + "'");
// return getEObjectByID(uriFragment);
}
syn ASTNode ASTNode.resolvePath(String[] path) {
ASTNode result = null;
boolean first = true;
if (path.length == 0) {
return resolvePathRootFragment("");
} else {
for (String fragment: path) {
if (first) {
first = false;
result = resolvePathRootFragment(fragment);
} else {
result = result.resolvePathFragment(fragment);
}
}
return result;
}
}
syn ASTNode ASTNode.resolvePathRootFragment(String fragment) {
// This method is only relevant if there are multiple roots, and in this case, in general, it is not possible to
// select the right one (because we cannot navigate to them)
return root();
}
syn ASTNode ASTNode.resolvePathFragment(String fragment) {
int length = fragment.length();
if (fragment.length() == 0) {
throw new RuntimeException("Empty fragment cannot be resolved!");
} else if (fragment.charAt(0) != '@') {
// resolve as name (with optional index)
if (fragment.charAt(0) == '%') {
// TODO this is ignored right now
throw new RuntimeException("Fragment cannot be resolved, because it starts with a '%': '" + fragment + "'.");
}
int dotIndex = fragment.lastIndexOf('.');
String name = dotIndex == -1 ? fragment : fragment.substring(0, dotIndex);
int count = 0;
if (dotIndex != -1) {
try {
count = Integer.parseInt(fragment.substring(dotIndex + 1));
} catch (NumberFormatException exception) {
throw new RuntimeException("Fragment cannot be resolved, because after the last dot is no number: '" + fragment + "'.");
}
}
if ("%".equals(name)) {
throw new RuntimeException("Fragment '%' cannot be resolved.");
}
// TODO decode the name
return getASTNodeByName(name, count);
}
int lastIndex = fragment.length() - 1;
char lastChar = fragment.charAt(lastIndex);
if (lastChar == ']') {
throw new RuntimeException("predicate references are not supported: '" + fragment + "'.");
} else {
int dotIndex = -1;
if (Character.isDigit(lastChar)) {
dotIndex = fragment.lastIndexOf('.', lastIndex - 1);
}
int index = -1;
if (dotIndex > 0) {
try {
index = Integer.parseInt(fragment.substring(dotIndex + 1));
} catch (NumberFormatException exception) {
throw new RuntimeException("the uri fragment contains a '.', but the string behind it is not a nuber: '" + fragment + "'.");
}
}
return resolveChild(fragment.substring(1, dotIndex), index);
}
}
coll java.util.Collection<EObject> EPackage.containedEObjects() [new java.util.ArrayList()] with add root EObject;
EObject contributes this to EPackage.containedEObjects() for root();
syn java.util.Map<String, ASTNode> ASTNode.idMap() {
java.util.Map<String, ASTNode> idMap = new java.util.HashMap<>();
// iterate all contents of the current subtree
for (ASTNode n: containedChildren()) {
if (n.id() != null) {
idMap.put(n.id(), n);
}
}
return idMap;
}
syn String ASTNode.id() = null;
syn String EObject.id() {
// TODO
return null;
}
syn String ASTNode.name() = null;
eq ENamedElement.name() = getName();
// from eObjectForURIFragmentNameSegment
/**
* The name of an ASTNode is only defined for NamedElements. This makes this method ecore-metamodel-specific
*/
syn ASTNode ASTNode.getASTNodeByName(String name, int index) {
int count = index;
// Look for a matching named element.
for (ASTNode child : containedChildren()) {
if (child.name() != null) {
String otherName = child.name();
if ((name == null ? otherName == null : name.equals(otherName)) && count-- == 0) {
return child;
}
}
}
throw new RuntimeException("Unable to find number '" + index + "'child with name '" + name + "'");
}
// public static String getID(EObject eObject) {
// EClass eClass = eObject.eClass();
// EAttribute eIDAttribute = eClass.getEIDAttribute();
// return eIDAttribute == null || !eObject.eIsSet(eIDAttribute) ? null : convertToString(eIDAttribute.getEAttributeType(), eObject.eGet(eIDAttribute));
// }
/**
* from: getEObjectByID
*/
syn ASTNode ASTNode.getASTNodeByID(String id) {
// in EMF, there is a map that caches all IDs
// Likewise, we create such an ID map and simply perform a lookup
return idMap().get(id);
}
syn ASTNode ASTNode.resolveChild(String name, int index) {
throw new RuntimeException("No child with name '" + name + "' found.");
}
}
......@@ -38,7 +38,7 @@ aspect XMIWriter {
// from EPackage
b.append(" nsURI=\"").append(getNsURI()).append("\"")
.append(" nsPrefix=\"").append(getNsPrefix()).append("\"");
if (containedChildren() == 0) {
if (numContainedChildren() == 0) {
b.append("/>\n");
return;
}
......@@ -82,7 +82,20 @@ aspect XMIWriter {
if (getInterface() == true) {
b.append(" interface=\"true\"");
}
if (containedChildren() == 0) {
if (!getESuperTypesList().isEmpty()) {
b.append(" eSuperTypes=\"");
boolean first = true;
for (EClass eSuperType : getESuperTypesList()) {
if (first) {
first = false;
} else {
b.append(" ");
}
b.append(eSuperType.xmiReference());
}
b.append("\"");
}
if (numContainedChildren() == 0) {
b.append("/>\n");
return;
}
......@@ -120,7 +133,7 @@ aspect XMIWriter {
// attributes
b.append(" name=\"").append(getName()).append("\"");
if (containedChildren() == 0) {
if (numContainedChildren() == 0) {
b.append("/>\n");
return;
}
......@@ -162,6 +175,7 @@ aspect XMIWriter {
if (getUpperBound() != 1) {
b.append(" upperBound=\"" + getUpperBound() + "\"");
}
b.append(" eType=\"").append(getEType().xmiReference()).append("\"");
// from EStructuralFEature
if (getChangeable() == false) {
b.append(" changeable=\"false\"");
......@@ -188,15 +202,18 @@ aspect XMIWriter {
if (getResolveProxies() == false) {
b.append(" resolveProxies=\"false\"");
}
if (hasEOpposite()) {
b.append(" eOpposite=\"").append(getEOpposite().xmiReference()).append("\"");
}
if (getNumChild() == 0) {
b.append("/>\n");
return;
}
if (containedChildren() == 0) {
if (numContainedChildren() == 0) {
b.append("/>\n");
return;
}
System.out.println(containedChildren());
System.out.println(numContainedChildren());
b.append(">\n");
// child nodes
// from EModelElement
......@@ -229,6 +246,7 @@ aspect XMIWriter {
if (getUpperBound() != 1) {
b.append(" upperBound=\"" + getUpperBound() + "\"");
}
b.append(" eType=\"").append(getEType().xmiReference()).append("\"");
// from EStructuralFEature
if (getChangeable() == false) {
b.append(" changeable=\"false\"");
......@@ -256,11 +274,10 @@ aspect XMIWriter {
b.append("/>\n");
return;
}
if (containedChildren() == 0) {
if (numContainedChildren() == 0) {
b.append("/>\n");
return;
}
System.out.println(containedChildren());
b.append(">\n");
// child nodes
// from EModelElement
......
......@@ -26,8 +26,8 @@ EParameter : ETypedElement;
EStringToStringMapEntry ::= <Key:String> <Value:String>;
ETypeParameter : ENamedElement ::= EBounds:EGenericType*;
EGenericType ::= [EUpperBound:EGenericType] [ELowerBound:EGenericType] [ETypeArguments:EGenericType];
ETypeParameter : ENamedElement ::= EBound:EGenericType*;
EGenericType ::= [EUpperBound:EGenericType] [ELowerBound:EGenericType] ETypeArgument:EGenericType*;
rel ETypedElement.EType -> EClassifier;
rel EOperation.EExceptions* -> EClassifier;
......
......@@ -194,7 +194,9 @@ public class EcoreParser {
eClass.setInterface(Boolean.valueOf(attribute.getValue()));
break;
case "eSuperTypes":
eClass.addESuperTypes(EClass.createRefDirection(attribute.getValue()));
for (String superType : attribute.getValue().split(" ")) {
eClass.addESuperTypes(EClass.createRefDirection(superType));
}
break;
default:
logger.warn("ignoring attribute {}:{}", attribute.getName().getPrefix(), attribute.getName().getLocalPart());
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment