Here are the current rules for draft 0.2 of sweet-expressions, as shown in:
 http://www.dwheeler.com/readable/version02.html
I'd love to hear feedback!

Sweet-expressions are simply extensions to traditional s-expressions, and are 
implemented by adding capabilities to the reader (usually named "read"). A 
sweet-expression reader can read ordinary s-expressions as usual, but can also 
read other syntax that are handy abbreviations - just as 'a is a handy 
abbreviation of (quote a).

Here are the draft sweet-expressions version 0.2 rules:
   1. Prefixed (...). Syntax of the form e(...) — with no whitespace 
between expression e and the open parenthesis — are mapped to (e ...). 
Any parameters in "..." are space-separated. This produces another expression, 
so this can be repeated (left-to-right). ‣ This adds support for 
traditional function notation. For example, "cos(x)" maps to "(cos x)", "max(3 
4)" maps to "(max 3 4)", and "f(x)(a b)" maps to "((f x) a b)". Note that this 
is especially convenient for certain styles of functional programming, 
including lambda expressions.

   2. Unprefixed (...). An expression beginning with an unprefixed open 
parenthesis "(" begins a traditional s-expression until its matching ")". 
‣ Implementations would typically call a "standard" s-expression reader. 
Because of this rule, a sweet-reader is extremely backward-compatible; a 
sweet-reader can read nearly all existing Lisp files. Note that any "(" 
preceded by whitespace, "(", "{", or "[" is unprefixed.

   3. Unprefixed {...}, aka infix. An unprefixed {...} contains an "infix 
list". If the enclosed infix list (1) has an odd number of parameters, (2) has 
at least 3 parameters, and (3) has equal even parameters, then it is mapped to 
"(even-parameter odd-parameters)". Otherwise, it is mapped to "(nfx list)" 
— you'll need to have a macro named "nfx" to use it. ‣ This rule 
means that {n = 0} maps to (= n 0), {3 + 4 + 5} maps to (+ 3 4 5), {3 + {4 * 
5}} maps to (+ 3 (* 4 5)), and {3 + 4 * 5} maps to (nfx 3 + 4 * 5). 
Consistently using {...} so infix operators are never mixed in a list has the 
advantage that all macros will see the usual list form with the function in the 
first position. If you want operator precedence, define an nfx macro to 
implement the precedence rules you desire. Or, if you never want precedence, 
define nfx to be an error. Every infix operator must be surrounded by 
whitespace for this rule to work as designed.

   4. Prefixed {...}. A prefixed expression f{...}, where f is an expression, 
is an abbreviation for f({...}). ‣ This rule simplifies combining 
function calls and infix expressions when there is only one parameter to the 
function call. Thus, f{n - 1} is equivalent to f({n - 1}), which maps to (f (- 
n 1)). When there is more than one function parameter, use the normal 
term-prefixing format, e.g., f({x - 1} {y - 1}) maps to (f (- x 1) (- y 1)).

   5. Indentation. Indentation is meaningful; the "I-expressions" of Scheme 
SFRI-49 are supported. An indented line is a parameter of its parent, later 
terms on a line are parameters of the first term, and lists of lists are marked 
with "group". A line with exactly one term, and no children, is simply that 
item; otherwise that line and its child lines are themselves a new list. 
Indentation is disabled inside the grouping pairs (), [], and {}, whether they 
are prefixed or not. Blank lines at the beginning of a new expression are 
ignored. ‣ A function call with 0 parameters must be surrounded or 
immediately followed by a pair of parentheses: (pi) or pi().

   6. Immediate completion. A single complete expression that begins at the 
left edge of a line, and is immediately followed by newline after it completes, 
causes the expression to immediately complete (without waiting for the next 
line of input). ‣ Thus, entering load("hello") and immediately pressing 
return will execute immediately, but load "hello" will require pressing Enter 
twice (because there might be another line to follow). This rule makes 
interactive use more pleasant, without harming file reading. It avoids two 
problems: (1) having to press Enter twice to execute simple one-line commands, 
and (2) allowing the command line to easily go "out of sync" (when, after 
pressing return, the user sees the result of the previous line). Type an 
initial space if you want to enter only a single complete expression on a line 
yet follow it with child lines.

   7. Unprefixed [...]. Unprefixed square brackets [..] disable indentation 
processing inside them. ‣ Use [...], instead of (...), to get the benefit 
of a list without disabling sweet-expression capabilities. These aren't used 
often, but they are critically necessary when you need them. The contents are 
not interpreted as infix, so [a + b(x)] maps to (a + (b x)).

   8. Prefixed [...]. Prefixed square brackets e[...] maps to (bracketaccess e 
...). ‣ Thus, "t[x]" maps to "(bracketaccess t x)". This is intended to 
simplify use of indexed arrays, associative arrays, and similar constructs. 

Note that usual Lisp quoting rules still work, so 'a still maps to (quote a). 
But they work with the new capabilities, so 'f(x) maps to (quote (f x)). Same 
with quasiquoting and comma-lifting. A ";" still begins a comment that 
continues to the end of a line, and "#" still begins special processing.

Note that you have to disable indentation to use infix operators as infix 
operators. This doesn't seem to be a problem in practice.

Shockingly, I've switched to infix as NOT the default, because in 
experimentation I found that it didn't have the positive effects I expected.  
Simply adding a way to mark infix lists using {...}, and a prefix f{...}, 
manages to do quite a lot.  See my examples for more.

--- David A. Wheeler

Reply via email to