Я пытаюсь создать простую грамматику с помощью xText. Грамматика должна определять язык для интерфейсов Java (только), и в настоящее время я борюсь с объявлениями импорта. Я хочу иметь возможность ссылаться на другие интерфейсы из других пакетов, которые я определил, используя их FQN. Вот как выглядит моя грамматика:

DomainModel:
    elements=AbstractElement;

AbstractElement:
    'package' packageDeclaration=PackageDeclaration 
    'import'? importDeclarations+=ImportDeclaration*
    typeDeclaration=TypeDeclaration;

PackageDeclaration:
    name=QualifiedName ';';

ImportDeclaration:
    importedNamespace=[ReferncedType|QualifiedName] ('.*')? ';';

ReferncedType:
    PackageDeclaration |InterfaceDeclaration; //need to combine both?? separated by '.'

TypeDeclaration:
    'interface' interfaceDeclaration=InterfaceDeclaration;

TypeList:
    Type ( ',' type+=Type)*;

Type:
    typeDefinition=[ReferncedType|ValidID];

InterfaceDeclaration:
    name=ValidID ('extends' superType=TypeList)? body=InterfaceBody;

InterfaceBody:
    '{' (declarations+=InterfaceBodyDeclaration)+ '}';

InterfaceBodyDeclaration:
    interfaceMemberDelcaration+=InterfaceMemberDeclaration ';';

InterfaceMemberDeclaration:
    InterfaceMethodDeclaration;
InterfaceMethodDeclaration:
    (Type | 'void') name+=ValidID '(' (formalParameters+=FormalParameters)* ')' ('throws'
    ....)?;

Я определил оба файла:

package org.first.sample;

interface Demo {
   void getA();
}

....

package org.second.sample;

import org.first.sample.Demo; // this line says that the reference to org.first.sample.Demo is invalid, but I am able to reference org.first.sample

interface AnotherDemo {
   Demo getDemo();
}

Есть ли у вас какие-либо идеи?

0
beastie 7 Июл 2014 в 16:46
Нет, демонстрационный класс скомпилирован.
 – 
beastie
7 Июл 2014 в 17:22

3 ответа

Лучший ответ

На самом деле @laune права. Xtext поддерживает это из коробки. Пока у упомянутых типов в модели есть функция, называемая «имя», полное имя типа создается «из коробки». Я заметил, что в моем определении грамматики Xtext неверно то, что пакет должен содержать интерфейс, так что, когда формируется полностью определенное имя, xtext создает его, комбинируя `` имя '' интерфейса с `` именем '' пакета (или его родитель). @Fabien, ваш ответ правильный, если правила грамматики xtext не содержат функций name. Это собственный способ построения fqns, если, например, мы используем это:

Package:
 'package' name=ID ';' imports=Import ';' interface=Interface ';'
;

Interface:
 qualifier=Qualifier !id=ID (instead of name=ID)
;

Затем мы должны явно создать fqn, потому что встроенная поддержка ищет только функции «name».

Итак, в моем случае правильный способ использовать это:

 Package:
 'package' name=ID; imports=Import typeDefinition=TypeDefinition;

Import:
 'import' importedNamespace=[TypeDefinition|QualifiedName] ';'
;

TypeDefinition:
  InterfaceDefinition | EnumDefinition ...
;

InterfaceDefinition:
 qualifier=Qualifier !name=ID
;
0
beastie 6 Авг 2014 в 11:22

Как я читаю грамматику:

ImportDeclaration:
    importedNamespace=[ReferncedType|QualifiedName] ('.*')? ';';

ReferncedType:
    PackageDeclaration |InterfaceDeclaration; //need to combine both?? separated by '.'

PackageDeclaration:
    name=QualifiedName ';';

Таким образом, за import может следовать (PackageDeclaration = QualifiedName , за которым следует ;, а затем, возвращаясь к правилу ImportDeclaration, должен следовать еще один ;.

Кроме того, я не понимаю, почему ReferncedType может также расширяться до InterfaceDeclaration, а это все?

< Сильный > В дальнейшем

Так что, возможно, "импорт" следует определять как

AbstractElement:
    'package' packageDeclaration=PackageDeclaration 
    importDeclarations+=ImportDeclaration*
    ...

ImportDeclaration
   'import' importedNamespace=QualifiedName ('.*')? ';';

Он не разрешает статический импорт, и нужно что-то делать, чтобы отслеживать. *, Если это происходит.

0
laune 7 Июл 2014 в 17:28
Ну, я не совсем уверен, что должно содержаться в правиле ReferencedType. Мне просто нужно иметь возможность импортировать типы, как в Java ( import com.somepackage . TypeName) или (com.sompackage.*)
 – 
beastie
7 Июл 2014 в 17:19
См. мое дополнение «Позднее».
 – 
laune
7 Июл 2014 в 17:28
Спасибо, но это не приведет к ошибке компиляции, если импортированный пакет недействителен. Он будет скомпилирован с любым допустимым полным именем. Мне нужно ссылаться только на существующие типы.
 – 
beastie
7 Июл 2014 в 17:34
Должно ли это работать как компилятор Java? Если это так, полное имя используется для доступа к файлу класса или, если все участвуют в компиляции, полное имя должно в конечном итоге ссылаться на (где-то еще) объявленный интерфейс. Но интерфейс не будет отображаться буквально и полностью при импорте.
 – 
laune
7 Июл 2014 в 17:47

Вы можете привязать настраиваемый QualifiedNameProvider для переопределения имени, экспортируемого вашими интерфейсами. Что-то вроде этого должно сделать ссылку на импорт в порядке: (import org.first.sample.Demo;)

public class CustomQualifiedNameProvider extends DefaultDeclarativeQualifiedNameProvider {
    @Override
    public QualifiedName getFullyQualifiedName(EObject obj) {
        if (obj instanceof InterfaceDeclaration && obj.eContainer().eContainer() instanceof AbstractElement) {
            QualifiedName packageQualifiedName = getFullyQualifiedName(((AbstractElement)obj.eContainer().eContainer()).getPackageDeclaration());
            return packageQualifiedName.append(((InterfaceDeclaration) obj).getName());
        }
        return super.getFullyQualifiedName(obj);
    }
}

Кроме того, вы можете нажать Ctrl + Shift + F3, чтобы узнать, какое имя имеют ваши экспортированные объекты.

0
Fabien Fleureau 7 Июл 2014 в 18:16
Спасибо! Это полезно.
 – 
beastie
7 Июл 2014 в 19:13