[racket-dev] Possible P4P or Honu ideas
Does anyone think this idea would work for P4P or Honu?
#lang alt-syntax
#|
Sets up a new reader that directly transforms the input into normal
S-Exprs, making this fully compatible with existing Racket (#lang
altsyntax would provide all of racket) and with macros.
Lexer Tokens
( ) [ ] { } (| |) _( : ): id string number char keyword etc...
Grammar
expr
: id
| constant
//Application with expr in app position
| '{' expr '}' '(' expr_lst ... ')' -> '(' expr expr_lst ... ')'
//Normal application f(a ...)
| id '(' expr ... ')' -> '(' id expr ... ')'
//Infix application
| '(|' expr_0 expr_1 expr_2 '|)' -> '(' expr_1 expr_0 expr_2 ')'
//Normal prefix s-exprs
| '[' expr ... ']' -> '(' expr ... ')'
| '_(' expr ... ')' -> '(' expr ... ')'
//Rules that use colon to replace parens
| id {no_ws()}? ':' ( { checkIndentation() }? expr ) ... -> '('
expr ... ')'
| ':' ( { checkIndentation() }? expr ) ... -> '(' expr ... ')'
| id '(' expr_0 ... '):' ( { checkIndentation() }? expr_1 ) ... ->
'(' id expr_0 ... expr_1 ...')'
;
Indentation rule for ':', checked by "checkIndentation()", is:
- Remember the column of the colon and indentation of the line it is on.
- exprs on the same line are included
- if there are no exprs on the same line, then include lines of the same
indentation for which that indentation is greater than the indentation
on the colon's line.
- if there is something on the same line as the colon, then include
lines of the same indentation for which that indentation is greater than
the colon's column.
The "no_ws()" check checks column of colon vs end column of id to make
sure there's no WS between them. This could be done by a lexer
returning ID and ID_COLON tokens instead.
Note that the "{ code-that-returns-boolean }?" notation is a "semantic
predicate" in ANTLR. Also "->" is a tree rewrite in ANTLR too.
Reasoning:
- Use Shriram's idea of ':' to indicate structure (like if, let, etc.)
- Use Shriram's idea of {} around expr in application position
- Keep LL(1)
- Use indentation to replace parens when using ':'
- Make this a direct and obvious conversion to S-Expr to maintain
library and macro compatability (not just for students!)
- Allow an infix notation, which is very helpful for math and
comparison. I use "(|" "|)" to maintain LL(1) parsing without stealing
{} from Shriram's use or '<' '>' which eliminates those chars in
operators, etc.
- Have function calls look like normal math, like f(a)
- Using [] is akin to saying "tuple", which is how it's often used in
let, for, etc. to pair id and value. So we can just parse them as normal
s-exprs
- Provide a way to write normal s-exprs if desired. Making everything
use [] could work, but I gave "_(" ")" as an alternative to allow
varying things.
- Code should be visually structured very much like Racket is now.
Below shows some examples.
|#
let: loop :[acc 1]
[acc2 2]
set!(a 1)
set!(b (|acc2 + 1|))
loop((|acc + a|) b)
{lambda: [a] a}(1)
{f}(a)
f(a)
[f a]
_(f a)
{g}(a b)
g(a b)
[g a b]
_(g a b)
(|a g b|)
if: (|a > 0|)
a
b
;if no tokens on the rest of the line, indent > line_indent vs. indent >
colon_column
cond:
[true
doit()]
[false
dontDoIt()]
[else
"Hello World"]
match: thing
["a" display("Thing A")]
["b" display("Thing B")]
[else display("Unknown")]
match:
thing
["a" display("Thing A")]
["b" display("Thing B")]
[else display("Unknown")]
;Blake's idea. Allow params both in parens and after colon for better
structure formatting.
match (thing):
["a" display("Thing A")]
["b" display("Thing B")]
[else display("Unknown")]
if((|a > 0|)):
a
b
;Can be abused too, but you'd never do that, right?
match (thing
["a" display("Thing A")]):
["b" display("Thing B")]
[else display("Unknown")]
let: :[a 1]
[b 2]
[c 3]
_(+ a b c)
let: :[a 1][b 2][c 3]
[+ a b c]
let:
:[a 1][b 2]
[c 3]
+(a b c)
define-syntax-rule:
test-term-equal(lhs rhs)
test-equal(term(lhs) term(rhs))
[define-syntax-rule [test-term-equal lhs rhs]
[test-equal [term lhs] [term rhs]]]
begin:
doA()
doB()
void()
;Use of infix for non-math operations works too, of course.
(| range(1 100) map + |)
;The following is a Redex grammar (a piece of a grammar I'm using)
define-language(lang):
e: v
@(e)
id
setop([pattern in e] e)
if(e e e)
let( [[id e]] e)
op(e ...)
k: ret
@(k)
setop(pattern e k)
if(e e k)
pop(eta k)
let(id e k)
op( [v ...] [e ...] k)
v: number
true false
error
string
[addr address]
[const-set v ...]
[const-tuple v ...]
Thanks,
-Everett Morse