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

How To Create Custom DSLs By PHP

Dec 21, 2014

Download

Technology

Atsuhiro Kubo

 
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 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

Page 2: How To Create Custom DSLs By PHP

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

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

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

Page 3: How To Create Custom DSLs By PHP

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

メタプログラムとは?

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

Page 4: How To Create Custom DSLs By PHP

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

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

プログラムジェネレータ

コンパイラ

インタプリタ

リフレクション

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

(Aspect Oriented Programming)

言語指向プログラミング

(Language Oriented Programming)

Page 5: How To Create Custom DSLs By PHP

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

言語指向プログラミング

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

Page 6: How To Create Custom DSLs By PHP

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

ドメイン特化言語

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

Page 7: How To Create Custom DSLs By PHP

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

ドメイン特化言語の例

TeX

SQL

Yacc

Lex

アクティブデータモデル

XML 設定ファイル

GUI ビルダ

Page 8: How To Create Custom DSLs By PHP

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)

Page 9: How To Create Custom DSLs By PHP

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

Page 10: How To Create Custom DSLs By PHP

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

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

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

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

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

Page 11: How To Create Custom DSLs By PHP

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

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

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

DSL スクリプト

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

PHP スクリプト

AST

セマンティックモデル

Parse Populate

Generate

オプション

Page 12: How To Create Custom DSLs By PHP

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

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

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

2. 同時に Parser を定義し、

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

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

5. 以上を繰り返す

Page 13: How To Create Custom DSLs By PHP

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

Lexer Generator と Parser Generator

Lexer Generator

- PHP_LexerGenerator

Parser Generator

- PHP_ParserGenerator

- kmyacc + PHP 対応パッチ

Page 14: How To Create Custom DSLs By 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

Page 15: How To Create Custom DSLs By PHP

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 定義

Page 16: How To Create Custom DSLs By PHP

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 定義

Page 17: How To Create Custom DSLs By PHP

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 定義

Page 18: How To Create Custom DSLs By PHP

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

DSL ローダの実装

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

DSL ローダの制御フロー

Page 19: How To Create Custom DSLs By PHP

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) の初期化

Page 20: How To Create Custom DSLs By PHP

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 に変換する

Page 21: How To Create Custom DSLs By PHP

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); }}...

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

Page 22: How To Create Custom DSLs By PHP

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

Page 23: How To Create Custom DSLs By PHP

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

Page 24: How To Create Custom DSLs By PHP

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

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

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

DSL スクリプト

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

PHP スクリプト

AST

セマンティックモデル

Parse Populate

Generate

オプション

Page 25: How To Create Custom DSLs By PHP

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

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

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

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

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

Page 26: How To Create Custom DSLs By PHP

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

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

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

2 Way モデリングの完成

Page 27: How To Create Custom DSLs By PHP

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

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

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

双方向の変更の反映

Page 28: How To Create Custom DSLs By PHP

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

おわりに

Page 29: How To Create Custom DSLs By PHP

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