Chibi-Scheme のsyntax-quote 構文

SRFI 149 のサンプル実装で使われている Chibi Scheme の独自機能は、 length* だけではありません。 もうひとつ、 syntax-quote という見慣れないキーワードが使われています。 syntax-quote の別名が使われている重要な場所は 2 ヶ所あります。 一つは、 パターンのリテラル比較コードの生成箇所で、 もう一つは、 テンプレートのリテラルの埋め込み箇所です。

https://srfi.schemers.org/srfi-149/srfi-149.html

 (_quote (rename 'syntax-quote))

 ; expand-pattern 中
    (list _and
          (list _compare v (list _rename (list _quote p)))
          (k vars))

 ; expand-template 中
    (list _rename (list _quote t))

Chibi Scheme のコードから syntax-quote の定義箇所を探すと、 SEXP_CORE_SYNTAX_QUOTE に対応しており、 strip 処理をしない quote 構文として定義してあります。

./eval.c:  {SEXP_CORE_SYNTAX_QUOTE, (sexp)"syntax-quote"},
static sexp analyze (sexp ctx, sexp object, int depth, int defok) {
//略
          switch (sexp_core_code(op)) {
//略
          case SEXP_CORE_QUOTE:
          case SEXP_CORE_SYNTAX_QUOTE:
            if (! (sexp_pairp(sexp_cdr(x)) && sexp_nullp(sexp_cddr(x))))
              res = sexp_compile_error(ctx, "bad quote form", x);
            else
              res = sexp_make_lit(ctx,
                                  (sexp_core_code(op) == SEXP_CORE_QUOTE) ?
                                  tmp=sexp_strip_synclos(ctx , NULL, 1, sexp_cadr(x)) :
                                  sexp_cadr(x));
            break;
//略
          }
//略
}

syntax-rules のリファレンス実装は、 syntax-rules マクロから er-macro-transformer マクロへ変換します。 そのとき、 元のマクロのリテラルを変換後にも同じ意味のまま受け渡すために使っています。 変換された er-macro-transformer マクロでリテラルを使うにはクォートする必要があるのですけど、 通常の quote 構文では構文情報を strip してしまいます。 strip されると識別子の意味が変化してしまうのでマクロからマクロへの変換には使えません。 そのために、 quote の意味を持ちつつ、 識別子をそのまま受け渡す特殊形式が必要になわけです。 マクロからマクロへの変換時に識別子を strip すると意味が変化するのは、 例えば、 syntax-rules で free-identifier=? を定義する有名な例があります。 通常の quote を使って strip すると、 リストの 3 番目は真であるはずなのに、 偽に展開されてしまいます。

(let-syntax
 ((free-id=?
   (syntax-rules ()
    ((free-id=? a b t f)
     (let-syntax
      ((test (syntax-rules (a) ((test a) t) ((test _) f))))
      (test b)))))
  (closed-foo
   (syntax-rules ()
    ((closed-foo pred a)
     (pred foo a #t #f)))))
  (list
   (free-id=? foo foo #t #f)
   (free-id=? foo bar #t #f)
   ((lambda (foo) (free-id=? foo foo #t #f)) 1)
   (closed-foo free-id=? foo)
   ((lambda (foo) (closed-foo free-id=? foo)) 1)))
; quote-syntax: (list #t #f ((lambda (foo.15) #t) 1) #t ((lambda (foo.24) #f) 1))
;        quote: (list #t #f ((lambda (foo.15) #f) 1) #t ((lambda (foo.24) #f) 1))