Xtext problem referencing grammar A from validator of grammar B
Xtext problem referencing grammar A from validator of grammar B
In Xtext, how do I follow a reference from grammar B to grammar A, within a validator of grammar B (which is in the ui-plugin)? Consider the following example.
Grammar A is org.xtext.people.People
org.xtext.people.People
grammar org.xtext.people.People with org.eclipse.xtext.common.Terminals
generate people "http://www.xtext.org/people/People"
People:
people+=Person*;
Person:
'person' name=ID ';';
and an instance
person Alice citizenship "MN"; id "12345";
person Bob citizenship "CH"; id "54321";
person Malice citizenship "XXX"; id "66666";
At an airport, entries of people are recorded.
enter Alice;
enter Bob;
enter Malice;
Entries are modelled with a second grammar B org.xtext.entries.Entries
org.xtext.entries.Entries
grammar org.xtext.entries.Entries with org.eclipse.xtext.common.Terminals
generate entries "http://www.xtext.org/entries/Entries"
import "http://www.xtext.org/people/People"
Entries:
entries+=Entry*;
Entry:
'enter' person=[Person] ';';
After ensuring that the Eclipse project org.xtext.entries
has the project org.xtext.people
on it's classpath, and ensuring that the org.xtext.entries
plugin has the org.xtext.people
as a dependency, all works as expected.
org.xtext.entries
org.xtext.people
org.xtext.entries
org.xtext.people
There is a travel ban on people from country XXX, although certain deserving people are excluded. Only the CIA knows who is excluded from the ban. Entries must not be allowed for people from XXX unless excluded.
The updated grammar is
grammar org.xtext.entries.Entries with org.eclipse.xtext.common.Terminals
generate entries "http://www.xtext.org/entries/Entries"
import "http://www.xtext.org/people/People"
Entries:
entries+=Entry*;
Entry:
travelBanOverride=TravelBanOverride?
'enter' person=[Person] ';';
TravelBanOverride: '@TravelBanOverride' '(' code=STRING ')';
with validator
package org.xtext.entries.validation
import org.eclipse.xtext.validation.Check
import org.xtext.entries.entries.EntriesPackage
import org.xtext.entries.entries.Entry
import org.xtext.entries.CIA
class EntriesValidator extends AbstractEntriesValidator
public static val BAN = 'BAN'
public static val ILLEGAL_OVERRIDE = 'ILLEGAL_OVERRIDE'
@Check
def checkBan(Entry entry)
if (entry.person.citizenship == "XXX")
if (entry.travelBanOverride === null)
error('Violation of Travel Ban', EntriesPackage.Literals.ENTRY__PERSON, BAN)
else
val overridecode = entry.travelBanOverride.code;
val valid = CIA.valid(entry.person.name, entry.person.id, overridecode)
if (!valid)
error('Illegal override code', EntriesPackage.Literals.ENTRY__TRAVEL_BAN_OVERRIDE, ILLEGAL_OVERRIDE)
where the driver for the external CIA web-app is modelled for example by
package org.xtext.entries;
public class CIA
public static boolean valid(String name, String id, String overrideCode)
System.out.println("UNValid["+name+","+overrideCode+"]");
return name.equals("Malice") && id.equals("66666") && overrideCode.equals("123");
The validations work as expected.
I now wish to provided a quick-fix for BAN
, that checks for an override code from the CIA.
BAN
package org.xtext.entries.ui.quickfix
import org.eclipse.xtext.ui.editor.quickfix.DefaultQuickfixProvider
import org.eclipse.xtext.ui.editor.quickfix.Fix
import org.xtext.entries.validation.EntriesValidator
import org.eclipse.xtext.validation.Issue
import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionAcceptor
import org.xtext.entries.entries.Entry
import org.xtext.entries.Helper
class EntriesQuickfixProvider extends DefaultQuickfixProvider
@Fix(EntriesValidator.BAN)
def tryOverride(Issue issue, IssueResolutionAcceptor acceptor)
val entry = element as Entry
// val person = entry.person // no such attribute
//val person = Helper.get(entry); // The method get(Entry) from the type Helper refers to the missing type Object
]
The first commented line does not compile: there is no attribute person
. The second commented line is an attempt to solve the problem by getting a helper class in org.xtext.entries
to get the person, but this does not compile either, giving a "The method get(Entry) from the type Helper refers to the missing type Object" error message.
person
org.xtext.entries
For completeness, here is that helper.
package org.xtext.entries
import org.xtext.people.people.Person
import org.xtext.entries.entries.Entry
class Helper
static def Person get(Entry entry)
return entry.person;
Further, entry.travelBanOverride
compiles fine, but entry.person
does not. Clicking on Entry in Eclipse takes one to the expected code, which has both travelBanOverride
and person
.
entry.travelBanOverride
entry.person
travelBanOverride
person
The issue does not occur with a Java class in the same project and package.
package org.xtext.entries.ui.quickfix;
import org.xtext.entries.entries.Entry;
import org.xtext.people.people.Person;
public class Test
public static void main(String args)
Entry entry = null;
Person p = entry.getPerson();
Rewriting the quickfix in Java solves the problem.
package org.xtext.entries.ui.quickfix;
import org.eclipse.xtext.ui.editor.quickfix.DefaultQuickfixProvider;
import org.eclipse.xtext.ui.editor.quickfix.Fix;
import org.xtext.entries.validation.EntriesValidator;
import org.eclipse.xtext.validation.Issue;
import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionAcceptor;
import org.xtext.entries.entries.Entry;
import org.xtext.entries.Helper;
import org.eclipse.xtext.ui.editor.model.edit.IModificationContext;
import org.eclipse.xtext.ui.editor.model.edit.ISemanticModification;
import org.eclipse.emf.ecore.EObject;
import org.xtext.entries.entries.Entry;
import org.xtext.people.people.Person;
public class EntriesQuickfixProvider extends DefaultQuickfixProvider
@Fix(EntriesValidator.BAN)
public void tryOverride(final Issue issue, IssueResolutionAcceptor acceptor)
acceptor.accept(issue,
"Try to override",
"Override",
"override.gif",
new ISemanticModification()
public void apply(EObject element, IModificationContext context)
Entry entry = (Entry) element;
System.out.println(entry.getPerson());
);
"val entry = element as Entry" complies fine. If I click on Entry it takes me to the definition with the expected expected method getPerson. But the compiler will have none of it. Just to double check, following a reference from the ui project should be no different to following it from the primary project. There is no well-known/obvious reason for it not to be so?
– fundagain
Sep 3 at 21:24
entry.travelBanOverride
compiles fine, but entry.person
does not. Clicking on Entry in Eclipse takes one to the expected code, which has both travelBanOverride
and person
. I have updated the OP to reflect this.– fundagain
Sep 3 at 22:23
entry.travelBanOverride
entry.person
travelBanOverride
person
It appears that the Java compiler has no problem. I have updated the OP with an example. Will try to write the quickfix in Java and see if this helps.
– fundagain
Sep 3 at 22:47
Rewriting the quickfix in Java solves the problem. I have updated the OP.
– fundagain
Sep 3 at 23:10
1 Answer
1
My mistake is the following.
After ensuring that the Eclipse project org.xtext.entries has the
project org.xtext.people on it's classpath, and ensuring that the
org.xtext.entries plugin has the org.xtext.people as a dependency, all
works as expected.
The org.xtext.entries.ui
ui-plugin must also have the org.xtext.people
on its Java (Eclipse project) build path. Exporting and making a plugin-dependency it not enough.
org.xtext.entries.ui
org.xtext.people
Note that this setting should be made early, before crafting the quick-fix, because the Xtend editor has refreshing issues.
Thanks for contributing an answer to Stack Overflow!
But avoid …
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
But avoid …
To learn more, see our tips on writing great answers.
Required, but never shown
Required, but never shown
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
i really cannot follow your issue: if you import the right Entry class then there should be a entry.person. for me it looks like there is a error in how you reference the dsls from each other. are you sure you added references to the manifest in the correct way (added it to required bundles)? you talk about project on the classpath. maybe you did the wrong thing
– Christian Dietrich
Sep 3 at 21:02