Предметно-ориентированные языки программирования (DSL)

Post on 06-Dec-2014

1.465 views 0 download

description

Доклад с конференции "На Стачку" 2013, Ульяновск.

Transcript of Предметно-ориентированные языки программирования (DSL)

Предметно-ориентированныеязыки программирования

Кириллов Александр, UNDEV

[ DSL ]

Предметно-ориентированный язык - Предметно-ориентированный язык -

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

Мартин Фаулер

[ DSL ]

Зачем?

[ DSL ]

Зачем?

[ DSL ]

Ох уж эти скобки...

Зачем?

[ DSL ]BankAccount.configure do |account| account.number 1234 account.type :checking account.openDate '11.04.1974' account.balance 25382.20 account.holder do |holder| holder.lastName 'Singh' holder.firstName 'Darshan' endend

BankAccount: number: 1234 type: checking open_date: '11.04.1974' balance: 25382.20 account_holder: last_name: Singh first_name: Darshan

Ruby:

YAML:

Зачем?

[ Ключевые моменты ]

Где и кто использует DSL?

[ Ключевые моменты ]

Где и кто использует DSL:- конфигурации# TravisCI config file (.yaml)script: "bundle exec rake travis"before_script: ./bin/ci/before_build.shservices: mongodbrvm: - 1.9.3notifications: email: - didier@nocoffee.fr - mario@mariovisic.com irc: "irc.freenode.org#locomotivecms"branches: only: - master

[ Ключевые моменты ]

Где и кто использует DSL:- конфигурации- зависимости пакетов# Gemfilesource 'http://rubygems.org'

gem 'rails', '3.2.12'group :assets do gem 'therubyracer' gem 'select2-rails', github: "argerim/select2-rails"endgroup :test do gem "minitest" gem 'mocha', require: falseend

[ Ключевые моменты ]

Где и кто использует DSL:- конфигурации- зависимости пакетов- части фреймворков# Sample resource routeresources :products do resources :comments resources :sales do get 'recent', on: :collection endend

[ Ключевые моменты ]

Где и кто использует DSL:- конфигурации- зависимости пакетов- части фреймворков- системы тестирования# Rspec exampledescribe Account do it "has a balance of zero when first created" do Account.new.balance.should eq(Money.new(0)) expect { @a = 5 }.to change { @a }.from(nil).to(5) endend

[ Ключевые моменты ]

Где и кто использует DSL:- системы тестирования# language: ruФункционал: Сложение чисел Чтобы не складывать в уме Все, у кого с этим туго Хотят автоматическое сложение целых чисел

Сценарий: Сложение двух целых чисел Допустим я ввожу число 50 И затем ввожу число 70 Если я нажимаю "+" То результатом должно быть число 120

[ Ключевые моменты ]

Где и кто использует DSL:- и еще-еще-еще...

[ Ключевые моменты ]

Язык программирования

[ Ключевые моменты ]

Язык программирования

Декларативный подходЧТО делатьвместо

КАК делать

[ Ключевые моменты ]

Язык программирования

Декларативный подход

Природа языка

[ Ключевые моменты ]

Язык программирования

Декларативный подход

Природа языка

Ограниченные выразительныевозможности

[ Ключевые моменты ]

Язык программирования

Декларативный подход

Природа языка

Ограниченные выразительныеВозможности

Ориентированность на предметную область

[ Категории DSL ]

{

Внутренний DSL: 'Lisp, Ruby, etc...',

}

[ Категории DSL ]

{

Внутренний DSL: 'Lisp, Ruby, etc...',

Внешний DSL: 'XML, RegExp, SQL, CSS'

}

[ Категории DSL ]

{

Внутренний DSL: 'Lisp, Ruby, etc...',

Внешний DSL: 'XML, RegExp, SQL, CSS',

Языковые инструментальные средства: '*'

}

[ Реализация DSL ]

[ Реализация DSL ]

[ Внутренний DSL ]

processor = Processor.new(arch: :i386, cores: 2)dsk1 = Disk.new(size: 150.GB, speed:7200)dsk2 = Disk.new(size: 70.GB, speed:7200)computer = Computer.new({ processor: processor, disks: [dsk1, dsk2]})

Применение обычного API:

> Текучий интерфейс (fluent interface)

[ Внутренний DSL ]

> Текучий интерфейс (fluent interface)

processor = Processor.new(arch: :i386, cores: 2)dsk1 = Disk.new(size: 150.GB, speed:7200)dsk2 = Disk.new(size: 70.GB, speed:7200)computer = Computer.new({ processor: processor, disks: [dsk1, dsk2]})

Применение обычного API:

...понятно програ

ммисту

непонятно специа

листу предметной об

ласти...

[ Внутренний DSL ]

computer() .processor() .cores(2) .x64() .disk() .size(150) .speed(7200) .disk() .size(70) .speed(7200)

Связывание методов:Связывание методов:

> Текучий интерфейс (fluent interface)

[ Внутренний DSL ]

$("#menu") .fadeIn('fast') .addClass("active") .css('marginRight', '10px');

Связывание методов:Связывание методов:

> Текучий интерфейс (fluent interface)

[ Внутренний DSL ]

$("#menu") .fadeIn('fast') .addClass("active") .css('marginRight', '10px');

Связывание методов:Связывание методов:

