fix: better constructor pattern parsing
This commit is contained in:
parent
ef9fd15e12
commit
72bf27d467
|
@ -575,6 +575,7 @@ pub enum Pattern<Constructor, Type> {
|
|||
|
||||
/// The constructor for a custom type. Starts with an uppercase letter.
|
||||
Constructor {
|
||||
is_record: bool,
|
||||
location: Span,
|
||||
name: String,
|
||||
arguments: Vec<CallArg<Self>>,
|
||||
|
|
|
@ -737,6 +737,7 @@ impl<'comments> Formatter<'comments> {
|
|||
args: &'a [CallArg<UntypedPattern>],
|
||||
module: &'a Option<String>,
|
||||
with_spread: bool,
|
||||
is_record: bool,
|
||||
) -> Document<'a> {
|
||||
fn is_breakable(expr: &UntypedPattern) -> bool {
|
||||
match expr {
|
||||
|
@ -754,25 +755,32 @@ impl<'comments> Formatter<'comments> {
|
|||
};
|
||||
|
||||
if args.is_empty() && with_spread {
|
||||
if is_record {
|
||||
name.append("{..}")
|
||||
} else {
|
||||
name.append("(..)")
|
||||
}
|
||||
} else if args.is_empty() {
|
||||
name
|
||||
} else if with_spread {
|
||||
name.append(wrap_args_with_spread(
|
||||
args.iter().map(|a| self.pattern_call_arg(a)),
|
||||
))
|
||||
let wrapped_args = if is_record {
|
||||
wrap_fields_with_spread(args.iter().map(|a| self.pattern_call_arg(a)))
|
||||
} else {
|
||||
wrap_args_with_spread(args.iter().map(|a| self.pattern_call_arg(a)))
|
||||
};
|
||||
|
||||
name.append(wrapped_args)
|
||||
} else {
|
||||
match args {
|
||||
[arg] if is_breakable(&arg.value) => name
|
||||
.append(if arg.label.is_some() { "{" } else { "(" })
|
||||
.append(if is_record { "{" } else { "(" })
|
||||
.append(self.pattern_call_arg(arg))
|
||||
.append(if arg.label.is_some() { "}" } else { ")" })
|
||||
.append(if is_record { "}" } else { ")" })
|
||||
.group(),
|
||||
|
||||
_ => name
|
||||
.append(wrap_args(
|
||||
args.iter()
|
||||
.map(|a| (self.pattern_call_arg(a), a.label.is_some())),
|
||||
args.iter().map(|a| (self.pattern_call_arg(a), is_record)),
|
||||
))
|
||||
.group(),
|
||||
}
|
||||
|
@ -1254,8 +1262,9 @@ impl<'comments> Formatter<'comments> {
|
|||
arguments: args,
|
||||
module,
|
||||
with_spread,
|
||||
is_record,
|
||||
..
|
||||
} => self.pattern_constructor(name, args, module, *with_spread),
|
||||
} => self.pattern_constructor(name, args, module, *with_spread, *is_record),
|
||||
};
|
||||
commented(doc, comments)
|
||||
}
|
||||
|
@ -1396,10 +1405,10 @@ where
|
|||
|
||||
let args = args.map(|a| a.0);
|
||||
|
||||
let ((open_broken, open_unbroken), close) = if curly {
|
||||
((" {", " { "), "}")
|
||||
let (open_broken, open_unbroken, close) = if curly {
|
||||
(" {", " { ", "}")
|
||||
} else {
|
||||
(("(", "("), ")")
|
||||
("(", "(", ")")
|
||||
};
|
||||
|
||||
break_(open_broken, open_unbroken)
|
||||
|
@ -1444,6 +1453,25 @@ where
|
|||
.group()
|
||||
}
|
||||
|
||||
pub fn wrap_fields_with_spread<'a, I>(args: I) -> Document<'a>
|
||||
where
|
||||
I: IntoIterator<Item = Document<'a>>,
|
||||
{
|
||||
let mut args = args.into_iter().peekable();
|
||||
if args.peek().is_none() {
|
||||
return "()".to_doc();
|
||||
}
|
||||
|
||||
break_(" {", " { ")
|
||||
.append(join(args, break_(",", ", ")))
|
||||
.append(break_(",", ", "))
|
||||
.append("..")
|
||||
.nest(INDENT)
|
||||
.append(break_("", " "))
|
||||
.append("}")
|
||||
.group()
|
||||
}
|
||||
|
||||
fn list<'a>(elements: Document<'a>, length: usize, tail: Option<Document<'a>>) -> Document<'a> {
|
||||
if length == 0 {
|
||||
return match tail {
|
||||
|
|
|
@ -913,7 +913,13 @@ pub fn pub_parser() -> impl Parser<Token, (), Error = ParseError> {
|
|||
|
||||
pub fn pattern_parser() -> impl Parser<Token, ast::UntypedPattern, Error = ParseError> {
|
||||
recursive(|r| {
|
||||
let constructor_pattern_arg_parser = choice((
|
||||
let no_label = r.clone().map_with_span(|pattern, span| ast::CallArg {
|
||||
location: span,
|
||||
value: pattern,
|
||||
label: None,
|
||||
});
|
||||
|
||||
let record_constructor_pattern_arg_parser = choice((
|
||||
select! {Token::Name {name} => name}
|
||||
.then_ignore(just(Token::Colon))
|
||||
.then(r.clone())
|
||||
|
@ -922,14 +928,8 @@ pub fn pattern_parser() -> impl Parser<Token, ast::UntypedPattern, Error = Parse
|
|||
label: Some(name),
|
||||
value: pattern,
|
||||
}),
|
||||
r.map_with_span(|pattern, span| ast::CallArg {
|
||||
location: span,
|
||||
value: pattern,
|
||||
label: None,
|
||||
}),
|
||||
));
|
||||
|
||||
let constructor_pattern_args_parser = constructor_pattern_arg_parser
|
||||
no_label.clone(),
|
||||
))
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.then(
|
||||
|
@ -938,12 +938,28 @@ pub fn pattern_parser() -> impl Parser<Token, ast::UntypedPattern, Error = Parse
|
|||
.ignored()
|
||||
.or_not(),
|
||||
)
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace));
|
||||
|
||||
let tuple_constructor_pattern_arg_parser = no_label
|
||||
.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)| (a, b.is_some()))
|
||||
.unwrap_or_else(|| (vec![], false))
|
||||
.map(|((a, b), c)| (a, b.is_some(), c))
|
||||
.unwrap_or_else(|| (vec![], false, false))
|
||||
});
|
||||
|
||||
let constructor_pattern_parser =
|
||||
|
@ -957,8 +973,9 @@ pub fn pattern_parser() -> impl Parser<Token, ast::UntypedPattern, Error = Parse
|
|||
.or_not(),
|
||||
)
|
||||
.map_with_span(|(name, opt_pattern), span| {
|
||||
if let Some((c_name, (arguments, with_spread))) = opt_pattern {
|
||||
if let Some((c_name, (arguments, with_spread, is_record))) = opt_pattern {
|
||||
ast::UntypedPattern::Constructor {
|
||||
is_record,
|
||||
location: span,
|
||||
name: c_name,
|
||||
arguments,
|
||||
|
@ -974,8 +991,10 @@ pub fn pattern_parser() -> impl Parser<Token, ast::UntypedPattern, Error = Parse
|
|||
}
|
||||
}
|
||||
}),
|
||||
constructor_pattern_parser.map_with_span(|(name, (arguments, with_spread)), span| {
|
||||
constructor_pattern_parser.map_with_span(
|
||||
|(name, (arguments, with_spread, is_record)), span| {
|
||||
ast::UntypedPattern::Constructor {
|
||||
is_record,
|
||||
location: span,
|
||||
name,
|
||||
arguments,
|
||||
|
@ -984,7 +1003,8 @@ pub fn pattern_parser() -> impl Parser<Token, ast::UntypedPattern, Error = Parse
|
|||
with_spread,
|
||||
tipo: (),
|
||||
}
|
||||
}),
|
||||
},
|
||||
),
|
||||
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
||||
ast::UntypedPattern::Discard {
|
||||
name,
|
||||
|
|
|
@ -409,6 +409,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
name,
|
||||
arguments: mut pattern_args,
|
||||
with_spread,
|
||||
is_record,
|
||||
..
|
||||
} => {
|
||||
// Register the value as seen for detection of unused values
|
||||
|
@ -525,6 +526,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
constructor,
|
||||
with_spread,
|
||||
tipo: instantiated_constructor_type,
|
||||
is_record,
|
||||
})
|
||||
} else {
|
||||
Err(Error::IncorrectArity {
|
||||
|
@ -552,6 +554,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
constructor,
|
||||
with_spread,
|
||||
tipo: instantiated_constructor_type,
|
||||
is_record,
|
||||
})
|
||||
} else {
|
||||
Err(Error::IncorrectArity {
|
||||
|
|
|
@ -33,9 +33,10 @@ pub fn spend(
|
|||
rdmr: Redeemer,
|
||||
ctx: spend.ScriptContext,
|
||||
) -> Bool {
|
||||
when datum.rdmr is {
|
||||
sample.Buy(tipo1, fin) -> fin > 0
|
||||
sample.Sell(twice, find: fin) -> fin > 0
|
||||
let x = datum.rdmr
|
||||
when x is {
|
||||
sample.Buy { fin: fin, .. } -> fin > 0
|
||||
sample.Sell { find: fin, .. } -> fin > 0
|
||||
sample.Hold(some) -> some > 0
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue