ウォンツテック

そでやまのーと

複数call/ccに対応

GitHub - sodeyama/slisp: lisp interpreter

sLispの以下の点を改善しました。

  • コメントを可能にしました
  • call/ccで生成するラムダ式で使う変数名をgensymで作るようにしました(変数名の衝突を防ぐ目的)
  • call/ccを複数書けるようにしました。(ただし、トップレベルの各S式中に1つのみ)
  • slisp-mode(emacsメジャーモード)。ファイル開いてC-c nで評価

各々の対応するコードは以下

コメント

(defun slisp-get-src-string (filename)
  (let ((pre-buffer (current-buffer))
        (ret ""))
    (find-file filename)
    (setq str (buffer-substring-no-properties (point-min) (point-max)))
    (let ((lines (split-string str "\n")))
      (dolist (line lines)
        (if (not (string-match "^;" line))
            (setq ret (concat ret line)))))
    (switch-to-buffer pre-buffer)
    ret))

ファイルを開いたバッファからslisp-get-tokensに渡す文字列を生成する段階でコメント行を排除。

call/ccで生成するラムダ式で使う変数名をgensymで生成

(defmacro with-gensyms (syms &rest body)
  (declare (indent 1))
  `(let ,(mapcar
          (lambda (sym)
            `(,sym (gensym)))
          syms)
     ,@body))

Common Lispでよく使われるwith-gensymsをelispのmacroで再現してます。

(with-gensyms (a b c)
  body)

のようなコードは

(let ((a (gensym))
      (b (gensym))
      (c (gensym)))
  body)

に展開されます。gensymは一意なシンボルを生成するelispのmacro。

call/ccを複数書けるように

(defun slisp-callcc-parse (exp env)
  (dolist (seed (cdr exp))
    (with-gensyms (variable)
      (let* ((ret (slisp-callcc-getcc seed variable env))
             (find (slisp-get-findcallcc ret))
             (cc (slisp-get-callcc ret)))
        (if find
            (progn
              (let ((sexp (list "lambda" (list variable) (list "throw" cc))))
                (slisp-callcc-fifo-set sexp))))))))

slisp-callcc-fifoをcall/ccで生成された継続を保存するfifoデータとしslisp-callcc-fifo-set, slisp-callcc-fifo-getでセット、ゲットしただけ。