Created
February 14, 2014 13:35
-
-
Save guicho271828/9001076 to your computer and use it in GitHub Desktop.
Common Lisp is still hard to satisfy. ref: http://qiita.com/guicho271828/items/2852196ddf4c48ff0e3c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defmacro name lambda-list &body body) | |
(macrolet bindigs &body body) | |
(eval form) | |
(compile name definition) | |
(macroexpand form &optional env) | |
(macroexpand-1 form &optional env) | |
*macroexpand-hook* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AUGMENT-ENVIRONMENT | |
COMPILER-LET | |
DECLARATION-INFORMATION | |
DEFINE-DECLARATION | |
ENCLOSE | |
FUNCTION-INFORMATION | |
PARSE-MACRO | |
VARIABLE-INFORMATION |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defun %%eval (exp env) | |
(cond | |
((symbolp exp) | |
;; CLHS 3.1.2.1.1 Symbols as Forms | |
(multiple-value-bind (value kind) (get-variable exp env) | |
(ecase kind | |
(:variable value) | |
(:expansion (%eval value env))))) | |
;; CLHS 3.1.2.1.3 Self-Evaluating Objects | |
((atom exp) exp) | |
;; CLHS 3.1.2.1.2 Conses as Forms | |
((consp exp) | |
(case (car exp) | |
;; CLHS 3.1.2.1.2.1 Special Forms | |
((block) (eval-block (cdr exp) env)) | |
((catch) (eval-catch (cdr exp) env)) | |
;; special form が20個ぐらい続く | |
;; | |
;; (略) | |
(t | |
(let ((dispatcher (getf *eval-dispatch-functions* (car exp)))) | |
(cond | |
(dispatcher ; cltl2:compiler-let のための処理 | |
(funcall dispatcher exp env)) | |
;; CLHS 3.1.2.1.2.4 Lambda Forms | |
((and (consp (car exp)) (eq (caar exp) 'lambda)) | |
(interpreted-apply (eval-function (list (car exp)) env) | |
(eval-args (cdr exp) env))) | |
(t | |
(multiple-value-bind (function kind) (get-function (car exp) env) | |
(ecase kind | |
;; CLHS 3.1.2.1.2.3 Function Forms | |
(:function (%apply function (eval-args (cdr exp) env))) | |
;; CLHS 3.1.2.1.2.2 Macro Forms | |
(:macro | |
;; **ここからがキモ** | |
;; **ここからがキモ** | |
))))))))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(let ((hook *macroexpand-hook*)) | |
(%eval (funcall hook ; 展開 | |
function | |
exp | |
(env-native-lexenv env)) | |
env)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; eval するコード | |
(let ((x 5)) | |
(my-unless (plusp x) | |
(print :minus))) | |
;; 展開してできるコード | |
(let ((x 5)) | |
(IF (NOT (PLUSP X)) | |
(PROGN (PRINT :MINUS)) | |
NIL)) | |
;; コールスタック | |
(eval ; let | |
(eval ; my-unless | |
(macroexpand) ; my-unless -> when -> if | |
(eval ; if | |
(eval (eval)) ; (not (plusp x)) | |
(eval)))) ; (progn ...) か NIL |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; eval するコード | |
(my-unless (plusp x) | |
(my-unless (minusp x) | |
(print :zero))) | |
;; 展開してできるコード | |
(IF (NOT (PLUSP X)) | |
(PROGN | |
(IF (NOT (MINUSP X)) | |
(PROGN (PRINT :ZERO)) | |
NIL)) | |
NIL) | |
;; コールスタック | |
(eval ; my-unless | |
(macroexpand) ; my-unless -> when -> if | |
(eval ; if | |
(eval ; (not (plusp)) | |
(eval ; my-unless | |
(macroexpand) ; my-unless -> when -> if | |
(eval ...))))) ; (not (minusp)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; iterate の簡易バージョン | |
;; iter の中にいるばあい、 | |
;; while は 引数が true の時だけ実行を次の節に続けます。 | |
;; collect はその引数を内部的な変数に集め、iterの返り値にします。 | |
;; iter の外で使われた時は、for と collect はエラーを投げます。 | |
(let ((i 0)) | |
(iter (while (< i 5)) | |
(incf i) | |
(collect (+ 3 (* 4 i))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(define-condition compile-error (simple-error) | |
((message :initarg :message :accessor message)) | |
(:report (lambda (c s) | |
(princ (message c) s)))) | |
(defmacro collect (x) | |
(declare (ignore x)) | |
(error 'compile-error | |
:message "`collect' must be used under `iter'")) | |
(defmacro while (x) | |
(declare (ignore x)) | |
(error 'compile-error | |
:message "`while' must be used under `iter'")) | |
(require :alexandria) | |
(use-package :alexandria) | |
(defmacro iter (&body body) | |
(with-gensyms (iter-block accumulate start) | |
`(block ,iter-block | |
(let ((,accumulate nil)) | |
(macrolet ((while (condition) | |
`(unless ,condition | |
(return-from ,',iter-block | |
(nreverse ,',accumulate)))) | |
(collect (thing) | |
`(push ,thing ,',accumulate))) | |
(tagbody | |
,start | |
,@body | |
(go ,start))))))) | |
(let ((i 0)) | |
(iter (while (< i 5)) | |
(incf i) | |
(collect (+ 3 (* 4 i))))) | |
;; --> (7 11 15 19 23) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(let ((i 0)) | |
(iter (while (< i 5)) | |
(incf i) | |
(print acc) ; <-- | |
(collect (+ 3 (* 4 i)) :into acc))) ; <-- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(collect (thing &key into) | |
(if into | |
(error 'accumulate-target :name into) ; コンパイルやり直し! | |
`(push ,thing ,',accumulate))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defmacro iter (&body body &continuation cont) | |
(with-gensyms (iter-block accumulate start) | |
(handler-case | |
(funcall #'cont | |
`(block ,iter-block | |
(let ((,accumulate nil)) | |
(macrolet ((while (condition) | |
`(unless ,condition | |
(return-from ,',iter-block | |
(nreverse ,',accumulate)))) | |
(collect (thing &key into) | |
(if into | |
(signal 'accumulate-target :name into) | |
`(push ,thing ,',accumulate)))) | |
(tagbody | |
,start | |
,@body | |
(go ,start)))))) | |
;; handler | |
(accumulate-target (c) | |
(setf accumulate (name c)) | |
(funcall #'cont | |
`(block ,iter-block | |
(let ((,accumulate nil)) | |
(macrolet ((while (condition) | |
`(unless ,condition | |
(return-from ,',iter-block | |
(nreverse ,',accumulate)))) | |
(collect (thing &key into) | |
`(push ,thing ,',accumulate))) | |
(tagbody | |
,start | |
,@body | |
(go ,start)))))))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 一階層隠蔽する | |
(defmacro my-collect (&rest args) | |
`(collect ,@args)) | |
(let ((i 0)) | |
(iter (while (< i 5)) | |
(incf i) | |
(print acc) | |
(my-collect (+ 3 (* 4 i)) into acc))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defmacro my-unless (condition &body body) | |
`(when (not ,condition) | |
,@body)) | |
(defparameter *form* | |
`(let ((x 5)) | |
(my-unless (plusp x) | |
(print :minus)))) | |
(macroexpand-1 *form*) | |
; --> | |
; (LET ((X 5)) | |
; (MY-UNLESS (PLUSP X) | |
; (PRINT :MINUS))) | |
; NIL |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(require :iterate) | |
(in-package :iterate) | |
(let ((i 0)) | |
(iter (while (< i 5)) | |
(incf i) | |
(print acc) | |
(macrolet ((my-collect (&rest args) | |
`(collect ,@args))) | |
(my-collect (+ 3 (* 4 i)) into acc)))) | |
; in: LET ((I 0)) ... | |
; | |
; caught WARNING: | |
; Iterate: | |
; Iterate does not know how to handle | |
; the special form (MACROLET ...) | |
; It will not be walked, which means that Iterate clauses | |
; inside it will not be seen. | |
; | |
; compilation unit finished | |
; Undefined function: | |
; COLLECT | |
; Undefined variables: | |
; ACC INTO |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defmacro iter (... &environment env) | |
... | |
(walk-code ... env)) | |
(defun walk-code (form env) | |
... | |
(when (eq 'macrolet (car form)) | |
(destructuring-bind (car macros . body) form | |
(declare (ignore car)) | |
(walk-code | |
`(progn ,@body) | |
(augment-environment | |
env | |
:macro (make-macro-functions macros)))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(eval ; let | |
(eval ; iter | |
(macroexpand) ; iterを展開 (中でwalk-codeを呼ぶ) | |
(eval))) ; 展開したコードをまた読み込み直す -- マクロのチェックもする |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(let ((x 0)) | |
(let ((y x)) | |
(declare (fixnum y)) | |
...)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
macroexpand -> eval -...-> eval -> macroexpand -...-> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defparameter *form2* | |
`(my-unless (plusp x) | |
(print :minus))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(macroexpand-1 *form2*) | |
;; --> | |
;; (WHEN (NOT (PLUSP X)) (PRINT :MINUS)) | |
;; T |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(macroexpand-1 (macroexpand-1 *form2*)) | |
;; -> | |
;; (IF (NOT (PLUSP X)) | |
;; (PROGN (PRINT :MINUS)) | |
;; NIL) | |
;; T | |
(macroexpand-1 (macroexpand-1 (macroexpand-1 *form2*))) | |
;; -> | |
;; (IF (NOT (PLUSP X)) ; 変化なし | |
;; (PROGN (PRINT :MINUS)) | |
;; NIL) | |
;; NIL |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(macroexpand *form2*) | |
;; --> | |
;; (IF (NOT (PLUSP X)) | |
;; (PROGN (PRINT :MINUS)) | |
;; NIL) | |
;; T |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(macroexpand *form*) | |
;; --> | |
;; (LET ((X 5)) | |
;; (MY-UNLESS (PLUSP X) | |
;; (PRINT :MINUS))) | |
;; NIL |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CL-USER> (setf *evaluator-mode* :interpret) | |
; --> :INTERPRET |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defun eval (original-exp) | |
(eval-in-lexenv original-exp (make-null-lexenv))) | |
;; ↓ | |
(defun eval-in-lexenv (exp lexenv) | |
(if (eq *evaluator-mode* :compile) | |
... | |
(sb!eval:eval-in-native-environment exp lexenv))) | |
;; ↓ | |
(defun eval-in-native-environment (form lexenv) | |
(handler-bind | |
((sb!impl::eval-error ...)) | |
... | |
(%eval form env))) | |
;; ↓ | |
(defun %eval (exp env) | |
... | |
(%%eval exp env)) | |
;; ↓ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment