how to create custom dsls by php

29
Copyright © 2009 ITEMAN, Inc. All rights reserved. - 1 - 久保敦啓 <[email protected]> PHP でメタプログラミング カスタム DSL 作成入門 PHP 関西勉強会 (2009/3/14) 株式会社アイテマン Piece Project

Upload: atsuhiro-kubo

Post on 21-Dec-2014

2.354 views

Category:

Technology


7 download

DESCRIPTION

 

TRANSCRIPT

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 1 -

久保敦啓 <[email protected]>

PHP でメタプログラミングカスタム DSL 作成入門

PHP 関西勉強会 (2009/3/14)

株式会社アイテマンPiece Project

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 2 -

メタプログラミングとは?

「他のプログラムや自分自身を記述したり、操作するプログラムを記述する」-- 「ジェネレーティブプログラミング」より

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 3 -

メタプログラムとは?

「他のプログラムを記述したり操作したりするプログラム」-- 「ジェネレーティブプログラミング」より

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 4 -

メタプログラミング/メタプログラムの例

プログラムジェネレータ

コンパイラ

インタプリタ

リフレクション

アスペクト指向プログラミング

(Aspect Oriented Programming)

言語指向プログラミング

(Language Oriented Programming)

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 5 -

言語指向プログラミング

「言語指向プログラミングとは、ドメイン特化言語を使ってソフトウェア構築を行う一般的な開発スタイルのことです。」- http://capsctrl.que.jp/kdmsnr/wiki/bliki/?LanguageWorkbench より

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 6 -

ドメイン特化言語

「ドメイン特化言語(DSL:Domain Specific Language)とは、ある特定の種類の問題に特化したコンピュータ言語のことです。」- http://capsctrl.que.jp/kdmsnr/wiki/bliki/?LanguageWorkbench より

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 7 -

ドメイン特化言語の例

TeX

SQL

Yacc

Lex

アクティブデータモデル

XML 設定ファイル

GUI ビルダ

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 8 -

言語指向プログラミング

Intentional Software

(Intentional Software)

MPS (JetBrains)

Software Factories (Microsoft)

Generative Programming

Language Workbenches

(Martin Fowler)

Oslo (Microsoft)

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 9 -

次期 Piece Framework のアーキテクチャ

ツリービュー

エディター

グラフィカルエディター

編集可能形editable representation

ソースコード、HTML ファイル、データベーススキーマ、...

抽象形abstract representation

保存形stored representation

投影 projection

Piece Framework ランタイムオブジェクト

実行可能形executable representation

双方向の変更の反映

Eclipse

PHP

Piece_IDE with TMFDSLの参照・編集

PDT, The Language Toolkit, ...

Piece Framework Webサービス

DSL スクリプト

生成 generation

復元

保存 store

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 10 -

PHP でカスタム DSL を作成する

1. DSL の設計と Lexer および Parser の実装

2. セマンティックモデル (ドメインモデル) の設計・実装

3. (オプション) Eclipse 上の DSL エディタの設計・実装

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 11 -

トランスフォーメーション

---------- ---------- ---------- ---------- ------

DSL スクリプト

---------- ---------- ---------- ---------- ------

PHP スクリプト

AST

セマンティックモデル

Parse Populate

Generate

オプション

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 12 -

DSL の設計と Lexer および Parser の実装

1. 具体的な DSL スクリプトを書きながら、

2. 同時に Parser を定義し、

3. 必要に応じて Lexer に手を加えて、

4. テストプログラムを実行する。

5. 以上を繰り返す

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 13 -

Lexer Generator と Parser Generator

Lexer Generator

- PHP_LexerGenerator

Parser Generator

- PHP_ParserGenerator

- kmyacc + PHP 対応パッチ

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 14 -

カスタム DSL の例

association skills { table skills type manyToMany property skills}

association computer { table computers type oneToOne property computer}

method findByIdAndNote { query "SELECT * FROM $__table WHERE id = $id AND note = $note"}

method findAllWithSkills1 { association skills}...

Employees.mapper - Piece_ORM マッパー DSL

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 15 -

Lexer 定義の例

.../*!lex2php%input $this->_input%counter $this->_counter%token $this->token%value $this->value%line $this->lineID = /[a-zA-Z_][a-zA-Z_0-9]*/WS = /[ \t\r\n]+/STRING = /\"[^\["\\]+\"/LCURLY = "{"RCURLY = "}"METHOD = "method"...SL_COMMENT = !//[^\n\r]*\r?\n!ML_COMMENT = !/\*[^*]*\*+([^*/][^*]*\*+)*/!*//*!lex2php%statename INITIAL...

MapperLexer.plex - Piece_ORM マッパー DSL の Lexer 定義

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 16 -

Lexer 定義の例

