言語組 : 課題候補 ~Rubyの文法を256倍いじって遊ぶ編~ 稲葉 一浩

言語組 : 課題候補
~Rubyの文法を256倍いじって遊ぶ編~
稲葉 一浩 (k.inaba)
www.kmonos.net
twitter.com/kinaba
要するに
• Ruby のスキャナ
や
• Ruby のパーサ
や
• RubyVM へのコンパイラ
を改造して、新しい機能を付け加えてみよう!
講師陣から出た案
• 多言語オペレータ
• パターンマッチ
例1:多言語オペレータ
• Rubyの普通のメソッド
class Warable
def waru(y)
…
end
end
a = Warable.new
b = a.waru( a ) # 普通
例1:多言語オペレータ
• 特別な記号をメソッド名にすると…
class Warable
def /(y)
…
end
end
a = Warable.new
b = a./( a ) # 普通
b = a / a # こう書いても大丈夫!
例1:多言語オペレータ
• ところで、
Rubyでは日本語メソッド名もつかえます
class わりざん
def わる(y)
…
end
end
a = わりざん.new
b = a.わる( a ) # 普通
【実装】これを作ろう【課題】
• 当然、こういうことがしたいですよね!
class わりざん
def ÷(y)
…
end
end
a = わりざん.new
b = a.÷( a ) # 普通
b = a ÷ a # 今はエラー!!!!!!!!!!!!!!!!!!
例1:多言語オペレータ
• やること
– 0: Rubyのスキャナとパーサの仕組みを把握
• “Rubyソースコード完全解説” の復習
– 1: 「+」「ー」「×」「÷」 演算子を増やしてみる
•
•
•
•
スキャナの変更???
パーサの変更???
VMへのコンパイラの変更???
ちゃんとした多エンコーディング対応???
例1:多言語オペレータ
• やること:発展編
– もっと汎用に演算子を増やせる仕組を考える
• 予約語 operator で宣言する???
• 優先順位や結合方向も汎用に増やすには???
class Fixnum
def ☆(y); self + y*y; end
end
p 12 ☆ 3 # エラー (12.☆(3) はOK)
operator ☆
p 12 ☆ 3 # 21
例2: パターンマッチ
• 文字列だとこんなことができます
def sample(str)
case str
when /^(.)..$/ # 3文字の文字列なら
$1 # 1文字目を返す
when /^abc(.)def$/ # (略)なら
$1 # 4文字目を返す
else; raise “えらー”
end
end
例2: パターンマッチ
• 配列だと?
def sample(arr)
if arr.size == 3
arr[0]
elsif arr.size == 7 && arr[0]==1 &&
arr[1]==2 && arr[2]==3 && arr[4]==4 &&
arr[5]==5 && arr[6]==6
arr[3]
end
end
【実装】これを作ろう【課題】
• 配列でもこんな風に…!
def sample(arr)
case arr
when [x,_,_] # 3要素の配列なら
x # 1個目を返す
when [1,2,3,x,4,5,6] # (略)なら
x # 4個目を返す
else; raise “えらー”
end
end
※注意
• 前のページの例は、今のRubyのparse.yでも
構文解析はできます
– 変数xにその時点で入っている値と等しいか
判定が行われる
x=6
case [1,2,3,9,4,5,6] #今のRubyで実行できるけど
when [1,2,3,x,4,5,6]
puts “にゃー” #ここには来ない
when [1,2,3,9,4,5,x]
puts “わん” #ここに来る
end
※注意
• なので(case式をそのまま使うなら)、
たぶんパーサーの変更は不要
• NODE_CASEをコンパイルするコードを
改造する???
例2:パターンマッチ
• やること
– 1: 配列パターンマッチ専用のキーワード
“match” を追加してみる(パーサの改造)
match arr when [x, y ,z] … end
– 1’: もしくは面倒なので case 式の意味を
勝手に変えちゃう覚悟を決める
case arr when [x, y ,z] … end
– 2: 一番簡単な場合。when 1つの場合の実装
• コンパイラの改造???VMの改造???
例2:パターンマッチ / やること
• 3: 複数のwhen。else
– match … when [x] … when [x,y] … else … end
• 4: *パターン
– match … when [x, *xs] … end
• 5: ネスト
– match … when [[x], y, z] … end
• 6: 定数パターン
– match … when [“hello”, x, y, 123, :symbol] … end
まとめ
• Rubyを256倍いじって遊ぶ編
– 多言語オペレータ
– パターンマッチ
– 他に作ってみたい追加文法がある方はどうぞ!