Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Restricting the scope / code suggestion(Understanding the scope provider)
Restricting the scope / code suggestion [message #697799] Mon, 18 July 2011 04:47 Go to next message
Moritz   is currently offline Moritz Friend
Messages: 22
Registered: July 2011
Junior Member
Hi,

first I want to say that I am very very happy about this framework. Smile Thank you!

I read through many blog posts and documentations for some time, most of them very helpful. Unfortunately, some are quite hard to follow and lack of some good examples imo (i.e. the chapter about scoping[1]). I would love if someone could help me understanding this part better.

Domainmodel:
	entities += Entity*
;
	
Entity:
	'entity' name = ID '{' 
		features += Feature* 
	'}'
;

Feature:
	'feature' name = ID ':' type = Type
;

Type:
	baseType = BaseType | reference = [Entity]
;

enum BaseType:
	String | Int
;


So here is a simple DSL similar to the one of the documentation. My questions are:

Image:[4]


  1. The type of a feature must not be the name of the entity wherein it is defined (so, no recursion allowed). This constraint can be easily implemented with a @Check in the validator, but it is then still contained in the proposal list.
    I assume one just has to adapt the scope provider, but I am still puzzled on how to use it properly. I think one has to start with a function as described in the documentation[2]:
    IScope scope_Feature_type(Type ctx, EReference ref)

    But how can I restrict the automatically created scope, or simply create a new one? Does the injected IScopeProvider offer help here? I think I nee something similar to this[3], but this code seems to use a rather old version.
  2. The type of the feature can either be a predefined (static) type, or a reference to an entity. Is there a more easy or elegant way to express this rule? How would you do it?


Any help is very appreciated. Thank you.

(I cannot use links yet)
[1]http //www.eclipse.org/Xtext/documentation/2_0_0/080-scoping.php
[2]http //www.eclipse.org/Xtext/documentation/2_0_0/080-scoping.php#local_scoping
[3]http //chilifreak.wordpress.com/2010/02/22/extending-proposals-in-xtext-using-scoping/
[4]http //s4.postimage.org/5zfdmtfbh/Reference1.png
Re: Restricting the scope / code suggestion [message #697812 is a reply to message #697799] Mon, 18 July 2011 06:03 Go to previous messageGo to next message
Alexander Nittka is currently offline Alexander NittkaFriend
Messages: 1193
Registered: July 2009
Senior Member
Hi,

as you said, the constraint can be enforced using the validator. In fact you *should* do it that way, as it allows for a meaningful error message ("a type is not allowed to be used in its feature list"). Solving it via scoping would give you "validation" and code completion out of the box, but how would you react as a user if you got the error message "could not resolve reference" if the thing you want to refer to is defined the line above?
You should override the corresponding code completion function. In fact, the resolveCrossReference-method has several signatures that allow for a filter to be passed. There you could filter out the context entity.

Typically you would not hard code base types in the grammar. The suggested way is the library approach. You ship a "common types"-model along with your language. Something like
entity String{}
entity Int{}
If your setup is correct, these entities are picked up by the index and are referrable as any entity the user defines. So you only need
Type: reference=[Enitity]
or rather
Feature: 'feature' name = ID ':' type = [Entity];

Alex

P.S.: It is still correct that the chapter on scoping needs some more high-level introduction in order to get a feeling for the concepts.


Need training, onsite consulting or any other kind of help for Xtext?
Go visit http://xtext.itemis.com or send a mail to xtext@itemis.de
Re: Restricting the scope / code suggestion [message #697824 is a reply to message #697812] Mon, 18 July 2011 06:57 Go to previous messageGo to next message
Balazs Varnai is currently offline Balazs VarnaiFriend
Messages: 21
Registered: June 2011
Junior Member
Hi,

I am using also something like the 'baseType' enum. Alex suggested to get rid of it and use a common type model. What's the easiest way to embed it? Can this be defined in the current grammar/model?

Balazs
Re: Restricting the scope / code suggestion [message #697828 is a reply to message #697824] Mon, 18 July 2011 07:14 Go to previous messageGo to next message
Alexander Nittka is currently offline Alexander NittkaFriend
Messages: 1193
Registered: July 2009
Senior Member
Hi,

you could ship the model file containing the base types along with the language plugin or within a separate project. The second alternative has the advantage that the user knows, why there should be a dependency to that project - if you name it something like mydsl.basetypes or mydsl.library.

You just have to make sure that the model file is on the classpath of the project that is to reference the base types, so that it is picked up by the index. You can check that it is visible at all by inspecting the open-model-element-dialog (shift-ctrl-F3) which tells you which elements are contained in the index.

Alex

[Updated on: Mon, 18 July 2011 07:44]

Report message to a moderator

Re: Restricting the scope / code suggestion [message #697982 is a reply to message #697828] Mon, 18 July 2011 14:37 Go to previous messageGo to next message
Moritz   is currently offline Moritz Friend
Messages: 22
Registered: July 2011
Junior Member
Hi Alex,

thank you very much for your explanation and the hint to the code completion and the filtering methods.
In fact, I tried it the way you proposed and the concept for Content Assist[1] is much easier to understand than scoping (combined with debugging) Smile

I want to show the code that I used to make it more understandable for people coming to a similar issue. With the Validator and the ProposalProvider it pretty much does exactly what I was hoping for. Anyway I have a few further quetions.

index.php/fa/3384/0/index.php/fa/3385/0/index.php/fa/3386/0/

At first, the code for the validator:

public class EntityDslJavaValidator extends AbstractEntityDslJavaValidator {
	
	@Check
	public void checkEntityRecursion(Feature feature) {
		checkEntityRecursion(feature, (Entity)feature.eContainer());
	}
	
	public void checkEntityRecursion(Feature feature, Entity rootEntity) {
		if (feature.getType() == null) return;
		Entity referencedEntity = feature.getType().getReference();
		
		if (referencedEntity == rootEntity) {
			error("A type is not allowed to be used recursively by its feature list", EntityDslPackage.Literals.FEATURE__TYPE);
		} else if (referencedEntity != null) {
			for (Feature f: referencedEntity.getFeatures()) {
				checkEntityRecursion(f, rootEntity);
			}
		}
	}
}


And the code for the ProposalProvider:

public class EntityDslProposalProvider extends AbstractEntityDslProposalProvider {
	
	@Override
	public void completeType_Reference(EObject model, Assignment assignment, 
			ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
		lookupCrossReference(((CrossReference)assignment.getTerminal()), context, acceptor,
				new RecursiveReferenceDetector((Feature)model));
	}
}

class RecursiveReferenceDetector implements Predicate<IEObjectDescription> {
	private final Entity rootEntity;
	
	public RecursiveReferenceDetector(Feature feature) {
		rootEntity = (Entity)feature.eContainer();
	}
	
	@Override
	public boolean apply(IEObjectDescription input) {
		return checkEntityRecursion((Entity)input.getEObjectOrProxy());
	}
	
	public boolean checkEntityRecursion(Entity referencedEntity) {
		if (referencedEntity == rootEntity) {
			return false;
		} else if (referencedEntity != null) {
			for (Feature f: referencedEntity.getFeatures()) {
				if (f.getType() == null) continue;
				if (!checkEntityRecursion(f.getType().getReference())) {
					return false;
				}
			}
		}
		return true;
	}
}




  1. In the completeType_Reference function, both the context.currentModel and the model refer to the same object of type FeatureImpl. I indeed need this Feature (or its container) to complete the Type_Reference, but how does Xtext decides which model is passed? What if there are more Rules with references to Type?
  2. Is there a good source or example that makes the usage of the scope provider more clear? Maybe one where the scope is restricted or just somehow modified.


Moritz


[1]http //www.eclipse.org/Xtext/documentation/2_0_0/150-contentassist.php
Re: Restricting the scope / code suggestion [message #698064 is a reply to message #697982] Mon, 18 July 2011 17:51 Go to previous messageGo to next message
Alexander Nittka is currently offline Alexander NittkaFriend
Messages: 1193
Registered: July 2009
Senior Member
Hi,

regarding 1) I can't give you the definition, but I can give you an idea. Usually when typing and using code completion, you have an incomplete model. The framework determines all possible continuations, i.e. valid semantic models with the given "document prefix". This is how different context objects are possible.
If there are different rules referring to Type, they would cause a different completion function to be invoked. Your job here would be to extract code to be used by all of them to helper methods.

regarding 2) Look at the community projects, the examples shipped with Xtext, search for AbstractDeclarativeScopeProvider... Search this forum for threads on scoping. And, as you did in your original post, ask specific questions about what you want to achieve. Then you are likely to get helpful pointers.

Alex
Re: Restricting the scope / code suggestion [message #698265 is a reply to message #698064] Tue, 19 July 2011 06:38 Go to previous messageGo to next message
Daniel Missing name is currently offline Daniel Missing nameFriend
Messages: 101
Registered: July 2011
Senior Member
I have an addition to this problem/solution: Think of a referenced child/parent customer or a bidirectional association you try to prevent. Your problem also regards to a recursive inheritance. Think of:
entity A extends C {}
entity B extends A {}
entity C extends B {}
entity D extends D {}


I've written a small algorithm (find cycle in a directed graph) which checks this:

@Check
public void checkEntityInheritance(Entity entity) {
    Entity hierarchyLoopElement = getHierarchyLoop(entity);
    if (hierarchyLoopElement != null) {
      error(String.format("Cycle detected: a cycle exists in the type hierarchy between %s and %s", 
                           entity.getName(), entity.getSuperType().getName()),
            BachLangPackage.Literals.ENTITY__SUPER_TYPE, INHERITANCE_LOOP,
            hierarchyLoopElement.getName());
    }
}

private static Entity getHierarchyLoop(Entity element) {
    Set<Entity> visited = new HashSet<Entity>();
    visited.add(element);

    Entity currentSubType = element;
    Entity currentSuperType = getSuperType(element);
    while (currentSuperType != null) {
      if (visited.contains(currentSuperType)) {
        return currentSubType;
      }

      visited.add(currentSuperType);

      currentSubType = currentSuperType;
      currentSuperType = getSuperType(currentSubType);
    }

    return null;
}

private static Entity getSuperType(Entity element) {
    return element.getSuperType();
}



If you need a more generic way you can modify the getHierarchyLoop and getSuperType to use your base-object which provides a getSuperType. Or you can use reflection for calling a method.

[Updated on: Tue, 19 July 2011 06:38]

Report message to a moderator

Re: Restricting the scope / code suggestion [message #701342 is a reply to message #698064] Mon, 25 July 2011 01:38 Go to previous message
Moritz   is currently offline Moritz Friend
Messages: 22
Registered: July 2011
Junior Member
Alexander Nittka wrote on Mon, 18 July 2011 13:51
regarding 2) Look at the community projects, the examples shipped with Xtext, search for AbstractDeclarativeScopeProvider... Search this forum for threads on scoping. And, as you did in your original post, ask specific questions about what you want to achieve. Then you are likely to get helpful pointers.


Thanks again. I think the best way to get started is to I look at AbstractDeclarativeScopeProvider.getScope and and implement some of the computed methods..
I posted another question that fits to the topic of this thread, so if anyone is interested here is the link:

www.eclipse.org/forums/index.php/m/701329/#msg_701329


Daniel wrote on Tue, 19 July 2011 02:38
I have an addition to this problem/solution: Think of a referenced child/parent customer or a bidirectional association you try to prevent.


Yes you're right, the code did not cover that.


blog.efftinge.de/2009/01/xtext-scopes-and-emf-index.html
zarnekow.blogspot.com/2009/01/xtext-corner-2-linking-and-scoping.html
Previous Topic:How do I get a IEObjectDescription from EObject?
Next Topic:LWC2011 document, "Using the manually maintained Ecore model"
Goto Forum:
  


Current Time: Wed Sep 23 07:23:06 GMT 2020

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

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

Back to the top