feat: move anon fn, let, and expect
This commit is contained in:
parent
9c98fc8026
commit
eea94fc9a4
|
@ -11,6 +11,7 @@ mod utils;
|
||||||
pub use annotation::parser as annotation;
|
pub use annotation::parser as annotation;
|
||||||
pub use definitions::parser as definitions;
|
pub use definitions::parser as definitions;
|
||||||
pub use expr::parser as expression;
|
pub use expr::parser as expression;
|
||||||
|
pub use pattern::parser as pattern;
|
||||||
|
|
||||||
use crate::ast::{self, BinOp, Span};
|
use crate::ast::{self, BinOp, Span};
|
||||||
use chumsky::{chain::Chain, prelude::*};
|
use chumsky::{chain::Chain, prelude::*};
|
||||||
|
@ -96,32 +97,6 @@ pub fn module(
|
||||||
Ok((module, extra))
|
Ok((module, extra))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn anon_fn_param_parser() -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {
|
|
||||||
// TODO: return a better error when a label is provided `UnexpectedLabel`
|
|
||||||
choice((
|
|
||||||
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
|
||||||
ast::ArgName::Discarded {
|
|
||||||
label: name.clone(),
|
|
||||||
name,
|
|
||||||
location: span,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
select! {Token::Name {name} => name}.map_with_span(|name, span| ast::ArgName::Named {
|
|
||||||
label: name.clone(),
|
|
||||||
name,
|
|
||||||
location: span,
|
|
||||||
is_validator_param: false,
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
|
||||||
.map_with_span(|(arg_name, annotation), span| ast::Arg {
|
|
||||||
location: span,
|
|
||||||
annotation,
|
|
||||||
tipo: (),
|
|
||||||
arg_name,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn when_clause_guard_parser() -> impl Parser<Token, ast::ClauseGuard<()>, Error = ParseError> {
|
pub fn when_clause_guard_parser() -> impl Parser<Token, ast::ClauseGuard<()>, Error = ParseError> {
|
||||||
recursive(|r| {
|
recursive(|r| {
|
||||||
let var_parser = select! {
|
let var_parser = select! {
|
||||||
|
@ -237,190 +212,3 @@ pub fn when_clause_guard_parser() -> impl Parser<Token, ast::ClauseGuard<()>, Er
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pattern_parser() -> impl Parser<Token, ast::UntypedPattern, Error = ParseError> {
|
|
||||||
recursive(|r| {
|
|
||||||
let record_constructor_pattern_arg_parser = choice((
|
|
||||||
select! {Token::Name {name} => name}
|
|
||||||
.then_ignore(just(Token::Colon))
|
|
||||||
.then(r.clone())
|
|
||||||
.map_with_span(|(name, pattern), span| ast::CallArg {
|
|
||||||
location: span,
|
|
||||||
label: Some(name),
|
|
||||||
value: pattern,
|
|
||||||
}),
|
|
||||||
select! {Token::Name{name} => name}.map_with_span(|name, span| ast::CallArg {
|
|
||||||
location: span,
|
|
||||||
value: ast::UntypedPattern::Var {
|
|
||||||
name: name.clone(),
|
|
||||||
location: span,
|
|
||||||
},
|
|
||||||
label: Some(name),
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.allow_trailing()
|
|
||||||
.then(
|
|
||||||
just(Token::DotDot)
|
|
||||||
.then_ignore(just(Token::Comma).or_not())
|
|
||||||
.ignored()
|
|
||||||
.or_not(),
|
|
||||||
)
|
|
||||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace));
|
|
||||||
|
|
||||||
let tuple_constructor_pattern_arg_parser = r
|
|
||||||
.clone()
|
|
||||||
.map(|pattern| ast::CallArg {
|
|
||||||
location: pattern.location(),
|
|
||||||
value: pattern,
|
|
||||||
label: None,
|
|
||||||
})
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.allow_trailing()
|
|
||||||
.then(
|
|
||||||
just(Token::DotDot)
|
|
||||||
.then_ignore(just(Token::Comma).or_not())
|
|
||||||
.ignored()
|
|
||||||
.or_not(),
|
|
||||||
)
|
|
||||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen));
|
|
||||||
|
|
||||||
let constructor_pattern_args_parser = choice((
|
|
||||||
record_constructor_pattern_arg_parser.map(|a| (a, true)),
|
|
||||||
tuple_constructor_pattern_arg_parser.map(|a| (a, false)),
|
|
||||||
))
|
|
||||||
.or_not()
|
|
||||||
.map(|opt_args| {
|
|
||||||
opt_args
|
|
||||||
.map(|((a, b), c)| (a, b.is_some(), c))
|
|
||||||
.unwrap_or_else(|| (vec![], false, false))
|
|
||||||
});
|
|
||||||
|
|
||||||
let constructor_pattern_parser =
|
|
||||||
select! {Token::UpName { name } => name}.then(constructor_pattern_args_parser);
|
|
||||||
|
|
||||||
choice((
|
|
||||||
select! { Token::Name {name} => name }
|
|
||||||
.then(
|
|
||||||
just(Token::Dot)
|
|
||||||
.ignore_then(constructor_pattern_parser.clone())
|
|
||||||
.or_not(),
|
|
||||||
)
|
|
||||||
.map_with_span(|(name, opt_pattern), span| {
|
|
||||||
if let Some((c_name, (arguments, with_spread, is_record))) = opt_pattern {
|
|
||||||
ast::UntypedPattern::Constructor {
|
|
||||||
is_record,
|
|
||||||
location: span,
|
|
||||||
name: c_name,
|
|
||||||
arguments,
|
|
||||||
module: Some(name),
|
|
||||||
constructor: (),
|
|
||||||
with_spread,
|
|
||||||
tipo: (),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ast::UntypedPattern::Var {
|
|
||||||
location: span,
|
|
||||||
name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
constructor_pattern_parser.map_with_span(
|
|
||||||
|(name, (arguments, with_spread, is_record)), span| {
|
|
||||||
ast::UntypedPattern::Constructor {
|
|
||||||
is_record,
|
|
||||||
location: span,
|
|
||||||
name,
|
|
||||||
arguments,
|
|
||||||
module: None,
|
|
||||||
constructor: (),
|
|
||||||
with_spread,
|
|
||||||
tipo: (),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
|
||||||
ast::UntypedPattern::Discard {
|
|
||||||
name,
|
|
||||||
location: span,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
select! {Token::Int {value, base} => (value, base)}.map_with_span(
|
|
||||||
|(value, base), span| ast::UntypedPattern::Int {
|
|
||||||
location: span,
|
|
||||||
value,
|
|
||||||
base,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
r.clone()
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.allow_trailing()
|
|
||||||
.delimited_by(
|
|
||||||
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
|
|
||||||
just(Token::RightParen),
|
|
||||||
)
|
|
||||||
.map_with_span(|elems, span| ast::UntypedPattern::Tuple {
|
|
||||||
location: span,
|
|
||||||
elems,
|
|
||||||
}),
|
|
||||||
just(Token::LeftSquare)
|
|
||||||
.ignore_then(r.clone().separated_by(just(Token::Comma)))
|
|
||||||
.then(choice((
|
|
||||||
just(Token::Comma)
|
|
||||||
.ignore_then(just(Token::DotDot).ignore_then(r.clone().or_not()).or_not()),
|
|
||||||
just(Token::Comma).ignored().or_not().map(|_| None),
|
|
||||||
)))
|
|
||||||
.then_ignore(just(Token::RightSquare))
|
|
||||||
.validate(|(elements, tail), span: Span, emit| {
|
|
||||||
let tail = match tail {
|
|
||||||
// There is a tail and it has a Pattern::Var or Pattern::Discard
|
|
||||||
Some(Some(
|
|
||||||
pat @ (ast::UntypedPattern::Var { .. }
|
|
||||||
| ast::UntypedPattern::Discard { .. }),
|
|
||||||
)) => Some(pat),
|
|
||||||
Some(Some(pat)) => {
|
|
||||||
emit(ParseError::expected_input_found(
|
|
||||||
pat.location(),
|
|
||||||
None,
|
|
||||||
Some(error::Pattern::Match),
|
|
||||||
));
|
|
||||||
|
|
||||||
Some(pat)
|
|
||||||
}
|
|
||||||
// There is a tail but it has no content, implicit discard
|
|
||||||
Some(None) => Some(ast::UntypedPattern::Discard {
|
|
||||||
location: Span {
|
|
||||||
start: span.end - 1,
|
|
||||||
end: span.end,
|
|
||||||
},
|
|
||||||
name: "_".to_string(),
|
|
||||||
}),
|
|
||||||
// No tail specified
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
ast::UntypedPattern::List {
|
|
||||||
location: span,
|
|
||||||
elements,
|
|
||||||
tail: tail.map(Box::new),
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
.then(
|
|
||||||
just(Token::As)
|
|
||||||
.ignore_then(select! { Token::Name {name} => name})
|
|
||||||
.or_not(),
|
|
||||||
)
|
|
||||||
.map_with_span(|(pattern, opt_as), span| {
|
|
||||||
if let Some(name) = opt_as {
|
|
||||||
ast::UntypedPattern::Assign {
|
|
||||||
name,
|
|
||||||
location: span,
|
|
||||||
pattern: Box::new(pattern),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pattern
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ast,
|
||||||
|
expr::{FnStyle, UntypedExpr},
|
||||||
|
parser::{annotation, error::ParseError, token::Token},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parser<'a>(
|
||||||
|
seq_r: Recursive<'a, Token, UntypedExpr, ParseError>,
|
||||||
|
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + 'a {
|
||||||
|
just(Token::Fn)
|
||||||
|
.ignore_then(
|
||||||
|
params()
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
||||||
|
)
|
||||||
|
.then(just(Token::RArrow).ignore_then(annotation()).or_not())
|
||||||
|
.then(seq_r.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)))
|
||||||
|
.map_with_span(
|
||||||
|
|((arguments, return_annotation), body), span| UntypedExpr::Fn {
|
||||||
|
arguments,
|
||||||
|
body: Box::new(body),
|
||||||
|
location: span,
|
||||||
|
fn_style: FnStyle::Plain,
|
||||||
|
return_annotation,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn params() -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {
|
||||||
|
// TODO: return a better error when a label is provided `UnexpectedLabel`
|
||||||
|
choice((
|
||||||
|
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
||||||
|
ast::ArgName::Discarded {
|
||||||
|
label: name.clone(),
|
||||||
|
name,
|
||||||
|
location: span,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
select! {Token::Name {name} => name}.map_with_span(|name, span| ast::ArgName::Named {
|
||||||
|
label: name.clone(),
|
||||||
|
name,
|
||||||
|
location: span,
|
||||||
|
is_validator_param: false,
|
||||||
|
}),
|
||||||
|
))
|
||||||
|
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||||
|
.map_with_span(|(arg_name, annotation), span| ast::Arg {
|
||||||
|
location: span,
|
||||||
|
annotation,
|
||||||
|
tipo: (),
|
||||||
|
arg_name,
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ast,
|
||||||
|
expr::UntypedExpr,
|
||||||
|
parser::{annotation, error::ParseError, pattern, token::Token},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn let_(
|
||||||
|
r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||||
|
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||||
|
assignment(r, Token::Let)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expect(
|
||||||
|
r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||||
|
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||||
|
assignment(r, Token::Expect)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assignment(
|
||||||
|
r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||||
|
keyword: Token,
|
||||||
|
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||||
|
let kind = if keyword == Token::Let {
|
||||||
|
ast::AssignmentKind::Let
|
||||||
|
} else {
|
||||||
|
ast::AssignmentKind::Expect
|
||||||
|
};
|
||||||
|
|
||||||
|
just(keyword)
|
||||||
|
.ignore_then(pattern())
|
||||||
|
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||||
|
.then_ignore(just(Token::Equal))
|
||||||
|
.then(r.clone())
|
||||||
|
.map_with_span(
|
||||||
|
move |((pattern, annotation), value), span| UntypedExpr::Assignment {
|
||||||
|
location: span,
|
||||||
|
value: Box::new(value),
|
||||||
|
pattern,
|
||||||
|
kind,
|
||||||
|
annotation,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
use chumsky::prelude::*;
|
use chumsky::prelude::*;
|
||||||
use vec1::{vec1, Vec1};
|
use vec1::{vec1, Vec1};
|
||||||
|
|
||||||
|
pub mod anonymous_function;
|
||||||
|
pub mod assignment;
|
||||||
mod block;
|
mod block;
|
||||||
mod bytearray;
|
mod bytearray;
|
||||||
mod if_else;
|
mod if_else;
|
||||||
|
@ -13,6 +15,7 @@ pub mod string;
|
||||||
mod tuple;
|
mod tuple;
|
||||||
mod var;
|
mod var;
|
||||||
|
|
||||||
|
pub use anonymous_function::parser as anonymous_function;
|
||||||
pub use block::parser as block;
|
pub use block::parser as block;
|
||||||
pub use bytearray::parser as bytearray;
|
pub use bytearray::parser as bytearray;
|
||||||
pub use if_else::parser as if_else;
|
pub use if_else::parser as if_else;
|
||||||
|
@ -49,25 +52,6 @@ pub fn parser(
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
let anon_fn_parser = just(Token::Fn)
|
|
||||||
.ignore_then(
|
|
||||||
anon_fn_param_parser()
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.allow_trailing()
|
|
||||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
|
||||||
)
|
|
||||||
.then(just(Token::RArrow).ignore_then(annotation()).or_not())
|
|
||||||
.then(seq_r.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)))
|
|
||||||
.map_with_span(
|
|
||||||
|((arguments, return_annotation), body), span| UntypedExpr::Fn {
|
|
||||||
arguments,
|
|
||||||
body: Box::new(body),
|
|
||||||
location: span,
|
|
||||||
fn_style: FnStyle::Plain,
|
|
||||||
return_annotation,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let anon_binop_parser = select! {
|
let anon_binop_parser = select! {
|
||||||
Token::EqualEqual => BinOp::Eq,
|
Token::EqualEqual => BinOp::Eq,
|
||||||
Token::NotEqual => BinOp::NotEq,
|
Token::NotEqual => BinOp::NotEq,
|
||||||
|
@ -216,36 +200,6 @@ pub fn parser(
|
||||||
clauses,
|
clauses,
|
||||||
});
|
});
|
||||||
|
|
||||||
let let_parser = just(Token::Let)
|
|
||||||
.ignore_then(pattern_parser())
|
|
||||||
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
|
||||||
.then_ignore(just(Token::Equal))
|
|
||||||
.then(r.clone())
|
|
||||||
.map_with_span(
|
|
||||||
|((pattern, annotation), value), span| UntypedExpr::Assignment {
|
|
||||||
location: span,
|
|
||||||
value: Box::new(value),
|
|
||||||
pattern,
|
|
||||||
kind: ast::AssignmentKind::Let,
|
|
||||||
annotation,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let expect_parser = just(Token::Expect)
|
|
||||||
.ignore_then(pattern_parser())
|
|
||||||
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
|
||||||
.then_ignore(just(Token::Equal))
|
|
||||||
.then(r.clone())
|
|
||||||
.map_with_span(
|
|
||||||
|((pattern, annotation), value), span| UntypedExpr::Assignment {
|
|
||||||
location: span,
|
|
||||||
value: Box::new(value),
|
|
||||||
pattern,
|
|
||||||
kind: ast::AssignmentKind::Expect,
|
|
||||||
annotation,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let expr_unit_parser = choice((
|
let expr_unit_parser = choice((
|
||||||
string(),
|
string(),
|
||||||
int(),
|
int(),
|
||||||
|
@ -256,12 +210,12 @@ pub fn parser(
|
||||||
tuple(r),
|
tuple(r),
|
||||||
bytearray(),
|
bytearray(),
|
||||||
list(r),
|
list(r),
|
||||||
anon_fn_parser,
|
anonymous_function(seq_r),
|
||||||
anon_binop_parser,
|
anon_binop_parser,
|
||||||
block(seq_r),
|
block(seq_r),
|
||||||
when_parser,
|
when_parser,
|
||||||
let_parser,
|
assignment::let_(r),
|
||||||
expect_parser,
|
assignment::expect(r),
|
||||||
if_else(seq_r, r),
|
if_else(seq_r, r),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,195 @@
|
||||||
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
use crate::ast;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
error::{self, ParseError},
|
||||||
|
token::Token,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parser() -> impl Parser<Token, ast::UntypedPattern, Error = ParseError> {
|
||||||
|
recursive(|r| {
|
||||||
|
let record_constructor_pattern_arg_parser = choice((
|
||||||
|
select! {Token::Name {name} => name}
|
||||||
|
.then_ignore(just(Token::Colon))
|
||||||
|
.then(r.clone())
|
||||||
|
.map_with_span(|(name, pattern), span| ast::CallArg {
|
||||||
|
location: span,
|
||||||
|
label: Some(name),
|
||||||
|
value: pattern,
|
||||||
|
}),
|
||||||
|
select! {Token::Name{name} => name}.map_with_span(|name, span| ast::CallArg {
|
||||||
|
location: span,
|
||||||
|
value: ast::UntypedPattern::Var {
|
||||||
|
name: name.clone(),
|
||||||
|
location: span,
|
||||||
|
},
|
||||||
|
label: Some(name),
|
||||||
|
}),
|
||||||
|
))
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.then(
|
||||||
|
just(Token::DotDot)
|
||||||
|
.then_ignore(just(Token::Comma).or_not())
|
||||||
|
.ignored()
|
||||||
|
.or_not(),
|
||||||
|
)
|
||||||
|
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace));
|
||||||
|
|
||||||
|
let tuple_constructor_pattern_arg_parser = r
|
||||||
|
.clone()
|
||||||
|
.map(|pattern| ast::CallArg {
|
||||||
|
location: pattern.location(),
|
||||||
|
value: pattern,
|
||||||
|
label: None,
|
||||||
|
})
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.then(
|
||||||
|
just(Token::DotDot)
|
||||||
|
.then_ignore(just(Token::Comma).or_not())
|
||||||
|
.ignored()
|
||||||
|
.or_not(),
|
||||||
|
)
|
||||||
|
.delimited_by(just(Token::LeftParen), just(Token::RightParen));
|
||||||
|
|
||||||
|
let constructor_pattern_args_parser = choice((
|
||||||
|
record_constructor_pattern_arg_parser.map(|a| (a, true)),
|
||||||
|
tuple_constructor_pattern_arg_parser.map(|a| (a, false)),
|
||||||
|
))
|
||||||
|
.or_not()
|
||||||
|
.map(|opt_args| {
|
||||||
|
opt_args
|
||||||
|
.map(|((a, b), c)| (a, b.is_some(), c))
|
||||||
|
.unwrap_or_else(|| (vec![], false, false))
|
||||||
|
});
|
||||||
|
|
||||||
|
let constructor_pattern_parser =
|
||||||
|
select! {Token::UpName { name } => name}.then(constructor_pattern_args_parser);
|
||||||
|
|
||||||
|
choice((
|
||||||
|
select! { Token::Name {name} => name }
|
||||||
|
.then(
|
||||||
|
just(Token::Dot)
|
||||||
|
.ignore_then(constructor_pattern_parser.clone())
|
||||||
|
.or_not(),
|
||||||
|
)
|
||||||
|
.map_with_span(|(name, opt_pattern), span| {
|
||||||
|
if let Some((c_name, (arguments, with_spread, is_record))) = opt_pattern {
|
||||||
|
ast::UntypedPattern::Constructor {
|
||||||
|
is_record,
|
||||||
|
location: span,
|
||||||
|
name: c_name,
|
||||||
|
arguments,
|
||||||
|
module: Some(name),
|
||||||
|
constructor: (),
|
||||||
|
with_spread,
|
||||||
|
tipo: (),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ast::UntypedPattern::Var {
|
||||||
|
location: span,
|
||||||
|
name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
constructor_pattern_parser.map_with_span(
|
||||||
|
|(name, (arguments, with_spread, is_record)), span| {
|
||||||
|
ast::UntypedPattern::Constructor {
|
||||||
|
is_record,
|
||||||
|
location: span,
|
||||||
|
name,
|
||||||
|
arguments,
|
||||||
|
module: None,
|
||||||
|
constructor: (),
|
||||||
|
with_spread,
|
||||||
|
tipo: (),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
||||||
|
ast::UntypedPattern::Discard {
|
||||||
|
name,
|
||||||
|
location: span,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
select! {Token::Int {value, base} => (value, base)}.map_with_span(
|
||||||
|
|(value, base), span| ast::UntypedPattern::Int {
|
||||||
|
location: span,
|
||||||
|
value,
|
||||||
|
base,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
r.clone()
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(
|
||||||
|
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
|
||||||
|
just(Token::RightParen),
|
||||||
|
)
|
||||||
|
.map_with_span(|elems, span| ast::UntypedPattern::Tuple {
|
||||||
|
location: span,
|
||||||
|
elems,
|
||||||
|
}),
|
||||||
|
just(Token::LeftSquare)
|
||||||
|
.ignore_then(r.clone().separated_by(just(Token::Comma)))
|
||||||
|
.then(choice((
|
||||||
|
just(Token::Comma)
|
||||||
|
.ignore_then(just(Token::DotDot).ignore_then(r.clone().or_not()).or_not()),
|
||||||
|
just(Token::Comma).ignored().or_not().map(|_| None),
|
||||||
|
)))
|
||||||
|
.then_ignore(just(Token::RightSquare))
|
||||||
|
.validate(|(elements, tail), span: ast::Span, emit| {
|
||||||
|
let tail = match tail {
|
||||||
|
// There is a tail and it has a Pattern::Var or Pattern::Discard
|
||||||
|
Some(Some(
|
||||||
|
pat @ (ast::UntypedPattern::Var { .. }
|
||||||
|
| ast::UntypedPattern::Discard { .. }),
|
||||||
|
)) => Some(pat),
|
||||||
|
Some(Some(pat)) => {
|
||||||
|
emit(ParseError::expected_input_found(
|
||||||
|
pat.location(),
|
||||||
|
None,
|
||||||
|
Some(error::Pattern::Match),
|
||||||
|
));
|
||||||
|
|
||||||
|
Some(pat)
|
||||||
|
}
|
||||||
|
// There is a tail but it has no content, implicit discard
|
||||||
|
Some(None) => Some(ast::UntypedPattern::Discard {
|
||||||
|
location: ast::Span {
|
||||||
|
start: span.end - 1,
|
||||||
|
end: span.end,
|
||||||
|
},
|
||||||
|
name: "_".to_string(),
|
||||||
|
}),
|
||||||
|
// No tail specified
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
ast::UntypedPattern::List {
|
||||||
|
location: span,
|
||||||
|
elements,
|
||||||
|
tail: tail.map(Box::new),
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
))
|
||||||
|
.then(
|
||||||
|
just(Token::As)
|
||||||
|
.ignore_then(select! { Token::Name {name} => name})
|
||||||
|
.or_not(),
|
||||||
|
)
|
||||||
|
.map_with_span(|(pattern, opt_as), span| {
|
||||||
|
if let Some(name) = opt_as {
|
||||||
|
ast::UntypedPattern::Assign {
|
||||||
|
name,
|
||||||
|
location: span,
|
||||||
|
pattern: Box::new(pattern),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pattern
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue