Version 1.0 is out!
SL is a complex dependency fixer.
Use SL to support two wildly different forks of a library like swank and slynk.
(defsl operator-arglist :fn :eq slynk swank)
SL is a Domain Specific Language (ie. simple programming language) for dealing with ambiguous dependency situations. It is more expressive than the standard method in Common Lisp: the use of reader macros. It provides symbol aliasing based on compile-time rules.
Symbols are then defined in the SL package, which is an artifact of the fact that it was designed primarily to allow supporting both the slynk and swank language servers.
TODO: allow defining them in other packages
I made this since asdf
was not enough abstraction for what I needed: to
arbitrarily choose dependencies and renames for any symbol. I could write what I
am doing twice, or I could write the compiler for SL
(ie. the first two
letters of SLy and SLime). Once I have that, I can bend that fork until I have a
coherent set of names for all the functions I need, and which work on both (in
principle). You could just intern the symbols (like with #+ reader syntax) but
those tend to explode exponentially; since SL is using the compiler,
a much more powerful solution is implemented in macros.
- Symbol aliasing at compile time provides a means of abstracting separate
but similar interfaces. Forked projects, or projects that duplicate work.
- Far more expressive and concise than reader macros, while still very simple.
- There is also the use case of renaming things for import, like
with-gensyms
to with-unique-names
or similar.
none
The only external macro is defsl
. There is BNF below, though some examples are in order.
This defines operator-arglist
(in the current package) as
slynk:operator-arglist
, unless slynk
is unavailable, in which case
swank:operator-arglist
is used.
(defsl operator-arglist :fn :eq slynk swank)
The :fn
shows that a FUNCTION is being defined, as opposed to a :sym
symbol;
to define another namespace a list is required: (accessor-fn boundp-fn)
. :eq
denotes that the packages have the same name for this function.
For this simplest of examples, consider the reader macro alternative.
#+slynk
(setf (symbol-function 'operator-arglist)
slynk:operator-arglist)
#+(and (not slynk) swank)
(setf (symbol-function 'operator-arglist)
swank:operator-arglist)
(defsl gensymmer (macro-function macro-function)
utils with-unique-names
alexandria with-gensyms)
To break this down:
sl:gensymmer
is now defined asutils:with-unique-names
.macro-function
was used twice: once as asetfable
place, and once as a
predicate.
- If the
utils
package does not exist, thensl:gensymmer
is defined asalexanrdia:with-gensyms
. - to define different names for each package, they must be “qualified” with the package name.
Use ASDF to install. Usually this should work:
$ cd ~/common-lisp/
$ git clone git@github.com:equwal/sl.git
CL-USER> (asdf:load-system :sl)
(defsl <sl-name> <fnsym> <package spec>) <package spec> ::= <eq> | <packages> <eq> ::= :eq <preferences> <fnsym> ::= :fn | :sym | <fnpair> <fnpair> ::= (setfable-place bound-predicate) <packages> ::= <package> <fn name> <more packages> <package> ::= symbol <fn name> ::= symbol <preferences> ::= <package> <more packages> <more packages> ::= ε | <package> | <package> <more packages>
- defsl is a hygienic macro