Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions examples/pattern_matching.simf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
fn main() {
let complex_pattern: Either<(u32, u32, (u1, u1)), [u1; 8]> = Left((32, 3, (0, 1)));

let a: u32 = match complex_pattern {
Left((a, b,(c, d)): (u32, u32, (u1, u1))) => {
assert!(jet::eq_32(b, 3));
assert!(jet::eq_1(c, 0));
assert!(jet::eq_1(d, 1));
a
}
Right(_: [u1; 8]) => 0,
};

assert!(jet::eq_32(a, 32));
}
14 changes: 10 additions & 4 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1400,16 +1400,22 @@ impl AbstractSyntaxTree for Match {
Expression::analyze(from.scrutinee(), &scrutinee_ty, scope).map(Arc::new)?;

scope.push_scope();
if let Some((id_l, ty_l)) = from.left().pattern().as_typed_variable() {
if let Some((pat_l, ty_l)) = from.left().pattern().as_typed_pattern() {
let ty_l = scope.resolve(ty_l).with_span(from)?;
scope.insert_variable(id_l.clone(), ty_l);
let typed_variables = pat_l.is_of_type(&ty_l).with_span(from)?;
for (identifier, ty) in typed_variables {
scope.insert_variable(identifier, ty);
}
}
let ast_l = Expression::analyze(from.left().expression(), ty, scope).map(Arc::new)?;
scope.pop_scope();
scope.push_scope();
if let Some((id_r, ty_r)) = from.right().pattern().as_typed_variable() {
if let Some((pat_r, ty_r)) = from.right().pattern().as_typed_pattern() {
let ty_r = scope.resolve(ty_r).with_span(from)?;
scope.insert_variable(id_r.clone(), ty_r);
let typed_variables = pat_r.is_of_type(&ty_r).with_span(from)?;
for (identifier, ty) in typed_variables {
scope.insert_variable(identifier, ty);
}
}
let ast_r = Expression::analyze(from.right().expression(), ty, scope).map(Arc::new)?;
scope.pop_scope();
Expand Down
8 changes: 4 additions & 4 deletions src/compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,9 +656,9 @@ impl Match {
scope.insert(
self.left()
.pattern()
.as_variable()
.as_pattern()
.cloned()
.map_or(Pattern::Ignore, Pattern::Identifier),
.unwrap_or(Pattern::Ignore),
);
let left = self.left().expression().compile(scope)?;
scope.pop_scope();
Expand All @@ -667,9 +667,9 @@ impl Match {
scope.insert(
self.right()
.pattern()
.as_variable()
.as_pattern()
.cloned()
.map_or(Pattern::Ignore, Pattern::Identifier),
.unwrap_or(Pattern::Ignore),
);
let right = self.right().expression().compile(scope)?;
scope.pop_scope();
Expand Down
7 changes: 7 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,13 @@ pub(crate) mod tests {
.assert_run_success();
}

#[test]
fn pattern_matching() {
TestCase::program_file("./examples/pattern_matching.simf")
.with_witness_values(WitnessValues::default())
.assert_run_success();
}

#[test]
#[cfg(feature = "serde")]
fn sighash_non_interactive_fee_bump() {
Expand Down
32 changes: 16 additions & 16 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,23 +429,23 @@ impl MatchArm {
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum MatchPattern {
/// Bind inner value of left value to variable name.
Left(Identifier, AliasedType),
/// Bind inner value of right value to variable name.
Right(Identifier, AliasedType),
/// Bind inner value of left value to a pattern.
Left(Pattern, AliasedType),
/// Bind inner value of right value to a pattern.
Right(Pattern, AliasedType),
/// Match none value (no binding).
None,
/// Bind inner value of some value to variable name.
Some(Identifier, AliasedType),
/// Bind inner value of some value to a pattern.
Some(Pattern, AliasedType),
/// Match false value (no binding).
False,
/// Match true value (no binding).
True,
}

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

/// Access the identifier and the type of a pattern that binds a variable.
pub fn as_typed_variable(&self) -> Option<(&Identifier, &AliasedType)> {
/// Access the pattern and the type of a match pattern that binds a variables.
pub fn as_typed_pattern(&self) -> Option<(&Pattern, &AliasedType)> {
match self {
MatchPattern::Left(i, ty) | MatchPattern::Right(i, ty) | MatchPattern::Some(i, ty) => {
Some((i, ty))
Expand Down Expand Up @@ -1623,17 +1623,17 @@ impl ChumskyParse for MatchPattern {
where
I: ValueInput<'tokens, Token = Token<'src>, Span = Span>,
{
let wrapper = |name: &'static str, ctor: fn(Identifier, AliasedType) -> Self| {
let wrapper = |name: &'static str, ctor: fn(Pattern, AliasedType) -> Self| {
select! { Token::Ident(i) if i == name => i }
.ignore_then(delimited_with_recovery(
Identifier::parser()
Pattern::parser()
.then_ignore(just(Token::Colon))
.then(AliasedType::parser()),
Token::LParen,
Token::RParen,
|_| {
(
Identifier::from_str_unchecked(""),
Pattern::Ignore,
AliasedType::alias(AliasName::from_str_unchecked("error")),
)
},
Expand Down Expand Up @@ -2130,16 +2130,16 @@ impl crate::ArbitraryRec for Match {
let scrutinee = Expression::arbitrary_rec(u, budget).map(Arc::new)?;
let (pat_l, pat_r) = match u.int_in_range(0..=2)? {
0 => {
let id_l = Identifier::arbitrary(u)?;
let id_l = Pattern::arbitrary(u)?;
let ty_l = AliasedType::arbitrary(u)?;
let pat_l = MatchPattern::Left(id_l, ty_l);
let id_r = Identifier::arbitrary(u)?;
let id_r = Pattern::arbitrary(u)?;
let ty_r = AliasedType::arbitrary(u)?;
let pat_r = MatchPattern::Right(id_r, ty_r);
(pat_l, pat_r)
}
1 => {
let id_r = Identifier::arbitrary(u)?;
let id_r = Pattern::arbitrary(u)?;
let ty_r = AliasedType::arbitrary(u)?;
let pat_r = MatchPattern::Some(id_r, ty_r);
(MatchPattern::None, pat_r)
Expand Down
Loading