[[tags: egg]]
[[toc:]]
== srfi-105
Curly infix expressions. For more information, see
[[http://srfi.schemers.org/srfi-105/srfi-105.html|SRFI-105]].
=== Modules
==== srfi-105
The core srfi as specified in
[[http://srfi.schemers.org/srfi-105/srfi-105.html|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.
===== Further details
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 [[https://wiki.call-cc.org/eggref/5/srfi-123|srfi-123]] for more
information.
===== Precedence
(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
[[https://docs.python.org/3/reference/expressions.html#operator-precedence|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)
Applies {{expt}} on all arguments right-associatively.
(% . rest)
Applies {{modulo}} on all arguments left-associatively.
(<< . rest)
Applies {{arithmetic-shift}} on all arguments left-associatively. Equivalent to
a left shift if shift is positive, right shift if shift is negative.
(>> . 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.
(^ . rest)
Applies {{bitwise-xor}} on all arguments left-associatively.
(ior . rest)
Applies {{bitwise-ior}} on all arguments left-associatively.
(& . rest)
Applies {{bitwise-and}} on all arguments left-associatively.
(~ arg)
An alias for {{bitwise-not}}.
(~ 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.
($nfx$ . rest)
Group the infix expression specified by the elements of {{rest}} according to
{{mixed-operator-precedence}}.
($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