mirror of
https://github.com/PDP-10/its.git
synced 2026-01-18 01:02:15 +00:00
222 lines
5.8 KiB
Common Lisp
Executable File
222 lines
5.8 KiB
Common Lisp
Executable File
;;;-*- Mode:Lisp; Package:SI -*-
|
||
|
||
(declare (and (status feature maclisp)
|
||
(load '((alan) lspenv init))))
|
||
|
||
(declare (special *rest* *normal* *optional*))
|
||
|
||
(defun bind-arguments-&parse (pattern body)
|
||
(prog (pat x)
|
||
(setq pat pattern)
|
||
norm (cond ((atom pat)
|
||
(setq *rest* pat)
|
||
(return body)))
|
||
(setq x (car pat))
|
||
(cond ((eq x '&optional)
|
||
(go opt))
|
||
((memq x '(&rest &body))
|
||
(go rst))
|
||
((eq x '&aux)
|
||
(go ax)))
|
||
(push x *normal*)
|
||
(setq pat (cdr pat))
|
||
(go norm)
|
||
opt (cond ((atom (setq pat (cdr pat)))
|
||
(setq *rest* pat)
|
||
(return body)))
|
||
(setq x (car pat))
|
||
(cond ((eq x '&optional)
|
||
(go barf))
|
||
((memq x '(&rest &body))
|
||
(go rst))
|
||
((eq x '&aux)
|
||
(go ax)))
|
||
(push (if (atom x) (list x) x) *optional*)
|
||
(go opt)
|
||
rst (if (atom (setq pat (cdr pat)))
|
||
(go barf))
|
||
(setq *rest* (car pat))
|
||
(if (null (setq pat (cdr pat)))
|
||
(return body))
|
||
(if (or (atom pat)
|
||
(not (eq (car pat) '&aux)))
|
||
(go barf))
|
||
ax (return
|
||
(do ((l (reverse (cdr pat)) (cdr l))
|
||
(var) (val)
|
||
(body body `(((lambda (,var) ,@body) ,val))))
|
||
((null l) body)
|
||
(if (atom (car l))
|
||
(setq var (car l) val nil)
|
||
(setq var (caar l) val (cadar l)))))
|
||
barf (ferror "Bad pattern: ~S" pattern)))
|
||
|
||
(eval-when (eval compile)
|
||
(defmacro bind-arguments-ignorable (x)
|
||
`(memq ,x '(ignore ignored))))
|
||
|
||
(defun bind-arguments/ macro (x)
|
||
(bind-arguments (((pattern form &optional barf) &body body) (cdr x)
|
||
(error '|-- bad format.| x))
|
||
(let ((body (bind-arguments-internal pattern form barf body)))
|
||
(if (null (cdr body))
|
||
(car body)
|
||
`(progn ,@body)))))
|
||
|
||
(defun bind-arguments-internal (pattern form barf body)
|
||
(cond
|
||
((bind-arguments-ignorable pattern) `(,form ,@body))
|
||
((null pattern) `((or (null ,form) ,barf) ,@body))
|
||
((atom pattern) `(((lambda (,pattern) ,@body) ,form)))
|
||
(t
|
||
(let* ((*normal* nil)
|
||
(*optional* nil)
|
||
(*rest* nil)
|
||
(body (bind-arguments-&parse pattern body))
|
||
(lst? (if (null *normal*)
|
||
(or (null *optional*)
|
||
(and (atom form)
|
||
(null *rest*)
|
||
(null (cdr *optional*))))
|
||
(and (null *optional*)
|
||
(atom form)
|
||
(null *rest*)
|
||
(null (cdr *normal*)))))
|
||
(lst (if lst? form (gensym)))
|
||
(len? (or (null *optional*)
|
||
(and (null (cdr *optional*))
|
||
(null *normal*)
|
||
(not (null *rest*)))))
|
||
(len (if len? `(length ,lst) (gensym)))
|
||
(barf (or barf `(ferror '|~S doesn't match pattern ~S|
|
||
,lst ',pattern))))
|
||
(setq body `(,@(bind-arguments-error-check len barf)
|
||
,@(bind-arguments-internal-1 barf body lst len
|
||
#'bind-arguments-nth
|
||
#'bind-arguments-nthcdr)))
|
||
(or len?
|
||
(setq body `(((lambda (,len) ,@body) (length ,lst)))))
|
||
(if lst?
|
||
body
|
||
`(((lambda (,lst) ,@body) ,form)))))))
|
||
|
||
(defun bind-arguments-internal-1 (barf body lst len ref-one ref-rest)
|
||
(let ((n (+ (length *normal*) (length *optional*))))
|
||
(or (null *rest*)
|
||
(setq body
|
||
(bind-arguments-internal *rest* (funcall ref-rest n lst)
|
||
barf body)))
|
||
(dolist (opt *optional*)
|
||
(setq n (1- n))
|
||
(cond ((cddr opt)
|
||
(setq body
|
||
`(((lambda (,(caddr opt))
|
||
,@(if (bind-arguments-ignorable (car opt))
|
||
body
|
||
(bind-arguments-internal
|
||
(car opt)
|
||
`(cond (,(caddr opt) ,(funcall ref-one n lst))
|
||
(t ,(cadr opt)))
|
||
barf
|
||
body)))
|
||
(> ,len ,n)))))
|
||
((not (bind-arguments-ignorable (car opt)))
|
||
(setq body
|
||
(bind-arguments-internal
|
||
(car opt)
|
||
`(cond ((> ,len ,n) ,(funcall ref-one n lst))
|
||
(t ,(cadr opt)))
|
||
barf
|
||
body)))))
|
||
(dolist (pat *normal*)
|
||
(setq n (1- n))
|
||
(or (bind-arguments-ignorable pat)
|
||
(setq body
|
||
(bind-arguments-internal pat (funcall ref-one n lst)
|
||
barf body))))
|
||
body))
|
||
|
||
(defun bind-arguments-error-check (len barf)
|
||
(let ((nlen (length *normal*))
|
||
(olen (length *optional*)))
|
||
(if (null *rest*)
|
||
(if (null *optional*)
|
||
`((or (= ,len ,nlen)
|
||
,barf))
|
||
(if (null *normal*)
|
||
`((and (> ,len ,olen)
|
||
,barf))
|
||
`((and (or (< ,len ,nlen)
|
||
(> ,len ,(+ olen nlen)))
|
||
,barf))))
|
||
(if (null *normal*)
|
||
`()
|
||
`((and (< ,len ,nlen)
|
||
,barf))))))
|
||
|
||
(defun bind-arguments-nth (n v)
|
||
(caseq n
|
||
(0 `(car ,v))
|
||
(1 `(cadr ,v))
|
||
(2 `(caddr ,v))
|
||
(3 `(cadddr ,v))
|
||
(t (bind-arguments-nth (- n 4) `(cddddr ,v)))))
|
||
|
||
(defun bind-arguments-nthcdr (n v)
|
||
(caseq n
|
||
(0 v)
|
||
(1 `(cdr ,v))
|
||
(2 `(cddr ,v))
|
||
(3 `(cdddr ,v))
|
||
(t (bind-arguments-nthcdr (- n 4) `(cddddr ,v)))))
|
||
|
||
#+maclisp
|
||
(defun (defun& macro) (x)
|
||
(let ((name (cadr x))
|
||
(pattern (caddr x))
|
||
(body (cdddr x)))
|
||
(cond ((memq pattern '(fexpr macro))
|
||
(ferror "Cannot mix &-keywords and ~S definitions: ~S"
|
||
pattern x))
|
||
((eq pattern 'expr)
|
||
(setq pattern (pop body)))
|
||
((not (symbolp pattern)))
|
||
((memq name '(fexpr macro))
|
||
(ferror "Cannot mix &-keywords and ~S definitions: ~S"
|
||
pattern x))
|
||
((eq name 'expr)
|
||
(setq name pattern)
|
||
(setq pattern (pop body))))
|
||
(if (bind-arguments-ignorable pattern)
|
||
(let ((n (gensym)))
|
||
`(defun ,name ,n ,n ,@body))
|
||
(let* ((*normal* nil)
|
||
(*optional* nil)
|
||
(*rest* nil)
|
||
(body (bind-arguments-&parse pattern body))
|
||
(len (gensym))
|
||
(barf `(ferror '|~S doesn't match pattern ~S|
|
||
(listify ,len) ',pattern)))
|
||
`(defun ,name ,len
|
||
,@(bind-arguments-error-check len barf)
|
||
,@(bind-arguments-internal-1 barf body len len
|
||
#'bind-arguments-arg
|
||
#'bind-arguments-listify))))))
|
||
|
||
#+maclisp
|
||
(defun bind-arguments-arg (n v)
|
||
v ;ignored
|
||
`(arg ,(1+ n)))
|
||
|
||
#+maclisp
|
||
(defun bind-arguments-listify (n v)
|
||
(if (zerop n)
|
||
`(listify ,v)
|
||
`(listify (- ,n ,v))))
|
||
|
||
#+maclisp
|
||
(defprop bind-arguments bind-arguments/ macro macro)
|
||
|
||
#+lispm
|
||
(fdefine 'bind-arguments '(macro . bind-arguments/ macro) t)
|