В Xtext, как мне следовать ссылке из грамматики B в грамматику A в рамках валидатора грамматики B (который есть в плагине ui)? Рассмотрим следующий пример.
Грамматика А это 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 ';';
и экземпляр
person Alice {citizenship "MN"; id "12345"; }
person Bob {citizenship "CH"; id "54321";}
person Malice {citizenship "XXX"; id "66666"; }
В аэропорту записываются записи людей.
enter Alice;
enter Bob;
enter Malice;
Записи моделируются второй грамматикой B 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] ';';
Убедившись, что у проекта Eclipse org.xtext.entries
есть проект org.xtext.people
на своем пути к классам, и убедившись, что плагин org.xtext.entries
имеет org.xtext.people
в качестве зависимости, все работает должным образом.
Существует запрет на поездки людей из страны XXX, хотя некоторые достойные люди исключены. Только ЦРУ знает, кто исключен из бана. Записи не должны быть разрешены для людей из XXX, если не исключено.
Обновленная грамматика
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 ')';
с валидатором
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)
}
}
}
}
}
, где драйвер для внешнего веб-приложения CIA моделируется, например,
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");
}
}
Проверки работают как положено.
Теперь я хочу предоставить быстрое исправление для 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) {
acceptor.accept(issue, 'Try override', 'Override if CIA says so.', 'override.png')
[element ,context |
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
]
}
}
Первая закомментированная строка не компилируется: атрибута нет person
. Вторая закомментированная строка - это попытка решить проблему путем получения вспомогательного класса в org.xtext.entries
для получения человека, но это также не компилируется, давая "Метод get (Entry) из типа 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;
}
}
Далее, entry.travelBanOverride
компилируется нормально, а entry.person
- нет. Нажатие на Entry в Eclipse приводит к переходу к ожидаемому коду, который имеет как travelBanOverride
, так и person
.
.
Проблема не возникает с классом Java в том же проекте и пакете.
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();
}
}
Переписывание быстрого исправления в Java решает проблему.
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());
}
}
);
}
}
- Как мне следовать ссылке из грамматики B (Записи) на грамматику A (Люди) в рамках валидатора грамматики B?