diff --git a/src/CHANGELOG b/src/CHANGELOG index 587bfe939..54fd54444 100644 --- a/src/CHANGELOG +++ b/src/CHANGELOG @@ -1069,8 +1069,12 @@ ECL 0.8 delimiting char is used instead. - Two separate functions SI::PROCESS-LAMBDA & SI::PROCESS-LAMBDA-LIST to - parse functions and general lambda lists. The code has been improved and - it is now smaller. + parse functions and general lambda lists. The code has been improved, + it is now smaller, and it is also used in DESTRUCTURING-BIND and + DEFMACRO (defmacro.lsp). + + - DO and DO* have now different macroexpansions, with less gotos; + which leads to smaller C code. * Visible changes: diff --git a/src/c/compiler.d b/src/c/compiler.d index 23500d803..64da78d90 100644 --- a/src/c/compiler.d +++ b/src/c/compiler.d @@ -1947,10 +1947,11 @@ compile_body(cl_object body) { #define push(v,l) l = CONS(v, l) #define push_var(v, list) \ - check_symbol(v); \ - if (v->symbol.stype == stp_constant) \ - FEillegal_variable_name(v); \ - push(v, list); + if (context == @'function') { \ + assert_type_symbol(v); \ + if (v->symbol.stype == stp_constant) \ + FEillegal_variable_name(v); } \ + push(v, list) /* Handles special declarations, removes declarations from body @@ -1982,7 +1983,7 @@ compile_body(cl_object body) { if (CAR(sentence) == @'special') for (vars = CDR(sentence); !endp(vars); vars = CDR(vars)) { v = CAR(vars); - check_symbol(v); + assert_type_symbol(v); push(v,specials); } } @@ -2030,14 +2031,19 @@ si_process_lambda_list(cl_object org_lambda_list, cl_object context) int nreq = 0, nopt = 0, nkey = 0, naux = 0, stage = 0; cl_object allow_other_keys = Cnil; + if (!CONSP(lambda_list) && lambda_list != Cnil) + goto ILLEGAL_LAMBDA; LOOP: if (ATOM(lambda_list)) { if (lambda_list == Cnil) goto OUTPUT; else if (context == @'function') goto ILLEGAL_LAMBDA; - else + else { + v = lambda_list; + lambda_list = Cnil; goto REST; + } } v = CAR(lambda_list); lambda_list = CDR(lambda_list); @@ -2048,9 +2054,14 @@ LOOP: goto LOOP; } if (v == @'&rest' || (v == @'&body' && context != @'function')) { + if (ATOM(lambda_list)) + goto ILLEGAL_LAMBDA; + v = CAR(lambda_list); + lambda_list = CDR(lambda_list); REST: if (stage >= AT_REST) goto ILLEGAL_LAMBDA; stage = AT_REST; + push_var(v, rest); goto LOOP; } if (v == @'&key') { @@ -2102,12 +2113,9 @@ REST: if (stage >= AT_REST) } break; case AT_REST: - if (rest == Cnil) { - push_var(v, rest); - } else { - goto ILLEGAL_LAMBDA; - } - break; + /* If we get here, the user has declared more than one + * &rest variable, as in (lambda (&rest x y) ...) */ + goto ILLEGAL_LAMBDA; case AT_KEYS: init = Cnil; spp = Cnil; @@ -2128,11 +2136,11 @@ REST: if (stage >= AT_REST) if (endp(CDR(v)) || !endp(CDDR(v))) goto ILLEGAL_LAMBDA; v = CADR(v); - check_symbol(v); - check_symbol(key); + assert_type_symbol(v); + assert_type_symbol(key); } else { int intern_flag; - check_symbol(v); + assert_type_symbol(v); key = intern(v->symbol.name, keyword_package, &intern_flag); } nkey++; diff --git a/src/lsp/defmacro.lsp b/src/lsp/defmacro.lsp index 073f57f59..0d4f249f6 100644 --- a/src/lsp/defmacro.lsp +++ b/src/lsp/defmacro.lsp @@ -98,97 +98,57 @@ (declare (si::c-local)) (error "Too many arguments are supplied to defmacro-lambda-list.")) -(defun sys::destructure (vl whole macro &aux (*dl* nil) (*key-check* nil) (*arg-check* nil)) +(defun sys::destructure (vl whole macro) (declare (si::c-local)) - (labels ((dm-vl (vl whole top &aux v allow-other-keys-p) - (do*((optionalp) (restp) (keyp) - (allow-other-keys-p) (auxp) - (rest) (allow-other-keys) (keys) (no-check) - (n (if top 1 0)) (ppn 0) (v)) - ((not (consp vl)) - (when vl - (when restp (dm-bad-key '&rest)) - (push (list vl (dm-nth-cdr n whole)) *dl*) - (setq no-check t)) - (when (and rest (not allow-other-keys)) - (push (cons rest keys) *key-check*)) - (unless no-check (push (cons whole n) *arg-check*)) - ppn) - (declare (fixnum n ppn)) - (setq v (car vl)) - (cond - ((eq v '&optional) - (when optionalp (dm-bad-key '&optional)) - (setq optionalp t) - (pop vl)) - ((and macro (eq v '&body)) - (when restp (dm-bad-key v)) - (dm-v (second vl) (dm-nth-cdr n whole)) - (setq restp t optionalp t no-check t) - (setq vl (cddr vl)) - (setq ppn (if top (1- n) n))) - ((or (eq v '&rest) (eq v '&body)) - (when restp (dm-bad-key v)) - (dm-v (second vl) (dm-nth-cdr n whole)) - (setq restp t optionalp t no-check t) - (setq vl (cddr vl))) - ((eq v '&key) - (when keyp (dm-bad-key '&key)) - (setq rest (gensym)) - (push (list rest (dm-nth-cdr n whole)) *dl*) - (setq keyp t restp t optionalp t no-check t) - (pop vl)) - ((eq v '&allow-other-keys) - (when (or (not keyp) allow-other-keys-p) - (dm-bad-key '&allow-other-keys)) - (setq allow-other-keys-p t) - (setq allow-other-keys t) - (pop vl)) - ((eq v '&aux) - (when auxp (dm-bad-key '&aux)) - (setq auxp t allow-other-keys-p t keyp t restp t optionalp t) - (pop vl)) - (auxp - (let (x (init nil)) - (cond ((symbolp v) (setq x v)) - (t (setq x (car v)) - (unless (endp (cdr v)) (setq init (second v))))) - (dm-v x init)) - (pop vl)) - (keyp - (let ((temp (gensym)) x k (init nil) (sv nil)) - (cond ((symbolp v) (setq x v - k (intern (string v) 'keyword))) - (t (if (symbolp (car v)) - (setq x (car v) - k (intern (string (car v)) 'keyword)) - (setq x (cadar v) k (caar v))) - (unless (endp (cdr v)) - (setq init (second v)) - (unless (endp (cddr v)) - (setq sv (caddr v)))))) - (dm-v temp `(search-keyword ,rest ',k)) - (dm-v x `(if (eq ,temp 'failed) ,init ,temp)) - (when sv (dm-v sv `(not (eq ,temp 'failed)))) - (push k keys)) - (pop vl)) - (optionalp - (let (x (init nil) (sv nil)) - (cond ((symbolp v) (setq x v)) - (t (setq x (car v)) - (unless (endp (cdr v)) - (setq init (second v)) - (unless (endp (cddr v)) - (setq sv (caddr v)))))) - (dm-v x `(if ,(dm-nth-cdr n whole) ,(dm-nth n whole) ,init)) - (when sv (dm-v sv `(not (null ,(dm-nth-cdr n whole)))))) - (incf n) - (pop vl)) - (t (dm-v v `(if ,(dm-nth-cdr n whole) - ,(dm-nth n whole) - (dm-too-few-arguments))) - (incf n) - (pop vl))))) + (labels ((dm-vl (vl whole macro) + (let ((n (if macro 1 0)) + (ppn 0) + (no-check nil) + all-keywords) + (multiple-value-bind (reqs opts rest allow-other-keys keys auxs) + (si::process-lambda-list vl (if macro 'macro 'destructuring-bind)) + (dolist (v (cdr reqs)) + (dm-v v `(if ,(dm-nth-cdr n whole) + ,(dm-nth n whole) + (dm-too-few-arguments))) + (incf n)) + (dotimes (i (pop opts)) + (let* ((x (first opts)) + (init (second opts)) + (sv (third opts))) + (setq opts (cdddr opts)) + (dm-v x `(if ,(dm-nth-cdr n whole) ,(dm-nth n whole) ,init)) + (when sv (dm-v sv `(not (null ,(dm-nth-cdr n whole))))) + (incf n))) + (when rest + (dm-v (setq rest (first rest)) (dm-nth-cdr n whole)) + (setq no-check t + rest nil) + (when (and (null (last vl 0)) (member '&body vl)) + (setq ppn (if macro (1- n) n)))) + (dotimes (i (pop keys)) + (unless rest + (setq rest (gensym)) + (dm-v rest (dm-nth-cdr n whole)) + (setq no-check t)) + (let* ((temp (gensym)) + (k (first keys)) + (v (second keys)) + (init (third keys)) + (sv (fourth keys))) + (setq keys (cddddr keys)) + (dm-v temp `(search-keyword ,rest ',k)) + (dm-v v `(if (eq ,temp 'failed) ,init ,temp)) + (when sv (dm-v sv `(not (eq ,temp 'failed)))) + (push k all-keywords))) + (do ((l auxs (cddr l))) ((endp l)) + (let ((v (first l)) + (init (second l))) + (dm-v v init))) + (when (and rest (not allow-other-keys)) + (push (cons rest all-keywords) *key-check*)) + (unless no-check (push (cons whole n) *arg-check*))) + ppn)) (dm-v (v init) (cond ((symbolp v) @@ -229,7 +189,10 @@ (cond ((listp vl)) ((symbolp vl) (setq vl (list '&rest vl))) (t (error "The destructuring-lambda-list ~s is not a list." vl))) - (let ((ppn (dm-vl vl whole macro))) + (let* ((*dl* nil) + (*key-check* nil) + (*arg-check* nil) + (ppn (dm-vl vl whole macro))) (values ppn (nreverse *dl*) *key-check* *arg-check*)))) ;;; valid lambda-list to DEFMACRO is: