feat: better errors for incorrect contructor making
This commit is contained in:
parent
7e6dc978a1
commit
7875af7d35
|
@ -839,17 +839,34 @@ impl<'comments> Formatter<'comments> {
|
|||
}
|
||||
|
||||
fn call<'a>(&mut self, fun: &'a UntypedExpr, args: &'a [CallArg<UntypedExpr>]) -> 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<UntypedExpr>) -> Document<'a> {
|
||||
fn call_arg<'a>(&mut self, arg: &'a CallArg<UntypedExpr>, 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))
|
||||
|
|
|
@ -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<Token, ast::UntypedPattern, Error = Parse
|
|||
|
||||
let tuple_constructor_pattern_arg_parser = r
|
||||
.clone()
|
||||
.map_with_span(|pattern, span| ast::CallArg {
|
||||
location: span,
|
||||
.map(|pattern| ast::CallArg {
|
||||
location: pattern.location(),
|
||||
value: pattern,
|
||||
label: None,
|
||||
})
|
||||
|
|
|
@ -115,6 +115,12 @@ pub enum Pattern {
|
|||
"If no label is provided then only variables\nmatching a field name are allowed"
|
||||
))]
|
||||
RecordPunning,
|
||||
#[error("Unexpected label")]
|
||||
#[diagnostic(help("You can only use labels with curly braces"))]
|
||||
Label,
|
||||
#[error("Unexpected hole")]
|
||||
#[diagnostic(help("You can only use capture syntax with functions not constructors"))]
|
||||
Discard,
|
||||
}
|
||||
|
||||
impl From<char> for Pattern {
|
||||
|
|
|
@ -46,4 +46,4 @@ pub fn incrementor(counter: Int, target: Int) -> Int {
|
|||
}
|
||||
}
|
||||
|
||||
pub const big_a = 5
|
||||
pub const big_a = 5
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in New Issue