Проверка пространства имен импорта Xtext

Я пытаюсь изучить Xtext, определяя грамматику с помощью java-подобных пакетов, классов и импорта. Фрагмент моей грамматики выглядит так, где CompilationUnit является корневым объектом.

CompilationUnit:
  packageDeclaration=PackageDeclaration?
  imports+=ImportDeclaration*
  topClass=Class
;

packageDeclaration:
  'package' path=QualifiedName ';'
;

ImportDeclaration:
  'import' importedNamespace=QualifiedNameWithWildCard ';'
;

Class:
  {Class} visibility=Visibility isStatic?='static' 'class' name=ID ('extends' superClass=[Class|QualifiedName])? body=ClassBody
;

Для импорта перекрестных ссылок я использую DefaultGlobalScopeProvider, и я заменил QualifiedNameProvider моей собственной версией, которая добавляет имя пакета в качестве префикса для QualifiedName из topClass. Для автоматизации импорта собственного пакета я отредактировал ScopeProvider для конкретного проекта. Все это, кажется, прекрасно работает, и с помощью созданной Eclipse IDE я могу импортировать классы из других файлов, используя «import [packageName].[*|ClassName]». (Все еще продолжается работа над автоматическим импортом классов в том же пакете с реферером, но на данный момент я могу обойтись явным импортом)

Следующим шагом, который я пытаюсь выполнить, является проверка объявлений импорта и пакета. Я хочу реализовать то же ограничение, что и Java, что объявление пакета файла должно равняться относительному пути файла, а с другой стороны, я хочу проверить существование импортированного класса или пакета. Проблема в том, что через eResource объекта EObject я могу получить доступ только к полному URI ресурсов (например, platform:/resource/Sample/src/mypack/Sample.myjava), в то время как имя пути относительно исходной папки будет короче ( mypack/Sample.myjava). Я еще не понял, должен ли я обрезать URI с некоторой логикой или использовать какой-то совершенно другой подход.

Одна из возможных идей, возможно, заключалась бы в том, чтобы каким-то образом получить URI каждого каталога пути к классам проекта и работать оттуда, но я еще не понял, как это сделать.

Любая идея, как я должен проверить мой пакет и декларации импорта? Я продолжаю чувствовать, что я очень близко, но все же так далеко.

Изменить: устранено неверное представление о поведении DefaultGlobalScopeProvider. Это не связано с иерархией файлов, а только с полными именами. Также у меня работает автоматический импорт собственного пакета.

Обновление: если подумать, я должен проверить импорт, просто перечислив доступные ресурсы и проверив их полные имена. Тогда только проверка объявления пакета потребует проверки файловой иерархии.

Обновление 2: кажется, что в eclipse URI ресурса всегда имеет формат «платформа:/ресурс/[Проект]/[папка src]/…». Предполагая, что это будет означать, что я могу просто жестко проверить это, но выполнение этого в валидаторе проекта грамматики создаст зависимость на уровне грамматики от Eclipse, что, вероятно, не будет хорошей идеей для любого серьезного проекта DSL. Однако комментарий в этом посте заставил меня подумать, что, возможно, мне следует вообще не выполнять проверку местоположения пакета на уровне грамматики, а только в проекте пользовательского интерфейса (который я еще не изменил). Идея состоит в том, что расположение ресурса, возможно, следует оставить в более абстрактной форме, чем традиционная иерархия файловой системы.


person Fluster    schedule 04.07.2018    source источник
comment
вы смотрели на jdt/IjavaProjects и возможность доступа к исходным папкам? Вы смотрели на проверку в xtend? org.eclipse.xtend.ide.validator.XtendUIValidator.checkFileNamingConventions(XtendFile)   -  person Christian Dietrich    schedule 04.07.2018
comment
В этом проекте проверка, похоже, выполняется в проекте пользовательского интерфейса, а не в проекте грамматики, и это заставило меня задуматься, следует ли мне вообще выполнять проверку местоположения пакета еще в проекте грамматики. Добавил обновление в свой пост по этому поводу.   -  person Fluster    schedule 05.07.2018
comment
в автономном режиме нет проектов и исходных папок   -  person Christian Dietrich    schedule 05.07.2018


Ответы (1)


Я смог создать решение. Следующий код представляет собой грубую реализацию проверки объявлений импорта, которая может нуждаться в некоторой очистке, но в основном делает свое дело.

@Check
def checkImportSanity(ImportDeclaration imp) {

    val importQN = qualifiedNameConverter.toQualifiedName(imp.importedNamespace)
    val hasWildcard = isImportWildcard(importQN.getLastSegment)

    for (r:imp.eContainer.eResource.resourceSet.resources) {
        val classQN = qualifiedNameProvider.getFullyQualifiedName((r.getContents().get(0) as CompilationUnit).topClass)
        if (hasWildcard && classQN.skipLast(1).equals(importQN.skipLast(1))) {
            return
        }
        else if (classQN.equals(importQN)) {
            return
        }
    }

    error("This import doesn't match any class!",
        imp, MyJavaPackage.Literals.IMPORT_DECLARATION__IMPORTED_NAMESPACE
    );
}

Короче говоря, он просто перебирает все ресурсы и сравнивает полные имена импорта и верхнего класса ресурса, игнорируя любые имена файлов. КвалифицированныйNameProvider является моим собственным, который добавляет имя пакета к имени класса. Таким образом, он может проверять только импорт высшего класса, но я могу пойти дальше позже. Не знаю, будет ли этого достаточно для импорта внешних библиотек, но это другая тема, которая меня сейчас не интересует.

Кроме того, я решил не проверять имена пакетов по именам файлов. В то время как Java делает это, я думаю, что в современном мире было бы лучше оставить это ограничение на уровне редактора и игнорировать его на уровне грамматики.

person Fluster    schedule 06.07.2018