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**: 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**: 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**: 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
|
## [v0.0.29] - 2023-MM-DD
|
||||||
|
|
||||||
|
|
|
@ -936,6 +936,29 @@ impl TypedClause {
|
||||||
pub fn find_node(&self, byte_index: usize) -> Option<&TypedExpr> {
|
pub fn find_node(&self, byte_index: usize) -> Option<&TypedExpr> {
|
||||||
self.then.find_node(byte_index)
|
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<()>;
|
pub type UntypedClauseGuard = ClauseGuard<()>;
|
||||||
|
|
|
@ -921,15 +921,9 @@ pub fn expr_parser(
|
||||||
);
|
);
|
||||||
|
|
||||||
let when_clause_parser = pattern_parser()
|
let when_clause_parser = pattern_parser()
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.at_least(1)
|
|
||||||
.then(
|
.then(
|
||||||
just(Token::Vbar)
|
just(Token::Vbar)
|
||||||
.ignore_then(
|
.ignore_then(pattern_parser().map(|pattern| vec![pattern]))
|
||||||
pattern_parser()
|
|
||||||
.separated_by(just(Token::Comma))
|
|
||||||
.at_least(1),
|
|
||||||
)
|
|
||||||
.repeated()
|
.repeated()
|
||||||
.or_not(),
|
.or_not(),
|
||||||
)
|
)
|
||||||
|
@ -968,9 +962,9 @@ pub fn expr_parser(
|
||||||
}),
|
}),
|
||||||
)))
|
)))
|
||||||
.map_with_span(
|
.map_with_span(
|
||||||
|(((patterns, alternative_patterns_opt), guard), then), span| ast::UntypedClause {
|
|(((pattern, alternative_patterns_opt), guard), then), span| ast::UntypedClause {
|
||||||
location: span,
|
location: span,
|
||||||
pattern: patterns,
|
pattern: vec![pattern],
|
||||||
alternative_patterns: alternative_patterns_opt.unwrap_or_default(),
|
alternative_patterns: alternative_patterns_opt.unwrap_or_default(),
|
||||||
guard,
|
guard,
|
||||||
then,
|
then,
|
||||||
|
|
|
@ -11,14 +11,14 @@ fn assert_definitions(code: &str, definitions: Vec<ast::UntypedDefinition>) {
|
||||||
let (module, _extra) = parser::module(code, ast::ModuleKind::Validator).unwrap();
|
let (module, _extra) = parser::module(code, ast::ModuleKind::Validator).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
module,
|
|
||||||
ast::UntypedModule {
|
ast::UntypedModule {
|
||||||
docs: vec![],
|
docs: vec![],
|
||||||
kind: ast::ModuleKind::Validator,
|
kind: ast::ModuleKind::Validator,
|
||||||
name: "".to_string(),
|
name: "".to_string(),
|
||||||
type_info: (),
|
type_info: (),
|
||||||
definitions,
|
definitions,
|
||||||
}
|
},
|
||||||
|
module
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -901,11 +901,10 @@ fn block() {
|
||||||
fn when() {
|
fn when() {
|
||||||
let code = indoc! {r#"
|
let code = indoc! {r#"
|
||||||
pub fn wow2(a: Int){
|
pub fn wow2(a: Int){
|
||||||
when a, b is {
|
when a is {
|
||||||
1, 2 -> 3
|
2 -> 3
|
||||||
1 | 4, 5 -> {
|
1 | 4 | 5 -> {
|
||||||
let amazing = 5
|
let amazing = 5
|
||||||
|
|
||||||
amazing
|
amazing
|
||||||
}
|
}
|
||||||
3 -> 9
|
3 -> 9
|
||||||
|
@ -933,100 +932,88 @@ fn when() {
|
||||||
tipo: (),
|
tipo: (),
|
||||||
}],
|
}],
|
||||||
body: expr::UntypedExpr::When {
|
body: expr::UntypedExpr::When {
|
||||||
location: Span::new((), 23..138),
|
location: Span::new((), 23..132),
|
||||||
subjects: vec![
|
subjects: vec![expr::UntypedExpr::Var {
|
||||||
expr::UntypedExpr::Var {
|
|
||||||
location: Span::new((), 28..29),
|
location: Span::new((), 28..29),
|
||||||
name: "a".to_string(),
|
name: "a".to_string(),
|
||||||
},
|
}],
|
||||||
expr::UntypedExpr::Var {
|
|
||||||
location: Span::new((), 31..32),
|
|
||||||
name: "b".to_string(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
clauses: vec![
|
clauses: vec![
|
||||||
ast::Clause {
|
ast::Clause {
|
||||||
location: Span::new((), 42..51),
|
location: Span::new((), 39..45),
|
||||||
pattern: vec![
|
pattern: vec![ast::Pattern::Int {
|
||||||
ast::Pattern::Int {
|
location: Span::new((), 39..40),
|
||||||
location: Span::new((), 42..43),
|
|
||||||
value: "1".to_string(),
|
|
||||||
},
|
|
||||||
ast::Pattern::Int {
|
|
||||||
location: Span::new((), 45..46),
|
|
||||||
value: "2".to_string(),
|
value: "2".to_string(),
|
||||||
},
|
}],
|
||||||
],
|
|
||||||
alternative_patterns: vec![],
|
alternative_patterns: vec![],
|
||||||
guard: None,
|
guard: None,
|
||||||
then: expr::UntypedExpr::Int {
|
then: expr::UntypedExpr::Int {
|
||||||
location: Span::new((), 50..51),
|
location: Span::new((), 44..45),
|
||||||
value: "3".to_string(),
|
value: "3".to_string(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ast::Clause {
|
ast::Clause {
|
||||||
location: Span::new((), 56..112),
|
location: Span::new((), 50..106),
|
||||||
pattern: vec![ast::Pattern::Int {
|
pattern: vec![ast::Pattern::Int {
|
||||||
location: Span::new((), 56..57),
|
location: Span::new((), 50..51),
|
||||||
value: "1".to_string(),
|
value: "1".to_string(),
|
||||||
}],
|
}],
|
||||||
alternative_patterns: vec![vec![
|
alternative_patterns: vec![
|
||||||
ast::Pattern::Int {
|
vec![ast::Pattern::Int {
|
||||||
location: Span::new((), 60..61),
|
location: Span::new((), 54..55),
|
||||||
value: "4".to_string(),
|
value: "4".to_string(),
|
||||||
},
|
}],
|
||||||
ast::Pattern::Int {
|
vec![ast::Pattern::Int {
|
||||||
location: Span::new((), 63..64),
|
location: Span::new((), 58..59),
|
||||||
value: "5".to_string(),
|
value: "5".to_string(),
|
||||||
},
|
}],
|
||||||
]],
|
],
|
||||||
guard: None,
|
guard: None,
|
||||||
then: expr::UntypedExpr::Sequence {
|
then: expr::UntypedExpr::Sequence {
|
||||||
location: Span::new((), 76..106),
|
location: Span::new((), 71..100),
|
||||||
expressions: vec![
|
expressions: vec![
|
||||||
expr::UntypedExpr::Assignment {
|
expr::UntypedExpr::Assignment {
|
||||||
location: Span::new((), 76..91),
|
location: Span::new((), 71..86),
|
||||||
value: Box::new(expr::UntypedExpr::Int {
|
value: Box::new(expr::UntypedExpr::Int {
|
||||||
location: Span::new((), 90..91),
|
location: Span::new((), 85..86),
|
||||||
value: "5".to_string(),
|
value: "5".to_string(),
|
||||||
}),
|
}),
|
||||||
pattern: ast::Pattern::Var {
|
pattern: ast::Pattern::Var {
|
||||||
location: Span::new((), 80..87),
|
location: Span::new((), 75..82),
|
||||||
name: "amazing".to_string(),
|
name: "amazing".to_string(),
|
||||||
},
|
},
|
||||||
kind: ast::AssignmentKind::Let,
|
kind: ast::AssignmentKind::Let,
|
||||||
annotation: None,
|
annotation: None,
|
||||||
},
|
},
|
||||||
expr::UntypedExpr::Var {
|
expr::UntypedExpr::Var {
|
||||||
location: Span::new((), 99..106),
|
location: Span::new((), 93..100),
|
||||||
name: "amazing".to_string(),
|
name: "amazing".to_string(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ast::Clause {
|
ast::Clause {
|
||||||
location: Span::new((), 117..123),
|
location: Span::new((), 111..117),
|
||||||
pattern: vec![ast::Pattern::Int {
|
pattern: vec![ast::Pattern::Int {
|
||||||
location: Span::new((), 117..118),
|
location: Span::new((), 111..112),
|
||||||
value: "3".to_string(),
|
value: "3".to_string(),
|
||||||
}],
|
}],
|
||||||
alternative_patterns: vec![],
|
alternative_patterns: vec![],
|
||||||
guard: None,
|
guard: None,
|
||||||
then: expr::UntypedExpr::Int {
|
then: expr::UntypedExpr::Int {
|
||||||
location: Span::new((), 122..123),
|
location: Span::new((), 116..117),
|
||||||
value: "9".to_string(),
|
value: "9".to_string(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ast::Clause {
|
ast::Clause {
|
||||||
location: Span::new((), 128..134),
|
location: Span::new((), 122..128),
|
||||||
pattern: vec![ast::Pattern::Discard {
|
pattern: vec![ast::Pattern::Discard {
|
||||||
name: "_".to_string(),
|
name: "_".to_string(),
|
||||||
location: Span::new((), 128..129),
|
location: Span::new((), 122..123),
|
||||||
}],
|
}],
|
||||||
alternative_patterns: vec![],
|
alternative_patterns: vec![],
|
||||||
guard: None,
|
guard: None,
|
||||||
then: expr::UntypedExpr::Int {
|
then: expr::UntypedExpr::Int {
|
||||||
location: Span::new((), 133..134),
|
location: Span::new((), 127..128),
|
||||||
value: "4".to_string(),
|
value: "4".to_string(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1038,7 +1025,7 @@ fn when() {
|
||||||
public: true,
|
public: true,
|
||||||
return_annotation: None,
|
return_annotation: None,
|
||||||
return_type: (),
|
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 typed_subjects = Vec::with_capacity(subjects_count);
|
||||||
let mut subject_types = 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();
|
let return_type = self.new_unbound_var();
|
||||||
|
|
||||||
|
@ -1911,7 +1911,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
)
|
)
|
||||||
.map_err(|e| e.case_clause_mismatch())?;
|
.map_err(|e| e.case_clause_mismatch())?;
|
||||||
|
|
||||||
typed_clauses.push(typed_clause);
|
typed_clauses.append(&mut typed_clause.desugarize());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(unmatched) =
|
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