> Текучий интерфейс (fluent interface)

$("#thumbnails li").mouseenter(function(e){ $(this).find('img') .stop() .animate({opacity: 0.8}, 300) .end() .find('.viewcasestudy') .fadeIn('fast');}).fadeIn('fast');

[ Внутренний DSL ]

computer()--processor()----cores(2)----x64()--disk()----size(150)----speed(7200)--disk()----size(70)----speed(7200)

Последовательность функций:Последовательность функций:Связывание методов

> Текучий интерфейс (fluent interface)

[ Внутренний DSL ]

computer(--processor(----cores(2),----x64()––),--disk(----size(150),----speed(7200)––),--disk(----size(70),----speed(7200)--))

Вложенные функции:Вложенные функции:Связывание методовПоследовательность функций

> Текучий интерфейс (fluent interface)

[ Внутренний DSL ]

ComputerBuilder.build do |c| c.processor do |p| p.cores 2 p.x64 p.speed 2.2 end c.disk do |d| d.size 120 end c.disk do |d| d.size 70 d.speed 7200 d.sata endend

Замыкания:Замыкания:Последовательность функцийВложенные функции

Связывание методов> Текучий интерфейс (fluent interface)

[ Внутренний DSL ]

> Текучий интерфейс (fluent interface)

> Работа с синтаксическим деревом

[ Внутренний DSL ]

> Текучий интерфейс (fluent interface)

> Работа с синтаксическим деревом

> Аннотации

[ Внутренний DSL ]

> Текучий интерфейс (fluent interface)

> Работа с синтаксическим деревом

> Аннотации

> Макросы

[ Внутренний DSL ]

> Текучий интерфейс (fluent interface)

> Работа с синтаксическим деревом

> Аннотации

> Макросы

> Динамический отклик

def method_missing(m, *args, &block) puts "There's no method called #{m} here."end

[ Внешний DSL ]

> Синтаксический анализ

[ Внешний DSL ]

> Синтаксический анализ

Входной поток — это обычный текст (...обычно o_0)

[ Внешний DSL ]

> Синтаксический анализ

event door_openedevent link_clickedevent window_closed

command play_musiccommand volume_up 10command send_message "Hello, world"

Управляемая разделителями трансляцияDelimiter-Directed Translation

[ Внешний DSL ]

> Синтаксический анализ

event door_opened\nevent link_clickedevent window_closed

command play_musiccommand volume_up 10command send_message "Hello, world"

разделитель

инструкция

Управляемая разделителями трансляцияDelimiter-Directed Translation

[ Внешний DSL ]

> Синтаксический анализ

event door_openedevent link_clickedevent window_closed

command play_musiccommand volume_up 10command send_message "Hello, world"

Управляемая разделителями трансляцияDelimiter-Directed Translation

Ограничение:

Нет способов обработкииерархического контекста

[ Внешний DSL ]

> Синтаксический анализ

event door_opened link_clickedend

command play_music volume_up 10 send_message "Hello, world"end

Синтаксически управляемая трансляцияSyntax-Directed Translation

commandsblock

command endcommandDec commandDec

play_music volume_up 10

[ Внешний DSL ]

> Синтаксический анализ

Грамматика входного языка.

list : eventList commandList ;eventList : 'events' eventDec* 'end';eventDec : identifier ;commandList : 'commands' commandDec* 'end';commandDec : identifier identifier? ;

[ Внешний DSL ]

> Синтаксический анализ

Грамматика входного языка.

Форма Бэкуса-Наура

[E]BNFlist : eventList commandList ;eventList : 'events' eventDec* 'end';eventDec : identifier ;commandList : 'commands' commandDec* 'end';commandDec : identifier identifier? ;

[ Внешний DSL ]

> Синтаксический анализ

Синтаксический анализатор на основерекурсивного спускаRecursive Descent Parser

[ Внешний DSL ]

> Синтаксический анализ

Комбинатор синтаксических анализаторовParser Combinator

Комбинаторкоманд

Анализаторначала блока команд

Комбинаторсписка команд

Анализаторконца блока команд

Анализаторкоманды

Анализатораргумента команды

[ Внешний DSL ]

> Синтаксический анализ

Генератор синтаксических анализаторовParser Generator

Грамматика

a : ID INT ;ID : 'a'..'z'+ ;INT : '0'..'9'+;

Синтаксическийанализатор

Генерация

[ Для чего все это? ]

В результате мы должны иметьпостроенную семантическую модель

[ Для чего все это? ]

В результате мы должны иметьпостроенную семантическую модель

> Для использования в программном продукте

[ Для чего все это? ]

В результате мы должны иметьпостроенную семантическую модель

> Для использования в программном продукте

> Для генерации нового кода

[ Генерация кода ]

> Генерация c помощью преобразователя Transformer Generation

[ Генерация кода ]

> Генерация c помощью преобразователя Transformer Generation

> Шаблонная генерация Templated Generation

[ Генерация кода ]

> Генерация c помощью преобразователя Transformer Generation

> Шаблонная генерация Templated Generation

> Встроенный помощник Embedment Helper

[ Если Вы заинтересованы ]

http://martinfowler.com/dslCatalog/

[ Спасибо за внимание! ]

Кириллов Александрhttp://twitter.com/saratovsource