130 likes | 240 Views
内部ドメイン専用言語支援のための 型に連動した字句・構文ルールの 変更機構. 理学部 情報科学科 千葉研究室 07_02363 市川 和央 指導教員 千葉 滋 教授. 内部 ドメイン専用言語(内部 DSL ). ホスト言語の中で作った DSL ホスト言語: 枠組みとなる既存言語 DSL : ある問題の解決に特化した言語 生産性・保守性が向上 繰り返しを排除した可読性の高いコード ホスト言語との連携が容易 Java 中で SQL を利用. Java の中に SQL の select 文を記述. void printCandidates(int score) {
E N D
内部ドメイン専用言語支援のための型に連動した字句・構文ルールの変更機構内部ドメイン専用言語支援のための型に連動した字句・構文ルールの変更機構 理学部 情報科学科 千葉研究室 07_02363 市川 和央 指導教員 千葉 滋 教授
内部ドメイン専用言語(内部DSL) • ホスト言語の中で作ったDSL • ホスト言語:枠組みとなる既存言語 • DSL:ある問題の解決に特化した言語 • 生産性・保守性が向上 • 繰り返しを排除した可読性の高いコード • ホスト言語との連携が容易 • Java中でSQLを利用 Javaの中にSQLのselect文を記述 void printCandidates(int score) { SQLResult candidates = select name from employees where TOEIC_score >= score; System.out.println(candidates.toString());} nameやTOEIC_scoreはJavaの変数ではない
従来の内部DSLの実現手法の問題点 1/3 • 表現能力が低い • 同じ構文の衝突 • 難しい endマクロに書き換えられてしまい正しくコンパイルできない どのような文を表現するのかわかりづらい 例1. C/C++言語 #define select select_( #define from , #define where , #define end ); void printNum(int beg, int end) { for(int i = beg; i < end; i++) printf(“%d\n”, i); } 条件部分を文字列で渡している SQLResult candidates = select “name” from employees where “TOEIC_score >= 600” end
従来の内部DSLの実現手法の問題点 2/3 例2. Scheme >=マクロが適用されてしまう (define-syntax select (syntax-rules (from where) ((select col from table where cond) (select_ ‘col table cond)))) (define-syntax >= (syntax-rules () ((>= col val) (geq ‘col val)))) (if (>= (row_count candidates) 10) (draw_lots candidates) candidates) 前置記法に変化括弧も増えている (define candidates (select name from employeeswhere (>= TOEIC_score score)))
従来の内部DSLの実現手法の問題点 3/3 例3. Scheme(衝突回避版) 難しすぎる! (define-syntax select (syntax-case x () ((sql-syntax e ...) (with-syntax ((expr (datum->syntax (syntax k) ‘(let-syntax ((select (syntax-rules (from where) ((select col from table where cond) (select_ ‘col table cond)))) (>= (syntax-rules () ((>= col val) (geq ‘col val))))) ,(syntax->datum (syntax (begin e ...))))))) (syntax expr))))) (define candidates (sql-syntax (select name from employees where (>= TOEIC_score score))))
提案:Javaに型で制限されたユーザ定義N項演算子を導入提案:Javaに型で制限されたユーザ定義N項演算子を導入 • Javaで強力な内部DSLを実現可能に • DSLの構文をN項演算子として定義 • C++のオペレータオーバーロードの強化版 • 優先順位を設定可能に • N項演算子は型情報を持つ select...from...where...三項演算子とみなす ...>=...二項演算子とみなす SQLResult printCandidates(int score) { SQLResult candidates = select name from employees where TOEIC_score >= score; if(candidates.getRowCount() >= 10) drawLots(candidates); return candidates; } if(candidates.getRowCount() >= 10) drawLots(candidates); return candidates; Column型 Table型 SQLCond型 SQLResult型
N項演算子の定義 • メソッド定義と似た形式 • メソッド名にあたる部分はN項演算のパターン N項演算子のオペランド キーワード SQLResult select :col from :table where :cond (readas Column col, Table table, SQLCond cond) : priority = 100 { Connection con = ...; Statement stmt = con.createStatement(...); return new SQLResult(stmt.executeQuery(...)); } 各オペランドは引数と対応 select...from...where...の処理内容Javaで記述
型によるスコーピング • 期待される型によってN項演算子を制限 • 返り値の型が一致しないと利用されない • 引数の型もチェック SQLResult型が期待されるので、select...from...where...を利用 SQLCond型が期待されるので、SQLの...>=...を利用 SQLResult printCandidates(int score) { SQLResult candidates = select name from employees where TOEIC_score >= score; if(candidates.getRowCount() >= 10) drawLots(candidates); return candidates; } boolean型が期待されるので、通常の意味の...>=...を利用
字句・構文ルールの変更 • 利用するN項演算子によってルールを切り替え • キーワードの変更 • 必要に応じた識別子のリテラル化 select,from,whereはキーワード第一引数はColumn型として読む Column型リテラルとして読む select...from...where...のルールに切り替え SQLResult printCandidates(int score) { SQLResult candidates = select name from employees where TOEIC_score >= score; if(candidates.getRowCount() >= 10) drawLots(candidates); return candidates; } SQLの...>=...のルールに切り替え 通常の意味の...>=...のルールに切り替え
従来の手法の問題点を解決 • ホスト言語による制限が少ない • ホスト言語が構文解析できなくてもよい • 型をスコープとして衝突を回避 • 期待される型によって適切なN項演算子を選択 • ソースコードの改変を意識しなくてよい • メタプログラミングを隠蔽 • 実際に本システムで作成したDSL • 簡単なselect文(N項演算子定義部分は20行程度) • BNF(N項演算子定義部分は30行程度)
実装 • Javaにより実装 • 5500行程度 • コード生成はJavassistを利用 • 宣言部分と本体部分を別々に解析 • 本体部分の解析に型やN項演算子などの情報が必要 • 字句解析・構文解析・型チェックを連携 • 型によってN項演算子を選択し、字句・構文ルールを変更 • トップダウン構文解析 • 式を解析する前にその式の型がわかる必要
関連研究 • Scala • メソッドを単項・二項演算子のように見ることが可能 • 省略規則の応用によって実現 • Smalltalk • メッセージをN項演算のように記述する • Registration-Based Language Abstractions[S. Davis, et al, Onward! 2010] • エディタによって言語に新たな構文を追加できる • 構文木を変換するコードを書かなければならない • 字句ルールは変更できない
まとめ • Javaにユーザ定義N項演算子を導入することで内部DSLを実現可能に • 型によってN項演算子を制限 • 字句・構文ルールの切り替え • 今後の課題 • 表現力の強化 • 静的な構文スコープの導入 • コンパイル時のオーバーヘッドの測定