xtext: как отформатировать код, где блок должен иметь отступ

Моя грамматика дана:

Model:
    'module' (mn=ID)?
        (func+=Function)+
    'end_module'
;

Function:
    'function' name=ID '('')'
        (vars+=ID)*
    'end_function'
;

Я могу найти такой токен, как «функция», «(» и т. д.

  • Как If может принудительно добавить новую строку после токена «модуль», если необязательные данные mn не существуют, и после mn, если они существуют?
  • Как я могу сделать отступ в начале блока «модуль» и «конечный_модуль», а также «функция» и «конечная_функция»?

Форматирование, которое я ищу:

module test
  function fdf ()
    str1
    str2
  end_function

  function ff ()
  end_function
end_module

До сих пор я генерировал заглушки форматирования, используя: formatter = { generateStub = true }


person Johan    schedule 06.10.2016    source источник


Ответы (2)


это должно быть довольно прямолинейно, например.

@Inject extension MyDslGrammarAccess

def dispatch void format(Model model, extension IFormattableDocument document) {
    model.regionFor.keyword(modelAccess.end_moduleKeyword_3).prepend[newLine] 
    if (model.mn != null) {
        model.regionFor.feature(MyDslPackage.Literals.MODEL__MN).append[newLine]
        interior(
            model.regionFor.feature(MyDslPackage.Literals.MODEL__MN), 
            model.regionFor.keyword(modelAccess.end_moduleKeyword_3)
        ) [indent]
    } else {
        model.regionFor.keyword(modelAccess.moduleKeyword_0).append[newLine]
        interior(
            model.regionFor.keyword(modelAccess.moduleKeyword_0),
            model.regionFor.keyword(modelAccess.end_moduleKeyword_3)
        ) [indent]
    }
    for (Function func : model.getFunc()) {
        func.format;
    }
}

def dispatch void format(Function function, extension IFormattableDocument document) {
    function.regionFor.keyword(functionAccess.functionKeyword_0).append[newLine].prepend[newLine]
    function.regionFor.keyword(functionAccess.end_functionKeyword_5).prepend[newLine]
    interior(
        function.regionFor.keyword(functionAccess.functionKeyword_0),
        function.regionFor.keyword(functionAccess.end_functionKeyword_5)
    ) [indent]
}
person Christian Dietrich    schedule 08.10.2016

Как было предложено в Max's Answer, можно справиться с языками, поддерживающими пробелы, начиная с Xtext v2.8. Посмотрите!.

В вашем случае, я думаю, вы должны определить свою грамматику следующим образом:

Model:
    'module' (mn=ID)?
    BEGIN
        (func+=Function)+
    END
    'end_module'
;

Function:
    'function' name=ID '('')'
    BEGIN
        (vars+=ID)*
    END
    'end_function'
;

terminal BEGIN: 'synthetic:BEGIN';
terminal END: 'synthetic:END';

Если вы также хотите разрешить «пустые» функции, я думаю, вам следует изменить правило выше следующим образом:

Function:
    'function' name=ID '('')'
    (BEGIN
         (vars+=ID)*
    END)?
    'end_function'
;

Надеюсь, поможет!

person Lorenzo Addazi    schedule 06.10.2016
comment
Да, это очень помогает. Я должен отформатировать код вручную. как должно выглядеть тело format(Model, extension IFormattableDocument) для автоматического форматирования? - person Johan; 08.10.2016
comment
Вы можете взглянуть на пример проекта «Язык домашней автоматизации» из Xtext вместе с документацией о языках с поддержкой пробелов (ссылка в ответе выше). Я предлагаю вам начать с файла рабочего процесса (.mwe2), чтобы понять, как создать заглушку пользовательского форматирования. Затем «org.eclipse.xtext.example.homeautomation.formatting2.RuleEngineFormatter» и «org.eclipse.xtext.example.homeautomation.parser.antlr» будут содержать реальную реализацию, которую необходимо адаптировать для вашего языка. - person Lorenzo Addazi; 08.10.2016
comment
В примере RuleEn‌​gineFormatter используется org.eclipse.xtext.example.homeautomation.ruleEngine.Declaration, но мой проект не создает подобных файлов. Все связанные org.eclipse.xtext.example.homeautomation.ruleEngine.* отсутствуют в моем проекте. - person Johan; 08.10.2016
comment
Чтобы сгенерировать средство форматирования для вашего DSL, вам необходимо вставить formatter = {generateStub = true} в компонент «язык» внутри файла рабочего процесса (.mwe2) и запустить рабочий процесс. Обратите внимание, что «ruleEngine» — это название языка для примера, а «Declaration» соответствует одному из его правил. В вашем проекте у вас будет '‹yourDslName›Formatter', использующий классы, соответствующие правилам вашего языка. - person Lorenzo Addazi; 08.10.2016
comment
@Addazi, спасибо за помощь. Вы ответили на 50% моего вопроса, а Дитрих на остальные 50%. Сайт позволяет мне выбрать только один правильный ответ. - person Johan; 09.10.2016