.../*!lex2php%statename INITIAL

METHOD { if ($this->_debug) echo "found METHOD [ {$this->value} ]\n"; $this->token = MapperParser::METHOD;}

QUERY { if ($this->_debug) echo "found QUERY [ {$this->value} ]\n"; $this->token = MapperParser::QUERY;}

ORDER_BY { if ($this->_debug) echo "found ORDER_BY [ {$this->value} ]\n"; $this->token = MapperParser::ORDER_BY;}...

MapperLexer.plex - Piece_ORM マッパー DSL の Lexer 定義

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 17 -

Parser 定義の例

...start ::= topStatementList.

topStatementList ::= topStatementList topStatement.topStatementList ::= .

topStatement ::= method.topStatement ::= association.

method ::= METHOD ID(A) LCURLY methodStatementList(B) RCURLY. { if (array_key_exists(strtolower(A), $this->_methodDeclarations)) { throw new Exception("Cannot redeclare the method [ {A} ] (previously declared on line " . $this->_methodDeclarations[ strtolower(A) ] . ')' ); }

$this->_methodDeclarations[ strtolower(A) ] = $this->_mapperLexer->line; $this->_ast->addMethod(A, @B['query'], @B['orderBy'], @B['associations']);}...

MapperParser.y - Piece_ORM マッパー DSL の Parser 定義

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 18 -

DSL ローダの実装

...public function load(){ $this->_initializeAST(); $this->_loadAST(); $this->_loadSymbols(); $this->_createMapper();}...

DSL ローダの制御フロー

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 19 -

DSL ローダの実装

...private function _initializeAST(){ $this->_ast = new Ast();

foreach ($this->_metadata->getFieldNames() as $fieldName) { ... }

$this->_ast->addMethod('findAll', 'SELECT * FROM $__table'); $this->_ast->addMethod('insert'); $this->_ast->addMethod('update'); $this->_ast->addMethod('delete');}...

AST (Abstract Syntax Tree) の初期化

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 20 -

DSL ローダの実装

...private function _loadAST(){ $mapperLexer = new MapperLexer(file_get_contents($this->_configFile)); $mapperParser = new MapperParser($mapperLexer, $this->_ast, $this->_configFile);

try { while ($mapperLexer->yylex()) { $mapperParser->doParse($mapperLexer->token, $mapperLexer->value); } } catch (Exception $e) { throw new Exception($e->getMessage() . " in {$this->_configFile} on line {$mapperLexer->line}" ); }

$mapperParser->doParse(0, 0);}...

Lexer と Parser を実行し、DSL を AST に変換する

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 21 -

DSL ローダの実装

...private function _loadSymbols(){ try { $this->_loadMethods(); } catch (Exception $e) { throw new Exception($e->getMessage() . " in {$this->_configFile}"); }}

private function _createMapper(){ $this->_mapper = new Mapper($this->_mapperID); foreach ($this->_methods as $method) { $this->_mapper->addMethod($method); }}...

シンボルテーブルの作成とセマンティックモデルの作成

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 22 -

セマンティックモデル

...// A operational interfacepublic function executeQueryWithCriteria($methodName, $criteria, $isManip = false){ if (!$this->hasMethod($methodName)) { throw new Exception("The method [ $methodName ] was not defined"); }

$queryExecutor = new QueryExecutor($this, $isManip); return $queryExecutor->executeWithCriteria($this->_getMethod($methodName)->getName(), $criteria);}

// A population interfacepublic function addMethod(Method $method){ $this->_methods[ strtolower($method->getName()) ] = $method;}...

Operational Interface と Population Interface

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 23 -

AST クラスの実装

...class AST extends DOMDocument{ public function addMethod($name, $query = null, $orderBy = null, $associations = null) { $id = strtolower($name); $xpath = new DOMXPath($this); $methodNodeList = $xpath->query("//method[@id='$id']"); if (!$methodNodeList->length) { $methodElement = $this->appendChild(new DOMElement('method')); $methodElement->setAttribute('id', $id); $methodElement->setAttribute('name', $name); } else { $methodElement = $methodNodeList->item(0); } ... } ...

AST extends DOMDocument

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 24 -

トランスフォーメーション

---------- ---------- ---------- ---------- ------

DSL スクリプト

---------- ---------- ---------- ---------- ------

PHP スクリプト

AST

セマンティックモデル

Parse Populate

Generate

オプション

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 25 -

Eclipse 上の DSL エディタの設計・実装

1. TMF (Textual Modeling Framework) にDSLグラマーを移植する。 (グラマー言語は選択可能)

2. 補完、バリデーション、リファクタリングなどを実装する。

DSL エディタとツリービューの完成

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 26 -

Eclipse 上の DSL エディタの設計・実装

3. ページフローやワークフローのように可視化が効果的であればグラフィカルエディタも実装、TMF と統合する。

2 Way モデリングの完成

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 27 -

Eclipse 上の DSL エディタの設計・実装

4. PDT, Aptana など他のプラグインと協調できるように拡張する。

双方向の変更の反映

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 28 -

おわりに

Copyright © 2009 ITEMAN, Inc. All rights reserved.- 29 -

参考文献

Krzysztof Czarnecki, Ulrich Eisenecker, Generative Programming: Methods, Tools, and Applications, Addison-Wesley Pub (Sd), 2000, ISBN 978-0201309775 津田 義史、今関 剛、朝比奈 勲訳、『ジェネレーティブプログラミング』、翔泳社、2008年、ISBN 978-4798113319

http://capsctrl.que.jp/kdmsnr/wiki/bliki/?DomainSpecificLanguage

http://www.martinfowler.com/articles/languageWorkbench.html

http://capsctrl.que.jp/kdmsnr/wiki/bliki/?LanguageWorkbench

http://martinfowler.com/dslwip/index.html