parse functions

This commit is contained in:
mehbark 2026-01-02 01:55:25 -05:00
parent 86fb16faea
commit fcac4db1dc
2 changed files with 56 additions and 3 deletions

View file

@ -44,6 +44,9 @@ enum Token<'a> {
#[token("^")] #[token("^")]
Return, Return,
#[token("fn")]
Fn,
#[regex(r"[+*/%=-]")] #[regex(r"[+*/%=-]")]
BinOp(&'a str), BinOp(&'a str),
@ -70,6 +73,7 @@ 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"),
} }
@ -80,6 +84,7 @@ fn error_ast() -> Ast {
Ast::Var(Ident::Local("!invalid".to_owned())) Ast::Var(Ident::Local("!invalid".to_owned()))
} }
#[allow(clippy::too_many_lines, reason = "you're right but leave me alone")]
fn parser<'tokens, 'src: 'tokens, I>() fn parser<'tokens, 'src: 'tokens, I>()
-> impl Parser<'tokens, I, Vec<Ast>, extra::Err<Rich<'tokens, Token<'src>>>> -> impl Parser<'tokens, I, Vec<Ast>, extra::Err<Rich<'tokens, Token<'src>>>>
where where
@ -128,8 +133,8 @@ where
let block = expr let block = expr
.clone() .clone()
.separated_by(semicolon.clone()) .separated_by(semicolon.clone())
.allow_trailing()
.collect() .collect()
.map(Ast::Block)
.delimited_by(just(Token::OpenParen), just(Token::CloseParen)) .delimited_by(just(Token::OpenParen), just(Token::CloseParen))
.labelled("block"); .labelled("block");
@ -142,12 +147,60 @@ where
.delimited_by(just(Token::OpenBrace), just(Token::CloseBrace)) .delimited_by(just(Token::OpenBrace), just(Token::CloseBrace))
.labelled("map"); .labelled("map");
let arg_list = select! { Token::Var(s) => s.to_owned() }
.repeated()
.collect()
.delimited_by(just(Token::OpenBracket), just(Token::CloseBracket));
let signature = choice((
// ([x] [y])
arg_list
.clone()
.labelled("input list")
.then(arg_list.clone().labelled("output list")),
// ([x])
arg_list
.clone()
.labelled("input list")
.map(|x: Vec<_>| (x.clone(), x)),
// ()
empty().map(|()| (vec![], vec![])),
))
.delimited_by(just(Token::OpenParen), just(Token::CloseParen))
.labelled("function signature");
let lambda = just(Token::Fn)
.ignore_then(signature.clone())
.then(block.clone())
.map(|((inputs, outputs), body)| Ast::Fn {
inputs,
outputs,
body,
});
// this is purely syntax sugar
let standalone_func = just(Token::Fn)
.ignore_then(ident.clone())
.then(signature.clone())
.then(block.clone())
.map(|((id, (inputs, outputs)), body)| {
let lambda = Ast::Fn {
inputs,
outputs,
body,
};
Ast::Set(id, Box::new(lambda))
})
.labelled("standalone function");
let non_app = choice(( let non_app = choice((
set, set,
num, num,
standalone_func,
lambda,
ident.map(Ast::Var).labelled("variable"), ident.map(Ast::Var).labelled("variable"),
map, map,
block, block.map(Ast::Block),
)); ));
let app = non_app let app = non_app

View file

@ -18,7 +18,7 @@ impl fmt::Debug for Val {
Self::Number(n) => write!(f, "{n:?}"), Self::Number(n) => write!(f, "{n:?}"),
Self::Function { Self::Function {
inputs, outputs, .. inputs, outputs, ..
} => write!(f, "fn([{}], [{}]", inputs.join(" "), outputs.join(" ")), } => write!(f, "fn([{}] [{}])", inputs.join(" "), outputs.join(" ")),
Self::Map(map) => write!(f, "{map:?}"), Self::Map(map) => write!(f, "{map:?}"),
} }
} }