Skip to content

Commit 53b068f

Browse files
committed
Prepublication
1 parent 3df2a23 commit 53b068f

16 files changed

+2649
-0
lines changed

LICENSE

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright 1989-2021 Tim Bradshaw
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the
5+
"Software"), to deal in the Software without restriction, including
6+
without limitation the rights to use, copy, modify, merge, publish,
7+
distribute, sublicense, and/or sell copies of the Software, and to
8+
permit persons to whom the Software is furnished to do so, subject to
9+
the following conditions:
10+
11+
The above copyright notice and this permission notice shall be
12+
included in all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+905
Large diffs are not rendered by default.

abstract-classes.lisp

+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -*- Mode: Lisp -*- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2+
;; File - abstract-classes.lisp
3+
;; Description - Abstract classes in CL
4+
;; Author - Tim Bradshaw (tfb at lostwithiel)
5+
;; Created On - Sun Dec 10 18:21:40 2000
6+
;; Last Modified On - Sun Jan 17 16:49:17 2021
7+
;; Last Modified By - Tim Bradshaw (tfb at kingston.fritz.box)
8+
;; Update Count - 17
9+
;; Status - Unknown
10+
;;
11+
;; $Id$
12+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13+
14+
;;;; Abstract classes
15+
;;;
16+
;;; abstract-classes.lisp is copyright 2000-2001, 2021 by me, Tim
17+
;;; Bradshaw, and may be used for any purpose whatsoever by anyone. It
18+
;;; has no warranty whatsoever. I would appreciate acknowledgement if
19+
;;; you use it in anger, and I would also very much appreciate any
20+
;;; feedback or bug fixes.
21+
;;;
22+
23+
;;; Get Closer to MOP if this is being loaded as a module: this is
24+
;;; needed at runtime as well as compile time so a feature expression
25+
;;; won't work.
26+
;;;
27+
#-Lispworks
28+
(eval-when (:compile-toplevel :load-toplevel :execute)
29+
(unless (find-package :closer-common-lisp)
30+
#+quicklisp
31+
(ql:quickload "closer-mop")
32+
#-quicklisp
33+
(error "abstract-classes needs Closer to MOP")))
34+
35+
(defpackage :org.tfeb.hax.abstract-classes
36+
(:nicknames :org.tfeb.hax.final-classes)
37+
#-LispWorks
38+
(:use :closer-common-lisp)
39+
#+LispWorks
40+
(:use :cl :hcl)
41+
(:export #:abstract-class
42+
#:define-abstract-class
43+
#:final-class
44+
#:define-final-class))
45+
46+
(in-package :org.tfeb.hax.abstract-classes)
47+
48+
(provide :org.tfeb.hax.abstract-classes)
49+
(provide :org.tfeb.hax.final-classes)
50+
51+
(eval-when (:compile-toplevel :load-toplevel :execute)
52+
(unless (eq 'standard-class 'cl:standard-class)
53+
(warn "STANDARD-CLASS isn't: you're probably doomed")))
54+
55+
(defclass abstract-class (standard-class)
56+
()
57+
(:documentation "The class of abstract classes"))
58+
59+
(defmethod make-instance ((c abstract-class) &rest junk)
60+
(declare (ignore junk))
61+
(error "Trying to make an instance of ~A which is an abstract class"
62+
(class-name c)))
63+
64+
;;; The MOP requires this, but it's not clear that implementations do.
65+
;;; VALIDATE-SUPERCLASS specifies when a superclass is suitable for a
66+
;;; subclass. You have to be pretty specific, It's probably not in
67+
;;; general safe to do what we do here.
68+
;;;
69+
70+
(defmethod validate-superclass ((class abstract-class)
71+
(superclass standard-class))
72+
;; This is, in general, somewhat too permissive, but we are going to
73+
;; allow any instance of (a subclass of) STANDARD-CLASS to act as a
74+
;; superclass of any instance of ABSTRACT-CLASS...
75+
t)
76+
77+
(defmethod validate-superclass ((class standard-class)
78+
(superclass abstract-class))
79+
;; ... and the other way around.
80+
t)
81+
82+
83+
;;; I don't want to have to say ... (:metaclass abstract-class), but
84+
;;; there is no easy hook into processing the options to DEFCLASS:
85+
;;; ENSURE-CLASS-USING-CLASS, which would be the logical place to do
86+
;;; this, is called with a class of NIL if there is no existing class,
87+
;;; and so can't usefully be specialized.
88+
;;;
89+
90+
(defmacro define-abstract-class (class supers slots &rest options)
91+
(when (assoc ':metaclass options)
92+
(error "Defining an abstract class with a metaclass?"))
93+
`(defclass ,class ,supers ,slots
94+
,@options
95+
(:metaclass abstract-class)))
96+
97+
;;; Samples of abstract classes
98+
#||
99+
(define-abstract-class abstract-thing ()
100+
((s :accessor thing-s)))
101+
102+
(defclass thing (abstract-thing)
103+
((s :initform 1)))
104+
||#
105+
106+
;;; Benchmarks: for ACL 6.0 there is no performance hit.
107+
#||
108+
(define-abstract-class ac () ())
109+
(defclass ac-instantiable (ac) ())
110+
(defclass nac () ())
111+
(defclass nac-instantiable (nac) ())
112+
113+
(defun make-n-aci (n)
114+
(declare (type fixnum n)
115+
(optimize speed))
116+
(loop repeat n
117+
do (make-instance 'ac-instantiable)))
118+
119+
(defun make-n-naci (n)
120+
(declare (type fixnum n)
121+
(optimize speed))
122+
(loop repeat n
123+
do (make-instance 'nac-instantiable)))
124+
125+
(defun make-n-general (n cn)
126+
(declare (type fixnum n)
127+
(optimize speed))
128+
(loop repeat n
129+
do (make-instance cn)))
130+
||#
131+
132+
133+
;;;; Final classes
134+
;;;
135+
;;; Classes which may not be subclassed.
136+
;;;
137+
;;; I just know someone is going to ask for an abstract final class.
138+
139+
(defclass final-class (standard-class)
140+
()
141+
(:documentation "The class of classes which may not be subclassed"))
142+
143+
;;; The MOP requires this, but it's not clear that implementations do.
144+
;;; VALIDATE-SUPERCLASS specifies when a superclass is suitable for a
145+
;;; subclass. You have to be pretty specific, It's probably not in
146+
;;; general safe to do what we do here.
147+
;;;
148+
149+
(defmethod validate-superclass ((class final-class)
150+
(superclass standard-class))
151+
;; This is, in general, somewhat too permissive, but we are going to
152+
;; allow any instance of (a subclass of) STANDARD-CLASS to act as a
153+
;; superclass of any instance of ABSTRACT-CLASS...
154+
t)
155+
156+
(defmethod validate-superclass ((class standard-class)
157+
(superclass final-class))
158+
(error "Attempting to subclass a final class"))
159+
160+
161+
;;; I don't want to have to say ... (:metaclass final-class), but
162+
;;; there is no easy hook into processing the options to DEFCLASS:
163+
;;; ENSURE-CLASS-USING-CLASS, which would be the logical place to do
164+
;;; this, is called with a class of NIL if there is no existing class,
165+
;;; and so can't usefully be specialized.
166+
;;;
167+
168+
(defmacro define-final-class (class supers slots &rest options)
169+
(when (assoc ':metaclass options)
170+
(error "Defining a final class with a metaclass?"))
171+
`(defclass ,class ,supers ,slots
172+
,@options
173+
(:metaclass final-class)))

collecting.lisp

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -*- Mode: Lisp -*- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2+
;; File - collecting.lisp
3+
;; Description - Collecting lists forwards
4+
;; Author - Tim Bradshaw (tfb at lostwithiel)
5+
;; Created On - 1989
6+
;; Last Modified On - Sun Aug 30 14:06:06 2020
7+
;; Last Modified By - Tim Bradshaw (tfb at kingston.fritz.box)
8+
;; Update Count - 15
9+
;; Status - Unknown
10+
;;
11+
;; $Id$
12+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13+
14+
;;;; Collecting lists forwards
15+
;;; This is an old macro cleaned up a bit
16+
;;;
17+
;;; 2012: I have changed this to use local functions rather than macros,
18+
;;; on the assumption that implementations can optimize this pretty well now
19+
;;; and local functions are much semantically nicer than macros.
20+
;;;
21+
22+
;;; These macros hardly seem worth copyrighting, but are copyright
23+
;;; 1989-2012 by me, Tim Bradshaw, and may be used for any purpose
24+
;;; whatsoever by anyone. There is no warranty whatsoever. I would
25+
;;; appreciate acknowledgement if you use this in anger, and I would
26+
;;; also very much appreciate any feedback or bug fixes.
27+
28+
(defpackage :org.tfeb.hax.collecting
29+
(:use :cl)
30+
(:export #:collecting
31+
#:collect
32+
#:with-collectors))
33+
34+
(in-package :org.tfeb.hax.collecting)
35+
36+
(provide :org.tfeb.hax.collecting)
37+
38+
(defmacro collecting (&body forms)
39+
;; Collect some random stuff into a list by keeping a tail-pointer
40+
;; to it, return the collected list. This now uses a local function
41+
;; rather than a macro.
42+
"Collect things into a list forwards. Within the body of this macro
43+
The form `(COLLECT THING)' will collect THING into the list returned by
44+
COLLECTING. COLLECT is a local function so can be passed as an argument,
45+
or returned. Uses a tail pointer -> efficient."
46+
(let ((cn (make-symbol "C")) (tn (make-symbol "CT")))
47+
`(let ((,cn '()) (,tn nil))
48+
(flet ((collect (it)
49+
(if ,cn
50+
(setf (cdr ,tn) (list it)
51+
,tn (cdr ,tn))
52+
(setf ,tn (list it)
53+
,cn ,tn))
54+
it))
55+
(declare (inline collect))
56+
,@forms)
57+
,cn)))
58+
59+
(defmacro with-collectors ((&rest collectors) &body forms)
60+
;; multiple-collector version of COLLECTING.
61+
"Collect some things into lists forwards.
62+
The names in COLLECTORS are defined as local functions, which each collect into a
63+
separate list. Returns as many values as there are collectors."
64+
(let ((cvns (mapcar #'(lambda (c)
65+
(make-symbol (concatenate 'string
66+
(symbol-name c) "-VAR")))
67+
collectors))
68+
(ctns (mapcar #'(lambda (c)
69+
(make-symbol (concatenate 'string
70+
(symbol-name c) "-TAIL")))
71+
collectors)))
72+
`(let (,@cvns ,@ctns)
73+
(flet ,(mapcar (lambda (cn cvn ctn)
74+
`(,cn (it)
75+
(if ,cvn
76+
(setf (cdr ,ctn) (list it)
77+
,ctn (cdr ,ctn))
78+
(setf ,ctn (list it)
79+
,cvn ,ctn))
80+
it))
81+
collectors cvns ctns)
82+
(declare (inline ,@collectors))
83+
,@forms)
84+
(values ,@cvns))))

