1 ;;;;------------------------------------------------------------------
3 ;;;; Copyright (C) 2000-2005
4 ;;;; Department of Computer Science, University of Tromso, Norway
6 ;;;; Filename: environment.lisp
7 ;;;; Description: Compiler environment.
8 ;;;; Author: Frode Vatvedt Fjeld <frodef@acm.org>
9 ;;;; Created at: Fri Nov 3 11:40:15 2000
10 ;;;; Distribution: See the accompanying file COPYING.
12 ;;;; $Id: environment.lisp,v 1.22 2007/03/21 19:57:54 ffjeld Exp $
14 ;;;;------------------------------------------------------------------
18 (defun setf-name (name)
19 "If NAME is on the form (setf <x>), return <x>. Otherwise return NIL."
22 (eq 'muerte.cl
:setf
(first name
))
27 (defclass movitz-macro
()
29 :initarg expander-function
30 :reader movitz-macro-expander-function
)))
32 (defclass movitz-special-operator
(movitz-macro)
37 :reader movitz-special-operator-compiler-function
)))
39 (defclass movitz-environment
()
43 :reader movitz-environment-uplink
)
45 :initarg
:extent-uplink
46 :accessor movitz-environment-extent-uplink
)
49 :reader movitz-environment-funobj
)))
51 (defmethod initialize-instance :after
((instance movitz-environment
) &rest x
)
53 (unless (slot-boundp instance
'extent-uplink
)
54 (setf (movitz-environment-extent-uplink instance
)
55 (movitz-environment-uplink instance
))))
57 (defmethod movitz-environment-compiler-macros ((env movitz-environment
)) nil
)
58 (defmethod movitz-environment-function-cells ((env movitz-environment
))
59 (load-time-value (make-hash-table :test
#'eq
)))
60 (defmethod movitz-environment-modifies-stack ((env movitz-environment
))
61 "nil: no stack modification.
62 t: some (unknown amount) stack modified.
63 integer: that many words pushed on stack."
65 (defmethod movitz-environment-bindings ((env movitz-environment
))
67 (defmethod movitz-environment-plists ((env movitz-environment
))
69 (defmethod stack-used ((env movitz-environment
)) 0)
70 (defmethod num-specials ((x movitz-environment
)) 0)
71 (defmethod num-dynamic-slots ((x movitz-environment
)) 0)
73 (defclass global-env
(movitz-environment)
76 :accessor movitz-environment-properties
)
78 :initarg
:function-cells
79 :initform
(make-hash-table :test
#'eq
:size
11)
80 :reader movitz-environment-function-cells
)
82 :initform
(make-hash-table :test
#'eq
:size
11)
83 :accessor movitz-environment-setf-function-names
)
84 (plists ; this is a plist of plists
86 :accessor movitz-environment-plists
)
89 :accessor movitz-environment-bindings
)
92 :accessor movitz-environment-compiler-macros
)))
94 (defclass with-things-on-stack-env
(movitz-environment)
101 :initarg
:num-specials
102 :accessor num-specials
)))
104 (defclass progv-env
(with-things-on-stack-env)
110 (defun make-stack-use-env (stack-used)
111 (make-instance 'with-things-on-stack-env
112 :stack-used stack-used
))
114 (defclass let-env
(with-things-on-stack-env)
117 :accessor movitz-environment-bindings
)
118 (plists ; this is a plist of plists
120 :accessor movitz-environment-plists
)
123 :initarg
:num-specials
124 :accessor num-specials
)
125 (special-variable-shadows
127 :accessor special-variable-shadows
)))
129 (defclass with-dynamic-extent-scope-env
(let-env)
131 :initarg
:save-esp-binding
132 :accessor save-esp-binding
)
134 :initarg
:base-binding
135 :accessor base-binding
)
138 :reader dynamic-extent-scope-tag
)
143 :accessor dynamic-extent-scope-members
)))
145 (defun find-dynamic-extent-scope (env)
146 (loop for e
= env then
(movitz-environment-uplink e
)
147 while
(and e
(not (typep e
'funobj-env
)))
148 do
(when (typep e
'with-dynamic-extent-allocation-env
)
149 (return (allocation-env-scope e
)))))
151 (defun dynamic-extent-object-offset (scope-env object
)
152 (loop with offset
= 0
153 for x in
(dynamic-extent-scope-members scope-env
)
155 (return (* 8 offset
))
156 (incf offset
(truncate (+ (sizeof x
) 4) 8)))))
158 (defmethod print-object ((env with-dynamic-extent-scope-env
) stream
)
159 (print-unreadable-object (env stream
:type t
)
160 (princ (dynamic-extent-scope-tag env
) stream
))
163 (defclass with-dynamic-extent-allocation-env
(movitz-environment)
166 :reader allocation-env-scope
)))
168 (defclass funobj-env
(let-env)
170 (:documentation
"A funobj-env represents the (possibly null)
171 lexical environment that a closure funobj captures."))
173 (defclass function-env
(let-env)
174 ((without-check-stack-limit-p
175 :accessor without-check-stack-limit-p
177 (without-function-prelude-p
178 :accessor without-function-prelude-p
181 :accessor forward-2op
191 :accessor oddeven-args
)
193 :accessor allow-other-keys-p
)
196 :accessor rest-args-position
)
202 :accessor required-vars
)
205 :accessor optional-vars
)
211 :accessor key-vars-p
)
217 :accessor key-decode-map
)
219 :accessor key-decode-shift
)
223 (need-normalized-ecx-p
224 :initarg
:need-normalized-ecx-p
225 :accessor need-normalized-ecx-p
)
229 :accessor extended-code
)
230 (potentially-lended-bindings
232 :accessor potentially-lended-bindings
))
233 (:documentation
"A function-env represents the initial env. that
234 the function sets up itself. Its parent env. must be a funobj-env."))
236 (defun find-function-env (env funobj
)
237 "Starting from <env>, search for the parent environment that is <funobj>'s top env."
238 (assert env
() "funobj-env not found!")
239 (or (and (typep env
'function-env
)
240 (eq funobj
(movitz-environment-funobj env
))
242 (find-function-env (movitz-environment-uplink env
) funobj
)))
244 (defun sub-env-p (sub-env env
)
245 "Check if sub-env is a sub-environment (or eq) of env."
251 (t (sub-env-p (movitz-environment-uplink sub-env
) env
))))
253 (defmethod num-dynamic-slots ((x with-things-on-stack-env
))
256 (defmethod print-object ((object let-env
) stream
)
258 ((not *print-pretty
*)
260 (t (print-unreadable-object (object stream
:type t
:identity t
)
261 (format stream
"of ~A binding~?"
262 (movitz-funobj-name (movitz-environment-funobj object
))
263 "~#[ nothing~; ~S~; ~S and ~S~:;~@{~#[~; and~] ~S~^,~}~]"
264 (mapcar #'binding-name
(mapcar #'cdr
(movitz-environment-bindings object
)))))
268 (defclass operator-env
(movitz-environment)
271 :accessor movitz-environment-bindings
)
272 (plists ; this is a plist of plists
274 :accessor movitz-environment-plists
)))
276 (defclass lexical-exit-point-env
(let-env)
278 :initarg
:save-esp-variable
279 :reader save-esp-variable
)
284 :initarg
:exit-result-mode
285 :reader exit-result-mode
)
286 (lexical-catch-tag-variable
287 :initarg
:lexical-catch-tag-variable
288 :reader movitz-env-lexical-catch-tag-variable
)))
290 (defclass tagbody-env
(lexical-exit-point-env) ())
292 (defclass unwind-protect-env
(movitz-environment)
294 :initarg
:cleanup-form
295 :reader unwind-protect-env-cleanup-form
)))
297 (defmethod num-dynamic-slots ((x unwind-protect-env
)) 1)
299 (defclass simple-dynamic-env
(with-things-on-stack-env)
302 (:documentation
"An environment that installs one dynamic-env."))
304 (defmethod num-dynamic-slots ((x simple-dynamic-env
)) 1)
306 (defparameter *movitz-macroexpand-hook
*
307 #'(lambda (macro-function form environment
)
308 ;;; (warn "Expanding form ~W" form)
309 ;;; (warn "..with body ~W" macro-function)
310 (let ((expansion (funcall macro-function form environment
)))
312 #+ignore
((member (if (atom form
) form
(car form
))
313 '(setf pcnet-reg
) :test
#'string
=)
314 (warn "Expanded ~S to ~S" form expansion
)
317 #+ignore
(warn "Expanded ~A:~%~S."
318 (if (atom form
) form
(car form
))
322 (defun movitz-macroexpand-1 (form &optional env
)
323 (let ((movitz-form (translate-program form
:cl
:muerte.cl
)))
324 (typecase movitz-form
326 (let ((expander (movitz-macro-function (car movitz-form
) env
)))
328 (values movitz-form nil
)
329 (values (translate-program (funcall *movitz-macroexpand-hook
* expander movitz-form env
)
333 (let ((binding (movitz-binding movitz-form env
)))
334 (if (not (typep binding
'symbol-macro-binding
))
335 (values movitz-form nil
)
336 (values (translate-program (funcall *movitz-macroexpand-hook
*
337 (macro-binding-expander binding
)
341 (t (values movitz-form nil
)))))
343 (defun movitz-macroexpand (form &optional env
)
344 (let ((global-expanded-p nil
))
346 (multiple-value-bind (expansion expanded-p
)
347 (movitz-macroexpand-1 form env
)
349 (setf form expansion
)
350 (setf global-expanded-p expanded-p
))))
351 (values form global-expanded-p
)))
353 (define-symbol-macro *movitz-global-environment
*
354 (image-global-environment *image
*))
356 (defun movitz-env-add-binding (env binding
&optional
(variable (binding-name binding
)))
357 "Returns the binding."
358 (check-type binding binding
)
359 (check-type variable symbol
"a variable name")
360 (let ((env (or env
*movitz-global-environment
*)))
361 (assert (not (slot-boundp binding
'env
)) (binding)
362 "Binding ~S is already associated with ~S, can't also be associated with ~S."
363 binding
(binding-env binding
) env
)
364 (unless (eq env
*movitz-global-environment
*)
365 (assert (not (assoc variable
(movitz-environment-bindings env
))) ()
366 "Variable ~S is being multiple bound in ~S." variable env
))
367 (pushnew (cons variable binding
)
368 (movitz-environment-bindings env
)
370 (setf (binding-env binding
) env
)
373 (defun movitz-env-load-declarations (declarations environment context
)
374 (loop for
(declaration-identifier . data
) in declarations
375 do
(case declaration-identifier
376 ((muerte.cl
::ftype muerte.cl
::optimize
)
377 nil
) ; ignore for now
380 (check-type var symbol
)
381 (setf (movitz-env-get var
'ignore nil environment
) t
)))
382 (muerte.cl
::ignorable
384 (check-type var symbol
)
385 (setf (movitz-env-get var
'ignorable nil environment
) t
)))
386 (muerte::constant-variable
388 (check-type var symbol
)
389 (when (eq :declaim context
)
390 (pushnew :constant-variable
(movitz-symbol-flags (movitz-read var
))))
391 (setf (movitz-env-get var
'constantp nil environment
) t
)))
394 (check-type var symbol
)
395 (when (eq :declaim context
)
396 (pushnew :special-variable
(movitz-symbol-flags (movitz-read var
))))
397 (setf (movitz-env-get var
'special nil environment
) t
)))
398 (muerte.cl
:dynamic-extent
400 (setf (movitz-env-get var
'dynamic-extent nil environment
) t
)))
403 (setf (movitz-env-get var
'notinline nil environment
) t
)))
405 (destructuring-bind (typespec . vars
)
408 (setf (movitz-env-get var
:variable-type nil environment
) typespec
))))
409 (muerte::primitive-function
410 (unless (eq :funobj context
)
411 (warn "Declaration ~S appeared in context ~S but is only allowed in funobj context."
412 declaration-identifier context
))
413 (setf (getf (movitz-environment-properties environment
) 'primitive-function
) t
))
414 (muerte::without-function-prelude
415 (unless (eq :funobj context
)
416 (warn "Declaration ~S appeared in context ~S but is only allowed in funobj context."
417 declaration-identifier context
))
418 (setf (without-function-prelude-p environment
) t
))
419 (muerte::without-check-stack-limit
420 (unless (eq :funobj context
)
421 (warn "Declaration ~S appeared in context ~S but is only allowed in funobj context."
422 declaration-identifier context
))
423 (setf (without-check-stack-limit-p environment
) t
))
425 (unless (eq :funobj context
)
426 (warn "Declaration ~S appeared in context ~S but is only allowed in funobj context."
427 declaration-identifier context
))
428 (let ((symbol (car data
)))
429 (check-type symbol symbol
"a function name")
430 (setf (forward-2op environment
) (movitz-read symbol
))))
433 (setf (movitz-env-get var declaration-identifier nil environment
) t
)))
434 (t (let ((typespec declaration-identifier
)
437 (setf (movitz-env-get var
:variable-type nil environment
) typespec
))))))
440 (defun make-local-movitz-environment (uplink funobj
442 &key
(type 'global-env
)
443 declarations declaration-context bindings
445 (dolist (p '(:type
:declarations
:declaration-context
:bindings
))
447 (let ((env (apply #'make-instance type
448 :uplink
(or uplink
*movitz-global-environment
*)
451 (movitz-env-load-declarations declarations env declaration-context
)
452 (loop for
(nil . val
) in bindings
453 do
(movitz-env-add-binding env val
))
456 (defun make-global-movitz-environment ()
457 (let ((env (make-instance 'global-env
:uplink nil
)))
458 (setf (movitz-env-get 'nil
'constantp nil env
) t
459 (movitz-env-get 'muerte.cl
:t
'constantp nil env
) t
460 (symbol-value 'muerte.cl
:t
) 'muerte.cl
:t
)
465 (defun movitz-binding (symbol environment
&optional
(recurse t
))
466 (check-type symbol symbol
)
467 (if (not environment
)
469 (let ((local-binding (cdr (assoc symbol
(movitz-environment-bindings environment
)))))
470 (if (typep local-binding
'(and binding
(not operator-binding
)))
471 (values local-binding environment
)
472 (and recurse
(movitz-binding symbol
(movitz-environment-uplink environment
)))))))
474 (defun movitz-operator-binding (symbol environment
&optional
(recurse t
))
475 (labels ((operator-binding-p (b)
476 (or (typep b
'operator-binding
)
477 (and (typep b
'borrowed-binding
)
478 (operator-binding-p (borrowed-binding-target b
))))))
479 (if (not environment
)
481 (let ((local-binding (cdr (assoc symbol
(movitz-environment-bindings environment
)))))
482 (if (operator-binding-p local-binding
)
483 (values local-binding environment
)
484 (and recurse
(movitz-operator-binding symbol
(movitz-environment-uplink environment
))))))))
486 ;;; Accessor: movitz-env-get (symbol property)
488 (defun movitz-env-get (symbol indicator
&optional
(default nil
)
491 (loop for env
= (or environment
*movitz-global-environment
*)
492 then
(when recurse-p
(movitz-environment-uplink env
))
493 for plist
= (and env
(getf (movitz-environment-plists env
) symbol
))
495 do
(let ((val (getf plist indicator
'#0=#:not-found
)))
496 (unless (eq val
'#0#)
497 (return (values val env
))))
498 finally
(return default
)))
500 (defun (setf movitz-env-get
) (val symbol indicator
501 &optional default environment
)
502 (declare (ignore default
))
503 (setf (getf (getf (movitz-environment-plists (or environment
504 *movitz-global-environment
*))
509 ;;; Accessor: movitz-env-symbol-function
511 (defun movitz-env-symbol-function (symbol &optional env
)
512 (values (gethash symbol
(movitz-environment-function-cells (or env
*movitz-global-environment
*)))))
514 (defun (setf movitz-env-symbol-function
) (value symbol
&optional env
)
515 (setf (gethash symbol
(movitz-environment-function-cells (or env
*movitz-global-environment
*)))
518 (defun movitz-env-setf-operator-name (name &optional env
)
519 "Map an setf operator name like from (setf operator) to a symbol."
521 (or #0=(gethash name
(movitz-environment-setf-function-names *movitz-global-environment
*))
522 (let ((setf-symbol (make-symbol
523 (symbol-name name
))))
524 (setf (symbol-plist setf-symbol
) (list :setf-placeholder name
)
527 (defun movitz-env-named-function (name &optional env
)
530 (movitz-env-symbol-function (movitz-env-setf-operator-name
531 (setf-name name
) env
)))
533 (movitz-env-symbol-function name env
))
534 (t (error "Not a function name: ~S" name
))))
536 (defun (setf movitz-env-named-function
) (value name
&optional env
)
537 (check-type value movitz-funobj
)
538 (let ((effective-env (or env
*movitz-global-environment
*)))
541 (let* ((sn (setf-name name
))
542 (function-name (movitz-env-setf-operator-name sn env
)))
543 (setf (movitz-env-named-function function-name env
) value
)))
545 (setf (gethash name
(movitz-environment-function-cells effective-env
))
547 (t (error "Not a function name: ~S" name
)))))
549 (defun movitz-macro-function (symbol &optional environment
)
550 (or (let ((binding (movitz-operator-binding symbol
(or environment
*movitz-global-environment
*))))
551 (and (typep binding
'macro-binding
)
552 (macro-binding-expander binding
)))
553 (loop for env
= (or environment
*movitz-global-environment
*)
554 then
(movitz-environment-uplink env
)
555 for val
= (and env
(gethash symbol
(movitz-environment-function-cells env
)))
558 do
(return (and (typep val
'movitz-macro
)
559 (movitz-macro-expander-function val
))))))
561 (defun (setf movitz-macro-function
) (fun symbol
&optional environment
)
562 (let ((obj (or (gethash symbol
(movitz-environment-function-cells (or environment
563 *movitz-global-environment
*)))
564 (make-instance 'movitz-macro
))))
565 (setf (slot-value obj
'expander-function
) fun
)
566 (setf (gethash symbol
(movitz-environment-function-cells (or environment
567 *movitz-global-environment
*)))
571 ;;; Accessor: COMPILER-MACRO-FUNCTION
573 (defun movitz-compiler-macro-function (name &optional environment
)
574 (loop for env
= (or environment
*movitz-global-environment
*)
575 then
(movitz-environment-uplink env
)
576 for val
= (and env
(getf (movitz-environment-compiler-macros env
) name
))
578 when val do
(return val
)))
580 (defun (setf movitz-compiler-macro-function
) (fun name
&optional environment
)
581 (setf (getf (movitz-environment-compiler-macros (or environment
582 *movitz-global-environment
*))
586 ;;; Special operators
588 (defparameter *persistent-movitz-environment
* (make-global-movitz-environment))
590 (defun movitz-special-operator-p (symbol)
591 (let ((val (gethash symbol
(movitz-environment-function-cells *persistent-movitz-environment
*))))
592 (typep val
'movitz-special-operator
)))
594 (defun movitz-special-operator-compiler (symbol)
595 (movitz-special-operator-compiler-function
596 (gethash symbol
(movitz-environment-function-cells *persistent-movitz-environment
*))))