#17 Restricting Scope
Learn how to explicitly and implicitly restrict a scope of an object for a single reference. We will override AbstractDeclarativeScopeProvider reducing the default scope explicitly. Then we will revert changes, add validator and modify content assistant to achieve even better results reducing the default scope implicitly.
- Download:
- source code Project Files in Zip (113 KB)
- mp4 Full Size H.264 Video (21.5 MB)
- m4v Smaller H.264 Video (12.4 MB)
- webm Full Size VP8 Video (12.3 MB)
- ogv Full Size Theora Video (26.1 MB)
Scope - The region of program source in which an identifier is meaningful (http://en.wiktionary.org/wiki/scope)
The goal
Our DSL contains Greeting
and Farewell
objects. A greeting is either normal or honest (with the "!" at the end). A Farewell
object always needs a corresponding Greeting
object. The goal is to allow farewells only for honest greetings. Example:
Hello Eclipse // normal greeting
Hello XtextCasts! // honest greeting!
Bye XtextCasts // OK
Bye Eclipse // Error
Hello Eclipse // normal greeting Hello XtextCasts! // honest greeting! Bye XtextCasts // OK Bye Eclipse // Error
Grammar
grammar org.xtext.example.reducescope.mydsl.MyDsl with org.eclipse.xtext.common.Terminals
generate myDsl "http://www.xtext.org/example/reducescope/mydsl/MyDsl"
Model:
greetings+=Greeting*
farewells+=Farewell*
;
Greeting:
'Hello' name=ID honest?='!'?
;
Farewell:
'Bye' greeting=[Greeting]
;
grammar org.xtext.example.reducescope.mydsl.MyDsl with org.eclipse.xtext.common.Terminals generate myDsl "http://www.xtext.org/example/reducescope/mydsl/MyDsl" Model: greetings+=Greeting* farewells+=Farewell* ; Greeting: 'Hello' name=ID honest?='!'? ; Farewell: 'Bye' greeting=[Greeting] ;
Explicit restriction
MyDslScopeProvider.xtend
package org.xtext.example.reducescope.mydsl.scoping;
import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider;
import org.eclipse.xtext.scoping.IScope
import org.xtext.example.reducescope.mydsl.myDsl.Farewell
import org.eclipse.emf.ecore.EReference
import org.eclipse.xtext.scoping.Scopes
import org.xtext.example.reducescope.mydsl.myDsl.Model
public class MyDslScopeProvider extends AbstractDeclarativeScopeProvider {
def IScope scope_Farewell_greeting(Farewell farewell, EReference eReference) {
Scopes::scopeFor((farewell.eContainer as Model).greetings.filter [ honest ])
}
}
package org.xtext.example.reducescope.mydsl.scoping; import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider; import org.eclipse.xtext.scoping.IScope import org.xtext.example.reducescope.mydsl.myDsl.Farewell import org.eclipse.emf.ecore.EReference import org.eclipse.xtext.scoping.Scopes import org.xtext.example.reducescope.mydsl.myDsl.Model public class MyDslScopeProvider extends AbstractDeclarativeScopeProvider { def IScope scope_Farewell_greeting(Farewell farewell, EReference eReference) { Scopes::scopeFor((farewell.eContainer as Model).greetings.filter [ honest ]) } }
Implicit restriction
Adding validation
MyDslJavaValidator.java
package org.xtext.example.reducescope.mydsl.validation;
import org.eclipse.xtext.validation.Check;
import org.xtext.example.reducescope.mydsl.myDsl.Farewell;
import org.xtext.example.reducescope.mydsl.myDsl.MyDslPackage;
public class MyDslJavaValidator extends AbstractMyDslJavaValidator {
@Check
public void checkFarewellGreetings(Farewell farewell) {
if (farewell.getGreeting() != null && !farewell.getGreeting().isHonest()) {
error("Only honest greetings (greetings with '!') are allowed here",
MyDslPackage.Literals.FAREWELL__GREETING);
}
}
}
package org.xtext.example.reducescope.mydsl.validation; import org.eclipse.xtext.validation.Check; import org.xtext.example.reducescope.mydsl.myDsl.Farewell; import org.xtext.example.reducescope.mydsl.myDsl.MyDslPackage; public class MyDslJavaValidator extends AbstractMyDslJavaValidator { @Check public void checkFarewellGreetings(Farewell farewell) { if (farewell.getGreeting() != null && !farewell.getGreeting().isHonest()) { error("Only honest greetings (greetings with '!') are allowed here", MyDslPackage.Literals.FAREWELL__GREETING); } } }
Modifying content assistant
MyDslProposalProvider.xtend
package org.xtext.example.reducescope.mydsl.ui.contentassist;
import org.xtext.example.reducescope.mydsl.ui.contentassist.AbstractMyDslProposalProvider;
import org.eclipse.emf.ecore.EObject
import org.eclipse.xtext.Assignment
import org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext
import org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor
import org.eclipse.xtext.CrossReference
import org.xtext.example.reducescope.mydsl.myDsl.Greeting
public class MyDslProposalProvider extends AbstractMyDslProposalProvider {
override completeFarewell_Greeting(EObject model, Assignment assignment,
ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
lookupCrossReference(assignment.getTerminal() as CrossReference,
context, acceptor, [
(EObjectOrProxy as Greeting).honest
]
);
}
}
package org.xtext.example.reducescope.mydsl.ui.contentassist; import org.xtext.example.reducescope.mydsl.ui.contentassist.AbstractMyDslProposalProvider; import org.eclipse.emf.ecore.EObject import org.eclipse.xtext.Assignment import org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext import org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor import org.eclipse.xtext.CrossReference import org.xtext.example.reducescope.mydsl.myDsl.Greeting public class MyDslProposalProvider extends AbstractMyDslProposalProvider { override completeFarewell_Greeting(EObject model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) { lookupCrossReference(assignment.getTerminal() as CrossReference, context, acceptor, [ (EObjectOrProxy as Greeting).honest ] ); } }
Version information
- Eclipse: 4.2 (Juno)
- Xtext: 2.3