Skip to content

Commit 8c5ac11

Browse files
committed
Merge #242: More complex pattern matching in match statement.
767c636 add test for complex pattern matching in `match` (Volodymyr Herashchenko) 37cbc75 change Identifier to Pattern in `MatchPattern` (Volodymyr Herashchenko) Pull request description: Closes #240 and #241. Implementing this was easy enough, because we already have the logic for this pattern matching in assignments, so we simply reused it. Also existing logic allows us to use `_` for unused variable. ACKs for top commit: delta1: ACK 767c636; tested locally Tree-SHA512: 8209e9edb5c624040a7920409ce552987d1591b990c53d631af6c97de350bd03971b2fb0e5621020d66387b7b7c1ee27ec882da3d1b0e7ec86bc10c3ccb286aa
2 parents b1a8648 + 767c636 commit 8c5ac11

File tree

5 files changed

+52
-24
lines changed

5 files changed

+52
-24
lines changed

examples/pattern_matching.simf

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
fn main() {
2+
let complex_pattern: Either<(u32, u32, (u1, u1)), [u1; 8]> = Left((32, 3, (0, 1)));
3+
4+
let a: u32 = match complex_pattern {
5+
Left((a, b,(c, d)): (u32, u32, (u1, u1))) => {
6+
assert!(jet::eq_32(b, 3));
7+
assert!(jet::eq_1(c, 0));
8+
assert!(jet::eq_1(d, 1));
9+
a
10+
}
11+
Right(_: [u1; 8]) => 0,
12+
};
13+
14+
assert!(jet::eq_32(a, 32));
15+
}

src/ast.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,16 +1400,22 @@ impl AbstractSyntaxTree for Match {
14001400
Expression::analyze(from.scrutinee(), &scrutinee_ty, scope).map(Arc::new)?;
14011401

14021402
scope.push_scope();
1403-
if let Some((id_l, ty_l)) = from.left().pattern().as_typed_variable() {
1403+
if let Some((pat_l, ty_l)) = from.left().pattern().as_typed_pattern() {
14041404
let ty_l = scope.resolve(ty_l).with_span(from)?;
1405-
scope.insert_variable(id_l.clone(), ty_l);
1405+
let typed_variables = pat_l.is_of_type(&ty_l).with_span(from)?;
1406+
for (identifier, ty) in typed_variables {
1407+
scope.insert_variable(identifier, ty);
1408+
}
14061409
}
14071410
let ast_l = Expression::analyze(from.left().expression(), ty, scope).map(Arc::new)?;
14081411
scope.pop_scope();
14091412
scope.push_scope();
1410-
if let Some((id_r, ty_r)) = from.right().pattern().as_typed_variable() {
1413+
if let Some((pat_r, ty_r)) = from.right().pattern().as_typed_pattern() {
14111414
let ty_r = scope.resolve(ty_r).with_span(from)?;
1412-
scope.insert_variable(id_r.clone(), ty_r);
1415+
let typed_variables = pat_r.is_of_type(&ty_r).with_span(from)?;
1416+
for (identifier, ty) in typed_variables {
1417+
scope.insert_variable(identifier, ty);
1418+
}
14131419
}
14141420
let ast_r = Expression::analyze(from.right().expression(), ty, scope).map(Arc::new)?;
14151421
scope.pop_scope();

src/compile/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -656,9 +656,9 @@ impl Match {
656656
scope.insert(
657657
self.left()
658658
.pattern()
659-
.as_variable()
659+
.as_pattern()
660660
.cloned()
661-
.map_or(Pattern::Ignore, Pattern::Identifier),
661+
.unwrap_or(Pattern::Ignore),
662662
);
663663
let left = self.left().expression().compile(scope)?;
664664
scope.pop_scope();
@@ -667,9 +667,9 @@ impl Match {
667667
scope.insert(
668668
self.right()
669669
.pattern()
670-
.as_variable()
670+
.as_pattern()
671671
.cloned()
672-
.map_or(Pattern::Ignore, Pattern::Identifier),
672+
.unwrap_or(Pattern::Ignore),
673673
);
674674
let right = self.right().expression().compile(scope)?;
675675
scope.pop_scope();

src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,13 @@ pub(crate) mod tests {
491491
.assert_run_success();
492492
}
493493

494+
#[test]
495+
fn pattern_matching() {
496+
TestCase::program_file("./examples/pattern_matching.simf")
497+
.with_witness_values(WitnessValues::default())
498+
.assert_run_success();
499+
}
500+
494501
#[test]
495502
#[cfg(feature = "serde")]
496503
fn sighash_non_interactive_fee_bump() {

src/parse.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -429,23 +429,23 @@ impl MatchArm {
429429
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
430430
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
431431
pub enum MatchPattern {
432-
/// Bind inner value of left value to variable name.
433-
Left(Identifier, AliasedType),
434-
/// Bind inner value of right value to variable name.
435-
Right(Identifier, AliasedType),
432+
/// Bind inner value of left value to a pattern.
433+
Left(Pattern, AliasedType),
434+
/// Bind inner value of right value to a pattern.
435+
Right(Pattern, AliasedType),
436436
/// Match none value (no binding).
437437
None,
438-
/// Bind inner value of some value to variable name.
439-
Some(Identifier, AliasedType),
438+
/// Bind inner value of some value to a pattern.
439+
Some(Pattern, AliasedType),
440440
/// Match false value (no binding).
441441
False,
442442
/// Match true value (no binding).
443443
True,
444444
}
445445

446446
impl MatchPattern {
447-
/// Access the identifier of a pattern that binds a variable.
448-
pub fn as_variable(&self) -> Option<&Identifier> {
447+
/// Access the pattern of a match pattern that binds a variables.
448+
pub fn as_pattern(&self) -> Option<&Pattern> {
449449
match self {
450450
MatchPattern::Left(i, _) | MatchPattern::Right(i, _) | MatchPattern::Some(i, _) => {
451451
Some(i)
@@ -454,8 +454,8 @@ impl MatchPattern {
454454
}
455455
}
456456

457-
/// Access the identifier and the type of a pattern that binds a variable.
458-
pub fn as_typed_variable(&self) -> Option<(&Identifier, &AliasedType)> {
457+
/// Access the pattern and the type of a match pattern that binds a variables.
458+
pub fn as_typed_pattern(&self) -> Option<(&Pattern, &AliasedType)> {
459459
match self {
460460
MatchPattern::Left(i, ty) | MatchPattern::Right(i, ty) | MatchPattern::Some(i, ty) => {
461461
Some((i, ty))
@@ -1623,17 +1623,17 @@ impl ChumskyParse for MatchPattern {
16231623
where
16241624
I: ValueInput<'tokens, Token = Token<'src>, Span = Span>,
16251625
{
1626-
let wrapper = |name: &'static str, ctor: fn(Identifier, AliasedType) -> Self| {
1626+
let wrapper = |name: &'static str, ctor: fn(Pattern, AliasedType) -> Self| {
16271627
select! { Token::Ident(i) if i == name => i }
16281628
.ignore_then(delimited_with_recovery(
1629-
Identifier::parser()
1629+
Pattern::parser()
16301630
.then_ignore(just(Token::Colon))
16311631
.then(AliasedType::parser()),
16321632
Token::LParen,
16331633
Token::RParen,
16341634
|_| {
16351635
(
1636-
Identifier::from_str_unchecked(""),
1636+
Pattern::Ignore,
16371637
AliasedType::alias(AliasName::from_str_unchecked("error")),
16381638
)
16391639
},
@@ -2130,16 +2130,16 @@ impl crate::ArbitraryRec for Match {
21302130
let scrutinee = Expression::arbitrary_rec(u, budget).map(Arc::new)?;
21312131
let (pat_l, pat_r) = match u.int_in_range(0..=2)? {
21322132
0 => {
2133-
let id_l = Identifier::arbitrary(u)?;
2133+
let id_l = Pattern::arbitrary(u)?;
21342134
let ty_l = AliasedType::arbitrary(u)?;
21352135
let pat_l = MatchPattern::Left(id_l, ty_l);
2136-
let id_r = Identifier::arbitrary(u)?;
2136+
let id_r = Pattern::arbitrary(u)?;
21372137
let ty_r = AliasedType::arbitrary(u)?;
21382138
let pat_r = MatchPattern::Right(id_r, ty_r);
21392139
(pat_l, pat_r)
21402140
}
21412141
1 => {
2142-
let id_r = Identifier::arbitrary(u)?;
2142+
let id_r = Pattern::arbitrary(u)?;
21432143
let ty_r = AliasedType::arbitrary(u)?;
21442144
let pat_r = MatchPattern::Some(id_r, ty_r);
21452145
(MatchPattern::None, pat_r)

0 commit comments

Comments
 (0)