SQLResult candidates = select name from employees where

Download Report

Transcript SQLResult candidates = select name from employees where

内部ドメイン専用言語支援のための
型に連動した字句・構文ルールの
変更機構
1
理学部 情報科学科 千葉研究室
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の変数ではない
2
従来の内部DSLの実現手法の問題点 1/3
表現能力が低い
 同じ構文の衝突
 難しい
どのような文を表現す

endマクロに書き換えられてしまい
正しくコンパイルできない
るのかわかりづらい
例1. C/C++言語
#define
#define
#define
#define
select select_(
from ,
where ,
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
3
従来の内部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 employees where (>= TOEIC_score score)))
4
従来の内部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))))
5
提案: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 Column型
candidates; Table型
SQLCond型
}
SQLResult型
6
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(...));
}
N項演算子の
オペランド
各オペランドは
引数と対応
select...from...where...の処理内容
Javaで記述
7
型によるスコーピング

期待される型によって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型が期待されるので、
通常の意味の...>=...を利用
8
字句・構文ルールの変更

利用するN項演算子によってルールを切り替え
キーワードの変更
 必要に応じた識別子のリテラル化

Column型リテラル
として読む
select,from,whereはキーワード
第一引数は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の...>=...の
}
ルールに切り替え
通常の意味の...>=...の
ルールに切り替え
9
従来の手法の問題点を解決

ホスト言語による制限が少ない


型をスコープとして衝突を回避


ホスト言語が構文解析できなくてもよい
期待される型によって適切なN項演算子を選択
ソースコードの改変を意識しなくてよい

メタプログラミングを隠蔽
実際に本システムで作成したDSL
 簡単なselect文(N項演算子定義部分は20行程度)
 BNF(N項演算子定義部分は30行程度)
10
実装

Javaにより実装
5500行程度
 コード生成はJavassistを利用


宣言部分と本体部分を別々に解析


字句解析・構文解析・型チェックを連携


本体部分の解析に型やN項演算子などの情報が必要
型によってN項演算子を選択し、字句・構文ルールを変更
トップダウン構文解析

式を解析する前にその式の型がわかる必要
11
関連研究

Scala
メソッドを単項・二項演算子のように見ることが可能
 省略規則の応用によって実現


Smalltalk


メッセージをN項演算のように記述する
Registration-Based Language Abstractions
[S. Davis, et al, Onward! 2010]
エディタによって言語に新たな構文を追加できる
 構文木を変換するコードを書かなければならない
 字句ルールは変更できない

12
まとめ

Javaにユーザ定義N項演算子を導入することで
内部DSLを実現可能に
型によってN項演算子を制限
 字句・構文ルールの切り替え


今後の課題
表現力の強化
 静的な構文スコープの導入
 コンパイル時のオーバーヘッドの測定

13