TOC »
srfi-105
Curly infix expressions. For more information, see SRFI-105.
Modules
srfi-105
The core srfi as specified in SRFI-105. Note that the srfi does not on its own handle mixed operators or square-bracket neoteric expressions.
Notes
Dot notation
The special dot notation described in the original srfi is not supported, meaning the following examples do not work with this implemenation:
- {read(. options)} ⇒ (read . options)
- {a . z} ⇒ ($nfx$ a . z)
This is because chicken reserves the . symbol for special use, and I didn't feel it would be consistent (or worth jumping through hoops) to support it inside curly braces.
Neoteric expressions
In part due to the way that Chicken's reader ##sys#read is implemented, and in part becasue of the way neoteric-expression (n-expression) support is implemented, n-expressions inside curly braces (e.g. f(x)) are only partially supported. In particular, they will work as long as the n-expression is not nested directly within a lisp expression. However, this can be worked around by adding curly brackets directly around the n-expression.
To show what this means, here are some (non-exhaustive) examples:
DOES work - simple n-expressions:
- {f(x)} ⇒ (f x)
- {f(x) + 1} ⇒ (+ (f x) 1)
- {3 + f(x) + g(x)} ⇒ (+ 3 (f x) (g x))
DOES work - nested/chained n-expressions:
- DOES work: {f(x)(y)(z)} ⇒ (((f x) y) z)
- DOES work: {3 + 4 + f(x)(y)(z)} ⇒ (+ 3 4 (((f x) y) z))
- DOES work: {f(g(h(x)))} ⇒ (f (g (h x)))
- DOES work: {f(g(h(x))) * 5 * 3} ⇒ (* 5 3 (f (g (h x))))
- DOES work: {f(g(h(x)))(y)} ⇒ ((f (g (h x))) y)
- DOES work: {f(g{h(x) + 1})} ⇒ (f (g (+ (h x) 1)))
DOES NOT work - n-expressions nested inside lisp syntax:
- { (f (g h(x))) } ⇒ (f (g (h x))) - use { (f (g {h(x)})) } instead
- {#(1 2 f(a) 4)} ⇒ #(1 2 (f a) 4) - use {#(1 2 {f(a)} 4)} instead
- {(f #;g(x) h(x))} ⇒ (f (h x)) - no workaround available
- Any of the above working neoteric expressions within any lisp syntax - enclose them with additional curly brackets instead.
n-expression support is implemented by locally modifying the internal ##sys#read procedure which is not itself recursive, but rather uses an internal (and inaccesible) recursive read procedure. This means any modifications made to ##sys#read procedure cannot take effect inside lisp expressions, as the internal recursive read handles those and has no knowledge of the modifications.
The internal read procedure does however have knowledge of special read syntax, which is why this limitation can be 'escaped' with more curly bracket expressions.
This could potentially be worked around with a solid parser, but is a little out of the scope of this extension.
srfi-105.extra
Adds support for mixed operators and square bracket neoteric expressions. Importing this implies (import srfi-105), so one should not have to import both. $nfx$ as specified in the original SRFI document is implemented as syntax in order to be able to handle syntax operators like and, or, and some of the aliases defined in this module.
Usage
Upon importing this module, curly infix expressions with mixed operators as well as neoteric calls of the form x[a] should just work. Certain operators are handled specially by default. See mixed-operator-precedence for more information.
Notes
Unary operators in mixed expressions
"Loose" unary operators in mixed expressions are not supported. That is, something like {#t and not #f} should result in an error. To use unary operators, use lisp syntax ( {#t and (not #f)} ) or n-expressions {#t and not(#f)} .
Neoteric square bracket expressions
Square bracket n-expressions such as a[x] are handled using SRFI-123's ref*. See srfi-123 for more information.
Precedence
- mixed-operator-precedenceparameter
Defines the order of operations, or operator precedence, for supported operations. This should be a list of lists of symbols, each specifying a precedence group, ordered from highest to lowest precedence. Symbols are grouped with left-associativity by default. Instead of a symbol, (#:right symbol) can be used instead, indicating that symbol is an operator with right associativity.
If the first element of a group is the keyword #:comparison, the following members of that group should be treated as comparison operators that return a boolean, and are grouped as non-associative operators with and. For example, the group (#:comparison < >) implies that {1 > 3 < 4} will be grouped as (and (1 > 3) (3 > 4))
The special group (#:other) is a placeholder for any operators not present in (mixed-operator-precedence). These are grouped with left associativity. The parameter should contain at least this group, and is properly guarded as such.
The default roughly matches python's operator precedence:
'(((right: expt) (right: **)) (* / modulo % quotient remainder fx* fx/ fxmod fxrem fp* fp/) (+ - fx+ fx- fp+ fp-) (arithmetic-shift << >> fxshl fxshr) (bitwise-and & fxand) (bitwise-xor ^ fxxor) (bitwise-ior ior fxior) (other:) (comparison: < <= > >= = fx< fx<= fx> fx>= fx= fp< fp<= fp> fp>= fp=) (and) (or))
Aliases
These are provided because of the way the core srfi (unmixed operators) works. By default, something like {1 expt 3 expt 4} will not work. Since the srfi is associativity and precedence neutral, it will simply expand this to (expt 1 3 4) , which will result in an error since the expt procedure only takes 2 arguments.
Thus, most of the following are syntax wrappers for common infix operators whose chicken scheme implementation only takes two arguments. The macros handle more than two arguments with the correct associativity, and are fit for use in 'simple' (unmixed) curly infix expressions.
The procedure aliases simply provide common shorthand for some unary operators.
- (** . rest)syntax
Applies expt on all arguments right-associatively.
- (% . rest)syntax
Applies modulo on all arguments left-associatively.
- (<< . rest)syntax
Applies arithmetic-shift on all arguments left-associatively. Equivalent to a left shift if shift is positive, right shift if shift is negative.
- (>> . rest)syntax
Applies arithmetic-shift (with inverted direction) on all arguments left-associatively. Equivalent to a right shift if shift is positive, left shift if shift is negative.
- (^ . rest)syntax
Applies bitwise-xor on all arguments left-associatively.
- (ior . rest)syntax
Applies bitwise-ior on all arguments left-associatively.
- (& . rest)syntax
Applies bitwise-and on all arguments left-associatively.
- ~ argprocedure
An alias for bitwise-not.
- ~ argprocedure
An alias for boolean not.
Special symbols
In general, you shouldn't need to use the following directly, as curly expressions containing mixed operators or neoteric calls of the form x[a] will simply automatically expand into ($nfx$ ...) or ($bracket-apply$ x a), respectively.
- ($nfx$ . rest)syntax
Group the infix expression specified by the elements of rest according to mixed-operator-precedence.
- $bracket-apply$ obj iprocedure
An alias for SRFI-123's ref*.
Author
Reference implementation by David A. Wheeler and Alan Manual K. Gloria, Chicken-specific implementation and extras by Diego A. Mundo.
Repository
https://code.dieggsy.com/srfi-105
License
Copyright (C) 2012 David A. Wheeler and Alan Manuel K. Gloria. All Rights Reserved. Copyright (C) 2019 Diego A. Mundo
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Version History
- 0.1.6
- Add simpler and more robust neoteric expression support
- 0.1.5
- Rewrite curly expression reader more in accordance with reference
- 0.1.5
- Rewrite curly expression reader more in accordance with reference
- 0.1.4
- Temporarily drop neoteric expression support
- 0.1.3
- Rename extras module to srfi-105.extra
- 0.1.2
- Use standard keyword syntax, properly check for (#:other) group
- 0.1.1
- Initial implementation of base srfi + extras