PageRenderTime 273ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/src/cmp/cmplam.lsp

https://gitlab.com/jlarocco/ecl
Lisp | 615 lines | 466 code | 42 blank | 107 comment | 16 complexity | 8b33216168c279be731249729a4fecf5 MD5 | raw file
Possible License(s): LGPL-2.0, JSON
  1. ;;;; -*- Mode: Lisp; Syntax: Common-Lisp; indent-tabs-mode: nil; Package: C -*-
  2. ;;;; vim: set filetype=lisp tabstop=8 shiftwidth=2 expandtab:
  3. ;;;;
  4. ;;;; Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
  5. ;;;; Copyright (c) 1990, Giuseppe Attardi.
  6. ;;;;
  7. ;;;; This program is free software; you can redistribute it and/or
  8. ;;;; modify it under the terms of the GNU Library General Public
  9. ;;;; License as published by the Free Software Foundation; either
  10. ;;;; version 2 of the License, or (at your option) any later version.
  11. ;;;;
  12. ;;;; See file '../Copyright' for full details.
  13. ;;;; CMPLAM Lambda expression.
  14. (in-package "COMPILER")
  15. ;;; During Pass1, a lambda-list
  16. ;;;
  17. ;;; ( { var }*
  18. ;;; [ &optional { var | ( var [ initform [ svar ] ] ) }* ]
  19. ;;; [ &rest var ]
  20. ;;; [ &key { var | ( { var | ( kwd var ) } [initform [ svar ]])}*
  21. ;;; [&allow-other-keys]]
  22. ;;; [ &aux {var | (var [initform])}*]
  23. ;;; )
  24. ;;;
  25. ;;; is transformed into
  26. ;;;
  27. ;;; ( ( { var }* ) ; required
  28. ;;; ( { var initform svar }* ) ; optional
  29. ;;; { var | nil } ; rest
  30. ;;; allow-other-keys-flag
  31. ;;; ( { kwd-vv-index var initform svar }* ) ; key
  32. ;;; )
  33. ;;;
  34. ;;; where
  35. ;;; svar: NIL ; means svar is not supplied
  36. ;;; | var
  37. ;;;
  38. ;;; &aux parameters will be embedded into LET*.
  39. ;;;
  40. ;;; c1lambda-expr receives
  41. ;;; ( lambda-list { doc | decl }* . body )
  42. ;;; and returns
  43. ;;; ( lambda info-object lambda-list' doc body' )
  44. ;;;
  45. ;;; Doc is NIL if no doc string is supplied.
  46. ;;; Body' is body possibly surrounded by a LET* (if &aux parameters are
  47. ;;; supplied) and an implicit block.
  48. (defun c1lambda-doc (form)
  49. (second (c1form-args form)))
  50. (defun c1lambda-body (form)
  51. (third (c1form-args form)))
  52. (defun c1lambda-list (form)
  53. (first (c1form-args form)))
  54. (defun fun-needs-narg (fun)
  55. (not (fun-fixed-narg fun)))
  56. (defun fun-fixed-narg (fun)
  57. "Returns true if the function has a fixed number of arguments and it is not a closure.
  58. The function thus belongs to the type of functions that ecl_make_cfun accepts."
  59. (let (narg)
  60. (and (not (eq (fun-closure fun) 'CLOSURE))
  61. (= (fun-minarg fun) (setf narg (fun-maxarg fun)))
  62. (<= narg si::c-arguments-limit)
  63. narg)))
  64. (defun add-to-fun-referenced-vars (fun var-list)
  65. (loop with new-vars = (fun-referenced-vars fun)
  66. with locals = (fun-local-vars fun)
  67. with change = nil
  68. for v in var-list
  69. when (and (not (member v locals :test #'eq))
  70. (not (member v new-vars :test #'eq)))
  71. do (setf change t new-vars (cons v new-vars))
  72. finally (when change
  73. (setf (fun-referenced-vars fun) new-vars)
  74. (return t))))
  75. (defun add-to-fun-referenced-funs (fun fun-list)
  76. (loop with new-funs = (fun-referenced-funs fun)
  77. with change = nil
  78. for f in fun-list
  79. when (and (not (eq fun f))
  80. (not (member f new-funs :test #'eq))
  81. (not (child-function-p fun f)))
  82. do (setf change t
  83. new-funs (cons f new-funs)
  84. (fun-referencing-funs f) (cons fun (fun-referencing-funs f)))
  85. finally (when change
  86. (setf (fun-referenced-funs fun) new-funs)
  87. (return t))))
  88. (defun c1compile-function (lambda-list-and-body &key (fun (make-fun))
  89. (name (fun-name fun)) (CB/LB 'CB))
  90. (let ((lambda (if name
  91. `(ext:lambda-block ,name ,@lambda-list-and-body)
  92. `(lambda ,@lambda-list-and-body))))
  93. (setf (fun-name fun) name
  94. (fun-lambda-expression fun) lambda
  95. (fun-parent fun) *current-function*))
  96. (when *current-function*
  97. (push fun (fun-child-funs *current-function*)))
  98. (let* ((*current-function* fun)
  99. (*cmp-env* (setf (fun-cmp-env fun) (cmp-env-mark CB/LB)))
  100. (setjmps *setjmps*)
  101. (decl (si::process-declarations (rest lambda-list-and-body)))
  102. (global (and *use-c-global*
  103. (assoc 'SI::C-GLOBAL decl)
  104. (setf (fun-global fun) T)))
  105. (no-entry (assoc 'SI::C-LOCAL decl))
  106. (lambda-expr (c1lambda-expr lambda-list-and-body
  107. name
  108. (si::function-block-name name)))
  109. cfun exported minarg maxarg)
  110. (when (and no-entry (policy-debug-ihs-frame))
  111. (setf no-entry nil)
  112. (cmpnote "Ignoring SI::C-LOCAL declaration for~%~4I~A~%because the debug level is large" name))
  113. (unless (eql setjmps *setjmps*)
  114. (setf (c1form-volatile lambda-expr) t))
  115. (setf (fun-lambda fun) lambda-expr)
  116. (if global
  117. (multiple-value-setq (cfun exported) (exported-fname name))
  118. (setf cfun (next-cfun "LC~D~A" name) exported nil))
  119. #+ecl-min
  120. (when (member name c::*in-all-symbols-functions*)
  121. (setf no-entry t))
  122. (if exported
  123. ;; Check whether the function was proclaimed to have a certain
  124. ;; number of arguments, and otherwise produce a function with
  125. ;; a flexible signature.
  126. (progn
  127. (multiple-value-setq (minarg maxarg) (get-proclaimed-narg name))
  128. (format t "~&;;; Function ~A proclaimed (~A,~A)" name minarg maxarg)
  129. (unless minarg
  130. (setf minarg 0 maxarg call-arguments-limit)))
  131. (multiple-value-setq (minarg maxarg)
  132. (lambda-form-allowed-nargs lambda-expr)))
  133. (setf (fun-cfun fun) cfun
  134. (fun-exported fun) exported
  135. (fun-closure fun) nil
  136. (fun-minarg fun) minarg
  137. (fun-maxarg fun) maxarg
  138. (fun-description fun) name
  139. (fun-no-entry fun) no-entry)
  140. (loop for child in (fun-child-funs fun)
  141. do (add-to-fun-referenced-vars fun (fun-referenced-vars child))
  142. do (add-to-fun-referenced-funs fun (fun-referenced-funs child)))
  143. (loop for f in (fun-referenced-funs fun)
  144. do (add-to-fun-referenced-vars fun (fun-referenced-vars f)))
  145. (update-fun-closure-type fun)
  146. (when global
  147. (if (fun-closure fun)
  148. (cmpnote "Function ~A is global but is closed over some variables.~%~{~A ~}"
  149. (fun-name fun) (mapcar #'var-name (fun-referenced-vars fun)))
  150. (new-defun fun (fun-no-entry fun)))))
  151. fun)
  152. (defun cmp-process-lambda-list (list)
  153. (handler-case (si::process-lambda-list list 'function)
  154. (error (c) (cmperr "Illegal lambda list ~S:~%~A" list c))))
  155. (defun c1lambda-expr (lambda-expr function-name block-name
  156. &aux doc body ss is ts
  157. other-decls
  158. new-variables
  159. (type-checks '())
  160. (*permanent-data* t)
  161. (old-env *cmp-env*)
  162. (*cmp-env* (cmp-env-copy)))
  163. (declare (si::c-local))
  164. (cmpck (endp lambda-expr)
  165. "The lambda expression ~s is illegal." (cons 'LAMBDA lambda-expr))
  166. (multiple-value-setq (body ss ts is other-decls doc)
  167. (c1body (cdr lambda-expr) t))
  168. (when block-name (setq body (list (cons 'BLOCK (cons block-name body)))))
  169. (multiple-value-bind (requireds optionals rest key-flag keywords
  170. allow-other-keys aux-vars)
  171. (cmp-process-lambda-list (car lambda-expr))
  172. (do ((specs (setq requireds (cdr requireds)) (cdr specs)))
  173. ((endp specs))
  174. (let* ((name (first specs))
  175. (var (c1make-var name ss is ts)))
  176. (push var type-checks)
  177. (setf (first specs) var)
  178. (push-vars var)))
  179. (do ((specs (setq optionals (cdr optionals)) (cdddr specs)))
  180. ((endp specs))
  181. (let* ((name (first specs))
  182. (var (c1make-var name ss is ts))
  183. (init (second specs))
  184. (flag (third specs)))
  185. (setq init (if init
  186. (and-form-type (var-type var) (c1expr init) init
  187. :safe "In (LAMBDA ~a...)" function-name)
  188. (default-init var)))
  189. (push var type-checks)
  190. (push-vars var)
  191. (when flag
  192. (push-vars (setq flag (c1make-var flag ss is ts))))
  193. (setf (first specs) var
  194. (second specs) init
  195. (third specs) flag)))
  196. (when rest
  197. (push-vars (setq rest (c1make-var rest ss is ts))))
  198. (do ((specs (setq keywords (cdr keywords)) (cddddr specs)))
  199. ((endp specs))
  200. (let* ((key (first specs))
  201. (name (second specs))
  202. (var (c1make-var name ss is ts))
  203. (init (third specs))
  204. (flag (fourth specs)))
  205. (setq init (if init
  206. (and-form-type (var-type var) (c1expr init) init
  207. :safe "In (LAMBDA ~a...)" function-name)
  208. (default-init var)))
  209. (push var type-checks)
  210. (push-vars var)
  211. (when flag
  212. (push-vars (setq flag (c1make-var flag ss is ts))))
  213. (setf (second specs) var
  214. (third specs) init
  215. (fourth specs) flag)))
  216. ;; Make other declarations take effect right now
  217. (setf *cmp-env* (reduce #'add-one-declaration other-decls
  218. :initial-value *cmp-env*))
  219. ;; After creating all variables and processing the initalization
  220. ;; forms, we wil process the body. However, all free declarations,
  221. ;; that is declarations which do not refer to the function
  222. ;; arguments, have to be applied to the body. At the same time, we
  223. ;; replace &aux variables with a LET* form that defines them.
  224. (let* ((declarations other-decls)
  225. (type-checks (extract-lambda-type-checks
  226. function-name requireds optionals
  227. keywords ts other-decls))
  228. (type-check-forms (car type-checks))
  229. (let-vars (loop for spec on (nconc (cdr type-checks) aux-vars)
  230. by #'cddr
  231. for name = (first spec)
  232. for init = (second spec)
  233. collect (list name init)))
  234. (new-variables (cmp-env-new-variables *cmp-env* old-env))
  235. (already-declared-names (set-difference (mapcar #'var-name new-variables)
  236. (mapcar #'car let-vars))))
  237. ;; Gather declarations for &aux variables, either special...
  238. (let ((specials (set-difference ss already-declared-names)))
  239. (when specials
  240. (push `(special ,@specials) declarations)))
  241. ;; ...ignorable...
  242. (let ((ignorables (loop for (var . expected-uses) in is
  243. unless (member var already-declared-names)
  244. collect var)))
  245. (when ignorables
  246. (push `(ignorable ,@ignorables) declarations)))
  247. ;; ...or type declarations
  248. (loop for (var . type) in ts
  249. unless (member var already-declared-names)
  250. do (push `(type ,type ,var) declarations))
  251. ;; ...create the enclosing LET* form for the &aux variables
  252. (when (or let-vars declarations)
  253. (setq body `((let* ,let-vars
  254. (declare ,@declarations)
  255. ,@body))))
  256. ;; ...wrap around the optional type checks
  257. (setq body (nconc type-check-forms body))
  258. ;; ...now finally compile the body with the type checks
  259. (let ((*cmp-env* (cmp-env-copy *cmp-env*)))
  260. (setf body (c1progn body)))
  261. ;;
  262. ;; ...and verify whether all variables are used.
  263. (dolist (var new-variables)
  264. (check-vref var))
  265. (make-c1form* 'LAMBDA
  266. :local-vars new-variables
  267. :args (list requireds optionals rest key-flag keywords
  268. allow-other-keys)
  269. doc body))))
  270. (defun lambda-form-allowed-nargs (lambda)
  271. (let ((minarg 0)
  272. (maxarg call-arguments-limit))
  273. (destructuring-bind (requireds optionals rest key-flag keywords a-o-k)
  274. (c1form-arg 0 lambda)
  275. (when (and (null rest) (not key-flag) (not a-o-k))
  276. (setf minarg (length requireds)
  277. maxarg (+ minarg (/ (length optionals) 3)))))
  278. (values minarg maxarg)))
  279. #| Steps:
  280. 1. defun creates declarations for requireds + va_alist
  281. 2. c2lambda-expr adds declarations for:
  282. unboxed requireds
  283. lexical optionals (+ supplied-p), rest, keywords (+ supplied-p)
  284. Lexical optionals and keywords can be unboxed if:
  285. a. there is more then one reference in the body
  286. b. they are not referenced in closures
  287. 3. binding is performed for:
  288. special or unboxed requireds
  289. optionals, rest, keywords
  290. 4. the function name is optionally pushed onto the IHS when
  291. the caller asks for it.
  292. |#
  293. (defun c2lambda-expr
  294. (lambda-list body cfun fname use-narg required-lcls closure-type
  295. &aux (requireds (first lambda-list))
  296. (optionals (second lambda-list))
  297. (rest (third lambda-list)) rest-loc
  298. (keywords (fifth lambda-list))
  299. (allow-other-keys (sixth lambda-list))
  300. (nreq (length requireds))
  301. (nopt (/ (length optionals) 3))
  302. (nkey (/ (length keywords) 4))
  303. (varargs (or optionals rest keywords allow-other-keys))
  304. (fname-in-ihs-p (or (policy-debug-variable-bindings)
  305. (and (policy-debug-ihs-frame)
  306. fname)))
  307. simple-varargs
  308. (*permanent-data* t)
  309. (*unwind-exit* *unwind-exit*)
  310. (*env* *env*)
  311. (*inline-blocks* 0)
  312. (last-arg))
  313. (declare (fixnum nreq nkey))
  314. (if (and fname ;; named function
  315. ;; no required appears in closure,
  316. (dolist (var (car lambda-list) t)
  317. (declare (type var var))
  318. (when (var-ref-ccb var) (return nil)))
  319. (null (second lambda-list)) ;; no optionals,
  320. (null (third lambda-list)) ;; no rest parameter, and
  321. (null (fourth lambda-list))) ;; no keywords.
  322. (setf *tail-recursion-info* (cons *tail-recursion-info* (car lambda-list)))
  323. (setf *tail-recursion-info* nil))
  324. ;; check arguments
  325. (when (policy-check-nargs)
  326. (if (and use-narg (not varargs))
  327. (wt-nl "if (ecl_unlikely(narg!=" nreq ")) FEwrong_num_arguments_anonym();")
  328. (when varargs
  329. (when requireds
  330. (wt-nl "if (ecl_unlikely(narg<" nreq ")) FEwrong_num_arguments_anonym();"))
  331. (unless (or rest keywords allow-other-keys)
  332. (wt-nl "if (ecl_unlikely(narg>" (+ nreq nopt) ")) FEwrong_num_arguments_anonym();"))))
  333. (open-inline-block))
  334. ;; If the number of required arguments exceeds the number of variables we
  335. ;; want to pass on the C stack, we pass some of the arguments to the list
  336. ;; of optionals, which will eventually get passed in the lisp stack.
  337. (when (> nreq si::c-arguments-limit)
  338. (setf nopt (+ nopt (- nreq si::c-arguments-limit))
  339. nreq si::c-arguments-limit)
  340. (setf optionals (nconc (loop for var in (subseq requireds si::c-arguments-limit)
  341. nconc (list var *c1nil* NIL))
  342. optionals)
  343. requireds (subseq requireds 0 si::c-arguments-limit)
  344. varargs t))
  345. ;; For each variable, set its var-loc.
  346. ;; For optional and keyword parameters, and lexical variables which
  347. ;; can be unboxed, this will be a new LCL.
  348. ;; The bind step later will assign to such variable.
  349. (labels ((wt-decl (var)
  350. (let ((lcl (next-lcl (var-name var))))
  351. (wt-nl)
  352. (wt (rep-type->c-name (var-rep-type var)) " " *volatile* lcl ";")
  353. lcl))
  354. (do-decl (var)
  355. (when (local var) ; no LCL needed for SPECIAL or LEX
  356. (setf (var-loc var) (wt-decl var)))))
  357. ;; Declare unboxed required arguments
  358. (loop for var in requireds
  359. when (unboxed var)
  360. do (setf (var-loc var) (wt-decl var)))
  361. ;; dont create rest or varargs if not used
  362. (when (and rest (< (var-ref rest) 1))
  363. (setq rest nil
  364. varargs (or optionals keywords allow-other-keys)))
  365. ;; Declare &optional variables
  366. (do ((opt optionals (cdddr opt)))
  367. ((endp opt))
  368. (do-decl (first opt))
  369. (when (third opt) (do-decl (third opt))))
  370. ;; Declare &rest variables
  371. (when rest (setq rest-loc (wt-decl rest)))
  372. ;; Declare &key variables
  373. (do ((key keywords (cddddr key)))
  374. ((endp key))
  375. (do-decl (second key))
  376. (when (fourth key) (do-decl (fourth key)))))
  377. ;; Declare and assign the variable arguments pointer
  378. (when varargs
  379. (flet ((last-variable ()
  380. (cond (required-lcls
  381. (first (last required-lcls)))
  382. ((eq closure-type 'LEXICAL)
  383. (format nil "lex~D" (1- *level*)))
  384. (t "narg"))))
  385. (if (setq simple-varargs (and (not (or rest keywords allow-other-keys))
  386. (< (+ nreq nopt) 30)))
  387. (wt-nl "va_list args; va_start(args,"
  388. (last-variable)
  389. ");")
  390. (wt-nl "ecl_va_list args; ecl_va_start(args,"
  391. (last-variable) ",narg," nreq ");"))))
  392. ;; Bind required argumens. Produces C statements for unboxed variables,
  393. ;; which is why it is done after all declarations.
  394. (mapc #'bind required-lcls requireds)
  395. (when fname-in-ihs-p
  396. (open-inline-block)
  397. (setf *ihs-used-p* t)
  398. (push 'IHS *unwind-exit*)
  399. (when (policy-debug-variable-bindings)
  400. (build-debug-lexical-env (reverse requireds) t))
  401. (wt-nl "ecl_ihs_push(cl_env_copy,&ihs," (add-symbol fname)
  402. ",_ecl_debug_env);"))
  403. ;; Bind optional parameters as long as there remain arguments.
  404. (when optionals
  405. ;; When binding optional values, we use two calls to BIND. This means
  406. ;; 'BDS-BIND is pushed twice on *unwind-exit*, which results in two calls
  407. ;; to bds_unwind1(), which is wrong. A simple fix is to save *unwind-exit*
  408. ;; which is what we do here.
  409. (let ((va-arg-loc (if simple-varargs 'VA-ARG 'CL-VA-ARG)))
  410. ;; counter for optionals
  411. (wt-nl-open-brace)
  412. (wt-nl "int i = " nreq ";")
  413. (do ((opt optionals (cdddr opt)))
  414. ((endp opt))
  415. (wt-nl "if (i >= narg) {")
  416. (let ((*opened-c-braces* (1+ *opened-c-braces*)))
  417. (bind-init (second opt) (first opt))
  418. (when (third opt) (bind nil (third opt))))
  419. (wt-nl "} else {")
  420. (let ((*opened-c-braces* (1+ *opened-c-braces*))
  421. (*unwind-exit* *unwind-exit*))
  422. (wt-nl "i++;")
  423. (bind va-arg-loc (first opt))
  424. (when (third opt) (bind t (third opt))))
  425. (wt-nl "}"))
  426. (wt-nl-close-brace)))
  427. (when (or rest keywords allow-other-keys)
  428. (cond ((not (or keywords allow-other-keys))
  429. (wt-nl rest-loc " = cl_grab_rest_args(args);"))
  430. (t
  431. (cond (keywords
  432. (wt-nl-open-brace) ;; Brace [1]
  433. (wt-nl "cl_object keyvars[" (* 2 nkey) "];")
  434. (wt-nl "cl_parse_key(args," nkey "," cfun "keys,keyvars"))
  435. (t
  436. (wt-nl "cl_parse_key(args,0,NULL,NULL")))
  437. ;; This explicit coercion is required to remove the "volatile"
  438. ;; declaration on some variables.
  439. (if rest (wt ",(cl_object*)&" rest-loc) (wt ",NULL"))
  440. (wt (if allow-other-keys ",TRUE);" ",FALSE);"))))
  441. (when rest (bind rest-loc rest)))
  442. (when varargs
  443. (wt-nl (if simple-varargs "va_end(args);" "ecl_va_end(args);")))
  444. ;;; Bind keywords.
  445. (do ((kwd keywords (cddddr kwd))
  446. (all-kwd nil)
  447. (KEYVARS[i] `(KEYVARS 0))
  448. (i 0 (1+ i)))
  449. ((endp kwd)
  450. (when all-kwd
  451. (wt-nl-h "#define " cfun "keys (&" (add-keywords (nreverse all-kwd)) ")")
  452. (wt-nl-close-brace))) ;; Matches [1]
  453. (declare (fixnum i))
  454. (push (first kwd) all-kwd)
  455. (let ((key (first kwd))
  456. (var (second kwd))
  457. (init (third kwd))
  458. (flag (fourth kwd)))
  459. (cond ((and (eq (c1form-name init) 'LOCATION)
  460. (null (c1form-arg 0 init)))
  461. ;; no initform
  462. ;; ECL_NIL has been set in keyvars if keyword parameter is not supplied.
  463. (setf (second KEYVARS[i]) i)
  464. (bind KEYVARS[i] var))
  465. (t
  466. ;; with initform
  467. (setf (second KEYVARS[i]) (+ nkey i))
  468. (wt-nl "if (Null(") (wt-loc KEYVARS[i]) (wt ")) {")
  469. (let ((*unwind-exit* *unwind-exit*)
  470. (*opened-c-braces* (1+ *opened-c-braces*)))
  471. (bind-init init var))
  472. (wt-nl "} else {")
  473. (let ((*opened-c-braces* (1+ *opened-c-braces*)))
  474. (setf (second KEYVARS[i]) i)
  475. (bind KEYVARS[i] var))
  476. (wt-nl "}")))
  477. (when flag
  478. (setf (second KEYVARS[i]) (+ nkey i))
  479. (bind KEYVARS[i] flag))))
  480. (when *tail-recursion-info*
  481. (push 'TAIL-RECURSION-MARK *unwind-exit*)
  482. (wt-nl1 "TTL:"))
  483. ;;; Now the parameters are ready, after all!
  484. (c2expr body)
  485. (close-inline-blocks))
  486. (defun optimize-funcall/apply-lambda (lambda-form arguments apply-p
  487. &aux body apply-list apply-var
  488. let-vars extra-stmts all-keys)
  489. (multiple-value-bind (requireds optionals rest key-flag keywords
  490. allow-other-keys aux-vars)
  491. (cmp-process-lambda-list (car lambda-form))
  492. (when apply-p
  493. (setf apply-list (first (last arguments))
  494. apply-var (gensym)
  495. arguments (butlast arguments)))
  496. (setf arguments (copy-list arguments))
  497. (do ((scan arguments (cdr scan)))
  498. ((endp scan))
  499. (let ((form (first scan)))
  500. (unless (constantp form)
  501. (let ((aux-var (gensym)))
  502. (push `(,aux-var ,form) let-vars)
  503. (setf (car scan) aux-var)))))
  504. (when apply-var
  505. (push `(,apply-var ,apply-list) let-vars))
  506. (dolist (i (cdr requireds))
  507. (push (list i
  508. (cond (arguments
  509. (pop arguments))
  510. (apply-p
  511. `(if ,apply-var
  512. (pop ,apply-var)
  513. (si::dm-too-few-arguments nil)))
  514. (t
  515. (cmperr "Too few arguments for lambda form ~S"
  516. (cons 'LAMBDA lambda-form)))))
  517. let-vars))
  518. (do ((scan (cdr optionals) (cdddr scan)))
  519. ((endp scan))
  520. (let ((opt-var (first scan))
  521. (opt-flag (third scan))
  522. (opt-value (second scan)))
  523. (cond (arguments
  524. (setf let-vars
  525. (list* `(,opt-var ,(pop arguments))
  526. `(,opt-flag t)
  527. let-vars)))
  528. (apply-p
  529. (setf let-vars
  530. (list* `(,opt-var (if ,apply-var
  531. (pop ,apply-var)
  532. ,opt-value))
  533. `(,opt-flag ,apply-var)
  534. let-vars)))
  535. (t
  536. (setf let-vars
  537. (list* `(,opt-var ,opt-value)
  538. `(,opt-flag nil)
  539. let-vars))))))
  540. (when (or key-flag allow-other-keys)
  541. (unless rest
  542. (setf rest (gensym))))
  543. (when rest
  544. (push `(,rest ,(if arguments
  545. (if apply-p
  546. `(list* ,@arguments ,apply-var)
  547. `(list ,@arguments))
  548. (if apply-p apply-var nil)))
  549. let-vars))
  550. (loop while aux-vars
  551. do (push (list (pop aux-vars) (pop aux-vars)) let-vars))
  552. (do ((scan (cdr keywords) (cddddr scan)))
  553. ((endp scan))
  554. (let ((keyword (first scan))
  555. (key-var (second scan))
  556. (key-value (third scan))
  557. (key-flag (or (fourth scan) (gensym))))
  558. (push keyword all-keys)
  559. (setf let-vars
  560. (list*
  561. `(,key-var (if (eq ,key-flag 'si::missing-keyword) ,key-value ,key-flag))
  562. `(,key-flag (si::search-keyword ,rest ,keyword))
  563. let-vars))
  564. (when (fourth scan)
  565. (push `(setf ,key-flag (not (eq ,key-flag 'si::missing-keyword)))
  566. extra-stmts))))
  567. (when (and key-flag (not allow-other-keys))
  568. (push `(si::check-keyword ,rest ',all-keys) extra-stmts))
  569. `(let* ,(nreverse (delete-if-not #'first let-vars))
  570. ,@(and apply-var `((declare (ignorable ,apply-var))))
  571. ,@(multiple-value-bind (decl body)
  572. (si::find-declarations (rest lambda-form))
  573. (append decl extra-stmts body)))))