diff --git a/crates/lang/src/format.rs b/crates/lang/src/format.rs index 59fd21bf..eaf2fa2d 100644 --- a/crates/lang/src/format.rs +++ b/crates/lang/src/format.rs @@ -839,17 +839,34 @@ impl<'comments> Formatter<'comments> { } fn call<'a>(&mut self, fun: &'a UntypedExpr, args: &'a [CallArg]) -> Document<'a> { + let is_constr = match fun { + UntypedExpr::Var { name, .. } => name[0..1].chars().all(|c| c.is_uppercase()), + UntypedExpr::FieldAccess { container, .. } => { + matches!(&**container, UntypedExpr::Var { name, .. } if name[0..1].chars().all(|c| c.is_uppercase())) + } + _ => false, + }; + + let needs_curly = if is_constr { + args.iter().all(|arg| arg.label.is_some()) + } else { + false + }; + match args { [arg] if is_breakable_expr(&arg.value) => self .expr(fun) - .append("(") - .append(self.call_arg(arg)) - .append(")") + .append(if needs_curly { "{" } else { "(" }) + .append(self.call_arg(arg, needs_curly)) + .append(if needs_curly { "}" } else { ")" }) .group(), _ => self .expr(fun) - .append(wrap_args(args.iter().map(|a| (self.call_arg(a), false)))) + .append(wrap_args( + args.iter() + .map(|a| (self.call_arg(a, needs_curly), needs_curly)), + )) .group(), } } @@ -978,12 +995,18 @@ impl<'comments> Formatter<'comments> { self.expr(fun) } else if hole_in_first_position { // x |> fun(_, 2, 3) - self.expr(fun) - .append(wrap_args(args.iter().skip(1).map(|a| (self.call_arg(a), false))).group()) + self.expr(fun).append( + wrap_args( + args.iter() + .skip(1) + .map(|a| (self.call_arg(a, false), false)), + ) + .group(), + ) } else { // x |> fun(1, _, 3) self.expr(fun) - .append(wrap_args(args.iter().map(|a| (self.call_arg(a), false))).group()) + .append(wrap_args(args.iter().map(|a| (self.call_arg(a, false), false))).group()) } } @@ -997,14 +1020,14 @@ impl<'comments> Formatter<'comments> { [first, second] if is_breakable_expr(&second.value) && first.is_capture_hole() => { self.expr(fun) .append("(_, ") - .append(self.call_arg(second)) + .append(self.call_arg(second, false)) .append(")") .group() } - _ => self - .expr(fun) - .append(wrap_args(args.iter().map(|a| (self.call_arg(a), false))).group()), + _ => self.expr(fun).append( + wrap_args(args.iter().map(|a| (self.call_arg(a, false), false))).group(), + ), }, // The body of a capture being not a fn shouldn't be possible... @@ -1188,12 +1211,18 @@ impl<'comments> Formatter<'comments> { } } - fn call_arg<'a>(&mut self, arg: &'a CallArg) -> Document<'a> { + fn call_arg<'a>(&mut self, arg: &'a CallArg, can_pun: bool) -> Document<'a> { match &arg.label { - Some(s) => commented( - s.to_doc().append(": "), - self.pop_comments(arg.location.start), - ), + Some(s) => { + if can_pun && matches!(&arg.value, UntypedExpr::Var { name, .. } if name == s) { + nil() + } else { + commented( + s.to_doc().append(": "), + self.pop_comments(arg.location.start), + ) + } + } None => nil(), } .append(self.wrap_expr(&arg.value)) diff --git a/crates/lang/src/parser.rs b/crates/lang/src/parser.rs index ad18fd24..6bb7626e 100644 --- a/crates/lang/src/parser.rs +++ b/crates/lang/src/parser.rs @@ -650,21 +650,60 @@ pub fn expr_parser( choice(( select! {Token::Name {name} => name} .then_ignore(just(Token::Colon)) - .then(r.clone()) + .then(choice(( + r.clone(), + select! {Token::DiscardName {name} => name }.validate( + |_name, span, emit| { + emit(ParseError::expected_input_found( + span, + None, + Some(error::Pattern::Discard), + )); + + expr::UntypedExpr::Var { + location: span, + name: CAPTURE_VARIABLE.to_string(), + } + }, + ), + ))) .map_with_span(|(label, value), span| ast::CallArg { location: span, value, label: Some(label), }), - select! {Token::Name {name} => name}.map_with_span(|name, span| { - ast::CallArg { - location: span, - value: expr::UntypedExpr::Var { - name: name.clone(), - location: span, + choice(( + select! {Token::Name {name} => name}.map_with_span(|name, span| { + ( + expr::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), + )); + + ( + expr::UntypedExpr::Var { + location: span, + name: CAPTURE_VARIABLE.to_string(), + }, + name, + ) }, - label: Some(name), - } + ), + )) + .map(|(value, name)| ast::CallArg { + location: value.location(), + value, + label: Some(name), }), )) .separated_by(just(Token::Comma)) @@ -680,9 +719,36 @@ pub fn expr_parser( .map_with_span(|name, span| (name, span)), ) .then( - r.clone() - .map_with_span(|value, span| ast::CallArg { - location: span, + 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), + )); + + expr::UntypedExpr::Var { + location: span, + name: CAPTURE_VARIABLE.to_string(), + } + }, + ), + ))) + .map(|(_label, value)| ast::CallArg { + location: value.location(), value, label: None, }) @@ -1340,8 +1406,8 @@ pub fn pattern_parser() -> impl Parser for Pattern { diff --git a/examples/sample/lib/sample.ak b/examples/sample/lib/sample.ak index dedde05b..d9a51364 100644 --- a/examples/sample/lib/sample.ak +++ b/examples/sample/lib/sample.ak @@ -46,4 +46,4 @@ pub fn incrementor(counter: Int, target: Int) -> Int { } } -pub const big_a = 5 \ No newline at end of file +pub const big_a = 5 diff --git a/examples/sample/validators/swap.ak b/examples/sample/validators/swap.ak index 49a1a5d9..2409c40c 100644 --- a/examples/sample/validators/swap.ak +++ b/examples/sample/validators/swap.ak @@ -50,7 +50,8 @@ pub type Datum { } pub fn spend(datum: Datum, _rdmr: Nil, _ctx: Nil) -> Bool { - let x = Buy1 { signer: #[4, 4, 255], amount: 1000 } + let amount = 1000 + let x = Buy1 { signer: #[4, 4, 255], amount } when x is { Buy1 { signer, .. } -> signer == #[3, 3, 255] Stuff(signer, _) -> signer == #[3, 3, 255]