Index User Data [message #1839450] |
Sun, 21 March 2021 21:28 |
Alfredo Aldundi Messages: 38 Registered: July 2009 |
Member |
|
|
I am trying to understand the use of user data in the index in the context of the following simple type system:
Model:
types+=Type*
instances+=Instance*
;
Type:
abstract?='abstract'? 'type' name=ID ('extends' superType=[Type])? '{'
containments+=Containment*
'}'
;
Containment:
'contains' type=[Type]
;
Instance:
'instance' type=[Type] '{'
instances+=Instance*
'}'
;
Here three files:
abstract type Car {
contains Tire
}
type RacingCar extends Car { }
abstract type Tire { }
abstract type Slicks extends Tire { }
type SuperSoft extends Slicks { }
instance RacingCar {
instance SuperSoft { }
}
The instance model only supports non-abstract type references. For that I am putting the "abstract" flag into the index (using a custom IDefaultResourceDescriptionStrategy).
Now, I also want to make sure the containing instances are valid according to the type (e.g. what concrete type of tires are there for a Car). For that I need to know the super types. My first approach was to add all the super types as comma separated userdata into the index:
@Override
public boolean createEObjectDescriptions(EObject eObject, IAcceptor<IEObjectDescription> acceptor) {
if (eObject instanceof Type) {
Type type = (Type) eObject;
Map<String, String> userData = new HashMap<>();
userData.put("abstract", Boolean.toString(type.isAbstract()));
List<String> superTypes = new ArrayList<>();
Type current = type.getSuperType();
while (current != null) {
superTypes.add(current.getName());
current = current.getSuperType();
}
userData.put("super", superTypes.stream().collect(Collectors.joining(",")));
acceptor.accept(EObjectDescription.create(type.getName(), type, userData));
return true;
}
return super.createEObjectDescriptions(eObject, acceptor);
}
However, this somehow breaks the index. I get an error (gray x!?) in the file defining the cars on the Tire reference. I can get rid of that if I use the NodeModelUtils in resource description strategy. This however does not work as I can only support one level of inheritance. I guess from that error it is a bad idea to access cross references in the resource description strategy, right? I am still trying to figure out what is sensible to do in which part of the Xtext infrastructure.
So, how would you solve this? I can obviously just add the super type to the user data. But then I have to lookup the super types from the hierarchy one by one and find out if e.g. SuperSoft is really a Tire.
|
|
|
Re: Index User Data [message #1839454 is a reply to message #1839450] |
Mon, 22 March 2021 04:53 |
|
Indexing is done in a first step so at this point in type there is no resolved cross references
To access it you can use the NodeModelUtils to find out the direct super types
For transitive suoertypes you would then have to query the index and search all supertypes manually
Am still not sure which problem you actually try to solve by this
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
Re: Index User Data [message #1839461 is a reply to message #1839454] |
Mon, 22 March 2021 07:10 |
Alfredo Aldundi Messages: 38 Registered: July 2009 |
Member |
|
|
I try to implement the content assist. I only want to propose valid concrete types, e.g. SuperSoft.
public void completeInstance_Type(EObject model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
Instance instance = (Instance) model;
if (instance.eContainer() instanceof Instance) {
Instance container = (Instance) instance.eContainer();
lookupCrossReference(model, TypeDslPackage.Literals.INSTANCE__TYPE, acceptor, e -> {
if ("true".equals(e.getUserData("abstract"))) {
return false;
}
return ...; // is the candidate "e" valid in the context of the container instance?
}, getProposalFactory("ID", context));
} else {
lookupCrossReference(model, TypeDslPackage.Literals.INSTANCE__TYPE, acceptor, e -> !"true".equals(e.getUserData("abstract")), getProposalFactory("ID", context));
}
}
I'll do my experiments with the index.
|
|
|
|
|
Re: Index User Data [message #1839464 is a reply to message #1839463] |
Mon, 22 March 2021 08:23 |
Alfredo Aldundi Messages: 38 Registered: July 2009 |
Member |
|
|
Here is my current working "solution". I need to resolve a lot of proxies to get all the containments from the type inheritance hierarchy. It feels like I am missing something here :-S.
@Override
public void completeInstance_Type(EObject model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
Instance instance = (Instance) model;
IResourceDescriptions resourceDescriptions = index.getResourceDescriptions(model.eResource().getResourceSet());
if (instance.eContainer() instanceof Instance) {
Instance container = (Instance) EcoreUtil.resolve(instance.eContainer(), model);
lookupCrossReference(model, TypeDslPackage.Literals.INSTANCE__TYPE, acceptor, e -> {
if ("true".equals(e.getUserData("abstract"))) {
return false;
}
String superType = e.getUserData("super");
List<String> superTypes = getSuperTypes(resourceDescriptions, superType);
Type containerType = (Type) EcoreUtil.resolve(container.getType(), context.getResource());
Set<String> validContainments = new HashSet<>();
while (containerType != null) {
validContainments.addAll(containerType.getContainments().stream().map(Containment::getType).map(t -> ((Type) EcoreUtil.resolve(t, model)).getName()).collect(Collectors.toList()));
containerType = containerType.getSuperType();
}
return validContainments.stream().anyMatch(candidate -> superTypes.contains(candidate));
}, getProposalFactory("ID", context));
} else {
lookupCrossReference(model, TypeDslPackage.Literals.INSTANCE__TYPE, acceptor, e -> !"true".equals(e.getUserData("abstract")), getProposalFactory("ID", context));
}
}
private List<String> getSuperTypes(IResourceDescriptions resourceDescriptions, String superType) {
List<String> result = new LinkedList<>();
while (superType != null) {
result.add(superType);
Iterator<IEObjectDescription> descriptions = resourceDescriptions.getExportedObjects(TypeDslPackage.Literals.TYPE, QualifiedName.create(result), false).iterator();
if (descriptions.hasNext()) {
IEObjectDescription next = descriptions.next();
superType = next.getUserData("super");
} else {
superType = null;
}
}
return result;
}
|
|
|
|
Re: Index User Data [message #1839474 is a reply to message #1839467] |
Mon, 22 March 2021 10:10 |
Alfredo Aldundi Messages: 38 Registered: July 2009 |
Member |
|
|
Quote:there you are allowed to resolve one reference based on another (not the same)
I don't understand what you mean by that. What is "resolving a reference"? Accessing the getter, e.g. getSuperType()? What about navigating from getSuperType(), e.g. getSuperType().getSuperType()?
I moved from a "scoping" solution to the content proposal + validation solution because it gives the possibility to provide meaningful error messages and I thought in content proposal I should have a fully linked model. I thought in scoping the model is not yet linked because linking is based on scoping.
[Updated on: Mon, 22 March 2021 10:12] Report message to a moderator
|
|
|
Re: Index User Data [message #1839477 is a reply to message #1839474] |
Mon, 22 March 2021 10:34 |
|
yes if you ask for the superType you will resolve the first, when you ask that one again for its supertype you will resolve the second.
resolving is not possible during indexing / resourcedescriptionstrategy.
you can also resolve in the proposal provider by doing the initiial resolve manually and then follow the references but this will become terribly slow once you have 100s of model files
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
Powered by
FUDForum. Page generated in 0.04266 seconds