1
0
mirror of https://github.com/PDP-10/its.git synced 2026-01-18 09:12:08 +00:00
PDP-10.its/src/alan/binda.46
2016-12-23 07:23:28 -08:00

222 lines
5.8 KiB
Common Lisp
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;;-*- 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)