Used http://wcp.sdf-eu.org/software/sclf-20150207T213551.tbz (sha256 a231aeecdb9e87c72642292a1e083fffb33e69ec1d34e667326c6c35b8bcc794). There's no upstream repository nor a release since 2015, so importing seems to make a lot of sense. Since we can't subtree making any depot-related changes in a separate CL to make them more discoverable -- this is only the source import. Change-Id: Ia51a7f4029dba3abd1eee4eeebcf99aca5c5ba4c Reviewed-on: https://cl.tvl.fyi/c/depot/+/3376 Tested-by: BuildkiteCI Reviewed-by: grfn <grfn@gws.fyi>
		
			
				
	
	
		
			134 lines
		
	
	
		
			No EOL
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Common Lisp
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			No EOL
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Common Lisp
		
	
	
	
	
	
| ;;;  lazy.lisp --- lazy primitives
 | |
| 
 | |
| ;;;  Copyright (C) 2008, 2009, 2010 by Walter C. Pelissero
 | |
| 
 | |
| ;;;  Author: Walter C. Pelissero <walter@pelissero.de>
 | |
| ;;;  Project: sclf
 | |
| 
 | |
| #+cmu (ext:file-comment "$Module: lazy.lisp $")
 | |
| 
 | |
| ;;; This library is free software; you can redistribute it and/or
 | |
| ;;; modify it under the terms of the GNU Lesser General Public License
 | |
| ;;; as published by the Free Software Foundation; either version 2.1
 | |
| ;;; of the License, or (at your option) any later version.
 | |
| ;;; This library is distributed in the hope that it will be useful,
 | |
| ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| ;;; Lesser General Public License for more details.
 | |
| ;;; You should have received a copy of the GNU Lesser General Public
 | |
| ;;; License along with this library; if not, write to the Free
 | |
| ;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 | |
| ;;; 02111-1307 USA
 | |
| 
 | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | |
| ;;;
 | |
| ;;; Lazy primitives
 | |
| ;;;
 | |
| 
 | |
| (in-package :sclf)
 | |
| 
 | |
| (defstruct promise
 | |
|   procedure
 | |
|   value)
 | |
| 
 | |
| (defmacro lazy (form)
 | |
|   `(make-promise :procedure #'(lambda () ,form)))
 | |
| 
 | |
| (defun forced-p (promise)
 | |
|   (null (promise-procedure promise)))
 | |
| 
 | |
| (defun force (promise)
 | |
|   (if (forced-p promise)
 | |
|       (promise-value promise)
 | |
|       (prog1 (setf (promise-value promise)
 | |
| 		   (funcall (promise-procedure promise)))
 | |
| 	(setf (promise-procedure promise) nil))))
 | |
| 
 | |
| (defmacro deflazy (name value &optional documentation)
 | |
|   `(defparameter ,name (lazy ,value)
 | |
|      ,@(when documentation
 | |
| 	     (list documentation))))
 | |
| 
 | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | |
| 
 | |
| (defclass lazy-metaclass (standard-class)
 | |
|   ()
 | |
|   (:documentation "Metaclass for object having lazy slots.  Lazy slots
 | |
| should be specified with the :LAZY keyword which must be a function of
 | |
| one argument.  If required this function will be called once to get
 | |
| the value to memoize in the slot.  Lazy slots can also be set/read as
 | |
| any other."))
 | |
| 
 | |
| (defmethod validate-superclass ((class lazy-metaclass) (super standard-class))
 | |
|   "Lazy classes may inherit from ordinary classes."
 | |
|   (declare (ignore class super))
 | |
|   t)
 | |
| 
 | |
| (defmethod validate-superclass ((class standard-class) (super lazy-metaclass))
 | |
|   "Ordinary classes may inherit from lazy classes."
 | |
|   (declare (ignore class super))
 | |
|   t)
 | |
| 
 | |
| (defclass lazy-slot-mixin ()
 | |
|   ((lazy-function :initarg :lazy
 | |
| 		   :reader lazy-slot-function
 | |
| 		   :initform nil))
 | |
|   (:documentation
 | |
|    "Slot for LAZY-METACLASS classes.  Lazy slots must be declared with
 | |
| the argument :LAZY which must be a function accepting the object
 | |
| instance as argument."))
 | |
| 
 | |
| (defclass lazy-direct-slot-definition (lazy-slot-mixin standard-direct-slot-definition)
 | |
|   ())
 | |
| 
 | |
| (defclass lazy-effective-slot-definition (lazy-slot-mixin standard-effective-slot-definition)
 | |
|   ())
 | |
| 
 | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | |
| 
 | |
| (defmethod direct-slot-definition-class ((class lazy-metaclass) &rest initargs)
 | |
|   (if (getf initargs :lazy nil)
 | |
|       (find-class 'lazy-direct-slot-definition)
 | |
|       (call-next-method)))
 | |
| 
 | |
| (defmethod effective-slot-definition-class ((class lazy-metaclass) &rest initargs)
 | |
|   (if (getf initargs :lazy nil)
 | |
|       (find-class 'lazy-effective-slot-definition)
 | |
|       (call-next-method)))
 | |
| 
 | |
| (defmethod compute-effective-slot-definition-initargs ((class lazy-metaclass) direct-slots)
 | |
|   (let ((ds (car direct-slots)))
 | |
|     (if (typep ds 'lazy-direct-slot-definition)
 | |
|       (let ((form (lazy-slot-function ds))
 | |
| 	    (args (call-next-method)))
 | |
| 	(when (or (getf args :initarg)
 | |
| 		  (getf args :initform))
 | |
| 	  (error "Lazy slot ~S cannot have :INITARG nor :INITFORM arguments." ds))
 | |
| 	(list* :lazy
 | |
| 	       (cond ((and (listp form)
 | |
| 			   (eq 'lambda (car form)))
 | |
| 		      (compile nil form))
 | |
| 		     ((symbolp form)
 | |
| 		      form)
 | |
| 		     (t (compile nil `(lambda (self)
 | |
| 					(declare (ignorable self))
 | |
| 					,form))))
 | |
| 	       args))
 | |
|       (call-next-method))))
 | |
| 
 | |
| (defmethod slot-value-using-class ((class lazy-metaclass) instance (slot lazy-slot-mixin))
 | |
|   (declare (ignore class))
 | |
|   ;; If the slot is unbound, call the lazy function passing the
 | |
|   ;; instance and memoize the value in the slot.
 | |
|   (unless (slot-boundp-using-class class instance slot)
 | |
|     (setf (slot-value-using-class class instance slot)
 | |
| 	  (funcall (lazy-slot-function slot) instance)))
 | |
|   (call-next-method))
 | |
| 
 | |
| (defun reset-lazy-slots (object)
 | |
|   "Unbind all the lazy slots in OBJECT so that they will be
 | |
| re-evaluated next time their value is requested again."
 | |
|   (be* class (class-of object)
 | |
|     (dolist (slot (class-slots class))
 | |
|       (when (typep slot 'lazy-effective-slot-definition)
 | |
| 	(slot-makunbound object (slot-definition-name slot)))))) |