diff --git a/Code/Basic/basic.lisp b/Code/Basic/basic.lisp index 63295b1..db16370 100644 --- a/Code/Basic/basic.lisp +++ b/Code/Basic/basic.lisp @@ -1,265 +1,129 @@ (cl:in-package #:clostrum-basic) -;;; Function and variable entries. -(defclass operator-entry () - ((name - :initarg :name - :reader name) - (status - :initform nil - :accessor status - :type (member :function :macro :special-operator nil)) - ;; The CAR of the cell contains the function determined by the - ;; entry. The CDR of the cell contains a function that, when - ;; called, signals an error. When the function determined by the - ;; entry is undefined, the CAR of the cell is the same as the CDR - ;; of the cell. - (cell - :reader cell - :type cons) - (compiler-macro-function - :initform nil - :accessor compiler-macro-function - :type (or function null)) - (setf-expander - :initform nil - :accessor setf-expander - :type (or function null))) - (:default-initargs :name (error "The initarg :NAME is required."))) - -;;; Make sure NAME names a function entry in ENVIRONMENT. -;;; KEYWORD-ARGUMENTS are keyword/value pairs that will be passed -;;; either to MAKE-INSTANCE in order create a new entry if no entry -;;; exists, or will be passed to REINITIALIZE-INSTANCE to modify the -;;; existing entry if one does exist. The existing entry or the entry -;;; being created is returned. -(defun ensure-operator-entry (name environment &rest keyword-arguments) - (let ((entry (operator-entry name environment))) - (if (null entry) - (setf (operator-entry name environment) - (apply #'make-instance 'operator-entry - :name name keyword-arguments)) - (apply #'reinitialize-instance entry keyword-arguments)))) - -(defmethod initialize-instance :after ((instance operator-entry) &key name) - ;; We indicate that a function name is FUNBOUND by storing a - ;; function in the CAR of the cell that, when called, signals an - ;; UNDEFINED-FUNCTION error. This way, there is no need for an - ;; explicit test to verify that the name is FBOUND before calling - ;; the function. We store the same, as in EQ, function in the CDR - ;; of the cell. That way, testing whether the function is unbound - ;; is an EQ comparison between the CAR and the CDR of the cell, and - ;; FMAKUNBOUND is implemented by copying the CDR of the cell to the - ;; CAR. - (let ((unbound-function - (lambda (&rest args) - (declare (ignore args)) - (error 'undefined-function :name name)))) - (setf (slot-value instance 'cell) - (cons unbound-function unbound-function)))) - -(defun function-bound-p (operator-entry) - (let ((cell (cell operator-entry))) - (not (eq (car cell) (cdr cell))))) - -(defconstant +unbound+ 'unbound) - -(defclass variable-entry () - ((name - :initarg :name - :reader name) - (status - :initform nil - :accessor status - :type (member :constant :special :symbol-macro nil)) - ;; The CAR of the cell contains the value of the variable - ;; determined by the entry. The CDR of the cell contains a value - ;; that indicates that the variable is unbound. When the variable - ;; is unbound, the CAR and the CDR contain the same value. Since - ;; CL:MAKUNBOUND (which should really be called something else like - ;; MAKE-TO-HAVE-NO-VALUE) must take into account dynamic bindings - ;; of the variable, we do not supply code for MAKUNBOUND here. It - ;; must be implemented by the client. - (cell - :reader cell - :initform (cons +unbound+ +unbound+) - :type cons) - (symbol-macro-expander - :accessor symbol-macro-expander - :type (or function null)) - (plist - :initform nil - :accessor plist - :type list)) - (:default-initargs :name (error "The initarg :NAME is required."))) - -;;; Make sure NAME names a variable entry in ENVIRONMENT. -;;; KEYWORD-ARGUMENTS are keyword/value pairs that will be passed -;;; either to MAKE-INSTANCE in order create a new entry if no entry -;;; exists, or will be passed to REINITIALIZE-INSTANCE to modify the -;;; existing entry if one does exist. The existing entry or the entry -;;; being created is returned. -(defun ensure-variable-entry (name environment &rest keyword-arguments) - (let ((entry (variable-entry name environment))) - (if (null entry) - (setf (variable-entry name environment) - (apply #'make-instance 'variable-entry - :name name keyword-arguments)) - (apply #'reinitialize-instance entry keyword-arguments)))) - -(defun variable-bound-p (variable-entry) - (let ((cell (cell variable-entry))) - (not (eq (car cell) +unbound+)))) - -(defclass type-entry () - ((%name :initarg :name :reader name) - (%cell :initform (cons nil nil) :reader cell :type cons) - (%type-expander :initform nil :accessor type-expander - :type (or function null)))) - -;;; Make sure NAME names a type entry in ENVIRONMENT. -;;; KEYWORD-ARGUMENTS are keyword/value pairs that will be passed either -;;; to MAKE-INSTANCE in order to create a new entry if none exits, -;;; or to REINITIALIZE-INSTANCE to modify an existing entry. -;;; The new or exiting entry is returned. -(defun ensure-type-entry (name environment &rest keyword-arguments) - (let ((entry (type-entry name environment))) - (if (null entry) - (setf entry (apply #'make-instance 'type-entry :name name - keyword-arguments) - (type-entry name environment) entry) - (apply #'reinitialize-instance entry keyword-arguments)) - entry)) - ;;; Implementation of the Clostrum methods. -(declaim (inline cell-value (setf cell-value) cell-boundp cell-makunbound)) -(defun cell-value (cell) (car cell)) -(defun (setf cell-value) (new cell) (setf (car cell) new)) -(defun cell-boundp (cell) (not (eq (car cell) (cdr cell)))) -(defun cell-makunbound (cell) (setf (car cell) (cdr cell)) (values)) - -(defmethod sys:operator-cell-value (client cell) - (declare (ignore client)) - (cell-value cell)) -(defmethod (setf sys:operator-cell-value) (new client cell) +(defmethod sys:parent (client (env basic-environment)) (declare (ignore client)) - (setf (cell-value cell) new)) -(defmethod sys:operator-cell-boundp (client cell) - (declare (ignore client)) - (cell-boundp cell)) -(defmethod sys:operator-cell-makunbound (client cell) - (declare (ignore client)) - (cell-makunbound cell)) + (parent env)) -(defmethod sys:operator-status (client (env run-time-environment) name) +(defmethod sys:operator-status (client (env basic-environment) name) (declare (ignore client)) (let ((entry (operator-entry name env))) (if (null entry) nil (status entry)))) (defmethod (setf sys:operator-status) - (new client (env run-time-environment) name) - (declare (ignore client)) + (new client (env basic-environment) name) (let ((entry (if (null new) (operator-entry name env) - (ensure-operator-entry name env)))) + (ensure-operator-entry client name env)))) (unless (null entry) (setf (status entry) new))) new) -(defmethod sys:operator-cell (client (environment run-time-environment) name) - (declare (ignore client)) - (cell (ensure-operator-entry name environment))) - -(defmethod sys:compiler-macro-function (client (env run-time-environment) name) +(defmethod sys:compiler-macro-function (client (env basic-environment) name) (declare (ignore client)) (let ((entry (operator-entry name env))) (if (null entry) nil (compiler-macro-function entry)))) (defmethod (setf sys:compiler-macro-function) - (new-value client (environment run-time-environment) name) - (declare (ignore client)) + (new-value client (environment basic-environment) name) (let ((entry (if (null new-value) (operator-entry name environment) - (ensure-operator-entry name environment)))) + (ensure-operator-entry client name environment)))) (unless (null entry) (setf (compiler-macro-function entry) new-value))) new-value) -(defmethod sys:setf-expander (client (env run-time-environment) name) +(defmethod sys:setf-expander (client (env basic-environment) name) (declare (ignore client)) (let ((entry (operator-entry name env))) (if (null entry) nil (setf-expander entry)))) (defmethod (setf sys:setf-expander) - (new-value client (environment run-time-environment) name) - (declare (ignore client)) + (new-value client (environment basic-environment) name) (let ((entry (if (null new-value) (operator-entry name environment) - (ensure-operator-entry name environment)))) + (ensure-operator-entry client name environment)))) (unless (null entry) (setf (setf-expander entry) new-value))) new-value) - -;;; Variables. -(defmethod sys:variable-cell-value (client cell) +(defmethod sys:operator-inline (client (env basic-environment) name) (declare (ignore client)) - (cell-value cell)) -(defmethod (setf sys:variable-cell-value) (new client cell) - (declare (ignore client)) - (setf (cell-value cell) new)) -(defmethod sys:variable-cell-boundp (client cell) + (let ((entry (operator-entry name env))) + (if (null entry) + nil + (inline entry)))) +(defmethod (setf sys:operator-inline) (new client (env basic-environment) name) + (let ((entry (ensure-operator-entry client name env))) + (setf (inline-known-p entry) t (inline entry) new))) + +(defmethod sys:operator-inline-known-p (client (env basic-environment) name) (declare (ignore client)) - (cell-boundp cell)) -(defmethod sys:variable-cell-makunbound (client cell) + (let ((entry (operator-entry name env))) + (if (null entry) + nil + (inline-known-p entry)))) + +(defmethod sys:operator-inline-data (client (env basic-environment) name) (declare (ignore client)) - (cell-makunbound cell)) + (let ((entry (operator-entry name env))) + (if (null entry) + nil + (inline-data entry)))) +(defmethod (setf sys:operator-inline) (new client (env basic-environment) name) + (setf (inline-data (ensure-operator-entry client name env)) new)) -(defmethod sys:variable-cell - (client (environment run-time-environment) symbol) - (cell (ensure-variable-entry symbol environment))) +(defmethod sys:operator-ftype (client (env basic-environment) name) + (let ((entry (operator-entry name env))) + (if (null entry) + (top-type client) + (ftype entry)))) +(defmethod (setf sys:operator-ftype) + (new client (env basic-environment) name) + (setf (ftype (ensure-operator-entry client name env)) new)) + + +;;; Variables. (defmethod sys:variable-status - (client (environment run-time-environment) symbol) + (client (environment basic-environment) symbol) (let ((entry (variable-entry symbol environment))) (if (null entry) nil (status entry)))) (defmethod (setf sys:variable-status) - (new client (environment run-time-environment) symbol) + (new client (environment basic-environment) symbol) (let ((entry (if (null new) (variable-entry symbol environment) - (ensure-variable-entry symbol environment)))) + (ensure-variable-entry client symbol environment)))) (unless (null entry) (setf (status entry) new)) new)) (defmethod sys:variable-macro-expander - (client (environment run-time-environment) symbol) + (client (environment basic-environment) symbol) (let ((entry (variable-entry symbol environment))) (if (null entry) nil (symbol-macro-expander entry)))) (defmethod (setf sys:variable-macro-expander) - (new client (environment run-time-environment) symbol) + (new client (environment basic-environment) symbol) ;; NEW is always a function, as undefining a symbol macro is instead done by ;; changing its STATUS. So we don't need the (or ... (variable-entry ...)) - (setf (symbol-macro-expander (ensure-variable-entry symbol environment)) new)) + (setf (symbol-macro-expander (ensure-variable-entry client symbol environment)) new)) -(defmethod sys:symbol-plist (client (environment run-time-environment) symbol) - (declare (ignore client)) +(defmethod sys:variable-type (client (environment basic-environment) symbol) (let ((entry (variable-entry symbol environment))) - (if (null entry) - nil - (plist entry)))) -(defmethod (setf sys:symbol-plist) - (new client (environment run-time-environment) symbol) - (declare (ignore client)) - (setf (plist (ensure-variable-entry symbol environment)) new)) + (if entry + (vtype entry) + (top-type client)))) +(defmethod (setf sys:variable-type) + (new client (environment basic-environment) symbol) + (setf (vtype (ensure-variable-entry client symbol environment)) new)) ;;; Types and classes. @@ -277,16 +141,23 @@ (declare (ignore client)) (cell-makunbound cell)) -(defmethod sys:type-cell (client (environment run-time-environment) symbol) +(defmethod sys:type-cell (client (environment basic-environment) symbol) + (declare (ignore client)) + (let ((entry (type-entry symbol environment))) + (if entry + (cell entry) + nil))) + +(defmethod sys:ensure-type-cell (client (environment basic-environment) symbol) (cell (ensure-type-entry symbol environment))) -(defmethod sys:type-expander (client (environment run-time-environment) symbol) +(defmethod sys:type-expander (client (environment basic-environment) symbol) (let ((entry (type-entry symbol environment))) (if (null entry) nil (type-expander entry)))) (defmethod (setf sys:type-expander) - (new client (environment run-time-environment) symbol) + (new client (environment basic-environment) symbol) (let ((entry (if (null new) (type-entry symbol environment) (ensure-type-entry symbol environment)))) @@ -294,35 +165,25 @@ (setf (type-expander entry) new))) new) -;;; Packages. - -(defmethod sys:find-package - (client (environment run-time-environment) name) - (values (gethash name (packages environment)))) - -(defmethod (setf sys:find-package) - (new-package client (environment run-time-environment) name) - (if (null new-package) - (remhash name (packages environment)) - (setf (gethash name (packages environment)) new-package))) - -(defmethod sys:map-all-packages - (client (environment run-time-environment) function) - (maphash (lambda (name package) - (declare (ignore name)) - (funcall function package)) - (packages environment))) - ;;; Declarations. (defmethod sys:proclamation - (client (environment run-time-environment) name) + (client (environment basic-environment) name) (values (gethash name (declarations environment)))) (defmethod (setf sys:proclamation) - (new-value client (environment run-time-environment) name) + (new-value client (environment basic-environment) name) (cond ((null new-value) (remhash name (declarations environment))) (t (setf (gethash name (declarations environment)) new-value)))) + + +;;; Optimize. +(defmethod sys:optimize (client (environment basic-environment)) + (declare (ignore client)) + (optimize environment)) +(defmethod (setf sys:optimize) (new client (environment basic-environment)) + (declare (ignore client)) + (setf (optimize environment) new)) diff --git a/Code/Basic/clostrum-basic.asd b/Code/Basic/clostrum-basic.asd index 97d182f..0ce70f6 100644 --- a/Code/Basic/clostrum-basic.asd +++ b/Code/Basic/clostrum-basic.asd @@ -6,17 +6,18 @@ ;;; TODO ;;; -;;; - add entries like function-inline in the compilation environment ;;; - specify error conditions in documentation and use them (defsystem "clostrum-basic" :description "Example implementation of the Clostrum protocol." :depends-on ("clostrum") + :serial t :components ((:file "packages") - (:file "run-time-environment") + (:file "environment") + (:file "entry") (:file "basic") - (:file "compilation-environment")) + (:file "run-time")) :in-order-to ((test-op (load-op "clostrum-test"))) :perform (test-op (operation component) (flet ((s (name) (uiop:find-symbol* name '#:clostrum-basic))) diff --git a/Code/Basic/compilation-environment.lisp b/Code/Basic/compilation-environment.lisp deleted file mode 100644 index 986866f..0000000 --- a/Code/Basic/compilation-environment.lisp +++ /dev/null @@ -1,79 +0,0 @@ -(cl:in-package #:clostrum-basic) - -(defclass compilation-environment (env:compilation-environment) - ((%parent - :initarg :parent - :reader evaluation-environment) - (function-descriptions - :initarg :function-descriptions - :reader function-descriptions - :initform (make-hash-table :test #'equal)) - (variable-descriptions - :initarg :variable-descriptions - :reader variable-descriptions - :initform (make-hash-table :test #'eq)) - (type-descriptions - :initarg :type-descriptions - :reader type-descriptions - :initform (make-hash-table :test #'eq)) - (optimize-description - ;; Unfortunately there's really nothing we can sensibly use as a default here. - :initarg :optimize-description - :accessor optimize-description))) - -(defmethod sys:evaluation-environment (client (env compilation-environment)) - (declare (ignore client)) - (evaluation-environment env)) - -(defmethod sys:function-description - (client - (env compilation-environment) - function-name) - (or (gethash function-name (function-descriptions env)) - (sys:function-description client (sys:evaluation-environment client env) function-name))) - -(defmethod (setf sys:function-description) - (description - client - (env compilation-environment) - function-name) - (setf (gethash function-name (function-descriptions env)) - description)) - -(defmethod sys:variable-description - (client - (env compilation-environment) - symbol) - (or (gethash symbol (variable-descriptions env)) - (sys:variable-description client (sys:evaluation-environment client env) symbol))) - -(defmethod (setf sys:variable-description) - (description - client - (env compilation-environment) - symbol) - (setf (gethash symbol (variable-descriptions env)) - description)) - -(defmethod sys:type-description - (client - (env compilation-environment) - symbol) - (or (gethash symbol (type-descriptions env)) - (sys:type-description client (sys:evaluation-environment client env) symbol))) - -(defmethod (setf sys:type-description) - (description - client - (env compilation-environment) - symbol) - (setf (gethash symbol (type-descriptions env)) - description)) - -(defmethod sys:optimize-description (client (env compilation-environment)) - (declare (ignore client)) - (optimize-description env)) - -(defmethod (setf sys:optimize-description) (new client (env compilation-environment)) - (declare (ignore client)) - (setf (optimize-description env) new)) diff --git a/Code/Basic/entry.lisp b/Code/Basic/entry.lisp new file mode 100644 index 0000000..243555f --- /dev/null +++ b/Code/Basic/entry.lisp @@ -0,0 +1,179 @@ +(cl:in-package #:clostrum-basic) + +(defgeneric top-type (client) + (:method (client) + (declare (ignore client)) + ;; Default: use type specifiers. + t)) + +;;; Function and variable entries. +(defclass compilation-operator-entry () + ((name + :initarg :name + :reader name) + (status + :initform nil + :accessor status + :type (member :function :macro :special-operator nil)) + (compiler-macro-function + :initform nil + :accessor compiler-macro-function + :type (or function null)) + (setf-expander + :initform nil + :accessor setf-expander + :type (or function null)) + (ftype + :initarg :ftype + :accessor ftype) + (inline + :initform nil + :accessor inline) + (inline-known-p + :initform nil + :accessor inline-known-p) + (inline-data + :initform nil + :accessor inline-data)) + (:default-initargs :name (error "The initarg :NAME is required.") + :ftype (error "The initarg :FTYPE is required."))) + +(defclass operator-entry (compilation-operator-entry) + (;; The CAR of the cell contains the function determined by the + ;; entry. The CDR of the cell contains a function that, when + ;; called, signals an error. When the function determined by the + ;; entry is undefined, the CAR of the cell is the same as the CDR + ;; of the cell. + (cell + :reader cell + :type cons))) + +;;; Make sure NAME names a function entry in ENVIRONMENT. +;;; KEYWORD-ARGUMENTS are keyword/value pairs that will be passed +;;; either to MAKE-INSTANCE in order create a new entry if no entry +;;; exists, or will be passed to REINITIALIZE-INSTANCE to modify the +;;; existing entry if one does exist. The existing entry or the entry +;;; being created is returned. +(defun ensure-operator-entry (client name environment &rest keyword-arguments) + (let ((entry (operator-entry name environment))) + (if (null entry) + (setf (operator-entry name environment) + (etypecase environment + (run-time-environment + (apply #'make-instance 'operator-entry + :name name :ftype (top-type client) + keyword-arguments)) + (compilation-environment + (apply #'make-instance 'compilation-operator-entry + :name name :ftype (top-type client) + keyword-arguments)))) + (apply #'reinitialize-instance entry keyword-arguments)))) + +(defmethod initialize-instance :after ((instance operator-entry) &key name) + ;; We indicate that a function name is FUNBOUND by storing a + ;; function in the CAR of the cell that, when called, signals an + ;; UNDEFINED-FUNCTION error. This way, there is no need for an + ;; explicit test to verify that the name is FBOUND before calling + ;; the function. We store the same, as in EQ, function in the CDR + ;; of the cell. That way, testing whether the function is unbound + ;; is an EQ comparison between the CAR and the CDR of the cell, and + ;; FMAKUNBOUND is implemented by copying the CDR of the cell to the + ;; CAR. + (let ((unbound-function + (lambda (&rest args) + (declare (ignore args)) + (error 'undefined-function :name name)))) + (setf (slot-value instance 'cell) + (cons unbound-function unbound-function)))) + +(defun function-bound-p (operator-entry) + (let ((cell (cell operator-entry))) + (not (eq (car cell) (cdr cell))))) + +(defconstant +unbound+ 'unbound) + +(defclass compilation-variable-entry () + ((name + :initarg :name + :reader name) + (status + :initform nil + :accessor status + :type (member :constant :special :symbol-macro nil)) + (symbol-macro-expander + :accessor symbol-macro-expander + :type (or function null)) + (vtype + :initarg :vtype + :accessor vtype)) + (:default-initargs :name (error "The initarg :NAME is required.") + :vtype (error "The initarg :VTYPE is required."))) + +(defclass variable-entry (compilation-variable-entry) + (;; The CAR of the cell contains the value of the variable + ;; determined by the entry. The CDR of the cell contains a value + ;; that indicates that the variable is unbound. When the variable + ;; is unbound, the CAR and the CDR contain the same value. Since + ;; CL:MAKUNBOUND (which should really be called something else like + ;; MAKE-TO-HAVE-NO-VALUE) must take into account dynamic bindings + ;; of the variable, we do not supply code for MAKUNBOUND here. It + ;; must be implemented by the client. + (cell + :reader cell + :initform (cons +unbound+ +unbound+) + :type cons) + (plist + :initform nil + :accessor plist + :type list))) + +;;; Make sure NAME names a variable entry in ENVIRONMENT. +;;; KEYWORD-ARGUMENTS are keyword/value pairs that will be passed +;;; either to MAKE-INSTANCE in order create a new entry if no entry +;;; exists, or will be passed to REINITIALIZE-INSTANCE to modify the +;;; existing entry if one does exist. The existing entry or the entry +;;; being created is returned. +(defun ensure-variable-entry (client name environment &rest keyword-arguments) + (let ((entry (variable-entry name environment))) + (if (null entry) + (setf (variable-entry name environment) + (etypecase environment + (run-time-environment + (apply #'make-instance 'variable-entry + :name name :vtype (top-type client) + keyword-arguments)) + (compilation-environment + (apply #'make-instance 'compilation-variable-entry + :name name :vtype (top-type client) + keyword-arguments)))) + (apply #'reinitialize-instance entry keyword-arguments)))) + +(defun variable-bound-p (variable-entry) + (let ((cell (cell variable-entry))) + (not (eq (car cell) +unbound+)))) + +(defclass type-entry () + ((%name :initarg :name :reader name) + (%cell :initform (cons nil nil) :reader cell :type cons) + (%type-expander :initform nil :accessor type-expander + :type (or function null)))) + +;;; Make sure NAME names a type entry in ENVIRONMENT. +;;; KEYWORD-ARGUMENTS are keyword/value pairs that will be passed either +;;; to MAKE-INSTANCE in order to create a new entry if none exits, +;;; or to REINITIALIZE-INSTANCE to modify an existing entry. +;;; The new or exiting entry is returned. +(defun ensure-type-entry (name environment &rest keyword-arguments) + (let ((entry (type-entry name environment))) + (if (null entry) + (setf entry (apply #'make-instance 'type-entry :name name + keyword-arguments) + (type-entry name environment) entry) + (apply #'reinitialize-instance entry keyword-arguments)) + entry)) + +(declaim (cl:inline cell-value (setf cell-value) cell-boundp cell-makunbound)) +(defun cell-value (cell) (car cell)) +(defun (setf cell-value) (new cell) (setf (car cell) new)) +(defun cell-boundp (cell) (not (eq (car cell) (cdr cell)))) +(defun cell-makunbound (cell) (setf (car cell) (cdr cell)) (values)) diff --git a/Code/Basic/run-time-environment.lisp b/Code/Basic/environment.lisp similarity index 66% rename from Code/Basic/run-time-environment.lisp rename to Code/Basic/environment.lisp index 1495ce9..2c4245f 100644 --- a/Code/Basic/run-time-environment.lisp +++ b/Code/Basic/environment.lisp @@ -1,7 +1,9 @@ (cl:in-package #:clostrum-basic) -(defclass run-time-environment (env:run-time-environment) - ((functions +(defclass basic-environment () + ((parent :reader parent :initarg :parent + :initform nil) + (functions :reader functions :initform (make-hash-table :test #'equal)) (variables @@ -10,13 +12,22 @@ (types :reader types :initform (make-hash-table :test #'eq)) - (packages - :reader packages - :initform (make-hash-table :test #'equal)) + (optimize + :accessor optimize + :initform nil) (declarations :reader declarations :initform (make-hash-table :test #'eq)))) +(defclass run-time-environment (basic-environment env:run-time-environment) + ((packages + :reader packages + :initform (make-hash-table :test #'equal)))) + +(defclass compilation-environment (basic-environment env:compilation-environment) + () + (:default-initargs :parent (error "The initarg :PARENT is required."))) + (defun operator-entry (name env) (gethash name (functions env) nil)) diff --git a/Code/Basic/packages.lisp b/Code/Basic/packages.lisp index 76220b2..3e179ed 100644 --- a/Code/Basic/packages.lisp +++ b/Code/Basic/packages.lisp @@ -4,6 +4,7 @@ (:use #:cl) (:local-nicknames (#:env #:clostrum) (#:sys #:clostrum-sys)) - (:shadow #:compiler-macro-function) + (:shadow #:compiler-macro-function #:inline #:ftype #:optimize) (:export #:run-time-environment - #:compilation-environment)) + #:compilation-environment + #:top-type)) diff --git a/Code/Basic/run-time.lisp b/Code/Basic/run-time.lisp new file mode 100644 index 0000000..9857b5a --- /dev/null +++ b/Code/Basic/run-time.lisp @@ -0,0 +1,85 @@ +(cl:in-package #:clostrum-basic) + +;;; Implementation of the run-time-specific Clostrum methods. + +;;; Operators. + +(defmethod sys:operator-cell-value (client cell) + (declare (ignore client)) + (cell-value cell)) +(defmethod (setf sys:operator-cell-value) (new client cell) + (declare (ignore client)) + (setf (cell-value cell) new)) +(defmethod sys:operator-cell-boundp (client cell) + (declare (ignore client)) + (cell-boundp cell)) +(defmethod sys:operator-cell-makunbound (client cell) + (declare (ignore client)) + (cell-makunbound cell)) + +(defmethod sys:operator-cell (client (environment run-time-environment) name) + (declare (ignore client)) + (let ((entry (operator-entry name environment))) + (if entry + (cell entry) + nil))) + +(defmethod sys:ensure-operator-cell (client (environment run-time-environment) name) + (cell (ensure-operator-entry client name environment))) + + +;;; Variables. + +(defmethod sys:variable-cell-value (client cell) + (declare (ignore client)) + (cell-value cell)) +(defmethod (setf sys:variable-cell-value) (new client cell) + (declare (ignore client)) + (setf (cell-value cell) new)) +(defmethod sys:variable-cell-boundp (client cell) + (declare (ignore client)) + (cell-boundp cell)) +(defmethod sys:variable-cell-makunbound (client cell) + (declare (ignore client)) + (cell-makunbound cell)) + +(defmethod sys:variable-cell (client (environment run-time-environment) name) + (declare (ignore client)) + (let ((entry (variable-entry name environment))) + (if entry + (cell entry) + nil))) + +(defmethod sys:ensure-variable-cell + (client (environment run-time-environment) symbol) + (cell (ensure-variable-entry client symbol environment))) + +(defmethod sys:symbol-plist (client (environment run-time-environment) symbol) + (declare (ignore client)) + (let ((entry (variable-entry symbol environment))) + (if (null entry) + nil + (plist entry)))) +(defmethod (setf sys:symbol-plist) + (new client (environment run-time-environment) symbol) + (setf (plist (ensure-variable-entry client symbol environment)) new)) + + +;;; Packages. + +(defmethod sys:find-package + (client (environment run-time-environment) name) + (values (gethash name (packages environment)))) + +(defmethod (setf sys:find-package) + (new-package client (environment run-time-environment) name) + (if (null new-package) + (remhash name (packages environment)) + (setf (gethash name (packages environment)) new-package))) + +(defmethod sys:map-all-packages + (client (environment run-time-environment) function) + (maphash (lambda (name package) + (declare (ignore name)) + (funcall function package)) + (packages environment))) diff --git a/Code/Trucler/trucler.lisp b/Code/Trucler/trucler.lisp index 77cfb79..a87c56e 100644 --- a/Code/Trucler/trucler.lisp +++ b/Code/Trucler/trucler.lisp @@ -1,11 +1,12 @@ (cl:in-package #:clostrum-trucler) -(defmethod env:variable-description - (client (environment env:run-time-environment) name) - (ecase (sys:variable-status client environment name) +(defmethod trucler:describe-variable + (client (environment env:environment) name) + (ecase (env:variable-status client environment name) ((nil) nil) ((:special) (make-instance 'trucler:global-special-variable-description + :type (env:variable-type client environment name) :name name)) ((:constant) (make-instance 'trucler:constant-variable-description @@ -14,65 +15,53 @@ ((:symbol-macro) (make-instance 'trucler:global-symbol-macro-description :name name + :type (env:variable-type client environment name) :expansion (env:macroexpand-1 client environment name))))) -(defmethod trucler:describe-variable - (client (environment env:run-time-environment) name) - (env:variable-description client environment name)) - -(defmethod trucler:describe-variable - (client (environment env:compilation-environment) name) - (or (env:variable-description client environment name) - (env:variable-description - client (env:evaluation-environment client environment) name))) - -(defmethod env:function-description - (client (environment env:run-time-environment) name) - (ecase (sys:operator-status client environment name) +(defmethod trucler:describe-function + (client (environment env:environment) name) + (ecase (env:operator-status client environment name) ((nil) nil) ((:function) (make-instance 'trucler:global-function-description :name name + :type (env:operator-ftype client environment name) + :inline (env:operator-inline client environment name) + :inline-data (env:operator-inline-data client environment name) :compiler-macro (env:compiler-macro-function client environment name))) ((:macro) (make-instance 'trucler:global-macro-description :name name :expander (env:macro-function client environment name) + :inline (env:operator-inline client environment name) :compiler-macro (env:compiler-macro-function client environment name))) ((:special-operator) (make-instance 'trucler:special-operator-description :name name)))) -(defmethod trucler:describe-function - (client (environment env:run-time-environment) name) - (env:function-description client environment name)) - -(defmethod trucler:describe-function - (client (environment env:compilation-environment) name) - (or (env:function-description client environment name) - (env:function-description - client (env:evaluation-environment client environment) name))) - -(defmethod trucler:describe-optimize - (client (environment env:compilation-environment)) - (env:optimize-description client environment)) +(defmethod trucler:describe-optimize (client (environment env:environment)) + ;; Assume it's a possibly not normalized list. + (let ((optimize (env:optimize client environment))) + (flet ((quality (quality) + (cond ((member quality optimize) 3) + ((assoc quality optimize) (second (assoc quality optimize))) + ;; FIXME: No good default. + (t 3)))) + (make-instance 'trucler:optimize-description + :speed (quality 'speed) :debug (quality 'debug) :space (quality 'debug) + :safety (quality 'safety) :compilation-speed (quality 'compilation-speed))))) (defmethod trucler:describe-block - (client (environment env:compilation-environment) name) + (client (environment env:environment) name) (declare (ignore client name)) nil) (defmethod trucler:describe-tag - (client (environment env:compilation-environment) tag) - (declare (ignore client name)) + (client (environment env:environment) tag) + (declare (ignore client tag)) nil) (defmethod trucler:global-environment - (client (environment env:run-time-environment)) - (declare (ignore client)) - environment) - -(defmethod trucler:global-environment - (client (environment env:compilation-environment)) + (client (environment env:environment)) (declare (ignore client)) environment) diff --git a/Code/clostrum.lisp b/Code/clostrum.lisp index 9723f2f..4ac884f 100644 --- a/Code/clostrum.lisp +++ b/Code/clostrum.lisp @@ -1,7 +1,8 @@ (cl:in-package #:clostrum-implementation) -(defclass env:run-time-environment () ()) -(defclass env:compilation-environment () ()) +(defclass env:environment () ()) +(defclass env:run-time-environment (env:environment) ()) +(defclass env:compilation-environment (env:environment) ()) (defmacro define-accessor (name lambda-list &rest options) `(progn (defgeneric ,name ,lambda-list ,@options) @@ -9,14 +10,20 @@ ;;; System API -;;; Run-time environment. +(defgeneric sys:parent (client environment)) -(defgeneric sys:evaluation-environment (client environment)) +;;; Run-time environment. (define-accessor sys:operator-status (client environment operator-name)) (defgeneric sys:operator-cell (client environment operator-name)) +(defgeneric sys:ensure-operator-cell (client environment operator-name)) (define-accessor sys:compiler-macro-function (client environment operator-name)) (define-accessor sys:setf-expander (client environment operator-name)) +(define-accessor sys:operator-inline (client environment operator-name)) +(defgeneric sys:operator-inline-known-p (client environment operator-name)) +(define-accessor sys:operator-inline-data (client environment operator-name)) +(define-accessor sys:operator-ftype (client environment operator-name)) + (define-accessor sys:operator-cell-value (client cell)) (defgeneric sys:operator-cell-boundp (client cell)) (defgeneric sys:operator-cell-makunbound (client cell)) @@ -25,6 +32,8 @@ (defgeneric sys:variable-cell (client environment variable-name)) (define-accessor sys:variable-macro-expander (client environment variable-name)) +(define-accessor sys:variable-type (client environment variable-name)) + (define-accessor sys:variable-cell-value (client cell)) (defgeneric sys:variable-cell-boundp (client cell)) (defgeneric sys:variable-cell-makunbound (client cell)) @@ -40,39 +49,46 @@ (define-accessor sys:find-package (client environment name)) (defgeneric sys:map-all-packages (client environment function)) (define-accessor sys:proclamation (client environment name)) - -;;; Compilation environment. - -(define-accessor sys:function-description (client environment function-name)) -(define-accessor sys:variable-description (client environment variable-name)) -(define-accessor sys:type-description (client environment type-name)) -(define-accessor sys:optimize-description (client environment)) +(define-accessor sys:optimize (client environment)) ;;; High level API +(defgeneric env:merge-types (client type1 type2)) +(defgeneric env:merge-optimize (client new-optimize old-optimize)) + +(defgeneric env:operator-status (client environment operator-name)) (define-accessor env:fdefinition (client environment operator-name)) (defgeneric env:fboundp (client environment operator-name)) (defgeneric env:fmakunbound (client environment operator-name)) -(define-accessor env:macro-function (client environment operator-name)) (defgeneric env:special-operator-p (client environment operator-name)) (defgeneric env:make-special-operator (client environment operator-name new)) +(define-accessor env:operator-inline (client environment operator-name)) +(define-accessor env:operator-ftype (client environment operator-name)) +(define-accessor env:macro-function (client environment operator-name)) +(define-accessor env:compiler-macro-function (client environment operator-name)) (define-accessor env:setf-expander (client environment operator-name)) +(defgeneric env:variable-status (client environment variable-name)) (define-accessor env:symbol-value (client environment variable-name)) (defgeneric env:boundp (client env variable-name)) (defgeneric env:makunbound (client env variable-name)) +(define-accessor env:variable-type (client environment variable-name)) (defgeneric env:make-variable (client environment variable-name &optional value)) (defgeneric env:make-parameter (client environment variable-name value)) (defgeneric env:make-constant (client environment variable-name value)) (defgeneric env:make-symbol-macro (client environment variable-name expansion)) +(defgeneric env:ensure-type-cell (client environment name)) (define-accessor env:find-class (client environment class-name &optional errorp)) -(defgeneric env:make-type (client environment type-name expander)) +(define-accessor env:type-expander (client environment type-name)) (defgeneric env:type-expand-1 (client environment type-specifier)) (defgeneric env:type-expand (client environment type-expand)) +(defgeneric env:optimize (client environment)) +(defgeneric env:proclaim-optimize (client environment optimize)) + (defgeneric env:macroexpand-1 (client environment form)) (defgeneric env:macroexpand (client environment form)) (defgeneric env:constantp (client environment form)) diff --git a/Code/conditions.lisp b/Code/conditions.lisp index 2440666..3405576 100644 --- a/Code/conditions.lisp +++ b/Code/conditions.lisp @@ -85,6 +85,15 @@ or a macro." (name condition))))) +(define-condition env:attempt-to-set-ftype-of-non-function (error) + ((%name :initarg :name :reader name) + (%status :initarg :status :reader status)) + (:report (lambda (condition stream) + (format stream + "Attempt to proclaim an FTYPE for ~s,~@ + but the name is defined as a ~s." + (name condition) (status condition))))) + (define-condition env:undefined-class (cell-error) () (:report (lambda (condition stream) diff --git a/Code/default-methods.lisp b/Code/default-methods.lisp index c846c5f..77345f6 100644 --- a/Code/default-methods.lisp +++ b/Code/default-methods.lisp @@ -1,21 +1,58 @@ (cl:in-package #:clostrum-implementation) +(defmethod env:merge-types (client type1 type2) + (declare (ignore client)) + ;; by default, assume that they are just type expanders. + (cond ((eql type1 't) type2) + ((eql type2 't) type1) + (t `(and ,type1 ,type2)))) + +(defmethod env:merge-optimize (client new-optimize old-optimize) + (declare (ignore client)) + ;; by default, assume only standard qualities, and that the optimizes are raw. + (loop for quality in '(speed space safety debug compilation-speed) + if (member quality new-optimize) + collect `(,quality ,3) + else if (assoc quality new-optimize) + collect it + else if (member quality old-optimize) + collect `(,quality ,3) + else if (assoc quality old-optimize) + collect it)) + ;;; Operators +(defun find-operator-cell (client environment operator-name) + "Find an operator cell if it exists, or return NIL. Internal." + (etypecase environment + (env:compilation-environment + (find-operator-cell client (env:parent client environment) operator-name)) + (env:run-time-environment + (or (sys:operator-cell client environment operator-name) + (find-operator-cell client (env:parent client environment) operator-name))) + (null nil))) + +(defmethod env:operator-status (client environment operator-name) + (or (sys:operator-status client environment operator-name) + (let ((parent (env:parent client environment))) + (if parent + (env:operator-status client parent operator-name) + nil)))) + (defmethod env:fdefinition (client environment operator-name) - (let ((cell (sys:operator-cell client environment operator-name))) - (if (sys:operator-cell-boundp client cell) + (let ((cell (find-operator-cell client environment operator-name))) + (if (and cell (sys:operator-cell-boundp client cell)) (sys:operator-cell-value client cell) (error 'undefined-function :name operator-name)))) (defmethod (setf env:fdefinition) (new client environment operator-name) - (let ((cell (sys:operator-cell client environment operator-name))) + (let ((cell (env:ensure-operator-cell client environment operator-name))) (setf (sys:operator-status client environment operator-name) :function (sys:operator-cell-value client cell) new))) (defmethod env:fboundp (client environment operator-name) - (let ((cell (sys:operator-cell client environment operator-name))) - (sys:operator-cell-boundp client cell))) + (let ((cell (find-operator-cell client environment operator-name))) + (and cell (sys:operator-cell-boundp client cell)))) (defmethod env:fmakunbound (client environment operator-name) ;; NOTE: We do not forbid fmakunbound of special operators. If the client @@ -24,37 +61,88 @@ ;; macros as well, and that's out of scope for Clostrum. ;; Similar considerations apply to (setf fdefinition), etc. (setf (sys:operator-status client environment operator-name) nil) - (let ((cell (sys:operator-cell client environment operator-name))) + ;; We do ENSURE-OPERATOR-CELL so that fmakunbound cannot affect + ;; any ancestral environments. + (let ((cell (env:ensure-operator-cell client environment operator-name))) (sys:operator-cell-makunbound client cell)) operator-name) (defmethod env:macro-function (client environment operator-name) - (if (eq (sys:operator-status client environment operator-name) :macro) - (let ((cell (sys:operator-cell client environment operator-name))) - (if (sys:operator-cell-boundp client cell) + (if (eq (env:operator-status client environment operator-name) :macro) + (let ((cell (find-operator-cell client environment operator-name))) + (if (and cell (sys:operator-cell-boundp client cell)) (sys:operator-cell-value client cell) nil)) nil)) - (defmethod (setf env:macro-function) (new client environment operator-name) - (let ((cell (sys:operator-cell client environment operator-name))) + (let ((cell (env:ensure-operator-cell client environment operator-name))) (setf (sys:operator-status client environment operator-name) :macro (sys:operator-cell-value client cell) new))) +(defmethod env:compiler-macro-function (client environment operator-name) + (or (sys:compiler-macro-function client environment operator-name) + (let ((parent (env:parent client environment))) + (if parent + (env:compiler-macro-function client parent operator-name) + nil)))) +(defmethod (setf env:compiler-macro-function) (new client environment operator-name) + (setf (sys:compiler-macro-function client environment operator-name) new)) + (defmethod env:special-operator-p (client environment operator-name) - (eq (sys:operator-status client environment operator-name) :special-operator)) + (eq (env:operator-status client environment operator-name) :special-operator)) (defmethod env:make-special-operator (client environment operator-name new) - (let ((cell (sys:operator-cell client environment operator-name))) + (let ((cell (env:ensure-operator-cell client environment operator-name))) (setf (sys:operator-cell-value client cell) new (sys:operator-status client environment operator-name) :special-operator) operator-name)) -(defmethod env:setf-expander (client environment operator-name) - (sys:setf-expander client environment operator-name)) +(defmethod env:operator-ftype (client environment operator-name) + (let ((parent (env:parent client environment)) + (ftype (sys:operator-ftype client environment operator-name))) + (if parent + (env:merge-types client ftype (env:operator-ftype client parent operator-name)) + ftype))) +(defmethod (setf env:operator-ftype) (new client environment operator-name) + (let ((status (env:operator-status client environment operator-name))) + (if (eq :function status) + (setf (sys:operator-ftype client environment operator-name) new) + (error 'env:attempt-to-set-ftype-of-non-function + :name operator-name :status status)))) + +(defmethod env:operator-inline (client environment operator-name) + (if (sys:operator-inline-known-p client environment operator-name) + (sys:operator-inline client environment operator-name) + (let ((parent (env:parent client environment))) + (if parent + (env:operator-inline client parent operator-name) + nil)))) +(defmethod (setf env:operator-inline) (new client environment operator-name) + (setf (sys:operator-inline client environment operator-name) new)) + +(defmethod env:operator-inline-data (client environment operator-name) + (or (sys:operator-inline-data client environment operator-name) + (let ((parent (env:parent client environment))) + (if parent + (env:operator-inline-data client parent operator-name) + nil)))) +(defmethod (setf env:operator-inline) (new client environment operator-name) + (setf (sys:operator-inline-data client environment operator-name) new)) + +(defmethod env:setf-expander (client (environment env:compilation-environment) operator-name) + (let ((parent (env:parent client environment))) + (if parent + (env:setf-expander client parent operator-name) + nil))) +(defmethod env:setf-expander (client (environment env:run-time-environment) operator-name) + (or (sys:setf-expander client environment operator-name) + (let ((parent (env:parent client environment))) + (if parent + (env:setf-expander client parent operator-name) + nil)))) (defmethod (setf env:setf-expander) (new client environment operator-name) - (case (sys:operator-status client environment operator-name) + (case (env:operator-status client environment operator-name) ;; CLHS says DEFINE-SETF-EXPANDER only works on function and macro names, but ;; we loosen that restriction a bit so that a setf expander can be defined for ;; THE. If an environment wants to restrict DEFINE-SETF-EXPANDER it can do so @@ -68,38 +156,64 @@ ;;; Variables +(defun find-variable-cell (client environment variable-name) + "Find an variable cell if it exists, or return NIL. Internal." + (etypecase environment + (env:compilation-environment + (find-variable-cell client (env:parent client environment) variable-name)) + (env:run-time-environment + (or (sys:variable-cell client environment variable-name) + (find-variable-cell client (env:parent client environment) variable-name))) + (null nil))) + +(defmethod env:variable-status (client environment variable-name) + (or (sys:variable-status client environment variable-name) + (let ((parent (env:parent client environment))) + (if parent + (env:variable-status client parent variable-name) + nil)))) + (defmethod env:symbol-value (client environment variable-name) - (let ((cell (sys:variable-cell client environment variable-name))) - (if (sys:variable-cell-boundp client cell) + (let ((cell (find-variable-cell client environment variable-name))) + (if (and cell (sys:variable-cell-boundp client cell)) (sys:variable-cell-value client cell) (error 'unbound-variable :name variable-name)))) (defmethod (setf env:symbol-value) (new client environment variable-name) - (if (eq (sys:variable-status client environment variable-name) :constant) + (if (eq (env:variable-status client environment variable-name) :constant) (error 'env:attempt-to-set-constant-value :name variable-name) - (let ((cell (sys:variable-cell client environment variable-name))) + (let ((cell (env:ensure-variable-cell client environment variable-name))) (setf (sys:variable-cell-value client cell) new)))) (defmethod env:boundp (client environment variable-name) - (sys:variable-cell-boundp - client (sys:variable-cell client environment variable-name))) + (let ((cell (sys:variable-cell client environment variable-name))) + (and cell (sys:variable-cell-boundp client cell)))) (defmethod env:makunbound (client environment variable-name) (sys:variable-cell-makunbound - client (sys:variable-cell client environment variable-name))) + client (env:ensure-variable-cell client environment variable-name))) + +(defmethod env:variable-type (client environment variable-name) + (let ((parent (env:parent client environment)) + (type (sys:variable-type client environment variable-name))) + (if parent + (env:merge-types client type (env:variable-type client parent variable-name)) + type))) +(defmethod (setf env:variable-type) (new client environment variable-name) + (setf (sys:variable-type client environment variable-name) new)) (defmethod env:make-variable (client environment variable-name &optional (value nil valuep)) - (ecase (sys:variable-status client environment variable-name) + (ecase (env:variable-status client environment variable-name) ((nil) + (setf (sys:variable-status client environment variable-name) :special) (when valuep (setf (sys:variable-cell-value - client (sys:variable-cell client environment variable-name)) - value)) - (setf (sys:variable-status client environment variable-name) :special)) + client (env:ensure-variable-cell client environment variable-name)) + value))) ((:special) (when valuep - (let ((cell (sys:variable-cell client environment variable-name))) + (let ((cell (env:ensure-variable-cell client environment variable-name))) (unless (sys:variable-cell-boundp client cell) (setf (sys:variable-cell-value client cell) value))))) ((:constant) @@ -110,15 +224,15 @@ :name variable-name)))) (defmethod env:make-parameter (client environment variable-name new) - (ecase (sys:variable-status client environment variable-name) + (ecase (env:variable-status client environment variable-name) ((nil) (setf (sys:variable-cell-value - client (sys:variable-cell client environment variable-name)) + client (env:ensure-variable-cell client environment variable-name)) new (sys:variable-status client environment variable-name) :special)) ((:special) - (let ((cell (sys:variable-cell client environment variable-name))) + (let ((cell (env:ensure-variable-cell client environment variable-name))) (setf (sys:variable-cell-value client cell) new))) ((:constant) (error 'env:attempt-to-define-special-variable-for-existing-constant @@ -128,18 +242,18 @@ :name variable-name)))) (defmethod env:make-constant (client environment variable-name new) - (ecase (sys:variable-status client environment variable-name) + (ecase (env:variable-status client environment variable-name) ((nil) ; undefined: this is a new constant - (setf (sys:variable-cell-value - client (sys:variable-cell client environment variable-name)) - new - (sys:variable-status client environment variable-name) - :constant)) + (setf (sys:variable-status client environment variable-name) + :constant + (sys:variable-cell-value + client (env:ensure-variable-cell client environment variable-name)) + new)) ((:constant) (let ((old ;; The cell must be bound, as constants always are. (sys:variable-cell-value - client (sys:variable-cell client environment variable-name)))) + client (find-variable-cell client environment variable-name)))) (unless (eql old new) ;; TODO: Restarts? (error 'env:attempt-to-redefine-constant-incompatibly @@ -152,13 +266,23 @@ (error 'env:attempt-to-define-constant-for-existing-symbol-macro :name variable-name)))) +(defun env:variable-macro-expander (client environment variable-name) + (labels ((%variable-macro-expander (environment) + (or (sys:variable-macro-expander client environment variable-name) + ;; we already checked the status, + ;; so we know SOMETHING defines this expander. + (%variable-macro-expander (env:parent client environment))))) + (ecase (env:variable-status client environment variable-name) + ((nil :special :constant) nil) + ((:symbol-macro) (%variable-macro-expander environment))))) + (defun %make-symbol-macro-expander (expansion) (lambda (form env) (declare (ignore form env)) expansion)) (defmethod env:make-symbol-macro (client environment variable-name expansion) - (ecase (sys:variable-status client environment variable-name) + (ecase (env:variable-status client environment variable-name) ((nil :symbol-macro) (setf (sys:variable-macro-expander client environment variable-name) (%make-symbol-macro-expander expansion) @@ -173,8 +297,18 @@ ;;; Types and classes +(defun find-type-cell (client environment type-name) + "Find a type cell if it exists, or return NIL. Internal." + (etypecase environment + (env:compilation-environment + (find-type-cell client (env:parent client environment) type-name)) + (env:run-time-environment + (or (sys:type-cell client environment type-name) + (find-type-cell client (env:parent client environment) type-name))) + (null nil))) + (defmethod env:find-class (client environment class-name &optional (errorp t)) - (let ((cell (sys:type-cell client environment class-name))) + (let ((cell (find-type-cell client environment class-name))) (cond ((sys:type-cell-boundp client cell) (sys:type-cell-value client cell)) (errorp (error 'env:undefined-class :name class-name)) @@ -186,17 +320,27 @@ (setf (sys:type-expander client environment class-name) nil) (cond ((null new) (sys:type-cell-makunbound - client (sys:type-cell client environment class-name))) + client (env:ensure-type-cell client environment class-name))) (t (setf (sys:type-cell-value - client (sys:type-cell client environment class-name)) + client (env:ensure-type-cell client environment class-name)) new))) new) -(defmethod env:make-type (client environment type-name expander) +(defmethod env:type-expander (client environment type-name) + (let ((cell (find-type-cell client environment type-name))) + (if (and cell (sys:type-cell-boundp client cell)) + nil + (labels ((%type-expander (environment) + (if (null environment) + nil + (or (sys:type-expander client environment type-name) + (%type-expander (env:parent client environment)))))) + (%type-expander environment))))) +(defmethod (setf env:type-expander) (expander client environment type-name) (setf (sys:type-expander client environment type-name) expander) (sys:type-cell-makunbound client - (sys:type-cell client environment type-name)) + (env:ensure-type-cell client environment type-name)) type-name) (defmethod env:type-expand-1 (client environment (type-specifier symbol)) @@ -226,13 +370,20 @@ (setf ever-expanded t type-specifier expansion) (return (values type-specifier ever-expanded)))))) +;;; Optimize + +(defmethod env:optimize (client environment) (sys:optimize client environment)) +(defmethod env:proclaim-optimize (client environment optimize) + (setf (sys:optimize client environment) + (env:merge-optimize client optimize (env:optimize client environment)))) + ;;; Combination (defmethod env:macroexpand-1 (client environment (form symbol)) - (if (eq (sys:variable-status client environment form) :symbol-macro) - (let ((expander (sys:variable-macro-expander client environment form))) - (values (funcall *macroexpand-hook* expander form environment) t)) - (values form nil))) + (let ((expander (env:variable-macro-expander client environment form))) + (if expander + (values (funcall *macroexpand-hook* expander form environment) t) + (values form nil)))) (defmethod env:macroexpand-1 (client environment (form cons)) (let ((operator (car form))) @@ -256,7 +407,7 @@ (return (values form ever-expanded)))))) (defmethod env:constantp (client environment (form symbol)) - (case (sys:variable-status client environment form) + (case (env:variable-status client environment form) ((:constant) t) ((:symbol-macro) (env:constantp diff --git a/Code/documentation.lisp b/Code/documentation.lisp index 9598dec..3cf90a0 100644 --- a/Code/documentation.lisp +++ b/Code/documentation.lisp @@ -11,6 +11,8 @@ The status is either NIL, meaning not fbound, or :FUNCTION, :MACRO, or :SPECIAL- "Retrieve the cell for OPERATOR-NAME's fbinding in ENVIRONMENT. The nature of the cell is implementation-defined, except that it must work with OPERATOR-CELL-VALUE, OPERATOR-CELL-BOUNDP, and OPERATOR-CELL-MAKUNBOUND. Calls to this function always retrieve the same cell given the same arguments, regardless of the operator being fbound or not.") + (function sys:ensure-operator-cell + "Ensure that OPERATOR-NAME has a cell in ENVIRONMENT, and return that cell.") (function sys:compiler-macro-function "Return the compiler macro function for OPERATOR-NAME in ENVIRONMENT. This is NIL if no function has been set, or else the object set by (SETF COMPILER-MACRO-FUNCTION).") @@ -93,22 +95,8 @@ The return values of this function are undefined.")) "Set the proclamation associated with NAME in ENVIRONMENT.")) (documentation-utils:define-docs - (function sys:function-description - "Get the compiler function description for FUNCTION-NAME in ENVIRONMENT.") - (function (setf sys:function-description) - "Set the compiler function description for FUNCTION-NAME in ENVIRONMENT.") - (function sys:variable-description - "Get the compiler variable description for VARIABLE-NAME in ENVIRONMENT.") - (function (setf sys:variable-description) - "Set the compiler variable description for VARIABLE-NAME in ENVIRONMENT.") - (function sys:type-description - "Get the compiler type description for TYPE-NAME in ENVIRONMENT.") - (function (setf sys:type-description) - "Set the compiler type description for TYPE-NAME in ENVIRONMENT.")) - -(documentation-utils:define-docs - (function sys:evaluation-environment - "Given a compilation environment, return its corresponding evaluation environment.") + (function sys:parent + "Given an environment, return the environment it inherits from, or NIL if there is no such parent.") (type env:run-time-environment "Abstract class of run-time environments, containing actual definitions.") (type env:compilation-environment @@ -162,8 +150,6 @@ The nature of a setf expander is otherwise implementation-defined. One choice wo "As CL:FIND-CLASS. Return the class named CLASS-NAME in ENVIRONMENT. If there is no such class, return NIL, unless ERRORP is true in which case an error of type ERROR is signaled.") (function (setf env:find-class) "As (SETF CL:FIND-CLASS). Set the class for CLASS-NAME in ENVIRONMENT. ERRORP is ignored.") - (function env:make-type - "Functional version of CL:DEFTYPE. Define TYPE-NAME to be a derived type in ENVIRONMENT, with type expander EXPANDER. The consequences are unspecified if TYPE-NAME already names a class.") (function env:type-expand-1 "Operator analogous to CL:MACROEXPAND-1, but for type specifiers. Given a type specifier and an environment, return (values expansion true) if the type specifier is derived, otherwise (values specifier nil).") (function env:type-expand diff --git a/Code/packages.lisp b/Code/packages.lisp index 218c189..b6abd3e 100644 --- a/Code/packages.lisp +++ b/Code/packages.lisp @@ -1,73 +1,71 @@ ;;; Low level API. (defpackage #:clostrum-sys (:use #:cl) - (:shadow #:compiler-macro-function #:find-package #:symbol-plist) - (:export #:evaluation-environment) + (:shadow #:compiler-macro-function #:find-package #:symbol-plist #:optimize) + (:export #:parent) ;; Run-time environment accessors and readers ;; Operators - (:export #:operator-status #:operator-cell + (:export #:operator-status #:operator-cell #:ensure-operator-cell #:compiler-macro-function #:setf-expander #:operator-cell-value #:operator-cell-boundp #:operator-cell-makunbound + #:operator-inline #:operator-inline-known-p + #:operator-inline-data #:operator-ftype #:compiler-macro-function #:setf-expander) ;; Variables - (:export #:variable-status #:variable-cell #:variable-macro-expander + (:export #:variable-status #:variable-cell #:ensure-variable-cell #:variable-cell-value #:variable-cell-boundp #:variable-cell-makunbound + #:variable-type #:variable-macro-expander #:symbol-plist) ;; Types and classes (:export #:type-cell #:type-expander #:type-cell-value #:type-cell-boundp - #:type-cell-makunbound) + #:ensure-type-cell #:type-cell-makunbound) ;; Packages (:shadow #:find-package) (:export #:find-package #:map-all-packages) - ;; Proclamations - (:export #:proclamation) - ;; Compilation environment accessors - (:export #:function-description #:variable-description - #:type-description #:optimize-description)) + ;; Proclamations & optimize + (:export #:proclamation #:optimize)) ;;; High level API. (defpackage #:clostrum (:use #:cl) - ;; for reexport - (:shadowing-import-from #:clostrum-sys - #:find-package #:compiler-macro-function - #:symbol-plist) - (:import-from #:clostrum-sys #:type-expander - #:function-description #:variable-description - #:type-description #:optimize-description #:proclamation - #:evaluation-environment #:map-all-packages) + (:import-from #:clostrum-sys + #:parent + #:proclamation + #:ensure-operator-cell #:ensure-variable-cell #:ensure-type-cell) ;; Protocol classes: - (:export #:run-time-environment #:compilation-environment) + (:export #:environment #:run-time-environment #:compilation-environment) ;; Protocol functions: - (:export #:evaluation-environment) + (:export #:parent #:merge-types #:merge-optimize) ;; Operators (:shadow #:fdefinition #:fboundp #:fmakunbound #:macro-function - #:special-operator-p) - (:export #:fdefinition #:fboundp #:fmakunbound #:macro-function #:special-operator-p #:compiler-macro-function) + (:export #:operator-status #:ensure-operator-cell) + (:export #:fdefinition #:fboundp #:fmakunbound #:macro-function + #:special-operator-p #:compiler-macro-function + #:operator-ftype #:operator-inline #:operator-inline-data) (:export #:setf-expander #:make-special-operator) ;; Variables (:shadow #:symbol-value #:boundp #:makunbound) - (:export #:symbol-value #:boundp #:makunbound) + (:export #:ensure-variable-cell) + (:export #:variable-status #:symbol-value #:boundp #:makunbound) (:export #:make-variable #:make-parameter #:make-constant - #:make-symbol-macro) + #:make-symbol-macro #:variable-macro-expander #:variable-type) (:export #:symbol-plist) ;; Types and classes (:shadow #:find-class) + (:export #:ensure-type-cell) (:export #:find-class) - (:export #:make-type #:type-expand-1 #:type-expand #:type-expander) + (:export #:type-expand-1 #:type-expand #:type-expander) ;; Packages (:export #:find-package #:map-all-packages) - ;; Proclamations - (:export #:proclamation) + ;; Proclamations & optimize + (:shadow #:optimize) + (:export #:proclamation #:optimize #:proclaim-optimize) ;; General (:shadow #:macroexpand-1 #:macroexpand #:constantp) (:export #:macroexpand-1 #:macroexpand #:constantp) - ;; Compilation environment - (:export #:function-description #:variable-description - #:type-description #:optimize-description) ;; Condition types: (:export #:attempt-to-set-constant-value #:attempt-to-define-special-variable-for-existing-constant @@ -78,6 +76,7 @@ #:attempt-to-define-symbol-macro-for-existing-special-variable #:attempt-to-define-symbol-macro-for-existing-constant #:attempt-to-define-a-setf-expander-of-non-existing-function-or-macro + #:attempt-to-set-ftype-of-non-function #:undefined-class)) (defpackage #:clostrum-implementation