feat: start splitting apart expr_parser
This commit is contained in:
parent
e3ed5d3b00
commit
9c98fc8026
|
@ -0,0 +1,20 @@
|
||||||
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
expr::UntypedExpr,
|
||||||
|
parser::{error::ParseError, token::Token},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parser(
|
||||||
|
seq_r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||||
|
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||||
|
choice((
|
||||||
|
seq_r
|
||||||
|
.clone()
|
||||||
|
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
||||||
|
seq_r.clone().delimited_by(
|
||||||
|
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
|
||||||
|
just(Token::RightParen),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
expr::UntypedExpr,
|
||||||
|
parser::{error::ParseError, token::Token, utils},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
|
||||||
|
utils::bytearray().map_with_span(|(preferred_format, bytes), span| UntypedExpr::ByteArray {
|
||||||
|
location: span,
|
||||||
|
bytes,
|
||||||
|
preferred_format,
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ast,
|
||||||
|
expr::UntypedExpr,
|
||||||
|
parser::{error::ParseError, token::Token},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::block;
|
||||||
|
|
||||||
|
pub fn parser<'a>(
|
||||||
|
seq_r: Recursive<'a, Token, UntypedExpr, ParseError>,
|
||||||
|
r: Recursive<'a, Token, UntypedExpr, ParseError>,
|
||||||
|
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + 'a {
|
||||||
|
just(Token::If)
|
||||||
|
.ignore_then(r.clone().then(block(seq_r.clone())).map_with_span(
|
||||||
|
|(condition, body), span| ast::IfBranch {
|
||||||
|
condition,
|
||||||
|
body,
|
||||||
|
location: span,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
.then(
|
||||||
|
just(Token::Else)
|
||||||
|
.ignore_then(just(Token::If))
|
||||||
|
.ignore_then(r.clone().then(block(seq_r.clone())).map_with_span(
|
||||||
|
|(condition, body), span| ast::IfBranch {
|
||||||
|
condition,
|
||||||
|
body,
|
||||||
|
location: span,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
.repeated(),
|
||||||
|
)
|
||||||
|
.then_ignore(just(Token::Else))
|
||||||
|
.then(block(seq_r))
|
||||||
|
.map_with_span(|((first, alternative_branches), final_else), span| {
|
||||||
|
let mut branches = vec1::vec1![first];
|
||||||
|
|
||||||
|
branches.extend(alternative_branches);
|
||||||
|
|
||||||
|
UntypedExpr::If {
|
||||||
|
location: span,
|
||||||
|
branches,
|
||||||
|
final_else: Box::new(final_else),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
expr::UntypedExpr,
|
||||||
|
parser::{error::ParseError, token::Token},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
|
||||||
|
select! { Token::Int {value, base} => (value, base)}.map_with_span(|(value, base), span| {
|
||||||
|
UntypedExpr::Int {
|
||||||
|
location: span,
|
||||||
|
value,
|
||||||
|
base,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
expr::UntypedExpr,
|
||||||
|
parser::{error::ParseError, token::Token},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parser(
|
||||||
|
r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||||
|
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||||
|
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())
|
||||||
|
.map(Box::new)
|
||||||
|
.or_not(),
|
||||||
|
),
|
||||||
|
just(Token::Comma).ignored().or_not().map(|_| None),
|
||||||
|
)))
|
||||||
|
.then_ignore(just(Token::RightSquare))
|
||||||
|
// TODO: check if tail.is_some and elements.is_empty then return ListSpreadWithoutElements error
|
||||||
|
.map_with_span(|(elements, tail), span| UntypedExpr::List {
|
||||||
|
location: span,
|
||||||
|
elements,
|
||||||
|
tail,
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,15 +1,33 @@
|
||||||
use chumsky::prelude::*;
|
use chumsky::prelude::*;
|
||||||
use vec1::{vec1, Vec1};
|
use vec1::{vec1, Vec1};
|
||||||
|
|
||||||
|
mod block;
|
||||||
|
mod bytearray;
|
||||||
|
mod if_else;
|
||||||
|
mod int;
|
||||||
|
mod list;
|
||||||
|
mod record;
|
||||||
|
mod record_update;
|
||||||
mod sequence;
|
mod sequence;
|
||||||
pub mod string;
|
pub mod string;
|
||||||
|
mod tuple;
|
||||||
|
mod var;
|
||||||
|
|
||||||
|
pub use block::parser as block;
|
||||||
|
pub use bytearray::parser as bytearray;
|
||||||
|
pub use if_else::parser as if_else;
|
||||||
|
pub use int::parser as int;
|
||||||
|
pub use list::parser as list;
|
||||||
|
pub use record::parser as record;
|
||||||
|
pub use record_update::parser as record_update;
|
||||||
pub use sequence::parser as sequence;
|
pub use sequence::parser as sequence;
|
||||||
|
pub use string::parser as string;
|
||||||
|
pub use tuple::parser as tuple;
|
||||||
|
pub use var::parser as var;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{self, Span},
|
ast::{self, Span},
|
||||||
expr::UntypedExpr,
|
expr::UntypedExpr,
|
||||||
parser::error,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{error::ParseError, token::Token};
|
use super::{error::ParseError, token::Token};
|
||||||
|
@ -18,241 +36,6 @@ pub fn parser(
|
||||||
seq_r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
seq_r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||||
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||||
recursive(|r| {
|
recursive(|r| {
|
||||||
let string_parser =
|
|
||||||
select! {Token::String {value} => value}.map_with_span(|value, span| {
|
|
||||||
UntypedExpr::String {
|
|
||||||
location: span,
|
|
||||||
value,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let int_parser = select! { Token::Int {value, base} => (value, base)}.map_with_span(
|
|
||||||
|(value, base), span| UntypedExpr::Int {
|
|
||||||
location: span,
|
|
||||||
value,
|
|
||||||
base,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let record_update_parser = select! {Token::Name { name } => name}
|
|
||||||
.map_with_span(|module, span: Span| (module, span))
|
|
||||||
.then_ignore(just(Token::Dot))
|
|
||||||
.or_not()
|
|
||||||
.then(select! {Token::UpName { name } => name}.map_with_span(|name, span| (name, span)))
|
|
||||||
.then(
|
|
||||||
just(Token::DotDot)
|
|
||||||
.ignore_then(r.clone())
|
|
||||||
.then(
|
|
||||||
just(Token::Comma)
|
|
||||||
.ignore_then(
|
|
||||||
choice((
|
|
||||||
select! { Token::Name {name} => name }
|
|
||||||
.then_ignore(just(Token::Colon))
|
|
||||||
.then(r.clone())
|
|
||||||
.map_with_span(|(label, value), span| {
|
|
||||||
ast::UntypedRecordUpdateArg {
|
|
||||||
label,
|
|
||||||
value,
|
|
||||||
location: span,
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
select! {Token::Name {name} => name}.map_with_span(
|
|
||||||
|name, span| ast::UntypedRecordUpdateArg {
|
|
||||||
location: span,
|
|
||||||
value: UntypedExpr::Var {
|
|
||||||
name: name.clone(),
|
|
||||||
location: span,
|
|
||||||
},
|
|
||||||
label: name,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
))
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.allow_trailing(),
|
|
||||||
)
|
|
||||||
.or_not(),
|
|
||||||
)
|
|
||||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace))
|
|
||||||
.map_with_span(|a, span: Span| (a, span)),
|
|
||||||
)
|
|
||||||
.map(|((module, (name, n_span)), ((spread, opt_args), span))| {
|
|
||||||
let constructor = if let Some((module, m_span)) = module {
|
|
||||||
UntypedExpr::FieldAccess {
|
|
||||||
location: m_span.union(n_span),
|
|
||||||
label: name,
|
|
||||||
container: Box::new(UntypedExpr::Var {
|
|
||||||
location: m_span,
|
|
||||||
name: module,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
UntypedExpr::Var {
|
|
||||||
location: n_span,
|
|
||||||
name,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let spread_span = spread.location();
|
|
||||||
|
|
||||||
let location = Span::new((), spread_span.start - 2..spread_span.end);
|
|
||||||
|
|
||||||
let spread = ast::RecordUpdateSpread {
|
|
||||||
base: Box::new(spread),
|
|
||||||
location,
|
|
||||||
};
|
|
||||||
|
|
||||||
UntypedExpr::RecordUpdate {
|
|
||||||
location: constructor.location().union(span),
|
|
||||||
constructor: Box::new(constructor),
|
|
||||||
spread,
|
|
||||||
arguments: opt_args.unwrap_or_default(),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let record_parser = choice((
|
|
||||||
select! {Token::Name { name } => name}
|
|
||||||
.map_with_span(|module, span: Span| (module, span))
|
|
||||||
.then_ignore(just(Token::Dot))
|
|
||||||
.or_not()
|
|
||||||
.then(
|
|
||||||
select! {Token::UpName { name } => name}
|
|
||||||
.map_with_span(|name, span| (name, span)),
|
|
||||||
)
|
|
||||||
.then(
|
|
||||||
choice((
|
|
||||||
select! {Token::Name {name} => name}
|
|
||||||
.then_ignore(just(Token::Colon))
|
|
||||||
.then(choice((
|
|
||||||
r.clone(),
|
|
||||||
select! {Token::DiscardName {name} => name }.validate(
|
|
||||||
|_name, span, emit| {
|
|
||||||
emit(ParseError::expected_input_found(
|
|
||||||
span,
|
|
||||||
None,
|
|
||||||
Some(error::Pattern::Discard),
|
|
||||||
));
|
|
||||||
|
|
||||||
UntypedExpr::Var {
|
|
||||||
location: span,
|
|
||||||
name: ast::CAPTURE_VARIABLE.to_string(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)))
|
|
||||||
.map_with_span(|(label, value), span| ast::CallArg {
|
|
||||||
location: span,
|
|
||||||
value,
|
|
||||||
label: Some(label),
|
|
||||||
}),
|
|
||||||
choice((
|
|
||||||
select! {Token::Name {name} => name}.map_with_span(|name, span| {
|
|
||||||
(
|
|
||||||
UntypedExpr::Var {
|
|
||||||
name: name.clone(),
|
|
||||||
location: span,
|
|
||||||
},
|
|
||||||
name,
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
select! {Token::DiscardName {name} => name }.validate(
|
|
||||||
|name, span, emit| {
|
|
||||||
emit(ParseError::expected_input_found(
|
|
||||||
span,
|
|
||||||
None,
|
|
||||||
Some(error::Pattern::Discard),
|
|
||||||
));
|
|
||||||
|
|
||||||
(
|
|
||||||
UntypedExpr::Var {
|
|
||||||
location: span,
|
|
||||||
name: CAPTURE_VARIABLE.to_string(),
|
|
||||||
},
|
|
||||||
name,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
))
|
|
||||||
.map(|(value, name)| ast::CallArg {
|
|
||||||
location: value.location(),
|
|
||||||
value,
|
|
||||||
label: Some(name),
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.allow_trailing()
|
|
||||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
|
||||||
),
|
|
||||||
select! {Token::Name { name } => name}
|
|
||||||
.map_with_span(|module, span| (module, span))
|
|
||||||
.then_ignore(just(Token::Dot))
|
|
||||||
.or_not()
|
|
||||||
.then(
|
|
||||||
select! {Token::UpName { name } => name}
|
|
||||||
.map_with_span(|name, span| (name, span)),
|
|
||||||
)
|
|
||||||
.then(
|
|
||||||
select! {Token::Name {name} => name}
|
|
||||||
.ignored()
|
|
||||||
.then_ignore(just(Token::Colon))
|
|
||||||
.validate(|_label, span, emit| {
|
|
||||||
emit(ParseError::expected_input_found(
|
|
||||||
span,
|
|
||||||
None,
|
|
||||||
Some(error::Pattern::Label),
|
|
||||||
))
|
|
||||||
})
|
|
||||||
.or_not()
|
|
||||||
.then(choice((
|
|
||||||
r.clone(),
|
|
||||||
select! {Token::DiscardName {name} => name }.validate(
|
|
||||||
|_name, span, emit| {
|
|
||||||
emit(ParseError::expected_input_found(
|
|
||||||
span,
|
|
||||||
None,
|
|
||||||
Some(error::Pattern::Discard),
|
|
||||||
));
|
|
||||||
|
|
||||||
UntypedExpr::Var {
|
|
||||||
location: span,
|
|
||||||
name: CAPTURE_VARIABLE.to_string(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)))
|
|
||||||
.map(|(_label, value)| ast::CallArg {
|
|
||||||
location: value.location(),
|
|
||||||
value,
|
|
||||||
label: None,
|
|
||||||
})
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.allow_trailing()
|
|
||||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
.map_with_span(|((module, (name, n_span)), arguments), span| {
|
|
||||||
let fun = if let Some((module, m_span)) = module {
|
|
||||||
UntypedExpr::FieldAccess {
|
|
||||||
location: m_span.union(n_span),
|
|
||||||
label: name,
|
|
||||||
container: Box::new(UntypedExpr::Var {
|
|
||||||
location: m_span,
|
|
||||||
name: module,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
UntypedExpr::Var {
|
|
||||||
location: n_span,
|
|
||||||
name,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
UntypedExpr::Call {
|
|
||||||
arguments,
|
|
||||||
fun: Box::new(fun),
|
|
||||||
location: span,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let field_access_constructor = select! {Token::Name { name } => name}
|
let field_access_constructor = select! {Token::Name { name } => name}
|
||||||
.map_with_span(|module, span| (module, span))
|
.map_with_span(|module, span| (module, span))
|
||||||
.then_ignore(just(Token::Dot))
|
.then_ignore(just(Token::Dot))
|
||||||
|
@ -266,66 +49,6 @@ pub fn parser(
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
let var_parser = select! {
|
|
||||||
Token::Name { name } => name,
|
|
||||||
Token::UpName { name } => name,
|
|
||||||
}
|
|
||||||
.map_with_span(|name, span| UntypedExpr::Var {
|
|
||||||
location: span,
|
|
||||||
name,
|
|
||||||
});
|
|
||||||
|
|
||||||
let tuple = r
|
|
||||||
.clone()
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.at_least(2)
|
|
||||||
.allow_trailing()
|
|
||||||
.delimited_by(
|
|
||||||
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
|
|
||||||
just(Token::RightParen),
|
|
||||||
)
|
|
||||||
.map_with_span(|elems, span| UntypedExpr::Tuple {
|
|
||||||
location: span,
|
|
||||||
elems,
|
|
||||||
});
|
|
||||||
|
|
||||||
let bytearray = utils::bytearray().map_with_span(|(preferred_format, bytes), span| {
|
|
||||||
UntypedExpr::ByteArray {
|
|
||||||
location: span,
|
|
||||||
bytes,
|
|
||||||
preferred_format,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let list_parser = 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())
|
|
||||||
.map(Box::new)
|
|
||||||
.or_not(),
|
|
||||||
),
|
|
||||||
just(Token::Comma).ignored().or_not().map(|_| None),
|
|
||||||
)))
|
|
||||||
.then_ignore(just(Token::RightSquare))
|
|
||||||
// TODO: check if tail.is_some and elements.is_empty then return ListSpreadWithoutElements error
|
|
||||||
.map_with_span(|(elements, tail), span| UntypedExpr::List {
|
|
||||||
location: span,
|
|
||||||
elements,
|
|
||||||
tail,
|
|
||||||
});
|
|
||||||
|
|
||||||
let block_parser = choice((
|
|
||||||
seq_r
|
|
||||||
.clone()
|
|
||||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
|
||||||
seq_r.clone().delimited_by(
|
|
||||||
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
|
|
||||||
just(Token::RightParen),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
|
|
||||||
let anon_fn_parser = just(Token::Fn)
|
let anon_fn_parser = just(Token::Fn)
|
||||||
.ignore_then(
|
.ignore_then(
|
||||||
anon_fn_param_parser()
|
anon_fn_param_parser()
|
||||||
|
@ -523,57 +246,23 @@ pub fn parser(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let if_parser = just(Token::If)
|
|
||||||
.ignore_then(r.clone().then(block_parser.clone()).map_with_span(
|
|
||||||
|(condition, body), span| ast::IfBranch {
|
|
||||||
condition,
|
|
||||||
body,
|
|
||||||
location: span,
|
|
||||||
},
|
|
||||||
))
|
|
||||||
.then(
|
|
||||||
just(Token::Else)
|
|
||||||
.ignore_then(just(Token::If))
|
|
||||||
.ignore_then(r.clone().then(block_parser.clone()).map_with_span(
|
|
||||||
|(condition, body), span| ast::IfBranch {
|
|
||||||
condition,
|
|
||||||
body,
|
|
||||||
location: span,
|
|
||||||
},
|
|
||||||
))
|
|
||||||
.repeated(),
|
|
||||||
)
|
|
||||||
.then_ignore(just(Token::Else))
|
|
||||||
.then(block_parser.clone())
|
|
||||||
.map_with_span(|((first, alternative_branches), final_else), span| {
|
|
||||||
let mut branches = vec1::vec1![first];
|
|
||||||
|
|
||||||
branches.extend(alternative_branches);
|
|
||||||
|
|
||||||
UntypedExpr::If {
|
|
||||||
location: span,
|
|
||||||
branches,
|
|
||||||
final_else: Box::new(final_else),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let expr_unit_parser = choice((
|
let expr_unit_parser = choice((
|
||||||
string_parser,
|
string(),
|
||||||
int_parser,
|
int(),
|
||||||
record_update_parser,
|
record_update(r),
|
||||||
record_parser,
|
record(r),
|
||||||
field_access_constructor,
|
field_access_constructor,
|
||||||
var_parser,
|
var(),
|
||||||
tuple,
|
tuple(r),
|
||||||
bytearray,
|
bytearray(),
|
||||||
list_parser,
|
list(r),
|
||||||
anon_fn_parser,
|
anon_fn_parser,
|
||||||
anon_binop_parser,
|
anon_binop_parser,
|
||||||
block_parser,
|
block(seq_r),
|
||||||
when_parser,
|
when_parser,
|
||||||
let_parser,
|
let_parser,
|
||||||
expect_parser,
|
expect_parser,
|
||||||
if_parser,
|
if_else(seq_r, r),
|
||||||
));
|
));
|
||||||
|
|
||||||
// Parsing a function call into the appropriate structure
|
// Parsing a function call into the appropriate structure
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ast,
|
||||||
|
expr::UntypedExpr,
|
||||||
|
parser::{
|
||||||
|
error::{self, ParseError},
|
||||||
|
token::Token,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parser(
|
||||||
|
r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||||
|
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||||
|
choice((
|
||||||
|
select! {Token::Name { name } => name}
|
||||||
|
.map_with_span(|module, span: ast::Span| (module, span))
|
||||||
|
.then_ignore(just(Token::Dot))
|
||||||
|
.or_not()
|
||||||
|
.then(select! {Token::UpName { name } => name}.map_with_span(|name, span| (name, span)))
|
||||||
|
.then(
|
||||||
|
choice((
|
||||||
|
select! {Token::Name {name} => name}
|
||||||
|
.then_ignore(just(Token::Colon))
|
||||||
|
.then(choice((
|
||||||
|
r.clone(),
|
||||||
|
select! {Token::DiscardName {name} => name }.validate(
|
||||||
|
|_name, span, emit| {
|
||||||
|
emit(ParseError::expected_input_found(
|
||||||
|
span,
|
||||||
|
None,
|
||||||
|
Some(error::Pattern::Discard),
|
||||||
|
));
|
||||||
|
|
||||||
|
UntypedExpr::Var {
|
||||||
|
location: span,
|
||||||
|
name: ast::CAPTURE_VARIABLE.to_string(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)))
|
||||||
|
.map_with_span(|(label, value), span| ast::CallArg {
|
||||||
|
location: span,
|
||||||
|
value,
|
||||||
|
label: Some(label),
|
||||||
|
}),
|
||||||
|
choice((
|
||||||
|
select! {Token::Name {name} => name}.map_with_span(|name, span| {
|
||||||
|
(
|
||||||
|
UntypedExpr::Var {
|
||||||
|
name: name.clone(),
|
||||||
|
location: span,
|
||||||
|
},
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
select! {Token::DiscardName {name} => name }.validate(
|
||||||
|
|name, span, emit| {
|
||||||
|
emit(ParseError::expected_input_found(
|
||||||
|
span,
|
||||||
|
None,
|
||||||
|
Some(error::Pattern::Discard),
|
||||||
|
));
|
||||||
|
|
||||||
|
(
|
||||||
|
UntypedExpr::Var {
|
||||||
|
location: span,
|
||||||
|
name: ast::CAPTURE_VARIABLE.to_string(),
|
||||||
|
},
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.map(|(value, name)| ast::CallArg {
|
||||||
|
location: value.location(),
|
||||||
|
value,
|
||||||
|
label: Some(name),
|
||||||
|
}),
|
||||||
|
))
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
||||||
|
),
|
||||||
|
select! {Token::Name { name } => name}
|
||||||
|
.map_with_span(|module, span| (module, span))
|
||||||
|
.then_ignore(just(Token::Dot))
|
||||||
|
.or_not()
|
||||||
|
.then(select! {Token::UpName { name } => name}.map_with_span(|name, span| (name, span)))
|
||||||
|
.then(
|
||||||
|
select! {Token::Name {name} => name}
|
||||||
|
.ignored()
|
||||||
|
.then_ignore(just(Token::Colon))
|
||||||
|
.validate(|_label, span, emit| {
|
||||||
|
emit(ParseError::expected_input_found(
|
||||||
|
span,
|
||||||
|
None,
|
||||||
|
Some(error::Pattern::Label),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.or_not()
|
||||||
|
.then(choice((
|
||||||
|
r.clone(),
|
||||||
|
select! {Token::DiscardName {name} => name }.validate(
|
||||||
|
|_name, span, emit| {
|
||||||
|
emit(ParseError::expected_input_found(
|
||||||
|
span,
|
||||||
|
None,
|
||||||
|
Some(error::Pattern::Discard),
|
||||||
|
));
|
||||||
|
|
||||||
|
UntypedExpr::Var {
|
||||||
|
location: span,
|
||||||
|
name: ast::CAPTURE_VARIABLE.to_string(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)))
|
||||||
|
.map(|(_label, value)| ast::CallArg {
|
||||||
|
location: value.location(),
|
||||||
|
value,
|
||||||
|
label: None,
|
||||||
|
})
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.map_with_span(|((module, (name, n_span)), arguments), span| {
|
||||||
|
let fun = if let Some((module, m_span)) = module {
|
||||||
|
UntypedExpr::FieldAccess {
|
||||||
|
location: m_span.union(n_span),
|
||||||
|
label: name,
|
||||||
|
container: Box::new(UntypedExpr::Var {
|
||||||
|
location: m_span,
|
||||||
|
name: module,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
UntypedExpr::Var {
|
||||||
|
location: n_span,
|
||||||
|
name,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
UntypedExpr::Call {
|
||||||
|
arguments,
|
||||||
|
fun: Box::new(fun),
|
||||||
|
location: span,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ast,
|
||||||
|
expr::UntypedExpr,
|
||||||
|
parser::{error::ParseError, token::Token},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parser(
|
||||||
|
r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||||
|
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||||
|
select! {Token::Name { name } => name}
|
||||||
|
.map_with_span(|module, span: ast::Span| (module, span))
|
||||||
|
.then_ignore(just(Token::Dot))
|
||||||
|
.or_not()
|
||||||
|
.then(select! {Token::UpName { name } => name}.map_with_span(|name, span| (name, span)))
|
||||||
|
.then(
|
||||||
|
just(Token::DotDot)
|
||||||
|
.ignore_then(r.clone())
|
||||||
|
.then(
|
||||||
|
just(Token::Comma)
|
||||||
|
.ignore_then(
|
||||||
|
choice((
|
||||||
|
select! { Token::Name {name} => name }
|
||||||
|
.then_ignore(just(Token::Colon))
|
||||||
|
.then(r.clone())
|
||||||
|
.map_with_span(|(label, value), span| {
|
||||||
|
ast::UntypedRecordUpdateArg {
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
location: span,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
select! {Token::Name {name} => name}.map_with_span(|name, span| {
|
||||||
|
ast::UntypedRecordUpdateArg {
|
||||||
|
location: span,
|
||||||
|
value: UntypedExpr::Var {
|
||||||
|
name: name.clone(),
|
||||||
|
location: span,
|
||||||
|
},
|
||||||
|
label: name,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
))
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.allow_trailing(),
|
||||||
|
)
|
||||||
|
.or_not(),
|
||||||
|
)
|
||||||
|
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace))
|
||||||
|
.map_with_span(|a, span: ast::Span| (a, span)),
|
||||||
|
)
|
||||||
|
.map(|((module, (name, n_span)), ((spread, opt_args), span))| {
|
||||||
|
let constructor = if let Some((module, m_span)) = module {
|
||||||
|
UntypedExpr::FieldAccess {
|
||||||
|
location: m_span.union(n_span),
|
||||||
|
label: name,
|
||||||
|
container: Box::new(UntypedExpr::Var {
|
||||||
|
location: m_span,
|
||||||
|
name: module,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
UntypedExpr::Var {
|
||||||
|
location: n_span,
|
||||||
|
name,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let spread_span = spread.location();
|
||||||
|
|
||||||
|
let location = ast::Span::new((), spread_span.start - 2..spread_span.end);
|
||||||
|
|
||||||
|
let spread = ast::RecordUpdateSpread {
|
||||||
|
base: Box::new(spread),
|
||||||
|
location,
|
||||||
|
};
|
||||||
|
|
||||||
|
UntypedExpr::RecordUpdate {
|
||||||
|
location: constructor.location().union(span),
|
||||||
|
constructor: Box::new(constructor),
|
||||||
|
spread,
|
||||||
|
arguments: opt_args.unwrap_or_default(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,4 +1,17 @@
|
||||||
use crate::{ast, expr::UntypedExpr};
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ast,
|
||||||
|
expr::UntypedExpr,
|
||||||
|
parser::{error::ParseError, token::Token},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
|
||||||
|
select! {Token::String {value} => value}.map_with_span(|value, span| UntypedExpr::String {
|
||||||
|
location: span,
|
||||||
|
value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Interpret bytearray string literals written as utf-8 strings, as strings.
|
/// Interpret bytearray string literals written as utf-8 strings, as strings.
|
||||||
///
|
///
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
expr::UntypedExpr,
|
||||||
|
parser::{error::ParseError, token::Token},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parser(
|
||||||
|
r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||||
|
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||||
|
r.clone()
|
||||||
|
.separated_by(just(Token::Comma))
|
||||||
|
.at_least(2)
|
||||||
|
.allow_trailing()
|
||||||
|
.delimited_by(
|
||||||
|
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
|
||||||
|
just(Token::RightParen),
|
||||||
|
)
|
||||||
|
.map_with_span(|elems, span| UntypedExpr::Tuple {
|
||||||
|
location: span,
|
||||||
|
elems,
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
use chumsky::prelude::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
expr::UntypedExpr,
|
||||||
|
parser::{error::ParseError, token::Token},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
|
||||||
|
select! {
|
||||||
|
Token::Name { name } => name,
|
||||||
|
Token::UpName { name } => name,
|
||||||
|
}
|
||||||
|
.map_with_span(|name, span| UntypedExpr::Var {
|
||||||
|
location: span,
|
||||||
|
name,
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue