https://github.com/s-expressionists/eclector
A portable Common Lisp reader that is highly customizable, can recover from errors and can return concrete syntax trees
https://github.com/s-expressionists/eclector
common-lisp concrete-syntax-trees error-recovery extensible portable reader
Last synced: about 2 months ago
JSON representation
A portable Common Lisp reader that is highly customizable, can recover from errors and can return concrete syntax trees
- Host: GitHub
- URL: https://github.com/s-expressionists/eclector
- Owner: s-expressionists
- License: bsd-2-clause
- Created: 2018-01-20T17:25:29.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2024-08-19T20:03:28.000Z (9 months ago)
- Last Synced: 2025-02-10T01:38:41.353Z (3 months ago)
- Topics: common-lisp, concrete-syntax-trees, error-recovery, extensible, portable, reader
- Language: Common Lisp
- Homepage: https://s-expressionists.github.io/Eclector/
- Size: 8.77 MB
- Stars: 111
- Watchers: 13
- Forks: 9
- Open Issues: 12
-
Metadata Files:
- Readme: README.md
- Changelog: NEWS
- License: LICENSE
Awesome Lists containing this project
README
# Eclector: A portable and extensible Common Lisp Reader
## Introduction
The `eclector` system provides a portable implementation of a reader
following the Common Lisp specification.**``eclector`` is under active development. Its ASDF system structure,
package structure, exported symbols and protocols may change at any
time but are becoming less and less likely to do so in incompatible
ways. Consult the NEWS file or the "Changelog" section of the manual
for lists of changes in specific versions.**This document only gives a very brief overview and highlights some
features. Proper documentation can be found in the `documentation`
directory.## Usage Overview and Highlights
### Basics
In the simplest case, the eclector reader can be used like any Common
Lisp reader:* ```lisp
(with-input-from-string (stream "(1 2 3)")
(eclector.reader:read stream))
; => (1 2 3)
```* ```lisp
(eclector.reader:read-from-string "#C(1 1)")
; => #C(1 1) 7
```### Error Recovery
In contrast to many other reader implementations, eclector can recover
from most errors in the input supplied to it and continue
reading. This capability is realized as a restart named
`eclector.reader:recover` which is established whenever an error is
signaled for which a recovery strategy is available.For example, the following code
```lisp
(handler-bind ((error (lambda (condition)
(let ((restart (find-restart 'eclector.reader:recover)))
(format t "Recovering from error:~%~2@T~A~%using~%~2@T~A~%"
condition restart))
(eclector.reader:recover))))
(eclector.reader:read-from-string "`(::foo ,"))
```produces this:
```
Recovering from error:
A symbol token must not start with two package markers as in ::name.
using
Treat the character as if it had been escaped.
Recovering from error:
While reading unquote, expected an object when input ended.
using
Use NIL in place of the missing object.
Recovering from error:
While reading list, expected the character ) when input ended.
using
Return a list of the already read elements.
; => (ECLECTOR.READER:QUASIQUOTE (:FOO (ECLECTOR.READER:UNQUOTE NIL))) 9
```indicating that eclector recovered from multiple errors and consumed
all input. Of course, the returned expression is likely unsuitable for
evaluation, but recovery is useful for detecting multiple errors in
one go and performing further processing such as static analysis.### Custom Parse Results
Using features provided in the `eclector.parse-result` package,
the reader can produce parse results controlled by the client,
optionally including source tracking and representation of skipped
input (due to e.g. comments and reader conditionals):```lisp
(defclass my-client (eclector.parse-result:parse-result-client)
())(defmethod eclector.parse-result:make-expression-result
((client my-client) (result t) (children t) (source t))
(list :result result :source source :children children))(defmethod eclector.parse-result:make-skipped-input-result
((client my-client) (stream t) (reason t) (children t) (source t))
(list :reason reason :source source :children children))(with-input-from-string (stream "(1 #|comment|# \"string\")")
(eclector.parse-result:read (make-instance 'my-client) stream))
```### Concrete Syntax Trees
The `eclector.concrete-syntax-tree` system provides a variant of the
`eclector` reader that produces instances of the concrete syntax tree
classes provided by the [concrete syntax tree library]:```lisp
(eclector.concrete-syntax-tree:read-from-string "(1 2 3)")
; => # 7 NIL
```[concrete syntax tree library]: https://github.com/s-expressionists/Concrete-Syntax-Tree