Xtext Framework — как написать
IDE за один день
Что такое DSL и зачем он нужен?

Domain Specific Language — язык для
описания предметной области

Заточен под конкретную задачу

Предназначен для специалиста в
предметной области

Не требует навыков проектирования
программ
DSL подразделяются на

Внутренний DSL — является
подмножеством базового языка
программирования

Внешний DSL — не является
подмножеством базового языка

Текстовый

Графический
Общеизвестные DSL

SQL

HTML

Языки программной оболочки(tcl, bash)

Auto Lisp

UML

TeX/LaTeX язык вёрстки документов
Что такое Xtext?

Высокоуровневый фреймворк для создания
DSL языков

Позволяет создавать IDE на основе Eclipse
platform

Использует для парсинга ANTLR 3

Хранит дерево разбора с помощью Eclipse
Modelling Framework
Возможности Xtext

Генератор парсеров

Постпарсинг валидация

Кодогенерация

Форматирование

Поддержка юниттестов

Интеграция с IDE
Интеграция с IDE

Подсветка синтаксиса

Автокомплит

Поддержка форматирования

Поддержка сообщения о ошибках
компиляции/предупреждениях

Поддержка построения графических и
структурных диаграмм кода
DSL с редактором — пример из
жизни
 DSL как общая
часть портируемых
игр
 DSL для общения
дизайнера и
програмиста
Пример языка: CasualIntellect

Поведение агента задаётся с помощью
конечного автомата

Состояние агента опрашивается на каждый
тик игрового цикла, если выполняется
условие производится переход в состояние,
если нет – проверка другого условия из
списка. Если никакое условие не
выполняется
Как работает язык casualintellect?
Язык задающий конечный автомат для
управления игровым агентом
Как же создать DSL за один день?
Создаём проект
Определяем
грамматику
Генерируем Xtext
артифакты
Имплементируем
метод в валидаторе
Создаём Xtext проект
Главный проект
Содержит

Файл грамматики и
сопутствующие
файлы

Пакеты для

Форматирования

Проверки скоупа

Валидации
Проект UI
{Lang name}UiModule —
регистрация компонент
используемых с IDE
{lang name}ProposalProvider-
переопределение автокомплита
для всех правил грамматики
{lang_name}OutlineTreeProvider
— используется для управления
view outline
Определяем грамматику,
полезные детали

Список лексем Model:states+=State+;

Список с запятой, или его отсутствие
Transitions:
'transitions' ':' '{' list+=Transition? (Comma
list+=Transition)* '}';

Ключевое слово returns: Or returns Expression – Сгенерированный
интерфейс OR будет унаследован от Expression
Определяем грамматику,
полезные детали

Список лексем Model:states+=State+;

Список с запятой, или его отсутствие
Transitions:
'transitions' ':' '{' list+=Transition? (Comma
list+=Transition)* '}';

Ключевое слово returns: Or returns Expression – Сгенерированный
интерфейс OR будет унаследован от Expression
Определяем грамматику,
полезные детали

Фигурные скобки в теле выражения.
Entity: 'entity' {Entity} name = ID ('extends'
superType=[Entity])? '{'
attributes += Attribute*
'}' ; создаём сущность до полной инициализации.
Удаление левой рекурсии

Грамматика называется леворекурсивной,
если она содержит продукцию с вызовом
самой себя без продвижения по строке
Expression : Expression '+' Expression |
'(' Expression ')' |
INT;

ANTLR использует LL(*) алгоритм,
леворекурсивные грамматики он не парсит.
Удаление левой рекурсии

Грамматику можно менять с помощью
переписывания

Expression :
TerminalExpression ('+' TerminalExpression)?;
TerminalExpression :'(' Expression ')' |INT;
Удаление левой рекурсии
Но такое преобразование приведёт к созданию
лишних элементов AST. «(42)» будет
разобрано как
Operation {
left=Operation {
left=IntLiteral {
value=42
}
}
}
Удаление левой рекурсии
Чтобы избежать избыточности AST
произведём переписывание дерева
Expression :
TerminalExpression ({Operation.left=current}
op='+' right=Expression)?;
TerminalExpression returns Expression:
'(' Expression ')' |
{IntLiteral} value=INT;
Удаление левой рекурсии

Пытаемся разбирать выражение с помощью
правила TerminalExpression

Ищем опциональный + с последующим
другим выражением
• Если опциональная часть не найдена,
выражение совпадает с разобранным
элементом
• Иначе, создаём обьект «плюс» где левая
часть разобрана перед этим и правая часть
разбирается после +
Язык Xtend входной для Xtext

Выпущен Eclipse Fundation
http://www.eclipse.org/xtend/

Используется в Xtext начиная с версии 2.4

Транслируется в Java

Меньше шума – больше сахара
Язык Xtend входной для Xtext
Пример кода
class HelloWorld {
def static void main(String[] args){
println("Hello World")
}
}
Язык Xtend входной для Xtext
Сгенерированный код
import org.eclipse.xtext.xbase.lib.InputOutput;
@SuppressWarnings("all")
public class HelloWorld {
public static void main(final String[] args) {
InputOutput.<String>println("Hello World");
}
}
Язык Xtend, добавим сахару

Extension methods

Lambda Expressions

Switch with expressions

Patterns

Additional operators
Пишем код - кодогенерация

Интерфейс Igenerator
public void doGenerate(Resource input,
IFileSystemAccess fsa);

Проходит по узлам AST генерирует код
Пишем код - валидация

Используется для
постсинтаксического(семантического
анализа текста)

Класс наследуемый от
AbstractDeclarativeValidator

Для проверки используются методы
аннотированные @Check

Пример валидации:проверка
инициализации переменной до её
использования
Пишем код - форматирование
текста

Класс наследуется от
AbstractDeclarativeFormatter

Вставляем переход на новую строку,
увеличение/уменьшение отступа до и после
структуры данных
Пишем код - изменение outline

Класс наследуется от
DefaultEObjectLabelProvider

Содержится в ui проекте

Переопределяем метод text — изменяем
метку

Переопределяем метод image — изменяем
картинку
Тестирование

Xtext предоставляет полную поддержку TDD

Интегрирован с Junit 4(@Test, @Before,
TestSuite)

Аннотации для запуска тестов
XtextRunner(Запуск Junit4)
IinjectorProvider(Создаём Google Guice
инжектор)
Тестирование парсера

@Inject extension ParseHelper<Model>
парсит текст в модель

@Inject extension ValidationTestHelper
валидация модели
Тестирование кодогенерации

CompilationTestHelper компилирует
модель, генерит код
Вопросы?

