マクロの展開を考える

そろそろマクロの展開を考えよう。
とても簡単な例で妄想。

簡単な例

(define-syntax show
  (syntax-rules ()
    ((_ a) (display a))))

(show "higepon")

define-syntax の時点で、 syntax-rules はパースされて Node ツリーとなる。
"show" => [node-pattern1]
のように、パターンマッチの配列がハッシュに格納されるイメージ。(今回は配列の要素が1つ)


マクロを一切考慮しなければ (show "higepon") は

  1. Toknizer で token になる
  2. Parser で Node ツリーになる
  3. Translator で Scheme Object にマッピング

というフローで処理される。


さてマクロの展開はどこでされるのかな。
うーん、Translater が show というキーワードがマクロであることを発見して展開ってのが良さそう。

つまり Translaterは

-Node
--[SYMBOL] show (マクロ名だね!)
--[STRING] "higepon"

-Node
--[SYMBOL] display
--[STRING] "higepon"

に変換すれば良いことになる。(合ってる?)

マクロ名を含む場合

(define-syntax show
  (syntax-rules ()
    ((_ a) (display a))))

(define-syntax show-line
  (syntax-rules ()
    ((_ a) (show a) (newline))))
(show-newline "higepon")

マクロが、マクロを参照している場合はどうだろう?
Node がマクロ名に一致するシンボルを持っている限りそれを変換しつづければ良さそう。

-Node
--[SYMBOL] show-newline (マクロ名だね!)
--[STRING] "higepon"

-Node
--Node1
---[SYMBOL] show (マクロ名だね!)
---[STRING] "higepon"
--Node2
---[SYMBOL] newline

-Node
--Node1
---[SYMBOL] display
---[STRING] "higepon"
--Node2
---[SYMBOL] newline

とまあこんな感じだろう。

実装場所は?

Translater上に実装する。
Translaterは

  • マクロの辞書を持つ。
  • マクロ変換メソッドを持つ。

マクロのスコープを考えると実はマクロ辞書は Frame?(environment) に持つべき気もするが。。

テストの準備

Node -> Node 変換の行うのだけど人の目には、変換がうまくいっているかとても分かり辛いので、Node->toSExp() を実装しS式として比較する。
→実装しながら考えたけど、これはアホだ。toNodeがあるので、Nodeの結果を比べるのが正しい。(SExpは改行や空白が入ってまったく同じにするのが面倒だし)

まとめ

  • Node->toSexp()の実装 →間違い
  • Node->equals(Node*)
  • テストを用意
  • Translatorに実装する