Skip to content

Commit

Permalink
Deal with type declarations properly, I hope
Browse files Browse the repository at this point in the history
This improves the changes in 1.5.0
  • Loading branch information
tfeb committed Dec 25, 2024
1 parent 2a784dc commit 069cd3c
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 44 deletions.
31 changes: 24 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,28 @@ The simple thing that should be easy is providing a generalised version of `dest

`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].

## Contents
- [An example](#an-example)
- [The interface](#the-interface)
- [Conditions](#conditions)
- [Some simple examples](#some-simple-examples)
- [Another example: define-destructuring-macro](#another-example-define-destructuring-macro)
- [A final example: destructuring-bind](#a-final-example-destructuring-bind)
- [Notes on the implementation](#notes-on-the-implementation)
- [Lambda lists](#lambda-lists)
- [Structure sharing](#structure-sharing)
- [&rest lists may not be](#rest-lists-may-not-be)
- [Declarations](#declarations)
- [Dead code](#dead-code)
- [The lambda list parser & compiler](#the-lambda-list-parser--compiler)
- [Performance](#performance)
- [Layers](#layers)
- [Extensions](#extensions)
- [literals: check if some variables are literals](#literals-check-if-some-variables-are-literals)
- [Other notes](#other-notes)
- [Lost futures](#lost-futures)
- [Package, module, feature, dependencies](#package-module-feature-dependencies)

## An example
As an example, let's consider a macro where there are a few possible variations on the syntax:

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

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

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:

- 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;
- 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.

The assumption behind the second case is that any valid type specifier should be a recognizable subtype of `t`.
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.

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

Expand Down Expand Up @@ -365,7 +382,7 @@ What constitutes a blank variable is parameterized internally and could be made
## Package, module, feature, dependencies
`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.

`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").
`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").

---

Expand Down
52 changes: 15 additions & 37 deletions cpll.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -52,46 +52,24 @@

(defun canonicalize-declarations (declarations &optional (environment nil))
;; Turn DECLARATIONS into a larger set which affect at most one
;; variable each. I think this is safe: it relies on
;; VALID-TYPE-SPECIFIER-P, which see, to be correct for symbols, and
;; on the fact that any declaration where the specifier is a cons is
;; a type specifier, which I believe to be true.
;; variable each. I think this is safe: see
;; CANONICALIZE-DECLARATION-SPECIFIER.
(collecting
(dolist (decl declarations)
(dolist (dspec (rest decl))
(matching dspec
((head-matches (is 'type) (any))
;; obvious type declaration
(destructuring-bind (tp . vars) (rest dspec)
(dolist (v vars)
(collect `(declare (type ,tp ,v))))))
((list*-matches #'consp (list-of (var)))
;; a declaration identifier which is a cons is a type
;; specifier, especially if all the other elements of the
;; declaration are variables
(destructuring-bind (tp . vars) dspec
(dolist (v vars)
(collect `(declare (type ,tp ,v))))))
((head-matches (some-of (is 'ignore)
(is 'ignorable)
(is 'special)
(is 'dynamic-extent)))
(destructuring-bind (d . vars) dspec
(dolist (v vars)
(collect `(declare (,d ,v))))))
((list*-matches (all-of
#'symbolp
(lambda (ts)
(valid-type-specifier-p ts environment)))
(list-of (var)))
(print "here")
;; A symbol which is a type specifier
(destructuring-bind (ts . vars) dspec
(dolist (v vars)
(collect `(declare (type ,ts ,v))))))
(otherwise
;; No idea
(collect `(declare ,dspec))))))))
(destructuring-bind (identifier . rest) (canonicalize-declaration-specifier
dspec environment)
(case identifier
(type
(destructuring-bind (type . vars) rest
(dolist (var vars)
(collect `(declare (type ,type ,var))))))
((ignore ignorable special dynamic-extent)
(dolist (var rest)
(collect `(declare (,identifier ,var)))))
(otherwise
;; No idea
(collect `(declare ,dspec)))))))))

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

0 comments on commit 069cd3c

Please sign in to comment.