How To Create Custom DSLs By PHP
-
Upload
atsuhiro-kubo -
Category
Technology
-
view
2.355 -
download
7
description
Transcript of How To Create Custom DSLs By PHP
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.- 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