1 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; The software is in the public domain and is provided with
5 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
16 (declaim (ftype (sfunction (symbol &optional (or null lexenv))
17 (values (member nil :function :macro :special-form)
20 function-information))
21 (defun function-information (name &optional env)
22 "Return information about the function NAME in the lexical environment ENV.
23 Note that the global function binding may differ from the local one.
25 This function returns three values. The first indicates the type of
26 function definition or binding:
29 There is no apparent definition for NAME.
32 NAME refers to a function.
35 NAME refers to a macro.
38 NAME refers to a special operator. If the name refers to both a
39 macro and a special operator, the macro takes precedence.
41 The second value is true if NAME is bound locally.
43 The third value is an alist describing the declarations that apply to
44 the function NAME. Standard declaration specifiers that may appear in
45 CARS of the alist include:
48 If the CDR is T, NAME has been declared DYNAMIC-EXTENT. If the CDR
49 is NIL, the alist element may be omitted.
52 The CDR is one of the symbols INLINE, NOTINLINE, or NIL, to
53 indicate if the function has been declared INLINE or NOTINLINE. If
54 the CDR is NIL the alist element may be omitted.
57 The CDR is the type specifier associated with NAME, or the symbol
58 FUNCTION if there is functional type declaration or proclamation
59 associated with NAME. If the CDR is FUNCTION the alist element may
61 (let* ((*lexenv* (or env (make-null-lexenv)))
62 (fun (lexenv-find name funs))
63 binding localp ftype dx inlinep)
66 (let ((env-type (or (lexenv-find fun type-restrictions)
67 *universal-fun-type*)))
68 (setf binding :function
69 ftype (if (eq :declared (sb-c::leaf-where-from fun))
70 (type-intersection (sb-c::leaf-type fun)
73 dx (sb-c::leaf-dynamic-extent fun))
77 inlinep (sb-c::functional-inlinep fun)))
79 ;; Inlined known functions.
81 inlinep (sb-c::defined-fun-inlinep fun))))))
86 (case (info :function :kind name)
91 (setf binding :special-form
94 (setf binding :function
96 ftype (when (eq :declared (info :function :where-from name))
97 (info :function :type name))
98 inlinep (info :function :inlinep name))))))
102 (when (and ftype (neq *universal-fun-type* ftype))
103 (push (cons 'ftype (type-specifier ftype)) alist))
105 ((:inline :maybe-inline) (push (cons 'inline 'inline) alist))
106 (:notinline (push (cons 'inline 'notinline) alist))
108 (when dx (push (cons 'dynamic-extent t) alist))
111 (declaim (ftype (sfunction
112 (symbol &optional (or null lexenv))
113 (values (member nil :special :lexical :symbol-macro :constant :global)
116 variable-information))
117 (defun variable-information (name &optional env)
118 "Return information about the variable name VAR in the lexical environment ENV.
119 Note that the global binding may differ from the local one.
121 This function returns three values. The first indicated the type of the variable
125 There is no apparent binding for NAME.
128 NAME refers to a special variable.
131 NAME refers to a lexical variable.
134 NAME refers to a symbol macro.
137 NAME refers to a named constant defined using DEFCONSTANT, or NAME
141 NAME refers to a global variable. (SBCL specific extension.)
143 The second value is true if NAME is bound locally. This is currently
144 always NIL for special variables, although arguably it should be T
145 when there is a lexically apparent binding for the special variable.
147 The third value is an alist describind the declarations that apply to
148 the function NAME. Standard declaration specifiers that may appear in
149 CARS of the alist include:
152 If the CDR is T, NAME has been declared DYNAMIC-EXTENT. If the CDR
153 is NIL, the alist element may be omitted.
156 If the CDR is T, NAME has been declared IGNORE. If the CDR is NIL,
157 the alist element may be omitted.
160 The CDR is the type specifier associated with NAME, or the symbol
161 T if there is explicit type declaration or proclamation associated
162 with NAME. The type specifier may be equivalent to or a supertype
163 of the original declaration. If the CDR is T the alist element may
166 Additionally, the SBCL specific SB-EXT:ALWAYS-BOUND declaration will
167 appear with CDR as T if the variable has been declared always bound."
168 (let* ((*lexenv* (or env (make-null-lexenv)))
169 (kind (info :variable :kind name))
170 (var (lexenv-find name vars))
171 binding localp dx ignorep type)
174 (let ((env-type (or (lexenv-find var type-restrictions)
176 (setf type (if (eq :declared (sb-c::leaf-where-from var))
177 (type-intersection (sb-c::leaf-type var)
180 dx (sb-c::leaf-dynamic-extent var)))
183 (setf binding :lexical
185 ignorep (sb-c::lambda-var-ignorep var)))
186 ;; FIXME: IGNORE doesn't make sense for specials or constants
187 ;; -- though it is _possible_ to declare them ignored, but
188 ;; we don't keep the information around.
190 (setf binding (if (eq :global kind)
193 ;; FIXME: Lexically apparent binding or not for specials?
196 (setf binding :constant
199 (setf binding :symbol-macro
202 (let ((global-type (info :variable :type name)))
203 (setf binding (case kind
204 (:macro :symbol-macro)
207 type (if (eq *universal-type* global-type)
214 (when ignorep (push (cons 'ignore t) alist))
215 (when (and type (neq *universal-type* type))
216 (push (cons 'type (type-specifier type)) alist))
217 (when dx (push (cons 'dynamic-extent t) alist))
218 (when (info :variable :always-bound name)
219 (push (cons 'sb-ext:always-bound t) alist))
222 (declaim (ftype (sfunction (symbol &optional (or null lexenv)) t)
223 declaration-information))
224 (defun declaration-information (declaration-name &optional env)
225 "Return information about declarations named by DECLARATION-NAME.
227 If DECLARATION-NAME is OPTIMIZE return a list who's entries are of the
228 form \(QUALITY VALUE).
230 If DECLARATION-NAME is DECLARATION return a list of declaration names that
231 have been proclaimed as valid.
233 If DECLARATION-NAME is SB-EXT:MUFFLE-CONDITIONS return a type specifier for
234 the condition types that have been muffled."
235 (let ((env (or env (make-null-lexenv))))
236 (case declaration-name
238 (let ((policy (sb-c::lexenv-policy env)))
240 (dolist (name sb-c::*policy-qualities*)
241 (res (list name (cdr (assoc name policy)))))
242 (loop for (name . nil) in sb-c::*policy-dependent-qualities*
243 do (res (list name (sb-c::policy-quality policy name))))
245 (sb-ext:muffle-conditions
246 (car (rassoc 'muffle-warning
247 (sb-c::lexenv-handled-conditions env))))
249 ;; FIXME: This is a bit too deep in the guts of INFO for comfort...
250 (let ((type (sb-c::type-info-number
251 (sb-c::type-info-or-lose :declaration :recognized)))
253 (dolist (env *info-environment*)
254 (do-info (env :name name :type-number num :value value)
255 (when (and (= num type) value)
258 (t (error "Unsupported declaration ~S." declaration-name)))))
260 (defun parse-macro (name lambda-list body &optional env)
261 "Process a macro definition of the kind that might appear in a DEFMACRO form
262 into a lambda expression of two variables: a form and an environment. The
263 lambda edxpression will parse its form argument, binding the variables in
264 LAMBDA-LIST appropriately, and then excute BODY with those bindings in
266 (declare (ignore env))
267 (with-unique-names (whole environment)
268 (multiple-value-bind (body decls)
269 (parse-defmacro lambda-list whole body name
271 :environment environment)
272 `(lambda (,whole ,environment)
276 (defun enclose (lambda-expression &optional environment)
277 "Return a function consistent with LAMBDA-EXPRESSION in ENVIRONMENT: the
278 lambda expression is allowed to reference the declarations and macro
279 definitions in ENVIRONMENT, but consequences are undefined if lexical
280 variables, functions, tags or any other run-time entity defined in ENVIRONMENT
281 is referred to by the expression."
282 (let ((env (if environment
283 (sb-c::make-restricted-lexenv environment)
284 (make-null-lexenv))))
285 (compile-in-lexenv nil lambda-expression env)))