X text

  • 1.
    Xtext Framework —как написать IDE за один день
  • 2.
    Что такое DSLи зачем он нужен?  Domain Specific Language — язык для описания предметной области  Заточен под конкретную задачу  Предназначен для специалиста в предметной области  Не требует навыков проектирования программ
  • 3.
    DSL подразделяются на  ВнутреннийDSL — является подмножеством базового языка программирования  Внешний DSL — не является подмножеством базового языка  Текстовый  Графический
  • 4.
    Общеизвестные DSL  SQL  HTML  Языки программнойоболочки(tcl, bash)  Auto Lisp  UML  TeX/LaTeX язык вёрстки документов
  • 5.
    Что такое Xtext?  Высокоуровневыйфреймворк для создания DSL языков  Позволяет создавать IDE на основе Eclipse platform  Использует для парсинга ANTLR 3  Хранит дерево разбора с помощью Eclipse Modelling Framework
  • 6.
    Возможности Xtext  Генератор парсеров  Постпарсингвалидация  Кодогенерация  Форматирование  Поддержка юниттестов  Интеграция с IDE
  • 7.
    Интеграция с IDE  Подсветкасинтаксиса  Автокомплит  Поддержка форматирования  Поддержка сообщения о ошибках компиляции/предупреждениях  Поддержка построения графических и структурных диаграмм кода
  • 8.
    DSL с редактором— пример из жизни  DSL как общая часть портируемых игр  DSL для общения дизайнера и програмиста
  • 9.
    Пример языка: CasualIntellect  Поведениеагента задаётся с помощью конечного автомата  Состояние агента опрашивается на каждый тик игрового цикла, если выполняется условие производится переход в состояние, если нет – проверка другого условия из списка. Если никакое условие не выполняется
  • 10.
    Как работает языкcasualintellect? Язык задающий конечный автомат для управления игровым агентом
  • 11.
    Как же создатьDSL за один день? Создаём проект Определяем грамматику Генерируем Xtext артифакты Имплементируем метод в валидаторе
  • 12.
  • 13.
    Главный проект Содержит  Файл грамматикии сопутствующие файлы  Пакеты для  Форматирования  Проверки скоупа  Валидации
  • 14.
    Проект UI {Lang name}UiModule— регистрация компонент используемых с IDE {lang name}ProposalProvider- переопределение автокомплита для всех правил грамматики {lang_name}OutlineTreeProvider — используется для управления view outline
  • 15.
    Определяем грамматику, полезные детали  Списоклексем Model:states+=State+;  Список с запятой, или его отсутствие Transitions: 'transitions' ':' '{' list+=Transition? (Comma list+=Transition)* '}';  Ключевое слово returns: Or returns Expression – Сгенерированный интерфейс OR будет унаследован от Expression
  • 16.
    Определяем грамматику, полезные детали  Списоклексем Model:states+=State+;  Список с запятой, или его отсутствие Transitions: 'transitions' ':' '{' list+=Transition? (Comma list+=Transition)* '}';  Ключевое слово returns: Or returns Expression – Сгенерированный интерфейс OR будет унаследован от Expression
  • 17.
    Определяем грамматику, полезные детали  Фигурныескобки в теле выражения. Entity: 'entity' {Entity} name = ID ('extends' superType=[Entity])? '{' attributes += Attribute* '}' ; создаём сущность до полной инициализации.
  • 18.
    Удаление левой рекурсии  Грамматиканазывается леворекурсивной, если она содержит продукцию с вызовом самой себя без продвижения по строке Expression : Expression '+' Expression | '(' Expression ')' | INT;  ANTLR использует LL(*) алгоритм, леворекурсивные грамматики он не парсит.
  • 19.
    Удаление левой рекурсии  Грамматикуможно менять с помощью переписывания  Expression : TerminalExpression ('+' TerminalExpression)?; TerminalExpression :'(' Expression ')' |INT;
  • 20.
    Удаление левой рекурсии Нотакое преобразование приведёт к созданию лишних элементов AST. «(42)» будет разобрано как Operation { left=Operation { left=IntLiteral { value=42 } } }
  • 21.
    Удаление левой рекурсии Чтобыизбежать избыточности AST произведём переписывание дерева Expression : TerminalExpression ({Operation.left=current} op='+' right=Expression)?; TerminalExpression returns Expression: '(' Expression ')' | {IntLiteral} value=INT;
  • 22.
    Удаление левой рекурсии  Пытаемсяразбирать выражение с помощью правила TerminalExpression  Ищем опциональный + с последующим другим выражением • Если опциональная часть не найдена, выражение совпадает с разобранным элементом • Иначе, создаём обьект «плюс» где левая часть разобрана перед этим и правая часть разбирается после +
  • 23.
    Язык Xtend входнойдля Xtext  Выпущен Eclipse Fundation http://www.eclipse.org/xtend/  Используется в Xtext начиная с версии 2.4  Транслируется в Java  Меньше шума – больше сахара
  • 24.
    Язык Xtend входнойдля Xtext Пример кода class HelloWorld { def static void main(String[] args){ println("Hello World") } }
  • 25.
    Язык Xtend входнойдля Xtext Сгенерированный код import org.eclipse.xtext.xbase.lib.InputOutput; @SuppressWarnings("all") public class HelloWorld { public static void main(final String[] args) { InputOutput.<String>println("Hello World"); } }
  • 26.
    Язык Xtend, добавимсахару  Extension methods  Lambda Expressions  Switch with expressions  Patterns  Additional operators
  • 27.
    Пишем код -кодогенерация  Интерфейс Igenerator public void doGenerate(Resource input, IFileSystemAccess fsa);  Проходит по узлам AST генерирует код
  • 28.
    Пишем код -валидация  Используется для постсинтаксического(семантического анализа текста)  Класс наследуемый от AbstractDeclarativeValidator  Для проверки используются методы аннотированные @Check  Пример валидации:проверка инициализации переменной до её использования
  • 29.
    Пишем код -форматирование текста  Класс наследуется от AbstractDeclarativeFormatter  Вставляем переход на новую строку, увеличение/уменьшение отступа до и после структуры данных
  • 30.
    Пишем код -изменение outline  Класс наследуется от DefaultEObjectLabelProvider  Содержится в ui проекте  Переопределяем метод text — изменяем метку  Переопределяем метод image — изменяем картинку
  • 31.
    Тестирование  Xtext предоставляет полнуюподдержку TDD  Интегрирован с Junit 4(@Test, @Before, TestSuite)  Аннотации для запуска тестов XtextRunner(Запуск Junit4) IinjectorProvider(Создаём Google Guice инжектор)
  • 32.
    Тестирование парсера  @Inject extensionParseHelper<Model> парсит текст в модель  @Inject extension ValidationTestHelper валидация модели
  • 33.
  • 34.