├── .gitignore ├── src ├── specials.lisp ├── types.lisp ├── packages.lisp └── operators.lisp ├── contrib ├── annot.lisp ├── anonfun.lisp ├── markup.lisp ├── interpol.lisp ├── clsql.lisp └── fare-quasiquote.lisp ├── cl-syntax-fare-quasiquote.asd ├── cl-syntax-clsql.asd ├── cl-syntax-annot.asd ├── cl-syntax-markup.asd ├── cl-syntax-anonfun.asd ├── cl-syntax-interpol.asd ├── cl-syntax.asd └── README.markdown /.gitignore: -------------------------------------------------------------------------------- 1 | *.fasl 2 | *.dx64fsl 3 | *.dx32fsl 4 | *.lx64fsl 5 | *.x86f 6 | -------------------------------------------------------------------------------- /src/specials.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-syntax) 2 | 3 | (defvar *standard-package-syntax-name* (symbol-name :syntax)) 4 | -------------------------------------------------------------------------------- /contrib/annot.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | 3 | (syntax:define-package-syntax :cl-annot 4 | (:merge :standard) 5 | (:macro-char #\@ #'cl-annot.syntax:annotation-syntax-reader)) 6 | -------------------------------------------------------------------------------- /contrib/anonfun.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | 3 | (syntax:define-package-syntax :cl-anonfun 4 | (:merge :standard) 5 | (:dispatch-macro-char #\# #\% #'cl-anonfun::fn-reader)) 6 | -------------------------------------------------------------------------------- /contrib/markup.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | 3 | (syntax:define-package-syntax :cl-markup 4 | (:merge :standard) 5 | (:dispatch-macro-char #\# #\M #'cl-markup::markup-reader)) 6 | -------------------------------------------------------------------------------- /contrib/interpol.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | 3 | (syntax:define-package-syntax :cl-interpol 4 | (:merge :standard) 5 | (:dispatch-macro-char #\# #\? #'cl-interpol::interpol-reader)) 6 | -------------------------------------------------------------------------------- /src/types.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-syntax) 2 | 3 | (deftype syntax () 'readtable) 4 | 5 | (deftype syntax-designator () 6 | '(or syntax 7 | package-designator 8 | named-readtable-designator)) 9 | -------------------------------------------------------------------------------- /contrib/clsql.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | 3 | (syntax:define-package-syntax :clsql 4 | (:merge :standard) 5 | (:macro-char #\[ #'clsql-sys::sql-reader-open) 6 | (:macro-char #\] (cl:get-macro-character #\)))) 7 | -------------------------------------------------------------------------------- /cl-syntax-fare-quasiquote.asd: -------------------------------------------------------------------------------- 1 | (asdf:defsystem :cl-syntax-fare-quasiquote 2 | :version "0.1" 3 | :author "Tomohiro Matsuyama" 4 | :license "LLGPL" 5 | :description "cl-syntax support for fare-quasiquote" 6 | :depends-on (:cl-syntax :fare-quasiquote) 7 | :components ((:file "contrib/fare-quasiquote"))) 8 | -------------------------------------------------------------------------------- /contrib/fare-quasiquote.lisp: -------------------------------------------------------------------------------- 1 | (in-package :fare-quasiquote) 2 | 3 | (syntax:defsyntax fare-quasiquote-mixin 4 | (:macro-char #\` #'read-read-time-backquote) 5 | (:macro-char #\, #'read-comma) 6 | (:macro-char #\# :dispatch) 7 | (:dispatch-macro-char #\# #\( #'read-hash-paren)) 8 | 9 | (syntax:define-package-syntax :fare-quasiquote 10 | (:fuze :standard fare-quasiquote-mixin)) 11 | -------------------------------------------------------------------------------- /cl-syntax-clsql.asd: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | 3 | (defpackage :cl-syntax-clsql-asd 4 | (:use :cl :asdf)) 5 | (in-package :cl-syntax-clsql-asd) 6 | 7 | (defsystem :cl-syntax-clsql 8 | :version "0.1" 9 | :author "Tomohiro Matsuyama" 10 | :license "LLGPL" 11 | :description "CL-Syntax Reader Syntax for CLSQL" 12 | :depends-on (:cl-syntax :clsql) 13 | :components ((:file "contrib/clsql"))) 14 | -------------------------------------------------------------------------------- /cl-syntax-annot.asd: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | 3 | (defpackage :cl-syntax-annot-asd 4 | (:use :cl :asdf)) 5 | (in-package :cl-syntax-annot-asd) 6 | 7 | (defsystem :cl-syntax-annot 8 | :version "0.2" 9 | :author "Tomohiro Matsuyama" 10 | :license "LLGPL" 11 | :description "CL-Syntax Reader Syntax for cl-annot" 12 | :depends-on (:cl-syntax :cl-annot) 13 | :components ((:file "contrib/annot"))) 14 | -------------------------------------------------------------------------------- /cl-syntax-markup.asd: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | 3 | (defpackage :cl-syntax-markup-asd 4 | (:use :cl :asdf)) 5 | (in-package :cl-syntax-markup-asd) 6 | 7 | (defsystem :cl-syntax-markup 8 | :version "0.2" 9 | :author "Tomohiro Matsuyama" 10 | :license "LLGPL" 11 | :description "CL-Syntax Reader Syntax for CL-Markup" 12 | :depends-on (:cl-syntax :cl-markup) 13 | :components ((:file "contrib/markup"))) 14 | -------------------------------------------------------------------------------- /cl-syntax-anonfun.asd: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | 3 | (defpackage :cl-syntax-anonfun-asd 4 | (:use :cl :asdf)) 5 | (in-package :cl-syntax-anonfun-asd) 6 | 7 | (defsystem :cl-syntax-anonfun 8 | :version "0.2" 9 | :author "Tomohiro Matsuyama" 10 | :license "LLGPL" 11 | :description "CL-Syntax Reader Syntax for cl-anonfun" 12 | :depends-on (:cl-syntax :cl-anonfun) 13 | :components ((:file "contrib/anonfun"))) 14 | -------------------------------------------------------------------------------- /cl-syntax-interpol.asd: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | 3 | (defpackage :cl-syntax-interpol-asd 4 | (:use :cl :asdf)) 5 | (in-package :cl-syntax-interpol-asd) 6 | 7 | (defsystem :cl-syntax-interpol 8 | :version "0.2" 9 | :author "Tomohiro Matsuyama" 10 | :license "LLGPL" 11 | :description "CL-Syntax Reader Syntax for CL-INTERPOL" 12 | :depends-on (:cl-syntax :cl-interpol) 13 | :components ((:file "contrib/interpol"))) 14 | -------------------------------------------------------------------------------- /src/packages.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | 3 | (defpackage :cl-syntax 4 | (:nicknames :syntax) 5 | (:use :cl :named-readtables) 6 | (:import-from :trivial-types 7 | #:package-designator 8 | #:proper-list) 9 | (:export #:syntax 10 | #:syntax-designator 11 | #:defsyntax 12 | #:define-package-syntax 13 | #:find-syntax 14 | #:use-syntax)) 15 | -------------------------------------------------------------------------------- /cl-syntax.asd: -------------------------------------------------------------------------------- 1 | (in-package :cl-user) 2 | 3 | (defpackage :cl-syntax-asd 4 | (:use :cl :asdf)) 5 | (in-package :cl-syntax-asd) 6 | 7 | (defsystem :cl-syntax 8 | :version "0.3" 9 | :author "Tomohiro Matsuyama" 10 | :license "LLGPL" 11 | :description "Reader Syntax Coventions for Common Lisp and SLIME" 12 | :depends-on (:trivial-types 13 | :named-readtables) 14 | :components ((:module "src" 15 | :serial t 16 | :components ((:file "packages") 17 | (:file "specials") 18 | (:file "types") 19 | (:file "operators"))))) 20 | -------------------------------------------------------------------------------- /src/operators.lisp: -------------------------------------------------------------------------------- 1 | (in-package :cl-syntax) 2 | 3 | (eval-when (:compile-toplevel :load-toplevel :execute) 4 | (defun package-syntax-name (package) 5 | (intern *standard-package-syntax-name* package))) 6 | 7 | (defun get-options (name) 8 | "Get the options list for name, if it is available." 9 | (get (cond ((typep name 'syntax) nil) 10 | ((and (typep name 'package-designator) 11 | (find-package name)) 12 | (package-syntax-name name)) 13 | (t name)) 14 | :options)) 15 | 16 | (defmacro defsyntax (name &body options) 17 | `(progn 18 | (setf (get ',name :options) ',options) 19 | (defvar ,name (defreadtable ,name ,@options)))) 20 | 21 | (defmacro define-package-syntax (&body (package . options)) 22 | (unless (typep package 'package-designator) 23 | (push package options) 24 | (setq package *package*)) 25 | `(defsyntax ,(package-syntax-name package) 26 | ,@options)) 27 | 28 | (defun find-syntax (name) 29 | (declare (syntax-designator name)) 30 | (cond ((typep name 'syntax) name) 31 | ((and (typep name 'package-designator) 32 | (find-package name)) 33 | (find-readtable (package-syntax-name name))) 34 | (t (find-readtable name)))) 35 | 36 | (defun %use-syntax (names) 37 | (declare (type (or syntax-designator 38 | (proper-list syntax-designator)) 39 | names)) 40 | (unless (listp names) 41 | (setq names (list names))) 42 | (setq *readtable* (copy-readtable)) 43 | (loop for name in names 44 | for syntax = (find-syntax name) 45 | for options = (get-options name) 46 | if (assoc :fuze (if (consp (car options)) options (cdr options))) do 47 | (handler-bind ((named-readtables:reader-macro-conflict 48 | (lambda (_) (declare (ignore _)) 49 | (invoke-restart 'continue)))) 50 | (merge-readtables-into *readtable* syntax) ) 51 | else do 52 | (merge-readtables-into *readtable* syntax) ) 53 | (when (find-package :swank) 54 | (named-readtables::%frob-swank-readtable-alist *package* *readtable*))) 55 | 56 | (defmacro use-syntax (name) 57 | `(eval-when (:compile-toplevel :load-toplevel :execute) 58 | (%use-syntax ,name))) 59 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | CL-SYNTAX 2 | ========= 3 | 4 | CL-SYNTAX provides Reader Syntax Coventions for Common Lisp and SLIME. 5 | 6 | Overview 7 | -------- 8 | 9 | The well-known problem about reader macros is that SLIME can't handle 10 | these reader macros correctly. Consider the following code: 11 | 12 | (defpackage foo 13 | (:use :cl)) 14 | (in-package :foo) 15 | (cl-interpol:enable-interpol-syntax) 16 | 17 | (list #?"Current Time: ${(get-universal-time)}") 18 | 19 | By calling `cl-interpol:enable-interpol-syntax`, we can use a reader 20 | macro `#?`. However, actually, when we try to evaluate the last line, 21 | SLIME reports an error there is no such the reader macro `#?`. This 22 | error might be raised on most of Common Lisp implementations except 23 | SBCL. 24 | 25 | The goal of CL-SYNTAX is to solve these problems. Instead of using 26 | procedurally defined functions such like `enable-something-syntax`, we 27 | introduce syntactically and declaratively defined syntax data 28 | structure. With this data structure, we can handle `*readtable*` 29 | correctly and readtables of swank server. 30 | 31 | Usage 32 | ----- 33 | 34 | ### Macro: `defsyntax` 35 | 36 | defsyntax name &body options 37 | 38 | `defsyntax` defines a new syntax. `name` is a symbol and `options` is 39 | a list of option. 40 | 41 | If option formed `(:macro-character char fn &optional 42 | non-terminating-p)`, the syntax engine will call `set-macro-character` 43 | with the arguments when enabling the syntax. 44 | 45 | If option formed `(:dispatch-macro-character disp-ch sub-ch fn)`, the 46 | syntax engine will call `set-dispatch-macro-character` with the 47 | arguments when enabling the syntax. 48 | 49 | Here is an example: 50 | 51 | ;; Define cl-interpol syntax 52 | (defsyntax interpol-syntax 53 | (:dispatch-macro-character #\# #\? #'cl-interpol::interpol-reader)) 54 | 55 | This code is equivalent to: 56 | 57 | (defvar interpol-syntax 58 | `((:dispatch-macro-character #\# #\? ,#'cl-interpol::interpol-reader))) 59 | 60 | If you don't want to use `defsyntax` in some reasons, use this code 61 | instead. 62 | 63 | ### Macro: `use-syntax` 64 | 65 | use-syntax syntax-to-use 66 | 67 | `use-syntax` enables the syntax specified by 68 | `syntax-to-use`. `syntax-to-use` is a symbol which is defined by 69 | `defsyntax`. 70 | 71 | Here is an example: 72 | 73 | ;; use cl-interpol syntax defined before 74 | (use-syntax interpol-syntax) 75 | 76 | ---- 77 | 78 | Copyright (C) 2011-2015 Tomohiro Matsuyama <> 79 | --------------------------------------------------------------------------------