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
|
```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,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
.ignore_then(select! {
|
||||||
Token::Var(s) => Ident::Return(s.to_owned())
|
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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue