Okay, here are the last 2 key productions for sweet-expressions, "head" and
"rest". The "head" reads an indented line, and handles the first expression in
a line specially. If there's more than one expression on a line, it calls
"rest" to read the rest on that line.
Comments very very welcome.
Note: This doesn't include the calls or productions for the potential "restart"
semantics, whose fate is currently unknown. I want to discuss that in a
separate thread, after the proposal has matured a little.
I've tried to build on all past work. However, the BNF here is slightly more
complex than some older versions, because I'm trying to be *extremely* specific
about whitespace (SRFI-49 wasn't, and that caused lots of problems in
interpretation). In particular:
// This BNF uses the following slightly complicated pattern in many places:
// from_n_expr ((hspace+ (stuff /*= val1 */ | empty /*= val2 */ ))
// | empty /*= val2 */ )
// This is an expanded form of this BNF pattern (sans actions):
// from_n_expr (hspace+ stuff?)?
// Note that this pattern quietly removes horizontal spaces at the
// end of the line correctly; that's important because you can't see them,
// so quietly handling them eliminates a source of hard-to-find and
// unnecessary errors.
// If from_n_expr (etc.) is as greedy as possible (it needs to be),
// we *could* instead accept this simpler BNF pattern:
// from_n_expr hspace* stuff?
// but while that simpler BNF pattern would correctly accept *good* input,
// it would also accept *incorrect* input like "a(1)q" or other n-expressions
// followed immediately by other n-expressions without intervening whitespace.
// We want to detect such situations as errors, so we'll use the
// more complex (and more persnickety) BNF pattern instead.
I'd rather have the BNF slightly more complex, if the result is easier-to-use
and avoids surprising, hard-to-find errors.
--- David A. Wheeler
// The "head" is the production for 1+ n-expressions on one line; it will
// return the list of n-expressions on the line. If there is one n-expression
// on the line, it returns a list of exactly one item; this makes it
// easy to append to later (if appropriate). In some cases, we want
// single items to be themselves, not in a list; function monify does this.
// The "head" production never reads beyond the current line
// (except within a block comment), so it doesn't need to keep track
// of indentation, and indentation will NOT change within head.
// Callers can depend on "head" and "after" *not* changing indentation.
// On entry, all indentation/hspace must have already been read.
// On return, it will have consumed all hspace (spaces and tabs).
// On a non-tokenizing recursive descent parser, the "head" and its callees
// have to also read and determine if the n-expression is special
// (e.g., //, $, #!...!#, abbreviation + hspace), and have it return a
// distinct value if it is; head and friends operate a lot like a tokenizer
// in that case.
head returns [Object v]
: PERIOD
(hspace+
(n_expr1=n_expr hspace* {$v = list($n_expr1.v);} (n_expr2=n_expr error)?
| empty {$v = list(".");} /*= (list '.) */ )
| empty {$v = list(".");} /*= (list '.) */ )
| n_expr_first (
(hspace+
(rest2=rest {$v = cons($n_expr_first.v, $rest2.v);}
| empty {$v = list($n_expr_first.v);} ))
| empty {$v = list($n_expr_first.v);} ) ;
// The "rest" production reads the rest of the expressions on a line
// (the "rest of the head"), after the first expression of the line.
// Like head, it consumes any hspace before it returns.
// The "rest" production is written this way so a non-tokenizing
// implementation can read an expression specially. E.G., if it sees a period,
// read the expression directly and then see if it's just a period.
// Note that unlike the first head expression, block comments and
// datum comments that don't begin a line (after indent) are consumed,
// and abbreviations followed by a space merely apply to the
// next n-expression (not to the entire indented expression).
rest returns [Object v]
: PERIOD
(hspace+
(n_expr1=n_expr hspace* /* improper list. */
{$v = $n_expr1.v;}
(n_expr2=n_expr error)?
| empty {$v = list(".");})
| empty {$v = list(".");})
| scomment hspace* (rest1=rest {$v = $rest1.v;} | empty {$v = null;} )
| n_expr3=n_expr
((hspace+ (rest3=rest {$v = cons($n_expr3.v, $rest3.v);}
| empty {$v = list($n_expr3.v);} ))
| empty {$v = list($n_expr3.v);} ) ;
------------------------------------------------------------------------------
Master HTML5, CSS3, ASP.NET, MVC, AJAX, Knockout.js, Web API and
much more. Get web development skills now with LearnDevNow -
350+ hours of step-by-step video tutorials by Microsoft MVPs and experts.
SALE $99.99 this month only -- learn more at:
http://p.sf.net/sfu/learnmore_122812
_______________________________________________
Readable-discuss mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/readable-discuss