parse function application
This commit is contained in:
parent
a93092e925
commit
255c9f2109
2 changed files with 55 additions and 19 deletions
20
README.md
20
README.md
|
|
@ -73,3 +73,23 @@ compose f g x == (((compose f) g) x) == compose {f: f2, g} x == compose {x} f g
|
|||
```rust
|
||||
fn id([x]) ()
|
||||
```
|
||||
|
||||
"Maps" should really just be blocks
|
||||
```rust
|
||||
foo := 3;
|
||||
{
|
||||
x := 42;
|
||||
^twice_x := x * 2;
|
||||
^thrice_x := x * 3;
|
||||
^foo;
|
||||
}
|
||||
```
|
||||
becomes
|
||||
```json5
|
||||
{
|
||||
"twice_x": 84,
|
||||
"thrice_x": 126,
|
||||
// ^foo as a statement behaves like ^foo := foo, so we get that nice record field punning
|
||||
"foo": 3,
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ enum Token<'a> {
|
|||
#[token(":")]
|
||||
Colon,
|
||||
|
||||
#[token(",")]
|
||||
Comma,
|
||||
|
||||
#[token(";")]
|
||||
Semicolon,
|
||||
|
||||
|
|
@ -44,9 +47,6 @@ enum Token<'a> {
|
|||
#[regex(r"[+*/%=-]")]
|
||||
BinOp(&'a str),
|
||||
|
||||
#[token("fn")]
|
||||
Fn,
|
||||
|
||||
#[regex(r"[a-zA-Z_][a-zA-Z_0-9']*")]
|
||||
Var(&'a str),
|
||||
|
||||
|
|
@ -60,6 +60,7 @@ impl fmt::Display for Token<'_> {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Token::Colon => write!(f, ":"),
|
||||
Token::Comma => write!(f, ","),
|
||||
Token::Semicolon => write!(f, ";"),
|
||||
Token::Set => write!(f, ":="),
|
||||
Token::OpenParen => write!(f, "("),
|
||||
|
|
@ -69,7 +70,6 @@ impl fmt::Display for Token<'_> {
|
|||
Token::OpenBrace => write!(f, "{{"),
|
||||
Token::CloseBrace => write!(f, "}}"),
|
||||
Token::Return => write!(f, "^"),
|
||||
Token::Fn => write!(f, "fn"),
|
||||
Token::BinOp(x) | Token::Var(x) | Token::Num(x) => write!(f, "{x}"),
|
||||
Token::Error => write!(f, "ERROR"),
|
||||
}
|
||||
|
|
@ -85,14 +85,24 @@ fn parser<'tokens, 'src: 'tokens, I>()
|
|||
where
|
||||
I: ValueInput<'tokens, Token = Token<'src>, Span = SimpleSpan>,
|
||||
{
|
||||
let semicolon = just(Token::Semicolon)
|
||||
.repeated()
|
||||
.at_least(1)
|
||||
.labelled("semicolon");
|
||||
|
||||
recursive(|expr| {
|
||||
let expr = expr.labelled("expression");
|
||||
|
||||
let ident = choice((
|
||||
just(Token::Return).ignore_then(select! {
|
||||
just(Token::Return)
|
||||
.ignore_then(select! {
|
||||
Token::Var(s) => Ident::Return(s.to_owned())
|
||||
}),
|
||||
})
|
||||
.labelled("return identifier"),
|
||||
select! {
|
||||
Token::Var(s) => Ident::Local(s.to_owned()),
|
||||
},
|
||||
}
|
||||
.labelled("local identifier"),
|
||||
))
|
||||
.labelled("identifier");
|
||||
|
||||
|
|
@ -115,22 +125,28 @@ where
|
|||
})
|
||||
.labelled("number");
|
||||
|
||||
let semicolon = just(Token::Semicolon)
|
||||
.repeated()
|
||||
.at_least(1)
|
||||
.labelled("semicolon");
|
||||
|
||||
let block = just(Token::OpenParen)
|
||||
.ignore_then(expr.clone().separated_by(semicolon).collect())
|
||||
.then_ignore(just(Token::CloseParen))
|
||||
let block = expr
|
||||
.clone()
|
||||
.separated_by(semicolon.clone())
|
||||
.collect()
|
||||
.map(Ast::Block)
|
||||
.delimited_by(just(Token::OpenParen), just(Token::CloseParen))
|
||||
.labelled("block");
|
||||
|
||||
choice((set, ident.map(Ast::Var).labelled("variable"), num, block))
|
||||
let non_app = choice((set, num, ident.map(Ast::Var).labelled("variable"), block));
|
||||
|
||||
let app = non_app
|
||||
.clone()
|
||||
.foldl(non_app.clone().repeated(), |f, x| {
|
||||
Ast::App(Box::new(f), Box::new(x))
|
||||
})
|
||||
.labelled("function application");
|
||||
|
||||
app.or(non_app)
|
||||
})
|
||||
.labelled("expression")
|
||||
.then_ignore(just(Token::Semicolon).repeated().at_least(1))
|
||||
.repeated()
|
||||
.separated_by(semicolon)
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue