Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Index User Data
Index User Data [message #1839450] Sun, 21 March 2021 21:28 Go to next message
Alfredo Aldundi is currently offline Alfredo AldundiFriend
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 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14661
Registered: July 2009
Senior Member
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 Go to previous messageGo to next message
Alfredo Aldundi is currently offline Alfredo AldundiFriend
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 #1839462 is a reply to message #1839461] Mon, 22 March 2021 07:25 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14661
Registered: July 2009
Senior Member
yes but why do you want to query super types there and not the abstract only

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Index User Data [message #1839463 is a reply to message #1839462] Mon, 22 March 2021 08:19 Go to previous messageGo to next message
Alfredo Aldundi is currently offline Alfredo AldundiFriend
Messages: 38
Registered: July 2009
Member
in my example, a Car contains Tire. In the context of the concrete RacingCar I want a proposal for a valid Type in this context. So, this must be a concrete subtype of Tire.

When I query the index, I get all the types and iterate through them all (there is no way to query by user data). I will then hit SuperSoft. Now I need to know that SuperSoft is in fact a Tire. Its super type is Slicks. However, Car does not contain Slicks, but Tire. So I have to lookup Slicks and get its super type as well. Using the containments of the Type (and its super types) I can then check if SuperSoft is really allowed in the context of a RacingCar.

On the level of types I can reference concrete or abstract types. The hierarchy could be arbitrarily deep.

If there is a simpler way to achieve that, I am all ears :-).
Re: Index User Data [message #1839464 is a reply to message #1839463] Mon, 22 March 2021 08:23 Go to previous messageGo to next message
Alfredo Aldundi is currently offline Alfredo AldundiFriend
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 #1839467 is a reply to message #1839464] Mon, 22 March 2021 09:14 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14661
Registered: July 2009
Senior Member
you can do it in scoping. there you are allowed to resolve one reference based on another (not the same)

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Index User Data [message #1839474 is a reply to message #1839467] Mon, 22 March 2021 10:10 Go to previous messageGo to next message
Alfredo Aldundi is currently offline Alfredo AldundiFriend
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 Go to previous message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14661
Registered: July 2009
Senior Member
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
Previous Topic:Cross Referenced Objects not initialized in ProposalProvider
Next Topic:Generated validator is .java, not .xtend
Goto Forum:
  


Current Time: Thu Mar 28 16:07:01 GMT 2024

Powered by FUDForum. Page generated in 0.05930 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top