2010-m1s1-compilation/lisp2li.lisp

181 lines
4.8 KiB
Common Lisp
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(load "util.lisp")
;; `
(defvar my-quasiquote (car '`(,a)))
;; ,
(defvar my-unquote (caaadr '`(,a)))
;; ,@
(defvar my-unquote-unsplice (caaadr '`(,@a)))
(defun map-lisp2li (expr env)
(mapcar (lambda (x) (lisp2li x env)) expr))
(defun make-stat-env (params &optional env)
(append
(loop
for var in params
for j = 1 then (+ j 1)
for num-env = (+ (or (second (first env)) -1) 1)
collect (list var num-env j)
)
env))
(defun transform-quasiquote (expr)
(cond
;; a
((atom expr)
`',expr)
;; (a)
((atom (car expr))
`(cons ',(car expr)
,(transform-quasiquote (cdr expr))))
;; (,a)
((eq my-unquote (caar expr))
`(cons ,(cadar expr)
,(transform-quasiquote (cdr expr))))
;; (,@a)
((eq my-unquote-unsplice (caar expr))
(if (endp (cdr expr))
(cadar expr)
`(append ,(cadar expr)
,(transform-quasiquote (cdr expr)))))
;; ((a ...) ...)
(T
`(cons ,(transform-quasiquote (car expr))
,(transform-quasiquote (cdr expr))))))
(defmacro get-defun (symb)
`(get ,symb :defun))
(defun set-defun (li)
(setf (get-defun (cdaddr li)) (cdddr li)))
(defun lisp2li (expr env)
"Convertit le code LISP en un code intermédiaire reconnu
par le compilateur et par linterpréteur"
(cond
;; literaux
((and (atom expr) (constantp expr))
(cons :const expr))
;; symboles
((symbolp expr)
(let ((cell (assoc expr env)))
(if cell
`(:cvar ,(cadr cell) ,(caddr cell))
(error "Variable ~S unknown" expr))))
;; lambda solitaire ex: (lambda (x) x)
((eq 'lambda (car expr))
`(:lclosure . ,(cons (length (second expr))
(lisp2li (third expr)
(make-stat-env (second expr))))))
;; lambda ex: ((lambda (x) x) 1)
((and (consp (car expr))
(eq 'lambda (caar expr)))
`(:mcall ,(lisp2li (car expr) env)
,@(mapcar (lambda (param)
(lisp2li param env))
(cdr expr))))
;; (not-symbol ...)
((not (symbolp (car expr)))
(warn "~S isn't a symbol" (car expr)))
;; fonction inconnue
((and (not (fboundp (car expr)))
(not (get-defun (car expr))))
`(:unknown ,expr ,env))
;; if
((eq 'if (car expr))
(list :if
(lisp2li (second expr) env)
(lisp2li (third expr) env)
(lisp2li (fourth expr) env)))
;; quote
((eq 'quote (car expr))
(cons :const (second expr)))
;; quasiquote `
((eq my-quasiquote (car expr))
(lisp2li (transform-quasiquote (cadr expr)) env))
;; #'fn (FUNCTION fn)
((eq 'function (car expr))
`(:sclosure (cadr expr)))
;; defun
((eq 'defun (car expr))
`(:mcall set-defun (:const . ,(second expr))
,(lisp2li `(lambda ,(third expr) ,@(cdddr expr)) env)))
;; apply
((eq 'apply (car expr))
`(:sapply ,(second expr) (cddr expr)))
;; setf
((eq 'setf (car expr))
(if (symbolp (cadr expr))
(let ((cell (assoc (cadr expr) env)))
`(:set-var (,(second cell) ,(third cell)) ,(third expr)))
`(:set-fun ,(caadr expr) ,@(last expr) ,@(cdadr expr))))
;; progn
((eq 'progn (car expr))
(cons :progn (map-lisp2li (cdr expr) env)))
;; macros
((macro-function (car expr))
(lisp2li (macroexpand-1 expr) env))
;; foctions normales
((not (special-operator-p (car expr)))
`(:call ,(first expr) ,@(map-lisp2li (cdr expr) env)))
(T
(print expr)
(error "special form not yet implemented ~S" (car expr)))))
;; Test unitaire
(load "test-unitaire")
(erase-tests lisp2li)
(deftest (lisp2li make-stat-env)
(make-stat-env '(x y z))
'((x 0 1) (y 0 2) (z 0 3)))
(deftest (lisp2li make-stat-env)
(make-stat-env '(a b c d))
'((a 0 1) (b 0 2) (c 0 3) (d 0 4)))
(deftest (lisp2li make-stat-env)
(make-stat-env '(a b) '((x 0 1) (y 0 2)))
'((a 1 1) (b 1 2) (x 0 1) (y 0 2)))
(deftest (lisp2li constante)
(lisp2li '3 ())
'(:const . 3))
(deftest (lisp2li constante)
(lisp2li ''x ())
'(:const . x))
(deftest (lisp2li constante)
(lisp2li ''(1 2 3) ())
'(:const 1 2 3))
(deftest (lisp2li defun)
(lisp2li '(defun foo (x) x) ())
'(:mcall set-defun (:const . foo) (:lclosure 1 :cvar 0 1)))
(deftest (lisp2li defun)
(lisp2li '(defun foo (x y z) (list x y z)) ())
'(:mcall set-defun (:const . foo)
(:lclosure 3 :call list
(:cvar 0 1)
(:cvar 0 2)
(:cvar 0 3))))
(deftest (lisp2li setf)
(lisp2li '(setf y 42) '((x 0 1) (y 0 2)))
'(:set-var (0 2) 42))
(deftest (lisp2li setf)
(lisp2li '(setf (cdr '(1 2 3)) 42) ())
'(:set-fun cdr 42 '(1 2 3)))
(deftest (lisp2li lambda)
(lisp2li '(mapcar (lambda (x y z) (list x y z)) '(1 2 3)) ())
'(:call mapcar (:lclosure 3 :call list
(:cvar 0 1)
(:cvar 0 2)
(:cvar 0 3))
(:const 1 2 3)))