Parendown
Parendown adds weak opening parentheses to Racket in the form of a language extension. A more extensive overview of Parendown’s uses can be found in the README at GitHub.
1 The Parendown Language Extension
#lang parendown | package: parendown-lib |
The parendown language is a language extension. To use it, specify another language after parendown on the #lang line. That language will have its readtable extended with a #/ syntax that behaves according to parendown-readtable-handler.
#lang parendown racket/base (displayln #/string-append "Hello, " "world!")
2 The parendown/slash Language Extension
#lang parendown/slash | package: parendown-lib |
The parendown/slash language is a language extension like parendown, but with a more streamlined syntax. To use it, specify another language after parendown/slash on the #lang line. That language will have its readtable extended with a / syntax that behaves according to parendown-readtable-handler.
This acts as a non-symbol-terminating readtable extension, so symbols like syntax/parse and any/c will be usable in the usual way. In order to make sure a / weak opening paren isn’t treated as part of the preceding symbol, it may be necessary to use whitespace in between.
#lang parendown/slash racket/base (displayln /string-append "Hello, " "world!")
Symbols beginning with /, such as the division operator /, may be more difficult to use with this extension in place. However, they can still be referred to using the alternative notations \/... and |/...|. In the case of division, that means writing \/ or |/|.
3 Parendown as a Library
(require parendown) | package: parendown-lib |
There is also a parendown module which lets Racket code use some features of Parendown even when they aren’t using the #lang directly.
syntax
(pd slash-symbol stx ...)
For instance, the form
(pd / begin (displayln / string-append "Hello, " "world!") (displayln / string-append "I can't use " "division!"))
expands to this:
(begin (displayln (string-append "Hello, " "world!")) (displayln (string-append "I can't use " "division!")))
An occurrence of a cons cell within the pd call syntax must have a set of scopes that’s equal to or a superset of the set of scopes on the (pd ...) call itself, or that cons cell (and all its contents) will be treated as a miscellaneous datum, rather than further traversed to find slash-symbol occurrences inside.
An occurrence of slash-symbol within the pd call syntax must have a set of scopes that’s equal to or a superset of the set of scopes on the binding occurrence of slash-symbol, or it’ll be treated as a miscellaneous datum.
These behaviors ensure that a pd call that occurs within a macro’s expansion template can have everyday Racket expressions interpolated into it by the template, without misinterpreting those expressions’ syntactic structure.
syntax
(pd (stx ...))
This is usually the result of the other case of pd. For instance, the form
(pd / begin (displayln / string-append "Hello, " "world!") (pd / displayln / string-append "I can't use " "division!"))
expands to this:
(begin (displayln (string-append "Hello, " "world!")) (pd (displayln (string-append "I can't use " "division!"))))
This contains another occurrence of pd, and this time, the code
(pd (displayln (string-append "I can't use " "division!")))
expands to this:
(displayln (string-append "I can't use " "division!"))
This behavior makes it so occurrences of the pd form can be generously added wherever they’re suspected to be needed, without causing conflicts with each other.
An occurrence of a cons cell within the pd call syntax must have a set of scopes that’s equal to or a superset of the set of scopes on the (pd ...) call itself. This behavior ensures that a pd call that occurs within a macro’s expansion template can have everyday Racket expressions interpolated into it by the template, without misinterpreting those expressions’ syntactic structure.
procedure
(parendown-readtable-handler name in) → any/c
name : char? in : input-port?
(parendown-readtable-handler name in src line col pos) → any/c name : char? in : input-port? src : any/c line : (or/c #f exact-positive-integer?) col : (or/c #f exact-nonnegative-integer?) pos : (or/c #f exact-positive-integer?)
When the terminating character is ] or }, the resulting list’s paren-shape syntax property is set to #\[ or #\{, respectively.
This readtable handler is sensitive to the read-accept-dot and read-accept-infix-dot parameters at the time the handler is invoked. This functionality of Parendown should be considered unstable, since it isn’t quite the same as what (, [, and { do on contemporary versions of Racket. Those characters’ default handlers are sensitive to the values of those parameters at the time the read is originally started, not the time they are encountered during the read. For instance, in contemprary versions of Racket, if (read-accept-dot) is #t at the time read is first called and then a custom reader syntax causes it to be set to #f, a subsequent occurrence of ( in the same read will be processed as though (read-accept-dot) were still #t.
procedure
(parendown-color-lexer weak-open-paren original-get-info) → procedure? weak-open-paren : (and/c string? immutable?) original-get-info : (-> any/c any/c any)