124 lines
3.6 KiB
Rust
124 lines
3.6 KiB
Rust
use chumsky::prelude::*;
|
|
|
|
use crate::{
|
|
ast,
|
|
expr::UntypedExpr,
|
|
parser::{annotation, error::ParseError, expr, token::Token, utils},
|
|
};
|
|
|
|
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
|
utils::optional_flag(Token::Pub)
|
|
.then_ignore(just(Token::Fn))
|
|
.then(select! {Token::Name {name} => name})
|
|
.then(
|
|
param(false)
|
|
.separated_by(just(Token::Comma))
|
|
.allow_trailing()
|
|
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
|
.map_with_span(|arguments, span| (arguments, span)),
|
|
)
|
|
.then(just(Token::RArrow).ignore_then(annotation()).or_not())
|
|
.then(
|
|
expr::sequence()
|
|
.or_not()
|
|
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
|
)
|
|
.map_with_span(
|
|
|((((public, name), (arguments, args_span)), return_annotation), body), span| {
|
|
ast::UntypedDefinition::Fn(ast::Function {
|
|
arguments,
|
|
body: body.unwrap_or_else(|| UntypedExpr::todo(None, span)),
|
|
doc: None,
|
|
location: ast::Span {
|
|
start: span.start,
|
|
end: return_annotation
|
|
.as_ref()
|
|
.map(|l| l.location().end)
|
|
.unwrap_or_else(|| args_span.end),
|
|
},
|
|
end_position: span.end - 1,
|
|
name,
|
|
public,
|
|
return_annotation,
|
|
return_type: (),
|
|
can_error: true,
|
|
})
|
|
},
|
|
)
|
|
}
|
|
|
|
pub fn param(is_validator_param: bool) -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {
|
|
choice((
|
|
select! {Token::Name {name} => name}
|
|
.then(select! {Token::DiscardName {name} => name})
|
|
.map_with_span(|(label, name), span| ast::ArgName::Discarded {
|
|
label,
|
|
name,
|
|
location: span,
|
|
}),
|
|
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
|
ast::ArgName::Discarded {
|
|
label: name.clone(),
|
|
name,
|
|
location: span,
|
|
}
|
|
}),
|
|
select! {Token::Name {name} => name}
|
|
.then(select! {Token::Name {name} => name})
|
|
.map_with_span(move |(label, name), span| ast::ArgName::Named {
|
|
label,
|
|
name,
|
|
location: span,
|
|
is_validator_param,
|
|
}),
|
|
select! {Token::Name {name} => name}.map_with_span(move |name, span| ast::ArgName::Named {
|
|
label: name.clone(),
|
|
name,
|
|
location: span,
|
|
is_validator_param,
|
|
}),
|
|
))
|
|
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
|
.map_with_span(|(arg_name, annotation), span| ast::Arg {
|
|
location: span,
|
|
annotation,
|
|
doc: None,
|
|
tipo: (),
|
|
arg_name,
|
|
})
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::assert_definition;
|
|
|
|
#[test]
|
|
fn function_empty() {
|
|
assert_definition!(
|
|
r#"
|
|
pub fn run() {}
|
|
"#
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn function_non_public() {
|
|
assert_definition!(
|
|
r#"
|
|
fn run() {}
|
|
"#
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn function_assignment_only() {
|
|
assert_definition!(
|
|
r#"
|
|
fn run() {
|
|
let x = 1 + 1
|
|
}
|
|
"#
|
|
);
|
|
}
|
|
}
|