Refactor chain parser
The main goal is to make the parser more reusable to be used for when-clauses, instead of the expression parser. A side goal has been to make it more readable by moving the construction of some untyped expression as method on UntypedExpr. Doing so, I got rid of the extra temporary 'ParseArg' type and re-used the generic 'CallArg' instead by simply using an Option<UntypedExpr> as value to get the same semantic as 'ParseArg' (which would distinguish between plain call args and holes). Now the chained parser is in a bit more reusable state.
This commit is contained in:
parent
549cf22cdd
commit
346df47232
|
@ -475,6 +475,7 @@ impl Constant {
|
|||
}
|
||||
|
||||
pub type TypedCallArg = CallArg<TypedExpr>;
|
||||
pub type ParsedCallArg = CallArg<Option<UntypedExpr>>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct CallArg<A> {
|
||||
|
|
|
@ -4,9 +4,9 @@ use vec1::Vec1;
|
|||
|
||||
use crate::{
|
||||
ast::{
|
||||
Annotation, Arg, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg,
|
||||
DefinitionLocation, IfBranch, Pattern, RecordUpdateSpread, Span, TraceKind, TypedClause,
|
||||
TypedRecordUpdateArg, UnOp, UntypedClause, UntypedRecordUpdateArg,
|
||||
self, Annotation, Arg, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg,
|
||||
DefinitionLocation, IfBranch, ParsedCallArg, Pattern, RecordUpdateSpread, Span, TraceKind,
|
||||
TypedClause, TypedRecordUpdateArg, UnOp, UntypedClause, UntypedRecordUpdateArg,
|
||||
},
|
||||
builtins::void,
|
||||
parser::token::Base,
|
||||
|
@ -564,6 +564,88 @@ impl UntypedExpr {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn tuple_index(self, index: usize, location: Span) -> Self {
|
||||
UntypedExpr::TupleIndex {
|
||||
location: self.location().union(location),
|
||||
index,
|
||||
tuple: Box::new(self),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field_access(self, label: String, location: Span) -> Self {
|
||||
UntypedExpr::FieldAccess {
|
||||
location: self.location().union(location),
|
||||
label,
|
||||
container: Box::new(self),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call(self, args: Vec<ParsedCallArg>, location: Span) -> Self {
|
||||
let mut holes = Vec::new();
|
||||
|
||||
let args = args
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, a)| match a {
|
||||
CallArg {
|
||||
value: Some(value),
|
||||
label,
|
||||
location,
|
||||
} => CallArg {
|
||||
value,
|
||||
label,
|
||||
location,
|
||||
},
|
||||
CallArg {
|
||||
value: None,
|
||||
label,
|
||||
location,
|
||||
} => {
|
||||
let name = format!("{}__{index}", ast::CAPTURE_VARIABLE);
|
||||
|
||||
holes.push(ast::Arg {
|
||||
location: Span::empty(),
|
||||
annotation: None,
|
||||
arg_name: ast::ArgName::Named {
|
||||
label: name.clone(),
|
||||
name,
|
||||
location: Span::empty(),
|
||||
is_validator_param: false,
|
||||
},
|
||||
tipo: (),
|
||||
});
|
||||
|
||||
ast::CallArg {
|
||||
label,
|
||||
location,
|
||||
value: UntypedExpr::Var {
|
||||
location,
|
||||
name: format!("{}__{index}", ast::CAPTURE_VARIABLE),
|
||||
},
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let call = UntypedExpr::Call {
|
||||
location: self.location().union(location),
|
||||
fun: Box::new(self),
|
||||
arguments: args,
|
||||
};
|
||||
|
||||
if holes.is_empty() {
|
||||
call
|
||||
} else {
|
||||
UntypedExpr::Fn {
|
||||
location: call.location(),
|
||||
fn_style: FnStyle::Capture,
|
||||
arguments: holes,
|
||||
body: Box::new(call),
|
||||
return_annotation: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append_in_sequence(self, next: Self) -> Self {
|
||||
let location = Span {
|
||||
start: self.location().start,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use super::{Chain, ParserArg};
|
||||
use super::Chain;
|
||||
use crate::{
|
||||
ast,
|
||||
ast::CallArg,
|
||||
expr::UntypedExpr,
|
||||
parser::{token::Token, ParseError},
|
||||
};
|
||||
|
@ -15,20 +15,19 @@ pub(crate) fn parser(
|
|||
.then_ignore(just(Token::Colon))
|
||||
.or_not()
|
||||
.then(expression)
|
||||
.map_with_span(|(label, value), span| {
|
||||
ParserArg::Arg(Box::new(ast::CallArg {
|
||||
.map_with_span(|(label, value), location| CallArg {
|
||||
label,
|
||||
location: span,
|
||||
value,
|
||||
}))
|
||||
location,
|
||||
value: Some(value),
|
||||
}),
|
||||
select! { Token::Name { name } => name }
|
||||
.then_ignore(just(Token::Colon))
|
||||
.or_not()
|
||||
.then_ignore(select! {Token::DiscardName {name} => name })
|
||||
.map_with_span(|label, span| ParserArg::Hole {
|
||||
location: span,
|
||||
.map_with_span(|label, location| CallArg {
|
||||
location,
|
||||
label,
|
||||
value: None,
|
||||
}),
|
||||
))
|
||||
.separated_by(just(Token::Comma))
|
||||
|
|
|
@ -1,22 +1,11 @@
|
|||
use crate::ast::{self, Span};
|
||||
use crate::expr::UntypedExpr;
|
||||
use crate::ast::{ParsedCallArg, Span};
|
||||
|
||||
pub(crate) mod call;
|
||||
pub(crate) mod field_access;
|
||||
pub(crate) mod tuple_index;
|
||||
|
||||
pub(crate) enum Chain {
|
||||
Call(Vec<ParserArg>, Span),
|
||||
Call(Vec<ParsedCallArg>, Span),
|
||||
FieldAccess(String, Span),
|
||||
TupleIndex(usize, Span),
|
||||
}
|
||||
|
||||
// Parsing a function call into the appropriate structure
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ParserArg {
|
||||
Arg(Box<ast::CallArg<UntypedExpr>>),
|
||||
Hole {
|
||||
location: Span,
|
||||
label: Option<String>,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -16,13 +16,9 @@ use super::var::parser as var;
|
|||
use super::when::parser as when;
|
||||
|
||||
use crate::{
|
||||
ast::{self, Span},
|
||||
expr::{FnStyle, UntypedExpr},
|
||||
expr::UntypedExpr,
|
||||
parser::{
|
||||
chain::{
|
||||
call::parser as call, field_access, tuple_index::parser as tuple_index, Chain,
|
||||
ParserArg,
|
||||
},
|
||||
chain::{call::parser as call, field_access, tuple_index::parser as tuple_index, Chain},
|
||||
error::ParseError,
|
||||
token::Token,
|
||||
},
|
||||
|
@ -40,71 +36,17 @@ pub fn parser<'a>(
|
|||
chain_start(sequence, expression)
|
||||
.then(chain.repeated())
|
||||
.foldl(|expr, chain| match chain {
|
||||
Chain::Call(args, span) => {
|
||||
let mut holes = Vec::new();
|
||||
|
||||
let args = args
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, a)| match a {
|
||||
ParserArg::Arg(arg) => *arg,
|
||||
ParserArg::Hole { location, label } => {
|
||||
let name = format!("{}__{index}", ast::CAPTURE_VARIABLE);
|
||||
|
||||
holes.push(ast::Arg {
|
||||
location: Span::empty(),
|
||||
annotation: None,
|
||||
arg_name: ast::ArgName::Named {
|
||||
label: name.clone(),
|
||||
name,
|
||||
location: Span::empty(),
|
||||
is_validator_param: false,
|
||||
},
|
||||
tipo: (),
|
||||
});
|
||||
|
||||
ast::CallArg {
|
||||
label,
|
||||
location,
|
||||
value: UntypedExpr::Var {
|
||||
location,
|
||||
name: format!("{}__{index}", ast::CAPTURE_VARIABLE),
|
||||
},
|
||||
}
|
||||
}
|
||||
Chain::Call(args, span) => expr.call(args, span),
|
||||
Chain::FieldAccess(label, span) => expr.field_access(label, span),
|
||||
Chain::TupleIndex(index, span) => expr.tuple_index(index, span),
|
||||
})
|
||||
.collect();
|
||||
|
||||
let call = UntypedExpr::Call {
|
||||
location: expr.location().union(span),
|
||||
fun: Box::new(expr),
|
||||
arguments: args,
|
||||
};
|
||||
|
||||
if holes.is_empty() {
|
||||
call
|
||||
} else {
|
||||
UntypedExpr::Fn {
|
||||
location: call.location(),
|
||||
fn_style: FnStyle::Capture,
|
||||
arguments: holes,
|
||||
body: Box::new(call),
|
||||
return_annotation: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Chain::FieldAccess(label, span) => UntypedExpr::FieldAccess {
|
||||
location: expr.location().union(span),
|
||||
label,
|
||||
container: Box::new(expr),
|
||||
},
|
||||
|
||||
Chain::TupleIndex(index, span) => UntypedExpr::TupleIndex {
|
||||
location: expr.location().union(span),
|
||||
index,
|
||||
tuple: Box::new(expr),
|
||||
.then(just(Token::Question).or_not())
|
||||
.map_with_span(|(value, token), location| match token {
|
||||
Some(_) => UntypedExpr::TraceIfFalse {
|
||||
value: Box::new(value),
|
||||
location,
|
||||
},
|
||||
None => value,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -53,16 +53,6 @@ pub fn pure_expression<'a>(
|
|||
sequence: Recursive<'a, Token, UntypedExpr, ParseError>,
|
||||
expression: Recursive<'a, Token, UntypedExpr, ParseError>,
|
||||
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + 'a {
|
||||
let chained_debugged = chained(sequence, expression)
|
||||
.then(just(Token::Question).or_not())
|
||||
.map_with_span(|(value, token), location| match token {
|
||||
Some(_) => UntypedExpr::TraceIfFalse {
|
||||
value: Box::new(value),
|
||||
location,
|
||||
},
|
||||
None => value,
|
||||
});
|
||||
|
||||
// Negate
|
||||
let op = choice((
|
||||
just(Token::Bang).to(ast::UnOp::Not),
|
||||
|
@ -85,7 +75,7 @@ pub fn pure_expression<'a>(
|
|||
let unary = op
|
||||
.map_with_span(|op, span| (op, span))
|
||||
.repeated()
|
||||
.then(chained_debugged)
|
||||
.then(chained(sequence, expression))
|
||||
.foldr(|(un_op, span), value| UntypedExpr::UnOp {
|
||||
op: un_op,
|
||||
location: span.union(value.location()),
|
||||
|
|
Loading…
Reference in New Issue