parse function application

This commit is contained in:
mehbark 2026-01-02 00:52:57 -05:00
parent a93092e925
commit 255c9f2109
2 changed files with 55 additions and 19 deletions

View file

@ -73,3 +73,23 @@ compose f g x == (((compose f) g) x) == compose {f: f2, g} x == compose {x} f g
```rust ```rust
fn id([x]) () 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,
}
```

View file

@ -17,6 +17,9 @@ enum Token<'a> {
#[token(":")] #[token(":")]
Colon, Colon,
#[token(",")]
Comma,
#[token(";")] #[token(";")]
Semicolon, Semicolon,
@ -44,9 +47,6 @@ enum Token<'a> {
#[regex(r"[+*/%=-]")] #[regex(r"[+*/%=-]")]
BinOp(&'a str), BinOp(&'a str),
#[token("fn")]
Fn,
#[regex(r"[a-zA-Z_][a-zA-Z_0-9']*")] #[regex(r"[a-zA-Z_][a-zA-Z_0-9']*")]
Var(&'a str), Var(&'a str),
@ -60,6 +60,7 @@ impl fmt::Display for Token<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Token::Colon => write!(f, ":"), Token::Colon => write!(f, ":"),
Token::Comma => write!(f, ","),
Token::Semicolon => write!(f, ";"), Token::Semicolon => write!(f, ";"),
Token::Set => write!(f, ":="), Token::Set => write!(f, ":="),
Token::OpenParen => write!(f, "("), Token::OpenParen => write!(f, "("),
@ -69,7 +70,6 @@ impl fmt::Display for Token<'_> {
Token::OpenBrace => write!(f, "{{"), Token::OpenBrace => write!(f, "{{"),
Token::CloseBrace => write!(f, "}}"), Token::CloseBrace => write!(f, "}}"),
Token::Return => write!(f, "^"), Token::Return => write!(f, "^"),
Token::Fn => write!(f, "fn"),
Token::BinOp(x) | Token::Var(x) | Token::Num(x) => write!(f, "{x}"), Token::BinOp(x) | Token::Var(x) | Token::Num(x) => write!(f, "{x}"),
Token::Error => write!(f, "ERROR"), Token::Error => write!(f, "ERROR"),
} }
@ -85,14 +85,24 @@ fn parser<'tokens, 'src: 'tokens, I>()
where where
I: ValueInput<'tokens, Token = Token<'src>, Span = SimpleSpan>, I: ValueInput<'tokens, Token = Token<'src>, Span = SimpleSpan>,
{ {
let semicolon = just(Token::Semicolon)
.repeated()
.at_least(1)
.labelled("semicolon");
recursive(|expr| { recursive(|expr| {
let expr = expr.labelled("expression");
let ident = choice(( let ident = choice((
just(Token::Return).ignore_then(select! { just(Token::Return)
Token::Var(s) => Ident::Return(s.to_owned()) .ignore_then(select! {
}), Token::Var(s) => Ident::Return(s.to_owned())
})
.labelled("return identifier"),
select! { select! {
Token::Var(s) => Ident::Local(s.to_owned()), Token::Var(s) => Ident::Local(s.to_owned()),
}, }
.labelled("local identifier"),
)) ))
.labelled("identifier"); .labelled("identifier");
@ -115,22 +125,28 @@ where
}) })
.labelled("number"); .labelled("number");
let semicolon = just(Token::Semicolon) let block = expr
.repeated() .clone()
.at_least(1) .separated_by(semicolon.clone())
.labelled("semicolon"); .collect()
let block = just(Token::OpenParen)
.ignore_then(expr.clone().separated_by(semicolon).collect())
.then_ignore(just(Token::CloseParen))
.map(Ast::Block) .map(Ast::Block)
.delimited_by(just(Token::OpenParen), just(Token::CloseParen))
.labelled("block"); .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") .labelled("expression")
.then_ignore(just(Token::Semicolon).repeated().at_least(1)) .separated_by(semicolon)
.repeated() .allow_trailing()
.collect() .collect()
} }