Support multi-clause patterns as syntactic sugar
And disable multi-patterns clauses. I was originally just controlling whether we did disable that from the parser but then I figured we could actually support multi-patterns clauses quite easily by simply desugaring a multi-pattern into multiple clauses. This is only a syntactic sugar, which means that the cost of writing that on-chain is as expensive as writing the fully expanded form; yet it seems like a useful shorthand; especially for short clause expressions. This commit however disables multi-pattern when clauses, which we do not support in the code-generation. Instead, one pattern on tuples for that.
This commit is contained in:
parent
660ca3fada
commit
c113582404
|
@ -19,6 +19,7 @@
|
|||
- **aiken-lang**: the compiler now provides better feedback for type holes (i.e. `_`) in type annotations
|
||||
- **aiken-lang**: assignment and clause guard are now always formatted on a new line
|
||||
- **aiken-lang**: unused let-bindings are now fully removed from generated code and discarded unused let-binding now raise a warning
|
||||
- **aiken-lang**: support multi-clause patterns (only as a syntactic sugar)
|
||||
|
||||
## [v0.0.29] - 2023-MM-DD
|
||||
|
||||
|
|
|
@ -936,6 +936,29 @@ impl TypedClause {
|
|||
pub fn find_node(&self, byte_index: usize) -> Option<&TypedExpr> {
|
||||
self.then.find_node(byte_index)
|
||||
}
|
||||
|
||||
pub fn desugarize(self) -> Vec<Self> {
|
||||
let mut alternative_patterns = self
|
||||
.alternative_patterns
|
||||
.into_iter()
|
||||
.map(|pattern| Self {
|
||||
location: self.location,
|
||||
pattern,
|
||||
alternative_patterns: vec![],
|
||||
guard: self.guard.clone(),
|
||||
then: self.then.clone(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut clauses = vec![Self {
|
||||
alternative_patterns: vec![],
|
||||
..self
|
||||
}];
|
||||
|
||||
clauses.append(&mut alternative_patterns);
|
||||
|
||||
clauses
|
||||
}
|
||||
}
|
||||
|
||||
pub type UntypedClauseGuard = ClauseGuard<()>;
|
||||
|
|
|
@ -921,15 +921,9 @@ pub fn expr_parser(
|
|||
);
|
||||
|
||||
let when_clause_parser = pattern_parser()
|
||||
.separated_by(just(Token::Comma))
|
||||
.at_least(1)
|
||||
.then(
|
||||
just(Token::Vbar)
|
||||
.ignore_then(
|
||||
pattern_parser()
|
||||
.separated_by(just(Token::Comma))
|
||||
.at_least(1),
|
||||
)
|
||||
.ignore_then(pattern_parser().map(|pattern| vec![pattern]))
|
||||
.repeated()
|
||||
.or_not(),
|
||||
)
|
||||
|
@ -968,9 +962,9 @@ pub fn expr_parser(
|
|||
}),
|
||||
)))
|
||||
.map_with_span(
|
||||
|(((patterns, alternative_patterns_opt), guard), then), span| ast::UntypedClause {
|
||||
|(((pattern, alternative_patterns_opt), guard), then), span| ast::UntypedClause {
|
||||
location: span,
|
||||
pattern: patterns,
|
||||
pattern: vec![pattern],
|
||||
alternative_patterns: alternative_patterns_opt.unwrap_or_default(),
|
||||
guard,
|
||||
then,
|
||||
|
|
|
@ -11,14 +11,14 @@ fn assert_definitions(code: &str, definitions: Vec<ast::UntypedDefinition>) {
|
|||
let (module, _extra) = parser::module(code, ast::ModuleKind::Validator).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
module,
|
||||
ast::UntypedModule {
|
||||
docs: vec![],
|
||||
kind: ast::ModuleKind::Validator,
|
||||
name: "".to_string(),
|
||||
type_info: (),
|
||||
definitions,
|
||||
}
|
||||
},
|
||||
module
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -901,11 +901,10 @@ fn block() {
|
|||
fn when() {
|
||||
let code = indoc! {r#"
|
||||
pub fn wow2(a: Int){
|
||||
when a, b is {
|
||||
1, 2 -> 3
|
||||
1 | 4, 5 -> {
|
||||
when a is {
|
||||
2 -> 3
|
||||
1 | 4 | 5 -> {
|
||||
let amazing = 5
|
||||
|
||||
amazing
|
||||
}
|
||||
3 -> 9
|
||||
|
@ -933,100 +932,88 @@ fn when() {
|
|||
tipo: (),
|
||||
}],
|
||||
body: expr::UntypedExpr::When {
|
||||
location: Span::new((), 23..138),
|
||||
subjects: vec![
|
||||
expr::UntypedExpr::Var {
|
||||
location: Span::new((), 28..29),
|
||||
name: "a".to_string(),
|
||||
},
|
||||
expr::UntypedExpr::Var {
|
||||
location: Span::new((), 31..32),
|
||||
name: "b".to_string(),
|
||||
},
|
||||
],
|
||||
location: Span::new((), 23..132),
|
||||
subjects: vec![expr::UntypedExpr::Var {
|
||||
location: Span::new((), 28..29),
|
||||
name: "a".to_string(),
|
||||
}],
|
||||
clauses: vec![
|
||||
ast::Clause {
|
||||
location: Span::new((), 42..51),
|
||||
pattern: vec![
|
||||
ast::Pattern::Int {
|
||||
location: Span::new((), 42..43),
|
||||
value: "1".to_string(),
|
||||
},
|
||||
ast::Pattern::Int {
|
||||
location: Span::new((), 45..46),
|
||||
value: "2".to_string(),
|
||||
},
|
||||
],
|
||||
location: Span::new((), 39..45),
|
||||
pattern: vec![ast::Pattern::Int {
|
||||
location: Span::new((), 39..40),
|
||||
value: "2".to_string(),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: None,
|
||||
then: expr::UntypedExpr::Int {
|
||||
location: Span::new((), 50..51),
|
||||
location: Span::new((), 44..45),
|
||||
value: "3".to_string(),
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
location: Span::new((), 56..112),
|
||||
location: Span::new((), 50..106),
|
||||
pattern: vec![ast::Pattern::Int {
|
||||
location: Span::new((), 56..57),
|
||||
location: Span::new((), 50..51),
|
||||
value: "1".to_string(),
|
||||
}],
|
||||
alternative_patterns: vec![vec![
|
||||
ast::Pattern::Int {
|
||||
location: Span::new((), 60..61),
|
||||
alternative_patterns: vec![
|
||||
vec![ast::Pattern::Int {
|
||||
location: Span::new((), 54..55),
|
||||
value: "4".to_string(),
|
||||
},
|
||||
ast::Pattern::Int {
|
||||
location: Span::new((), 63..64),
|
||||
}],
|
||||
vec![ast::Pattern::Int {
|
||||
location: Span::new((), 58..59),
|
||||
value: "5".to_string(),
|
||||
},
|
||||
]],
|
||||
}],
|
||||
],
|
||||
guard: None,
|
||||
then: expr::UntypedExpr::Sequence {
|
||||
location: Span::new((), 76..106),
|
||||
location: Span::new((), 71..100),
|
||||
expressions: vec![
|
||||
expr::UntypedExpr::Assignment {
|
||||
location: Span::new((), 76..91),
|
||||
location: Span::new((), 71..86),
|
||||
value: Box::new(expr::UntypedExpr::Int {
|
||||
location: Span::new((), 90..91),
|
||||
location: Span::new((), 85..86),
|
||||
value: "5".to_string(),
|
||||
}),
|
||||
pattern: ast::Pattern::Var {
|
||||
location: Span::new((), 80..87),
|
||||
location: Span::new((), 75..82),
|
||||
name: "amazing".to_string(),
|
||||
},
|
||||
kind: ast::AssignmentKind::Let,
|
||||
annotation: None,
|
||||
},
|
||||
expr::UntypedExpr::Var {
|
||||
location: Span::new((), 99..106),
|
||||
location: Span::new((), 93..100),
|
||||
name: "amazing".to_string(),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
location: Span::new((), 117..123),
|
||||
location: Span::new((), 111..117),
|
||||
pattern: vec![ast::Pattern::Int {
|
||||
location: Span::new((), 117..118),
|
||||
location: Span::new((), 111..112),
|
||||
value: "3".to_string(),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: None,
|
||||
then: expr::UntypedExpr::Int {
|
||||
location: Span::new((), 122..123),
|
||||
location: Span::new((), 116..117),
|
||||
value: "9".to_string(),
|
||||
},
|
||||
},
|
||||
ast::Clause {
|
||||
location: Span::new((), 128..134),
|
||||
location: Span::new((), 122..128),
|
||||
pattern: vec![ast::Pattern::Discard {
|
||||
name: "_".to_string(),
|
||||
location: Span::new((), 128..129),
|
||||
location: Span::new((), 122..123),
|
||||
}],
|
||||
alternative_patterns: vec![],
|
||||
guard: None,
|
||||
then: expr::UntypedExpr::Int {
|
||||
location: Span::new((), 133..134),
|
||||
location: Span::new((), 127..128),
|
||||
value: "4".to_string(),
|
||||
},
|
||||
},
|
||||
|
@ -1038,7 +1025,7 @@ fn when() {
|
|||
public: true,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 139,
|
||||
end_position: 133,
|
||||
})],
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1888,7 +1888,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
|
||||
let mut typed_subjects = Vec::with_capacity(subjects_count);
|
||||
let mut subject_types = Vec::with_capacity(subjects_count);
|
||||
let mut typed_clauses = Vec::with_capacity(clauses.len());
|
||||
let mut typed_clauses = Vec::new();
|
||||
|
||||
let return_type = self.new_unbound_var();
|
||||
|
||||
|
@ -1911,7 +1911,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
)
|
||||
.map_err(|e| e.case_clause_mismatch())?;
|
||||
|
||||
typed_clauses.push(typed_clause);
|
||||
typed_clauses.append(&mut typed_clause.desugarize());
|
||||
}
|
||||
|
||||
if let Err(unmatched) =
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# This file was generated by Aiken
|
||||
# You typically do not need to edit this file
|
||||
|
||||
requirements = []
|
||||
packages = []
|
|
@ -0,0 +1,2 @@
|
|||
name = "aiken-lang/acceptance_test_078"
|
||||
version = "0.0.0"
|
|
@ -0,0 +1,45 @@
|
|||
type DayOfTheWeek {
|
||||
Monday
|
||||
Tuesday
|
||||
Wednesday
|
||||
Thursday
|
||||
Friday
|
||||
Saturday
|
||||
Sunday
|
||||
}
|
||||
|
||||
fn is_work(day: DayOfTheWeek) {
|
||||
when day is {
|
||||
Tuesday | Wednesday | Thursday | Friday | Saturday ->
|
||||
True
|
||||
_ ->
|
||||
False
|
||||
}
|
||||
}
|
||||
|
||||
test is_work_1() {
|
||||
is_work(Thursday)
|
||||
}
|
||||
|
||||
test is_work_2() {
|
||||
!is_work(Monday)
|
||||
}
|
||||
|
||||
fn is_happy_hour(day: DayOfTheWeek, current_time: Int) {
|
||||
when day is {
|
||||
Monday | Sunday ->
|
||||
True
|
||||
Tuesday | Wednesday | Thursday | Friday | Saturday if current_time > 18 ->
|
||||
True
|
||||
_ ->
|
||||
False
|
||||
}
|
||||
}
|
||||
|
||||
test is_happy_hour_1() {
|
||||
is_happy_hour(Sunday, 14)
|
||||
}
|
||||
|
||||
test is_happy_hour_2() {
|
||||
is_happy_hour(Friday, 22)
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"preamble": {
|
||||
"title": "aiken-lang/acceptance_test_078",
|
||||
"version": "0.0.0",
|
||||
"plutusVersion": "v2"
|
||||
},
|
||||
"validators": []
|
||||
}
|
Loading…
Reference in New Issue