Contenu connexe
Similaire à How To Create Custom DSLs By PHP
Similaire à How To Create Custom DSLs By PHP (20)
Plus de Atsuhiro Kubo (18)
How To Create Custom DSLs By PHP
- 1. PHP 関西勉強会 (2009/3/14)
PHP でメタプログラミング
カスタム DSL 作成入門
株式会社アイテマン
Piece Project
久保敦啓 <kubo@iteman.jp>
Copyright © 2009 ITEMAN, Inc. All rights reserved.
-1-
- 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.
-8-
- 9. 次期 Piece Framework のアーキテクチャ
Eclipse
抽象形
PHP
abstract representation
DSL スクリプト
保存 store
保存形
stored representation
復元
DSLの参照・編集
Piece_IDE with TMF
生成 generation
ツリービュー 投影 projection
PDT, The Language Toolkit, ...
Piece Framework Webサービス Piece Framework ランタイムオブジェクト
エディター
双方向の変更の反映
グラフィカルエディター 実行可能形
executable representation
ソースコード、HTML ファイル、データベーススキーマ、...
編集可能形
editable representation
Copyright © 2009 ITEMAN, Inc. All rights reserved.
-9-
- 10. PHP でカスタム DSL を作成する
1. DSL の設計と Lexer および
Parser の実装
2. セマンティックモデル (ドメイン
モデル) の設計・実装
3. (オプション) Eclipse 上の DSL
エディタの設計・実装
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 10 -
- 11. トランスフォーメーション
セマンティックモデル
DSL スクリプト PHP スクリプト
---------- ----------
---------- ----------
---------- ----------
---------- ----------
------ ------
Generate
オプション
Parse Populate
AST
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 11 -
- 12. DSL の設計と Lexer および Parser の実装
1. 具体的な DSL スクリプトを書き
ながら、
2. 同時に Parser を定義し、
3. 必要に応じて Lexer に手を加え
て、
4. テストプログラムを実行する。
5. 以上を繰り返す
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 12 -
- 13. Lexer Generator と Parser Generator
Lexer Generator
- PHP_LexerGenerator
Parser Generator
- PHP_ParserGenerator
- kmyacc + PHP 対応パッチ
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 13 -
- 14. カスタム DSL の例
Employees.mapper - Piece_ORM マッパー DSL
association skills {
table skills
type manyToMany
property skills
}
association computer {
table computers
type oneToOne
property computer
}
method findByIdAndNote {
query quot;SELECT * FROM $__table WHERE id = $id AND note = $notequot;
}
method findAllWithSkills1 {
association skills
}
...
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 14 -
- 15. Lexer 定義の例
MapperLexer.plex - Piece_ORM マッパー DSL の Lexer 定義
...
/*!lex2php
%input $this->_input
%counter $this->_counter
%token $this->token
%value $this->value
%line $this->line
ID = /[a-zA-Z_][a-zA-Z_0-9]*/
WS = /[ trn]+/
STRING = /quot;[^[quot;]+quot;/
LCURLY = quot;{quot;
RCURLY = quot;}quot;
METHOD = quot;methodquot;
...
SL_COMMENT = !//[^nr]*r?n!
ML_COMMENT = !/*[^*]**+([^*/][^*]**+)*/!
*/
/*!lex2php
%statename INITIAL
...
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 15 -
- 16. Lexer 定義の例
MapperLexer.plex - Piece_ORM マッパー DSL の Lexer 定義
...
/*!lex2php
%statename INITIAL
METHOD {
if ($this->_debug) echo quot;found METHOD [ {$this->value} ]nquot;;
$this->token = MapperParser::METHOD;
}
QUERY {
if ($this->_debug) echo quot;found QUERY [ {$this->value} ]nquot;;
$this->token = MapperParser::QUERY;
}
ORDER_BY {
if ($this->_debug) echo quot;found ORDER_BY [ {$this->value} ]nquot;;
$this->token = MapperParser::ORDER_BY;
}
...
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 16 -
- 17. Parser 定義の例
MapperParser.y - Piece_ORM マッパー DSL の 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(quot;Cannot redeclare the method [ {A} ] (previously
declared on line quot; .
$this->_methodDeclarations[ strtolower(A) ] .
')'
);
}
$this->_methodDeclarations[ strtolower(A) ] = $this->_mapperLexer->line;
$this->_ast->addMethod(A, @B['query'], @B['orderBy'], @B['associations']);
}
...
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 17 -
- 18. DSL ローダの実装
DSL ローダの制御フロー
...
public function load()
{
$this->_initializeAST();
$this->_loadAST();
$this->_loadSymbols();
$this->_createMapper();
}
...
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 18 -
- 19. DSL ローダの実装
AST (Abstract Syntax Tree) の初期化
...
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');
}
...
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 19 -
- 20. DSL ローダの実装
Lexer と Parser を実行し、DSL を AST に変換する
...
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() .
quot; in {$this->_configFile} on line {$mapperLexer-
>line}quot;
);
}
$mapperParser->doParse(0, 0);
}
...
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 20 -
- 21. DSL ローダの実装
シンボルテーブルの作成とセマンティックモデルの作成
...
private function _loadSymbols()
{
try {
$this->_loadMethods();
} catch (Exception $e) {
throw new Exception($e->getMessage() . quot; in {$this->_configFile}quot;);
}
}
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.
- 21 -
- 22. セマンティックモデル
Operational Interface と Population Interface
...
// A operational interface
public function executeQueryWithCriteria($methodName, $criteria, $isManip =
false)
{
if (!$this->hasMethod($methodName)) {
throw new Exception(quot;The method [ $methodName ] was not definedquot;);
}
$queryExecutor = new QueryExecutor($this, $isManip);
return $queryExecutor->executeWithCriteria($this-
>_getMethod($methodName)->getName(), $criteria);
}
// A population interface
public function addMethod(Method $method)
{
$this->_methods[ strtolower($method->getName()) ] = $method;
}
...
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 22 -
- 23. AST クラスの実装
AST extends DOMDocument
...
class AST extends DOMDocument
{
public function addMethod($name, $query = null, $orderBy = null,
$associations = null)
{
$id = strtolower($name);
$xpath = new DOMXPath($this);
$methodNodeList = $xpath->query(quot;//method[@id='$id']quot;);
if (!$methodNodeList->length) {
$methodElement = $this->appendChild(new DOMElement('method'));
$methodElement->setAttribute('id', $id);
$methodElement->setAttribute('name', $name);
} else {
$methodElement = $methodNodeList->item(0);
}
...
}
...
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 23 -
- 24. トランスフォーメーション
セマンティックモデル
DSL スクリプト PHP スクリプト
---------- ----------
---------- ----------
---------- ----------
---------- ----------
------ ------
Generate
オプション
Parse Populate
AST
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 24 -
- 25. Eclipse 上の DSL エディタの設計・実装
1. TMF (Textual Modeling Framework) にDSL
グラマーを移植する。 (グラマー言語は選択可能)
2. 補完、バリデーション、リファクタリングなどを
実装する。
DSL エディタとツリービューの完成
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 25 -
- 26. Eclipse 上の DSL エディタの設計・実装
3. ページフローやワークフローのように可視化が効
果的であればグラフィカルエディタも実装、TMF と
統合する。
2 Way モデリングの完成
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 26 -
- 27. Eclipse 上の DSL エディタの設計・実装
4. PDT, Aptana など他のプラグインと協調できる
ように拡張する。
双方向の変更の反映
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 27 -
- 28. おわりに
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 28 -
- 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
Copyright © 2009 ITEMAN, Inc. All rights reserved.
- 29 -