| 1 | (in-package :named-readtables) |
|---|
| 2 | |
|---|
| 3 | (eval-when (:compile-toplevel :load-toplevel :execute) |
|---|
| 4 | (use-package :mgl-pax)) |
|---|
| 5 | |
|---|
| 6 | (defsection @named-readtables-manual (:title "Named Readtables Manual") |
|---|
| 7 | (named-readtables asdf:system) |
|---|
| 8 | (@named-readtables-introduction section) |
|---|
| 9 | (@named-readtables-overview section) |
|---|
| 10 | (@named-readtables-reference section)) |
|---|
| 11 | |
|---|
| 12 | (defsection @named-readtables-introduction (:title "Introduction") |
|---|
| 13 | "Named-Readtables is a library that provides a namespace for |
|---|
| 14 | readtables akin to the already-existing namespace of packages. In |
|---|
| 15 | particular: |
|---|
| 16 | |
|---|
| 17 | * you can associate readtables with names, and retrieve |
|---|
| 18 | readtables by names; |
|---|
| 19 | |
|---|
| 20 | * you can associate source files with readtable names, and be |
|---|
| 21 | sure that the right readtable is active when compiling/loading |
|---|
| 22 | the file; |
|---|
| 23 | |
|---|
| 24 | * similiarly, your development environment now has a chance to |
|---|
| 25 | automatically determine what readtable should be active while |
|---|
| 26 | processing source forms on interactive commands. (E.g. think of |
|---|
| 27 | `C-c C-c` in Slime (yet to be done)) |
|---|
| 28 | |
|---|
| 29 | It follows that Named-Readtables is a facility for using readtables in |
|---|
| 30 | a localized way. |
|---|
| 31 | |
|---|
| 32 | Additionally, it also attempts to become a facility for using |
|---|
| 33 | readtables in a _modular_ way. In particular: |
|---|
| 34 | |
|---|
| 35 | * it provides a macro to specify the content of a readtable at a |
|---|
| 36 | glance; |
|---|
| 37 | |
|---|
| 38 | * it makes it possible to use multiple inheritance between readtables." |
|---|
| 39 | (@named-readtables-links section) |
|---|
| 40 | (@named-readtables-acknowledgements section)) |
|---|
| 41 | |
|---|
| 42 | (defsection @named-readtables-links (:title "Links") |
|---|
| 43 | "Here is the [official repository][named-readtables-repo] and the |
|---|
| 44 | [HTML documentation][named-readtables-doc] for the latest version. |
|---|
| 45 | |
|---|
| 46 | [named-readtables-repo]: https://github.com/melisgl/named-readtables |
|---|
| 47 | [named-readtables-doc]: http://melisgl.github.io/mgl-pax-world/named-readtables-manual.html") |
|---|
| 48 | |
|---|
| 49 | (defsection @named-readtables-acknowledgements (:title "Acknowledgements") |
|---|
| 50 | "Thanks to Robert Goldman for making me want to write this library. |
|---|
| 51 | |
|---|
| 52 | Thanks to Stephen Compall, Ariel Badichi, David Lichteblau, Bart |
|---|
| 53 | Botta, David Crawford, and Pascal Costanza for being early adopters, |
|---|
| 54 | providing comments and bugfixes.") |
|---|
| 55 | |
|---|
| 56 | (defsection @named-readtables-overview (:title "Overview") |
|---|
| 57 | (@named-readtables-api-notes section) |
|---|
| 58 | (@named-readtables-api-idiosyncrasies section) |
|---|
| 59 | (@named-readtables-preregistered section) |
|---|
| 60 | (@named-readtables-examples section)) |
|---|
| 61 | |
|---|
| 62 | (defsection @named-readtables-api-notes (:title "Notes on the API" :export nil) |
|---|
| 63 | "The API heavily imitates the API of packages. This has the nice |
|---|
| 64 | property that any experienced Common Lisper will take it up without |
|---|
| 65 | effort. |
|---|
| 66 | |
|---|
| 67 | DEFREADTABLE - DEFPACKAGE |
|---|
| 68 | |
|---|
| 69 | IN-READTABLE - IN-PACKAGE |
|---|
| 70 | |
|---|
| 71 | MERGE-READTABLES-INTO - USE-PACKAGE |
|---|
| 72 | |
|---|
| 73 | MAKE-READTABLE - MAKE-PACKAGE |
|---|
| 74 | |
|---|
| 75 | UNREGISTER-READTABLE - DELETE-PACKAGE |
|---|
| 76 | |
|---|
| 77 | RENAME-READTABLE - RENAME-PACKAGE |
|---|
| 78 | |
|---|
| 79 | FIND-READTABLE - FIND-PACKAGE |
|---|
| 80 | |
|---|
| 81 | READTABLE-NAME - PACKAGE-NAME |
|---|
| 82 | |
|---|
| 83 | LIST-ALL-NAMED-READTABLES - LIST-ALL-PACKAGES") |
|---|
| 84 | |
|---|
| 85 | (defsection @named-readtables-api-idiosyncrasies |
|---|
| 86 | (:title "Important API idiosyncrasies" :export nil) |
|---|
| 87 | "There are three major differences between the API of Named-Readtables, |
|---|
| 88 | and the API of packages. |
|---|
| 89 | |
|---|
| 90 | 1. Readtable names are symbols not strings. |
|---|
| 91 | |
|---|
| 92 | Time has shown that the fact that packages are named by strings |
|---|
| 93 | causes severe headache because of the potential of package names |
|---|
| 94 | colliding with each other. |
|---|
| 95 | |
|---|
| 96 | Hence, readtables are named by symbols lest to make the |
|---|
| 97 | situation worse than it already is. Consequently, readtables |
|---|
| 98 | named `CL-ORACLE:SQL-SYNTAX` and `CL-MYSQL:SQL-SYNTAX` can |
|---|
| 99 | happily coexist next to each other. Or, taken to an extreme, |
|---|
| 100 | `SCHEME:SYNTAX` and `ELISP:SYNTAX`. |
|---|
| 101 | |
|---|
| 102 | If, for example to duly signify the importance of your cool |
|---|
| 103 | readtable hack, you really think it deserves a global name, you |
|---|
| 104 | can always resort to keywords. |
|---|
| 105 | |
|---|
| 106 | 2. The inheritance is resolved statically, not dynamically. |
|---|
| 107 | |
|---|
| 108 | A package that uses another package will have access to all the |
|---|
| 109 | other package's exported symbols, even to those that will be |
|---|
| 110 | added after its definition. I.e. the inheritance is resolved at |
|---|
| 111 | run-time, that is dynamically. |
|---|
| 112 | |
|---|
| 113 | Unfortunately, we cannot do the same for readtables in a |
|---|
| 114 | portable manner. |
|---|
| 115 | |
|---|
| 116 | Therefore, we do not talk about \"using\" another readtable but |
|---|
| 117 | about \"merging\" the other readtable's definition into the |
|---|
| 118 | readtable we are going to define. I.e. the inheritance is |
|---|
| 119 | resolved once at definition time, that is statically. |
|---|
| 120 | |
|---|
| 121 | (Such merging can more or less be implemented portably albeit at |
|---|
| 122 | a certain cost. Most of the time, this cost manifests itself at |
|---|
| 123 | the time a readtable is defined, i.e. once at compile-time, so |
|---|
| 124 | it may not bother you. Nonetheless, we provide extra support for |
|---|
| 125 | Sbcl, ClozureCL, and AllegroCL at the moment. Patches for your |
|---|
| 126 | implementation of choice are welcome, of course.) |
|---|
| 127 | |
|---|
| 128 | 3. DEFREADTABLE does not have compile-time effects. |
|---|
| 129 | |
|---|
| 130 | If you define a package via DEFPACKAGE, you can make that |
|---|
| 131 | package the currently active package for the subsequent |
|---|
| 132 | compilation of the same file via IN-PACKAGE. The same is, |
|---|
| 133 | however, not true for DEFREADTABLE and IN-READTABLE for the |
|---|
| 134 | following reason: |
|---|
| 135 | |
|---|
| 136 | It's unlikely that the need for special reader-macros arises for |
|---|
| 137 | a problem which can be solved in just one file. Most often, |
|---|
| 138 | you're going to define the reader macro functions, and set up |
|---|
| 139 | the corresponding readtable in an extra file. |
|---|
| 140 | |
|---|
| 141 | If DEFREADTABLE had compile-time effects, you'd have to wrap |
|---|
| 142 | each definition of a reader-macro function in an EVAL-WHEN to |
|---|
| 143 | make its definition available at compile-time. Because that's |
|---|
| 144 | simply not the common case, DEFREADTABLE does not have a |
|---|
| 145 | compile-time effect. |
|---|
| 146 | |
|---|
| 147 | If you want to use a readtable within the same file as its |
|---|
| 148 | definition, wrap the DEFREADTABLE and the reader-macro function |
|---|
| 149 | definitions in an explicit EVAL-WHEN.") |
|---|
| 150 | |
|---|
| 151 | (defsection @named-readtables-preregistered (:title "Preregistered Readtables" |
|---|
| 152 | :export nil) |
|---|
| 153 | "- NIL, :STANDARD, and :COMMON-LISP designate the |
|---|
| 154 | _standard readtable_. |
|---|
| 155 | |
|---|
| 156 | - :MODERN designates a _case-preserving_ _standard-readtable_. |
|---|
| 157 | |
|---|
| 158 | - :CURRENT designates the _current readtable_.") |
|---|
| 159 | |
|---|
| 160 | (defsection @named-readtables-examples (:title "Examples" :export nil) |
|---|
| 161 | "```commonlisp |
|---|
| 162 | (defreadtable elisp:syntax |
|---|
| 163 | (:merge :standard) |
|---|
| 164 | (:macro-char #\\? #'elisp::read-character-literal t) |
|---|
| 165 | (:macro-char #\\[ #'elisp::read-vector-literal t) |
|---|
| 166 | ... |
|---|
| 167 | (:case :preserve)) |
|---|
| 168 | |
|---|
| 169 | (defreadtable scheme:syntax |
|---|
| 170 | (:merge :standard) |
|---|
| 171 | (:macro-char #\\[ #'(lambda (stream char) |
|---|
| 172 | (read-delimited-list #\\] stream))) |
|---|
| 173 | (:macro-char #\\# :dispatch) |
|---|
| 174 | (:dispatch-macro-char #\\# #\\t #'scheme::read-#t) |
|---|
| 175 | (:dispatch-macro-char #\\# #\\f #'scheme::read-#f) |
|---|
| 176 | ... |
|---|
| 177 | (:case :preserve)) |
|---|
| 178 | |
|---|
| 179 | (in-readtable elisp:syntax) |
|---|
| 180 | |
|---|
| 181 | ... |
|---|
| 182 | |
|---|
| 183 | (in-readtable scheme:syntax) |
|---|
| 184 | |
|---|
| 185 | ... |
|---|
| 186 | ```") |
|---|
| 187 | |
|---|
| 188 | (defsection @named-readtables-reference (:title "Reference") |
|---|
| 189 | (defreadtable macro) |
|---|
| 190 | (in-readtable macro) |
|---|
| 191 | (make-readtable function) |
|---|
| 192 | (merge-readtables-into function) |
|---|
| 193 | (find-readtable function) |
|---|
| 194 | (ensure-readtable function) |
|---|
| 195 | (rename-readtable function) |
|---|
| 196 | (readtable-name function) |
|---|
| 197 | (register-readtable function) |
|---|
| 198 | (unregister-readtable function) |
|---|
| 199 | (copy-named-readtable function) |
|---|
| 200 | (list-all-named-readtables function) |
|---|
| 201 | (named-readtable-designator type) |
|---|
| 202 | (reader-macro-conflict condition) |
|---|
| 203 | (readtable-does-already-exist condition) |
|---|
| 204 | (readtable-does-not-exist condition)) |
|---|
| 205 | |
|---|
| 206 | |
|---|
| 207 | ;;;; Generating own docs |
|---|
| 208 | |
|---|
| 209 | (defun update-readmes () |
|---|
| 210 | (with-open-file (stream (asdf:system-relative-pathname :named-readtables |
|---|
| 211 | "README.md") |
|---|
| 212 | :direction :output |
|---|
| 213 | :if-does-not-exist :create |
|---|
| 214 | :if-exists :supersede) |
|---|
| 215 | (document @named-readtables-manual :stream stream) |
|---|
| 216 | (print-markdown-footer stream)) |
|---|
| 217 | (with-open-file (stream (asdf:system-relative-pathname :named-readtables |
|---|
| 218 | "README") |
|---|
| 219 | :direction :output |
|---|
| 220 | :if-does-not-exist :create |
|---|
| 221 | :if-exists :supersede) |
|---|
| 222 | (describe @named-readtables-manual stream) |
|---|
| 223 | (print-markdown-footer stream))) |
|---|
| 224 | |
|---|
| 225 | (defun print-markdown-footer (stream) |
|---|
| 226 | (format stream "~%* * *~%") |
|---|
| 227 | (format stream "###### \\[generated by ~ |
|---|
| 228 | [MGL-PAX](https://github.com/melisgl/mgl-pax)\\]~%")) |
|---|
| 229 | |
|---|
| 230 | #| |
|---|
| 231 | |
|---|
| 232 | (update-readmes) |
|---|
| 233 | |
|---|
| 234 | |# |
|---|