comment-form.lisp

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
;;;; Commenting forms
2+
;;;
3+
;;; Racket has #; to comment a form. You can do this in CL with
4+
;;; #+(or), but I thought an explicit equivalent might be interesting.
5+
;;; This comes from an answer on stack overflow:
6+
;;; https://stackoverflow.com/a/65649186/5920214
7+
;;;
8+
;;; comment-form.lisp is copyright 2021 by me, Tim Bradshaw, and may
9+
;;; be used for any purpose whatsoever by anyone. It has no warranty
10+
;;; whatsoever. I would appreciate acknowledgement if you use it in
11+
;;; anger, and I would also very much appreciate any feedback or bug
12+
;;; fixes.
13+
14+
(defpackage :org.tfeb.hax.comment-form
15+
(:use :cl)
16+
(:export #:make-comment-form-readtable))
17+
18+
(in-package :org.tfeb.hax.comment-form)
19+
20+
(provide :org.tfeb.hax.comment-form)
21+
22+
(defun make-comment-form-readtable (&key (from nil fromp) (to nil)
23+
(semicolon #\;))
24+
"Make a readtable with comment-form readmacro (#; by default).
25+
26+
Make a copy of FROM (defaultly the current readtable) and in it make
27+
#; (or as below) be a read macro which causes the next form to be
28+
skipped. #n; will skip n forms. Other than the skipping-n-forms
29+
thing, this is no more than what #+(or) will do, but it is clearer I
30+
think.
31+
32+
If TO is given, instead copy & modify FROM into TO (this behaviour is
33+
compatible with what COPY-READTABLE does).
34+
35+
If SEMICOLON is given, it is the dispatching character, instead of #\\;."
36+
(let ((cfrt (if fromp (copy-readtable from to) (copy-readtable))))
37+
(when (get-dispatch-macro-character #\# semicolon cfrt)
38+
(error "Someone is already using #~A" semicolon))
39+
(set-dispatch-macro-character
40+
#\# semicolon
41+
(lambda (stream char n)
42+
(declare (ignore char))
43+
(let ((*read-suppress* t))
44+
(dotimes (i (or n 1) (values))
45+
(read stream))))
46+
cfrt)
47+
cfrt))

0 commit comments

Comments
 (0)