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> {
|
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 {
|
match args {
|
||||||
[arg] if is_breakable_expr(&arg.value) => self
|
[arg] if is_breakable_expr(&arg.value) => self
|
||||||
.expr(fun)
|
.expr(fun)
|
||||||
.append("(")
|
.append(if needs_curly { "{" } else { "(" })
|
||||||
.append(self.call_arg(arg))
|
.append(self.call_arg(arg, needs_curly))
|
||||||
.append(")")
|
.append(if needs_curly { "}" } else { ")" })
|
||||||
.group(),
|
.group(),
|
||||||
|
|
||||||
_ => self
|
_ => self
|
||||||
.expr(fun)
|
.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(),
|
.group(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -978,12 +995,18 @@ impl<'comments> Formatter<'comments> {
|
||||||
self.expr(fun)
|
self.expr(fun)
|
||||||
} else if hole_in_first_position {
|
} else if hole_in_first_position {
|
||||||
// x |> fun(_, 2, 3)
|
// x |> fun(_, 2, 3)
|
||||||
self.expr(fun)
|
self.expr(fun).append(
|
||||||
.append(wrap_args(args.iter().skip(1).map(|a| (self.call_arg(a), false))).group())
|
wrap_args(
|
||||||
|
args.iter()
|
||||||
|
.skip(1)
|
||||||
|
.map(|a| (self.call_arg(a, false), false)),
|
||||||
|
)
|
||||||
|
.group(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
// x |> fun(1, _, 3)
|
// x |> fun(1, _, 3)
|
||||||
self.expr(fun)
|
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() => {
|
[first, second] if is_breakable_expr(&second.value) && first.is_capture_hole() => {
|
||||||
self.expr(fun)
|
self.expr(fun)
|
||||||
.append("(_, ")
|
.append("(_, ")
|
||||||
.append(self.call_arg(second))
|
.append(self.call_arg(second, false))
|
||||||
.append(")")
|
.append(")")
|
||||||
.group()
|
.group()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => self
|
_ => self.expr(fun).append(
|
||||||
.expr(fun)
|
wrap_args(args.iter().map(|a| (self.call_arg(a, false), false))).group(),
|
||||||
.append(wrap_args(args.iter().map(|a| (self.call_arg(a), false))).group()),
|
),
|
||||||
},
|
},
|
||||||
|
|
||||||
// The body of a capture being not a fn shouldn't be possible...
|
// 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 {
|
match &arg.label {
|
||||||
Some(s) => commented(
|
Some(s) => {
|
||||||
|
if can_pun && matches!(&arg.value, UntypedExpr::Var { name, .. } if name == s) {
|
||||||
|
nil()
|
||||||
|
} else {
|
||||||
|
commented(
|
||||||
s.to_doc().append(": "),
|
s.to_doc().append(": "),
|
||||||
self.pop_comments(arg.location.start),
|
self.pop_comments(arg.location.start),
|
||||||
),
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
None => nil(),
|
None => nil(),
|
||||||
}
|
}
|
||||||
.append(self.wrap_expr(&arg.value))
|
.append(self.wrap_expr(&arg.value))
|
||||||
|
|
|
@ -650,21 +650,60 @@ pub fn expr_parser(
|
||||||
choice((
|
choice((
|
||||||
select! {Token::Name {name} => name}
|
select! {Token::Name {name} => name}
|
||||||
.then_ignore(just(Token::Colon))
|
.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 {
|
.map_with_span(|(label, value), span| ast::CallArg {
|
||||||
location: span,
|
location: span,
|
||||||
value,
|
value,
|
||||||
label: Some(label),
|
label: Some(label),
|
||||||
}),
|
}),
|
||||||
|
choice((
|
||||||
select! {Token::Name {name} => name}.map_with_span(|name, span| {
|
select! {Token::Name {name} => name}.map_with_span(|name, span| {
|
||||||
ast::CallArg {
|
(
|
||||||
location: span,
|
expr::UntypedExpr::Var {
|
||||||
value: expr::UntypedExpr::Var {
|
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
location: span,
|
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,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.map(|(value, name)| ast::CallArg {
|
||||||
|
location: value.location(),
|
||||||
|
value,
|
||||||
label: Some(name),
|
label: Some(name),
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
.separated_by(just(Token::Comma))
|
.separated_by(just(Token::Comma))
|
||||||
|
@ -680,9 +719,36 @@ pub fn expr_parser(
|
||||||
.map_with_span(|name, span| (name, span)),
|
.map_with_span(|name, span| (name, span)),
|
||||||
)
|
)
|
||||||
.then(
|
.then(
|
||||||
r.clone()
|
select! {Token::Name {name} => name}
|
||||||
.map_with_span(|value, span| ast::CallArg {
|
.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,
|
location: span,
|
||||||
|
name: CAPTURE_VARIABLE.to_string(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)))
|
||||||
|
.map(|(_label, value)| ast::CallArg {
|
||||||
|
location: value.location(),
|
||||||
value,
|
value,
|
||||||
label: None,
|
label: None,
|
||||||
})
|
})
|
||||||
|
@ -1340,8 +1406,8 @@ pub fn pattern_parser() -> impl Parser<Token, ast::UntypedPattern, Error = Parse
|
||||||
|
|
||||||
let tuple_constructor_pattern_arg_parser = r
|
let tuple_constructor_pattern_arg_parser = r
|
||||||
.clone()
|
.clone()
|
||||||
.map_with_span(|pattern, span| ast::CallArg {
|
.map(|pattern| ast::CallArg {
|
||||||
location: span,
|
location: pattern.location(),
|
||||||
value: pattern,
|
value: pattern,
|
||||||
label: None,
|
label: None,
|
||||||
})
|
})
|
||||||
|
|
|
@ -115,6 +115,12 @@ pub enum Pattern {
|
||||||
"If no label is provided then only variables\nmatching a field name are allowed"
|
"If no label is provided then only variables\nmatching a field name are allowed"
|
||||||
))]
|
))]
|
||||||
RecordPunning,
|
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 {
|
impl From<char> for Pattern {
|
||||||
|
|
|
@ -50,7 +50,8 @@ pub type Datum {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spend(datum: Datum, _rdmr: Nil, _ctx: Nil) -> Bool {
|
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 {
|
when x is {
|
||||||
Buy1 { signer, .. } -> signer == #[3, 3, 255]
|
Buy1 { signer, .. } -> signer == #[3, 3, 255]
|
||||||
Stuff(signer, _) -> signer == #[3, 3, 255]
|
Stuff(signer, _) -> signer == #[3, 3, 255]
|
||||||
|
|
Loading…
Reference in New Issue