The illusion Reference Manual

Table of Contents

Next: , Previous: , Up: (dir)   [Contents][Index]

The illusion Reference Manual

This is the illusion Reference Manual, version 0.1, generated automatically by Declt version 2.4 patchlevel 1 "Will Decker" on Mon Jul 29 15:54:05 2019 GMT+0.


Next: , Previous: , Up: Top   [Contents][Index]

1 Introduction

Illusion

Illusion is a library for customization and management of Lisp left paren reader.

Overview

Why customize the reader macro of left paren? Some features are impossible without doing that, let's see a few short examples in Usage section.

Usage

Installation and import

Before illusion available in quicklisp, clone this repo to local-projects or adding to asdf:*central-registry* and:

(ql:quickload :illusion)

If you don't use other customized reader macros, just use :illusion-readtable:

(named-readtables:in-readtable :illusion-readtable)

Otherwise, merge :illusion-readtable into current one, it only changes definition of #\( and #\):

(handler-bind ((named-readtables:reader-macro-conflict #'continue))
           (named-readtables:merge-readtables-into your-readtable :illusion-readtable))

Set and delete a left paren reader

(illusion:set-paren-reader name predicate reader)

Use a SET-PAREN-READER to add or change a left paren reader. NAME is a keyword to identify and you can delete it by (DELETE-PAREN-READER NAME). PREDICATE is a function INDICATOR -> BOOLEAN. Indicator is the first element of every list. It's not necessarilly a symbol and first element of a list literal, e.g. a in (a b) is also indicator. So we must carefully check the condition that indicator satisfies in PREDICATE. And at last, READER is the function (STREAM INDICATOR) -> OBJECT that called when (PREDICATE INDICATOR) satisfied. Current position of input STREAM is just after read INDICATOR.

Examples

Temporarily change to preserve case reader after specific indicator

The first example, assume we want to write a DEFINE-CLI which take command line specs and produce a command line argument parser. The command line option is usually case sensitive, so this won't work:

(define-cli :main
    (v version "Display version of this program")
    (V verbose "Set verbose level"))

v and V will both read to V. We can use "v", #\v, \v or |v|, but each one is more verbose. Or we can (setf (readtable-case *readtable*) :preserve), but this force us to use upcase symbols for all CL symbols. What if the reader auto turns on preserve case after encounter DEFINE-CLI indicator? We can define it as:

(set-paren-reader :define-cli
                  (lambda (i)
                    (eql i 'stub-cli:define-cli))
                  (lambda (stream indicator)
                    (cons 'stub-cli:define-cli
                          (cons (read stream)
                                (with-reader-case :preserve
                                    (cl-read-list stream))))))

A few note about this left paren reader:

This only saving a little effort when define cli, but similar techniques can be helpful in accessing case sensitive foreign languages. For example, inline calling a JavaScript method as that in ClojureScript and inline calling a Qt method as if in C++.

Inline calling CommonQt methods

Calling a CommonQt method need a #_ reader macro:

(#_setBrush painter "brush name")

Using https://github.com/commonqt/commonqt methods a lot is not very pleasant because of many #_. If we're doing GUI programming with CommonQt, usually it make sense to have a whole package dedicated to UI definition and event handling. With the following left paren reader, we can use CommonQt methods as if using Common Lisp functions while let Common Lisp's package system and illusion do the symbol isolation:

(set-paren-reader :commonqt
                  #'qt-symbol-p
                  (lambda (stream indicator)
                    (list* 'optimized-call t (read stream) (symbol-name indicator)
                           (cl-read-list stream))))

Here (optimized-call t obj "methodName" arg1 arg2) is how CommonQt call Qt Method (#_methodName obj arg1 arg2) and after this SET-PAREN-READER we can simply use (|methodName obj arg1 arg2). Even better, we can use (ILLUSION:SET-INDICATOR-MODE :PRESERVE-CASE) then just (methodName obj arg1 arg2). In this indicator mode, it will first try the preserve case symbol and check if it satisfies any left paren reader predicate. If none, indicator will fallback to upcase, so all existing Common Lisp and user package symbols still works. In rare case if you have lower and mixed case symbol as function/macro names, try to isolate them with the scope that using CommonQt.

CSS id and class attached to html element creation function name

In https://github.com/ailisp/flute html generation library, HTML elements are defined with same name functions. (div ...) will create a div element. It's almost shortest possible way to generate html in Common Lisp, but with illusion, we can support haml and hiccup style id/class attached to function names like (div#my-div.class1.class2 ...). To keep example short, we only process id here and writing this left paren reader for a sub-html package, assume stub-html package has DIV exported:

(set-paren-reader :html
                  (lambda (i)
                    (when (symbolp i)
                      (let ((name (symbol-name i)))
                        (when (find #\# name)
                          (let ((name-and-id (split-sequence #\# name)))
                            (multiple-value-bind (symbol access) (find-symbol (first name-and-id) :stub-html)
                              (eql access :external)))))))
                  (lambda (stream indicator)
                    (let ((name-and-id (split-sequence #\# (symbol-name indicator))))
                      (list* (find-symbol (first name-and-id) :stub-html)
                             :id (string-downcase (second name-and-id))
                             (cl-read-list stream)))))

Set indicator mode

As showed in the CommonQt example, illusion support SET-INDICATOR-MODE. Currently :STANDARD (default), :PRESERVE-CASE and (INDICATOR-READER . INDICATOR-FALLBACK) is supported. INDICATOR-READER is a function take a stream as only required argument and return the indicator it reads. INDICATOR-FALLBACK is a function called when indicator not satisfied any left paren reader and take indicator as only argument, returns the object that CL:READ would return when reading that indicator.

Motivation

Illusion will obviously lead to more obscure code. It won't slow down the generated program since it all happens at read time. But if carefully used, the syntax can be further simplified and gives an illusion of having a more versatile ability with using plain parens. The example usages above are real usage in flute for html generation and lispy-cli. Hope illusion also help construct easier usage of your library!

License

Licensed under the MIT License. Copyright (c) 2018, Bo Yao. All rights reserved.


Next: , Previous: , Up: Top   [Contents][Index]

2 Systems

The main system appears first, followed by any subsystem dependency.


Previous: , Up: Systems   [Contents][Index]

2.1 illusion

Author

Bo Yao <icerove@gmail.com>

License

MIT

Description

Customize and manage Lisp parens reader

Long Description

# Illusion

Illusion is a library for customization and management of Lisp left paren reader.

# Overview

- Adding customized left paren reader macro, based on indicator (first element of list);
- Automatically use left paren reader macro when indicator satisfies user defined predicate;
- Optionally read indicator in case sensitive or customized mode and still read the rest with default reader behavior
- Delete paren left paren reader even they break reader behavior.

Why customize the reader macro of left paren? Some features are impossible without doing that, let’s see a few short examples in [Usage](#Usage) section.

# Usage
## Installation and import
Before illusion available in quicklisp, clone this repo to ‘local-projects‘ or adding to ‘asdf:*central-registry*‘ and:
“‘lisp
(ql:quickload :illusion)
“‘
If you don’t use other customized reader macros, just use ‘:illusion-readtable‘:
“‘lisp
(named-readtables:in-readtable :illusion-readtable)
“‘
Otherwise, merge ‘:illusion-readtable‘ into current one, it only changes definition of ‘#\(‘ and ‘#\)‘:
“‘lisp
(handler-bind ((named-readtables:reader-macro-conflict #’continue))
(named-readtables:merge-readtables-into your-readtable :illusion-readtable))
“‘
## Set and delete a left paren reader
“‘lisp
(illusion:set-paren-reader name predicate reader)
“‘

Use a ‘SET-PAREN-READER‘ to add or change a left paren reader. ‘NAME‘ is a keyword to identify and you can delete it by ‘(DELETE-PAREN-READER NAME)‘. ‘PREDICATE‘ is a function ‘INDICATOR -> BOOLEAN‘. Indicator is the first element of every list. It’s not necessarilly a symbol and first element of a list literal, e.g. ‘a‘ in ‘(a b)‘ is also indicator. So we must carefully check the condition that indicator satisfies in ‘PREDICATE‘. And at last, ‘READER‘ is the function ‘(STREAM INDICATOR) -> OBJECT‘ that called when ‘(PREDICATE INDICATOR)‘ satisfied. Current position of input ‘STREAM‘ is just after read ‘INDICATOR‘.

## Examples
### Temporarily change to preserve case reader after specific indicator
The first example, assume we want to write a ‘DEFINE-CLI‘ which take command line specs and produce a command line argument parser. The command line option is usually case sensitive, so this won’t work:
“‘lisp
(define-cli :main
(v version "Display version of this program")
(V verbose "Set verbose level"))
“‘
‘v‘ and ‘V‘ will both read to ‘V‘. We can use ‘"v"‘, ‘#\v‘, ‘\v‘ or ‘|v|‘, but each one is more verbose. Or we can ‘(setf (readtable-case *readtable*) :preserve)‘, but this force us to use upcase symbols for all CL symbols. What if the reader auto turns on preserve case after encounter ‘DEFINE-CLI‘ indicator? We can define it as:
“‘lisp
(set-paren-reader :define-cli
(lambda (i)
(eql i ’stub-cli:define-cli))
(lambda (stream indicator)
(cons ’stub-cli:define-cli
(cons (read stream)
(with-reader-case :preserve
(cl-read-list stream))))))
“‘
A few note about this left paren reader:
- To compare with a symbol, must given the symbol with its package name like ‘STUB-CLI:DEFINE-CLI‘
- The reader (third parameter of ‘SET-PAREN-READER‘ should return newly cons list. Avoid using ‘’‘ or backquote. Because sometimes they create lists with shared structure and cause strange behavior.
- ‘ILLUSION:WITH-READER-CASE‘ is a trivial but handy utility, that executing the body with ‘(READTABLE-CASE *READTABLE*)‘ bind to one of ‘:UPCASE‘, ‘:DOWNCASW‘, ‘:PRESERVE‘ or ‘:INVERSE‘, and unwind to previous ‘(READTABLE-CASE *READTABLE*)‘ setting after leave it.
- If you want this left paren make effect in current file, need to wrap ‘(set-paren-reader ...)‘ inside ‘(eval-when (:compile-toplevel :load-toplevel :execute) ...)‘ like changing other reader macros.

This only saving a little effort when define cli, but similar techniques can be helpful in accessing case sensitive foreign languages. For example, inline calling a JavaScript method as that in ClojureScript and inline calling a Qt method as if in C++.

### Inline calling CommonQt methods
Calling a CommonQt method need a ‘#_‘ reader macro:
“‘lisp
(#_setBrush painter "brush name")
“‘
Using [https://github.com/commonqt/commonqt](CommonQt) methods a lot is not very pleasant because of many ‘#_‘. If we’re doing GUI programming with CommonQt, usually it make sense to have a whole package dedicated to UI definition and event handling. With the following left paren reader, we can use CommonQt methods as if using Common Lisp functions while let Common Lisp’s package system and illusion do the symbol isolation:
“‘lisp
(set-paren-reader :commonqt
#’qt-symbol-p
(lambda (stream indicator)
(list* ’optimized-call t (read stream) (symbol-name indicator)
(cl-read-list stream))))
“‘

Here ‘(optimized-call t obj "methodName" arg1 arg2)‘ is how CommonQt call Qt Method ‘(#_methodName obj arg1 arg2)‘ and after this ‘SET-PAREN-READER‘ we can simply use ‘(|methodName obj arg1 arg2)‘. Even better, we can use ‘(ILLUSION:SET-INDICATOR-MODE :PRESERVE-CASE)‘ then just ‘(methodName obj arg1 arg2)‘.
In this indicator mode, it will first try the preserve case symbol and check if it satisfies any left paren reader predicate. If none, indicator will fallback to upcase, so all existing Common Lisp and user package symbols still works. In rare case if you have lower and mixed case symbol as function/macro names, try to isolate them with the scope that using CommonQt.
### CSS id and class attached to html element creation function name
In [https://github.com/ailisp/flute](flute) html generation library, HTML elements are defined with same name functions. ‘(div ...)‘ will create a div element. It’s almost shortest possible way to generate html in Common Lisp, but with illusion, we can support haml and hiccup style id/class attached to function names like ‘(div#my-div.class1.class2 ...)‘. To keep example short, we only process id here and writing this left paren reader for a sub-html package, assume stub-html package has ‘DIV‘ exported:
“‘
(set-paren-reader :html
(lambda (i)
(when (symbolp i)
(let ((name (symbol-name i)))
(when (find #\# name)
(let ((name-and-id (split-sequence #\# name)))
(multiple-value-bind (symbol access) (find-symbol (first name-and-id) :stub-html)
(eql access :external)))))))
(lambda (stream indicator)
(let ((name-and-id (split-sequence #\# (symbol-name indicator))))
(list* (find-symbol (first name-and-id) :stub-html)
:id (string-downcase (second name-and-id))
(cl-read-list stream)))))
“‘
## Set indicator mode
As showed in the CommonQt example, illusion support ‘SET-INDICATOR-MODE‘. Currently ‘:STANDARD‘ (default), ‘:PRESERVE-CASE‘ and ‘(INDICATOR-READER . INDICATOR-FALLBACK)‘ is supported. ‘INDICATOR-READER‘ is a function take a stream as only required argument and return the indicator it reads. ‘INDICATOR-FALLBACK‘ is a function called when indicator not satisfied any left paren reader and take indicator as only argument, returns the object that ‘CL:READ‘ would return when reading that indicator.

# Motivation

Illusion will obviously lead to more obscure code. It won’t slow down the generated program since it all happens at read time. But if carefully used, the syntax can be further simplified and gives an illusion of having a more versatile ability with using plain parens. The example usages above are real usage in [flute](https://github.com/ailisp/flute) for html generation and [lispy-cli](https://github.com/ailisp/lispy-cli). Hope illusion also help construct easier usage of your library!

# License

Licensed under the MIT License.
Copyright (c) 2018, Bo Yao. All rights reserved.

Version

0.1

Dependencies
Source

illusion.asd (file)

Component

src (module)


Next: , Previous: , Up: Top   [Contents][Index]

3 Modules

Modules are listed depth-first from the system components tree.


Previous: , Up: Modules   [Contents][Index]

3.1 illusion/src

Parent

illusion (system)

Location

src/

Component

illusion.lisp (file)


Next: , Previous: , Up: Top   [Contents][Index]

4 Files

Files are sorted by type and then listed depth-first from the systems components trees.


Previous: , Up: Files   [Contents][Index]

4.1 Lisp


Next: , Previous: , Up: Lisp files   [Contents][Index]

4.1.1 illusion.asd

Location

illusion.asd

Systems

illusion (system)


Previous: , Up: Lisp files   [Contents][Index]

4.1.2 illusion/src/illusion.lisp

Parent

src (module)

Location

src/illusion.lisp

Packages

illusion

Exported Definitions
Internal Definitions

Next: , Previous: , Up: Top   [Contents][Index]

5 Packages

Packages are listed by definition order.


Previous: , Up: Packages   [Contents][Index]

5.1 illusion

Source

illusion.lisp (file)

Use List

common-lisp

Exported Definitions
Internal Definitions

Next: , Previous: , Up: Top   [Contents][Index]

6 Definitions

Definitions are sorted by export status, category, package, and then by lexicographic order.


Next: , Previous: , Up: Definitions   [Contents][Index]

6.1 Exported definitions


Next: , Previous: , Up: Exported definitions   [Contents][Index]

6.1.1 Macros

Macro: with-reader-case CASE &body BODY
Package

illusion

Source

illusion.lisp (file)


Previous: , Up: Exported definitions   [Contents][Index]

6.1.2 Functions

Function: cl-read-list STREAM
Package

illusion

Source

illusion.lisp (file)

Function: delete-all-paren-readers ()
Package

illusion

Source

illusion.lisp (file)

Function: delete-paren-reader NAME
Package

illusion

Source

illusion.lisp (file)

Function: set-indicator-mode MODE
Package

illusion

Source

illusion.lisp (file)

Function: set-paren-reader NAME PREDICATE READER
Package

illusion

Source

illusion.lisp (file)


Previous: , Up: Definitions   [Contents][Index]

6.2 Internal definitions


Next: , Previous: , Up: Internal definitions   [Contents][Index]

6.2.1 Special variables

Special Variable: *in-list-p*
Package

illusion

Source

illusion.lisp (file)

Special Variable: *indicator-fallback*
Package

illusion

Source

illusion.lisp (file)

Special Variable: *indicator-reader*
Package

illusion

Source

illusion.lisp (file)

Special Variable: *paren-readers*
Package

illusion

Source

illusion.lisp (file)

Special Variable: +empty-list+
Package

illusion

Source

illusion.lisp (file)


Next: , Previous: , Up: Internal definitions   [Contents][Index]

6.2.2 Functions

Function: cl-read-right-paren STREAM
Package

illusion

Source

illusion.lisp (file)

Function: copy-paren-reader INSTANCE
Package

illusion

Source

illusion.lisp (file)

Function: fallback-indicator-upcase INDICATOR
Package

illusion

Source

illusion.lisp (file)

Function: find-paren-reader INDICATOR
Package

illusion

Source

illusion.lisp (file)

Function: find-paren-reader-by-name NAME
Package

illusion

Source

illusion.lisp (file)

Function: funcallable-p NAME
Package

illusion

Source

illusion.lisp (file)

Function: illusion-read-list STREAM IGNORE
Package

illusion

Source

illusion.lisp (file)

Function: illusion-read-right-paren STREAM RIGHT-PAREN
Package

illusion

Source

illusion.lisp (file)

Function: make-paren-reader &key (NAME NAME) (PREDICATE PREDICATE) (READER READER)
Package

illusion

Source

illusion.lisp (file)

Function: paren-reader-name INSTANCE
Function: (setf paren-reader-name) VALUE INSTANCE
Package

illusion

Source

illusion.lisp (file)

Function: paren-reader-name-matcher NAME
Package

illusion

Source

illusion.lisp (file)

Function: paren-reader-p OBJECT
Package

illusion

Source

illusion.lisp (file)

Function: paren-reader-predicate INSTANCE
Function: (setf paren-reader-predicate) VALUE INSTANCE
Package

illusion

Source

illusion.lisp (file)

Function: paren-reader-reader INSTANCE
Function: (setf paren-reader-reader) VALUE INSTANCE
Package

illusion

Source

illusion.lisp (file)

Function: read-indicator-preserve-case STREAM
Package

illusion

Source

illusion.lisp (file)


Previous: , Up: Internal definitions   [Contents][Index]

6.2.3 Structures

Structure: paren-reader ()
Package

illusion

Source

illusion.lisp (file)

Direct superclasses

structure-object (structure)

Direct slots
Slot: name
Readers

paren-reader-name (function)

Writers

(setf paren-reader-name) (function)

Slot: predicate
Readers

paren-reader-predicate (function)

Writers

(setf paren-reader-predicate) (function)

Slot: reader
Readers

paren-reader-reader (function)

Writers

(setf paren-reader-reader) (function)


Previous: , Up: Top   [Contents][Index]

Appendix A Indexes


Next: , Previous: , Up: Indexes   [Contents][Index]

A.1 Concepts

Jump to:   F   I   L   M  
Index Entry  Section

F
File, Lisp, illusion.asd: The illusion<dot>asd file
File, Lisp, illusion/src/illusion.lisp: The illusion/src/illusion<dot>lisp file

I
illusion.asd: The illusion<dot>asd file
illusion/src: The illusion/src module
illusion/src/illusion.lisp: The illusion/src/illusion<dot>lisp file

L
Lisp File, illusion.asd: The illusion<dot>asd file
Lisp File, illusion/src/illusion.lisp: The illusion/src/illusion<dot>lisp file

M
Module, illusion/src: The illusion/src module

Jump to:   F   I   L   M  

Next: , Previous: , Up: Indexes   [Contents][Index]

A.2 Functions

Jump to:   (  
C   D   F   I   M   P   R   S   W  
Index Entry  Section

(
(setf paren-reader-name): Internal functions
(setf paren-reader-predicate): Internal functions
(setf paren-reader-reader): Internal functions

C
cl-read-list: Exported functions
cl-read-right-paren: Internal functions
copy-paren-reader: Internal functions

D
delete-all-paren-readers: Exported functions
delete-paren-reader: Exported functions

F
fallback-indicator-upcase: Internal functions
find-paren-reader: Internal functions
find-paren-reader-by-name: Internal functions
funcallable-p: Internal functions
Function, (setf paren-reader-name): Internal functions
Function, (setf paren-reader-predicate): Internal functions
Function, (setf paren-reader-reader): Internal functions
Function, cl-read-list: Exported functions
Function, cl-read-right-paren: Internal functions
Function, copy-paren-reader: Internal functions
Function, delete-all-paren-readers: Exported functions
Function, delete-paren-reader: Exported functions
Function, fallback-indicator-upcase: Internal functions
Function, find-paren-reader: Internal functions
Function, find-paren-reader-by-name: Internal functions
Function, funcallable-p: Internal functions
Function, illusion-read-list: Internal functions
Function, illusion-read-right-paren: Internal functions
Function, make-paren-reader: Internal functions
Function, paren-reader-name: Internal functions
Function, paren-reader-name-matcher: Internal functions
Function, paren-reader-p: Internal functions
Function, paren-reader-predicate: Internal functions
Function, paren-reader-reader: Internal functions
Function, read-indicator-preserve-case: Internal functions
Function, set-indicator-mode: Exported functions
Function, set-paren-reader: Exported functions

I
illusion-read-list: Internal functions
illusion-read-right-paren: Internal functions

M
Macro, with-reader-case: Exported macros
make-paren-reader: Internal functions

P
paren-reader-name: Internal functions
paren-reader-name-matcher: Internal functions
paren-reader-p: Internal functions
paren-reader-predicate: Internal functions
paren-reader-reader: Internal functions

R
read-indicator-preserve-case: Internal functions

S
set-indicator-mode: Exported functions
set-paren-reader: Exported functions

W
with-reader-case: Exported macros

Jump to:   (  
C   D   F   I   M   P   R   S   W  

Next: , Previous: , Up: Indexes   [Contents][Index]

A.3 Variables

Jump to:   *   +  
N   P   R   S  
Index Entry  Section

*
*in-list-p*: Internal special variables
*indicator-fallback*: Internal special variables
*indicator-reader*: Internal special variables
*paren-readers*: Internal special variables

+
+empty-list+: Internal special variables

N
name: Internal structures

P
predicate: Internal structures

R
reader: Internal structures

S
Slot, name: Internal structures
Slot, predicate: Internal structures
Slot, reader: Internal structures
Special Variable, *in-list-p*: Internal special variables
Special Variable, *indicator-fallback*: Internal special variables
Special Variable, *indicator-reader*: Internal special variables
Special Variable, *paren-readers*: Internal special variables
Special Variable, +empty-list+: Internal special variables

Jump to:   *   +  
N   P   R   S  

Previous: , Up: Indexes   [Contents][Index]

A.4 Data types

Jump to:   I   P   S  
Index Entry  Section

I
illusion: The illusion system
illusion: The illusion package

P
Package, illusion: The illusion package
paren-reader: Internal structures

S
Structure, paren-reader: Internal structures
System, illusion: The illusion system

Jump to:   I   P   S