Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/guicho271828/aspectm

aspect-oriented hooks
https://github.com/guicho271828/aspectm

Last synced: 29 days ago
JSON representation

aspect-oriented hooks

Awesome Lists containing this project

README

        

* Aspectm - control macroexpand hooks

=*macroexpand-hook*= in Common Lisp is quite hard to maintain correctly,
since it is global and anyone can modify its value. This library is an
experimental attempt to provide a set of "acceptable" way of modifying the
hook. Well, I feel, kind of defeated.

AspectM provides CLOS-like /around/, /before/, /after/ hooks for
macroexpansion, and I planned to implement useful hooks based upon this system.

#+BEGIN_SRC lisp
(enable-macroexpand-hooks) ; enable around hooks, then
(add-around-hook 'standard-hook) ; register standard (=before+after) hook as an around hook

;; expanded before the main expansion, then prepended to the main expansion result
(defmacro force-inline (&whole form name args &body body)
(assert (eq 'defun (car form)))
`(declaim (inline ,name)))

(set-standard-hook 'defun 'force-inline :before)

(macroexpand
`(defun my-+ (x y) (+ x y)))

(remove-standard-hook 'defun 'force-inline :before)
;; there are also with-standard-hook
#+END_SRC

# Note: *ABOVE CODE DOES NOT WORK.*

I want the scope of these hooks to be file local, but not sure how.
This is the main reason I stopped the development.

# Sounds simple, but actually not. The main problem is about the invalidation
# of the compilation results, and the scope of the hook. What happends if we put a hook
# =set-standard-hook= in file A, which is loaded before a file B that
# contains =my-+= above, but the file B is already compiled? What if a user
# forgot adding =remove-standard-hook= in the end of file B? It affects every
# single file loaded after it. Well, this might be a matter of ASDF system
# definition, but there are various similar effects.
#
# The scope of a hook is package. Each enable-macroexpand-hooks remembers its

* Details

/around/ hooks are always nested, and I suppose this is the expected usage of
=*macroexpand-hook*=. Notable difference is that
every /around/ hooks MUST call the next hook by calling =(call-next-hook)=,
or it signals an compile-time error. This ensures that all hooks are called
in the right order without skipping/overriding.

Based on this system, AspectM implements a set of hooks
called /standard/ hooks, which consist of /before/ and /after/ hooks,
just like /before/ and /after/ methods in CLOS.
The functionalities of before/around hooks follow:

+ It can see the arguments of the macro.
+ It can prepend/append forms to the main form returned by the macro, each wrapped in progn.
+ However it cannot modify the main expansion result.

Expected usecases: Side-effects upon expansion. E.g. exporting symbols,
proclaim =inline=, or storing the form as a workaround for a system that
does not provide =function-lambda-expression=.

Unfortunately, =load= and =compile= does *not* rebind =*macroexpand-hook*=
as they do for =*readtable*= and =*package*=. You are warned.

* Setting a Standard Hook

/before/ and /after/ hooks are regular macro-functions of two arguments
(the form and environment). The example code below automatically adds
=inline= proclaration to all =defun=-ed function.

#+BEGIN_SRC lisp

(defmacro force-inline (&whole form name args &body body)
(assert (eq 'defun (car form)))
`(declaim (inline ,name)))

(set-standard-hook 'defun 'force-inline :before)

#+END_SRC

* Dependencies

This library is at least tested on implementation listed below:

+ SBCL 1.2.8 on X86-64 Linux 3.13.0-46-generic (author's environment)

Also, it depends on the following libraries:

+ alexandria by ::
Alexandria is a collection of portable public domain utilities.

+ lisp-namespace by Masataro Asai ::
Provides LISP-N --- extensible namespaces in Common Lisp.

* Copyright

Copyright (c) 2015 Masataro Asai ([email protected])

* License

Licensed under the LLGPL License.