ステップ実行eval開発中(6)

隠し束縛を安全に隠す方法を思い付いた。

  1. (gensym)を使って、文字列からは変換不可能なシンボルを生成する
  2. 対象モジュール内で、このシンボルに対して、隠したい内容(今回はspecial formの実体)を束縛する
  3. このシンボル内の束縛にアクセスする為には、元のシンボルを保持していないと不可能!
    • Gaucheのmodule-table手続き等の、モジュール操作関連の手続きを提供している場合は取り出せてしまうが、その場合はそもそもモジュールを逸脱した操作が既に提供されてしまってる気がする。
  4. これでは一見、マクロ展開時にも、このシンボルの解釈ができずに駄目なように思えるが、define-macroを使って、gensymシンボルを含むようにした場合は想定通りに機能した!
    • これが機能する(かも知れない)という事に気付くのに時間がかかった。そして機能した。


具体的には、以下のような感じになる。

(define m (make-module #f)) ; 対象モジュールを生成

(eval '(extend) m) ; 予め、束縛を完全に消しておく

(define (bind-in-m symbol expr) ; m内で、symbolに対してexprを束縛する手続き
  (eval `(define-in-module ,m ,symbol (quote ,expr)) (current-module)))

(define if-symbol (gensym)) ; ifを隠すシンボル
(bind-in-m if-symbol if) ; ifを隠し束縛に隠す
(global-variable-ref m if-symbol) ; => #<syntax if> が得られる事を確認
(global-variable-ref
  m
  (string->symbol
    (symbol->string if-symbol)))
;; => 文字列から得られるシンボルはエラーになる事を確認

;; 隠し束縛のifを呼び出すマクロを書いてみる
(define-macro (_if . args)
  ;; 実際には、ここに色々と余計な処理を追加する筈
  `(,if-symbol ,@args))
;; さっきのマクロをm内にインポートする
(bind-in-m '__if _if)
;; m内で、__ifを動かしてみる
(eval '(__if #f (not-reached) 123) m) ; => 123
(eval '(__if #t 456 (not-reached)) m) ; => 456

;; 最後に、mの束縛一覧を確認してみる
(module-parents m)
(module-precedence-list m)
(use util.list)
(hash-table->alist (module-table m))


完璧だ!……多分。
不安があるとすれば、未来のバージョンのGaucheでも確実に動く、という保証は無さそうな点ぐらいだ。
しかし、gauche.gongに向けての実装には、これで充分だろう。

      • -


gauche.nightの前売りチケットはもう少しで売り切れらしい。
しかし、自分自身が3/8に現地に行けるかどうかは、まだ謎のまま。
なんとかして現地参加したいが、こればっかりは別イベントの方のスケジュール判明を待つのみだ。