SECDR-schemeをつくる の2 - EIODを読む
常識的なScheme処理系を実装するためには、expanderを実装しないといけない。いわゆるexplicit-renamingなexpanderの方がプロトタイピング等の面で都合が良いので、まずはexplicit-renamingに実装する。
minimumなexpanderの実装としては、例えばEIODが有る。EIODはSRFI-46なsyntax-rulesを実装している(また、SRFI-46のリファレンス実装としても提供されている)。
遊んでみる
一応R6RSに移植してみたので、単純にチェックアウトしてnmoshなりなんなりで使ってみることが出来る。
凄く遅いことに注意する。
oku@cage ~/repos/eiod-r6rs $ nmosh eiod.scm eiod> (define-syntax add-a (syntax-rules () ((_ rest ...) (list 'a 'rest ...)))) eiod> (add-a 1 2 3) (a 1 2 3) eiod> (add-a x y z) (a x y z) eiod>
先頭にシンボルaを付け加えるquote、add-aを定義してみた。正常に動作する。
EIODのcore scheme
EIODのcore言語は、
- 構文
- q - シンボルしか取らないQuote
- def - シンプルなdefine(= (define (name arg0) ...) のようにして手続きを定義できない)
- define-syntax
- begin
- syntax - qの拡張版。identifierも素通しする
- get-env - (get-env) で、現在の環境を返す。
- 手続き
- delay*
- if*
- syntax-rules**
- (その他バックエンドschemeの手続き)
ifやdelayが手続きとして提供されているのは地味に興味深い。EIODでは、内蔵のifやdelayをsyntax-rulesで提供し、core言語構文からifやdelayを省略している。
(define-syntax if (syntax-rules () ((_ x y ...) (if* x (lambda () y) ...)))) (define-syntax delay (syntax-rules () ((_ x) (delay* (lambda () x)))))))
syntax-rules**は、R6RS的な文脈で言うところのtransformerを生成するために使われる。syntax-rules**は3引数id?、new-id、デフォルトのellipsisのidentifierオブジェクトを取り、syntax-rules*を生成して返す。
syntax-rules*は、マクロ環境(マクロが定義された時点での環境)とsyntax-rulesのパラメタ(ellipsisとして使うシンボルとリテラル扱いされるシンボル)、syntax-rulesの変換ルールを取り、変換器(Transformer)を生成して返す。
変換器は2引数、変換対象のS式と変換時点での環境を取り、変換したS式を返す。