## 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

*[parameter]*

`(mixed-operator-precedence)`

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.

*[syntax]*

`(** . rest)`

Applies `expt` on all arguments right-associatively.

*[syntax]*

`(% . rest)`

Applies `modulo` on all arguments left-associatively.

*[syntax]*

`(<< . rest)`

Applies `arithmetic-shift` on all arguments left-associatively. Equivalent to a left shift if shift is positive, right shift if shift is negative.

*[syntax]*

`(>> . rest)`

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.

*[syntax]*

`(^ . rest)`

Applies `bitwise-xor` on all arguments left-associatively.

*[syntax]*

`(ior . rest)`

Applies `bitwise-ior` on all arguments left-associatively.

*[syntax]*

`(& . rest)`

Applies `bitwise-and` on all arguments left-associatively.

*[procedure]*

`(~ arg)`

An alias for `bitwise-not`.

*[procedure]*

`(~ arg)`

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.

*[syntax]*

`($nfx$ . rest)`

Group the infix expression specified by the elements of `rest` according to `mixed-operator-precedence`.

*[procedure]*

`($bracket-apply$ obj i)`

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.

### 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