Skip to content

Commit

Permalink
[ast][hir] Add function that conversatively decide whether a matching…
Browse files Browse the repository at this point in the history
… pattern will always match (#1111)
  • Loading branch information
SamChou19815 authored Oct 21, 2023
1 parent 4032c16 commit 32acf75
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 25 deletions.
23 changes: 23 additions & 0 deletions crates/samlang-core/src/ast/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,29 @@ pub(crate) mod pattern {
}
}

pub(crate) fn always_matching(&self) -> bool {
match self {
Self::Tuple(_, elements) => {
for e in elements {
if !e.pattern.always_matching() {
return false;
}
}
true
}
Self::Object(_, elements) => {
for e in elements {
if !e.pattern.always_matching() {
return false;
}
}
true
}
Self::Variant(_) => false,
Self::Id(_, _) | Self::Wildcard(_) => true,
}
}

pub(crate) fn bindings(&self) -> HashSet<PStr> {
let mut set = HashSet::new();
self.collect_bindings(&mut set);
Expand Down
131 changes: 106 additions & 25 deletions crates/samlang-core/src/ast/source_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,34 @@ mod tests {
destructuring_pattern = pattern::DestructuringPattern::Wildcard(Location::dummy());
assert_eq!(*destructuring_pattern.loc(), Location::dummy());

let list = [
expr::BinaryOperator::MUL,
expr::BinaryOperator::DIV,
expr::BinaryOperator::MOD,
expr::BinaryOperator::PLUS,
expr::BinaryOperator::MINUS,
expr::BinaryOperator::CONCAT,
expr::BinaryOperator::LT,
expr::BinaryOperator::LE,
expr::BinaryOperator::GT,
expr::BinaryOperator::GE,
expr::BinaryOperator::EQ,
expr::BinaryOperator::NE,
expr::BinaryOperator::AND,
expr::BinaryOperator::OR,
];
let mut p = -1;
for op in list.iter() {
assert!(!op.clone().to_string().is_empty());
// Assert that the list above has precedence ordered.
let new_p = op.precedence();
assert!(p <= new_p);
p = new_p;
}
}

#[test]
fn pattern_matching_and_bindings_tests() {
let mut matching_pattern: pattern::MatchingPattern<()> = pattern::MatchingPattern::Object(
Location::dummy(),
vec![pattern::ObjectPatternElement {
Expand All @@ -62,6 +90,65 @@ mod tests {
}],
);
matching_pattern.bindings();
assert!(matching_pattern.always_matching());
matching_pattern = pattern::MatchingPattern::Object(
Location::dummy(),
vec![
pattern::ObjectPatternElement {
loc: Location::dummy(),
field_order: 0,
field_name: Id::from(PStr::UPPER_A),
pattern: Box::new(pattern::MatchingPattern::Wildcard(Location::dummy())),
shorthand: false,
type_: (),
},
pattern::ObjectPatternElement {
loc: Location::dummy(),
field_order: 0,
field_name: Id::from(PStr::UPPER_A),
pattern: Box::new(pattern::MatchingPattern::Variant(pattern::VariantPattern {
loc: Location::dummy(),
tag_order: 0,
tag: Id::from(PStr::UPPER_A),
data_variables: vec![(pattern::MatchingPattern::Wildcard(Location::dummy()), ())],
type_: (),
})),
shorthand: false,
type_: (),
},
],
);
matching_pattern.bindings();
assert!(!matching_pattern.always_matching());
matching_pattern = pattern::MatchingPattern::Object(
Location::dummy(),
vec![
pattern::ObjectPatternElement {
loc: Location::dummy(),
field_order: 0,
field_name: Id::from(PStr::UPPER_A),
pattern: Box::new(pattern::MatchingPattern::Variant(pattern::VariantPattern {
loc: Location::dummy(),
tag_order: 0,
tag: Id::from(PStr::UPPER_A),
data_variables: vec![(pattern::MatchingPattern::Wildcard(Location::dummy()), ())],
type_: (),
})),
shorthand: false,
type_: (),
},
pattern::ObjectPatternElement {
loc: Location::dummy(),
field_order: 0,
field_name: Id::from(PStr::UPPER_A),
pattern: Box::new(pattern::MatchingPattern::Wildcard(Location::dummy())),
shorthand: false,
type_: (),
},
],
);
matching_pattern.bindings();
assert!(!matching_pattern.always_matching());
assert_eq!(*matching_pattern.loc(), Location::dummy());
matching_pattern = pattern::MatchingPattern::Tuple(
Location::dummy(),
Expand All @@ -71,6 +158,22 @@ mod tests {
}],
);
matching_pattern.bindings();
assert!(matching_pattern.always_matching());
matching_pattern = pattern::MatchingPattern::Tuple(
Location::dummy(),
vec![pattern::TuplePatternElement {
pattern: Box::new(pattern::MatchingPattern::Variant(pattern::VariantPattern {
loc: Location::dummy(),
tag_order: 0,
tag: Id::from(PStr::UPPER_A),
data_variables: vec![(pattern::MatchingPattern::Wildcard(Location::dummy()), ())],
type_: (),
})),
type_: (),
}],
);
matching_pattern.bindings();
assert!(!matching_pattern.always_matching());
assert_eq!(*matching_pattern.loc(), Location::dummy());
matching_pattern = pattern::MatchingPattern::Variant(pattern::VariantPattern {
loc: Location::dummy(),
Expand All @@ -80,12 +183,15 @@ mod tests {
type_: (),
});
matching_pattern.bindings();
assert!(!matching_pattern.always_matching());
assert_eq!(*matching_pattern.clone().loc(), Location::dummy());
matching_pattern = pattern::MatchingPattern::Id(Id::from(PStr::LOWER_A), ());
matching_pattern.bindings();
assert!(matching_pattern.always_matching());
assert_eq!(*matching_pattern.loc(), Location::dummy());
matching_pattern = pattern::MatchingPattern::Wildcard(Location::dummy());
matching_pattern.bindings();
assert!(matching_pattern.always_matching());
assert_eq!(*matching_pattern.loc(), Location::dummy());
assert!(
pattern::MatchingPattern::Variant(pattern::VariantPattern {
Expand All @@ -102,31 +208,6 @@ mod tests {
type_: (),
})
);

let list = [
expr::BinaryOperator::MUL,
expr::BinaryOperator::DIV,
expr::BinaryOperator::MOD,
expr::BinaryOperator::PLUS,
expr::BinaryOperator::MINUS,
expr::BinaryOperator::CONCAT,
expr::BinaryOperator::LT,
expr::BinaryOperator::LE,
expr::BinaryOperator::GT,
expr::BinaryOperator::GE,
expr::BinaryOperator::EQ,
expr::BinaryOperator::NE,
expr::BinaryOperator::AND,
expr::BinaryOperator::OR,
];
let mut p = -1;
for op in list.iter() {
assert!(!op.clone().to_string().is_empty());
// Assert that the list above has precedence ordered.
let new_p = op.precedence();
assert!(p <= new_p);
p = new_p;
}
}

#[test]
Expand Down

0 comments on commit 32acf75

Please sign in to comment.