Skip to content
This repository was archived by the owner on Dec 13, 2025. It is now read-only.

Commit 069cd3c

Browse files
committed
Deal with type declarations properly, I hope
This improves the changes in 1.5.0
1 parent 2a784dc commit 069cd3c

File tree

2 files changed

+39
-44
lines changed

2 files changed

+39
-44
lines changed

README.md

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,28 @@ The simple thing that should be easy is providing a generalised version of `dest
55

66
`dsm`'s whole purpose in life is to allow you to pattern match against *source code*: it does not, for instance, support matching against instances of general classes, because instances of general classes do not occur in source code. It is a tool to make doing what Lisp does best easier: implementing programming languages built on Lisp. *And that is all it does.* Because this is all it is meant to do,`dsm` cares about correctness, but it does not care at all about performance: the performance of macroexpansion never matters[^2].
77

8+
## Contents
9+
- [An example](#an-example)
10+
- [The interface](#the-interface)
11+
- [Conditions](#conditions)
12+
- [Some simple examples](#some-simple-examples)
13+
- [Another example: define-destructuring-macro](#another-example-define-destructuring-macro)
14+
- [A final example: destructuring-bind](#a-final-example-destructuring-bind)
15+
- [Notes on the implementation](#notes-on-the-implementation)
16+
- [Lambda lists](#lambda-lists)
17+
- [Structure sharing](#structure-sharing)
18+
- [&rest lists may not be](#rest-lists-may-not-be)
19+
- [Declarations](#declarations)
20+
- [Dead code](#dead-code)
21+
- [The lambda list parser & compiler](#the-lambda-list-parser--compiler)
22+
- [Performance](#performance)
23+
- [Layers](#layers)
24+
- [Extensions](#extensions)
25+
- [literals: check if some variables are literals](#literals-check-if-some-variables-are-literals)
26+
- [Other notes](#other-notes)
27+
- [Lost futures](#lost-futures)
28+
- [Package, module, feature, dependencies](#package-module-feature-dependencies)
29+
830
## An example
931
As an example, let's consider a macro where there are a few possible variations on the syntax:
1032

@@ -271,12 +293,7 @@ Declarations are 'raised' to where they belong by the compiler, so something lik
271293

272294
Will do the right thing, and the guard clause will be within the scope of the declaration.
273295

274-
The system *attempts* to deal with the short form of type declarations properly. This is hard in CL because there is no predicate which tells you whether something is a valid type specifier or not. It tries to solve this problem two ways:
275-
276-
- anything of the form `(declare (<x> <v> ...))` where `<x>` is *not* a symbol and all the `<v>`s are variable names is a type declaration, as declaration specifiers need to be symbols;
277-
- for anything of the form `(declare (<s> <v> ...))` where `<s>` is a symbol and the `<v>`s are variable names it relies (indirectly) on catching an error from `(subtypep <s> t <env>)` where `<env>` is the lexical environment object.
278-
279-
The assumption behind the second case is that any valid type specifier should be a recognizable subtype of `t`.
296+
The system should now deal with the short form of type declarations properly. This is hard in CL because there is no predicate which tells you whether something is a valid type specifier or not. It now works by using `canonicalize-declaration-specifier` which should reliably deal with these.
280297

281298
However, if you want to declare types, just use the long form[^7].
282299

@@ -365,7 +382,7 @@ What constitutes a blank variable is parameterized internally and could be made
365382
## Package, module, feature, dependencies
366383
`dsm` lives in `org.tfeb.dsm` and provides `:org.tfeb.dsm`. The extension package is `org.tfeb.dsm/extensions`. There is an ASDF system definition for both it and its tests.
367384

368-
`dsm` depends on a fair number of other things I have written: if you have a recent Quicklisp distribution then it *should* know about all of them. At least, by the time `dsm` makes it into Quicklisp it should. If not, you need at least version 5 of [my CL hax](https://tfeb.github.io/tfeb-lisp-hax/ "TFEB.ORG Lisp hax"), and at least version 8 of [my CL tools](https://tfeb.github.io/tfeb-lisp-tools/ "TFEB.ORG Lisp tools").
385+
`dsm` depends on a fair number of other things I have written: if you have a recent Quicklisp distribution then it *should* know about all of them. At least, by the time `dsm` makes it into Quicklisp it should. If not, you need at least version 9 of [my CL hax](https://tfeb.github.io/tfeb-lisp-hax/ "TFEB.ORG Lisp hax"), and at least version 8 of [my CL tools](https://tfeb.github.io/tfeb-lisp-tools/ "TFEB.ORG Lisp tools").
369386

370387
---
371388

cpll.lisp

Lines changed: 15 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -52,46 +52,24 @@
5252

5353
(defun canonicalize-declarations (declarations &optional (environment nil))
5454
;; Turn DECLARATIONS into a larger set which affect at most one
55-
;; variable each. I think this is safe: it relies on
56-
;; VALID-TYPE-SPECIFIER-P, which see, to be correct for symbols, and
57-
;; on the fact that any declaration where the specifier is a cons is
58-
;; a type specifier, which I believe to be true.
55+
;; variable each. I think this is safe: see
56+
;; CANONICALIZE-DECLARATION-SPECIFIER.
5957
(collecting
6058
(dolist (decl declarations)
6159
(dolist (dspec (rest decl))
62-
(matching dspec
63-
((head-matches (is 'type) (any))
64-
;; obvious type declaration
65-
(destructuring-bind (tp . vars) (rest dspec)
66-
(dolist (v vars)
67-
(collect `(declare (type ,tp ,v))))))
68-
((list*-matches #'consp (list-of (var)))
69-
;; a declaration identifier which is a cons is a type
70-
;; specifier, especially if all the other elements of the
71-
;; declaration are variables
72-
(destructuring-bind (tp . vars) dspec
73-
(dolist (v vars)
74-
(collect `(declare (type ,tp ,v))))))
75-
((head-matches (some-of (is 'ignore)
76-
(is 'ignorable)
77-
(is 'special)
78-
(is 'dynamic-extent)))
79-
(destructuring-bind (d . vars) dspec
80-
(dolist (v vars)
81-
(collect `(declare (,d ,v))))))
82-
((list*-matches (all-of
83-
#'symbolp
84-
(lambda (ts)
85-
(valid-type-specifier-p ts environment)))
86-
(list-of (var)))
87-
(print "here")
88-
;; A symbol which is a type specifier
89-
(destructuring-bind (ts . vars) dspec
90-
(dolist (v vars)
91-
(collect `(declare (type ,ts ,v))))))
92-
(otherwise
93-
;; No idea
94-
(collect `(declare ,dspec))))))))
60+
(destructuring-bind (identifier . rest) (canonicalize-declaration-specifier
61+
dspec environment)
62+
(case identifier
63+
(type
64+
(destructuring-bind (type . vars) rest
65+
(dolist (var vars)
66+
(collect `(declare (type ,type ,var))))))
67+
((ignore ignorable special dynamic-extent)
68+
(dolist (var rest)
69+
(collect `(declare (,identifier ,var)))))
70+
(otherwise
71+
;; No idea
72+
(collect `(declare ,dspec)))))))))
9573

9674
(defun declarations-for (variables canonical-declarations)
9775
;; Return a list of declarations affecting VARs and the remaining

0 commit comments

Comments
 (0)