Skip to content
Merged
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
2 changes: 1 addition & 1 deletion harper-core/src/expr/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use super::Expr;
/// use harper_core::expr::{SequenceExpr, Filter, ExprExt};
/// use harper_core::{Span, Document};
///
/// let a = SequenceExpr::aco("chock").t_ws().t_aco("full");
/// let a = SequenceExpr::word_seq(&["chock", "full"]);
/// let b = WhitespacePattern;
///
/// let filter = Filter::new(vec![Box::new(a), Box::new(b)]);
Expand Down
18 changes: 18 additions & 0 deletions harper-core/src/expr/sequence_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ impl SequenceExpr {
Self::default().then_optional(expr)
}

/// Match a series of words separated by whitespace.
pub fn word_seq(words: &'static [&'static str]) -> Self {
Self::default().then_word_seq(words)
}

/// Match a fixed phrase.
pub fn fixed_phrase(phrase: &'static str) -> Self {
Self::default().then_fixed_phrase(phrase)
Expand Down Expand Up @@ -296,6 +301,19 @@ impl SequenceExpr {
self.then(Word::new_exact(word))
}

/// Match a series of words separated by whitespace.
pub fn then_word_seq(self, words: &'static [&'static str]) -> Self {
if let Some((first, rest)) = words.split_first() {
let mut expr = self.t_aco(first);
for word in rest {
expr = expr.t_ws().t_aco(word);
}
expr
} else {
self
}
}

/// Match a fixed phrase.
pub fn then_fixed_phrase(self, phrase: &'static str) -> Self {
self.then(FixedPhrase::from_phrase(phrase))
Expand Down
4 changes: 1 addition & 3 deletions harper-core/src/linting/a_some_time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ pub struct ASomeTime {
impl Default for ASomeTime {
fn default() -> Self {
Self {
expr: SequenceExpr::aco("a")
.t_ws()
.t_aco("some")
expr: SequenceExpr::word_seq(&["a", "some"])
.t_ws()
.then_any_of(vec![
Box::new(Word::new("time")),
Expand Down
4 changes: 1 addition & 3 deletions harper-core/src/linting/all_hell_break_loose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ pub struct AllHellBreakLoose {
impl Default for AllHellBreakLoose {
fn default() -> Self {
Self {
expr: SequenceExpr::aco("all")
.t_ws()
.t_aco("hell")
expr: SequenceExpr::word_seq(&["all", "hell"])
.t_ws()
.then_word_set(&["break", "breaking", "breaks", "broke", "broken"])
.t_ws()
Expand Down
8 changes: 3 additions & 5 deletions harper-core/src/linting/apart_from.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@ pub struct ApartFrom {

impl Default for ApartFrom {
fn default() -> Self {
let expr = SequenceExpr::any_capitalization_of("apart")
.t_ws()
.then_any_capitalization_of("form");

Self { expr }
Self {
expr: SequenceExpr::word_seq(&["apart", "form"]),
}
}
}

Expand Down
4 changes: 1 addition & 3 deletions harper-core/src/linting/as_how.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ pub struct AsHow {
impl Default for AsHow {
fn default() -> Self {
Self {
expr: SequenceExpr::any_capitalization_of("as")
.t_ws()
.t_aco("how"),
expr: SequenceExpr::word_seq(&["as", "how"]),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion harper-core/src/linting/change_tack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl Default for ChangeTack {
.t_ws()
.then_word_set(eggcorns),
),
Box::new(SequenceExpr::aco("different").t_ws().t_aco("tact")),
Box::new(SequenceExpr::word_seq(&["different", "tact"])),
]),
}
}
Expand Down
2 changes: 1 addition & 1 deletion harper-core/src/linting/else_possessive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl Default for ElsePossessive {
"everyone",
"nobody",
])
.or(SequenceExpr::aco("no").then_whitespace().t_aco("one"));
.or(SequenceExpr::word_seq(&["no", "one"]));

let pattern = SequenceExpr::with(pronouns)
.then_whitespace()
Expand Down
2 changes: 1 addition & 1 deletion harper-core/src/linting/everyday.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub struct Everyday {
impl Default for Everyday {
fn default() -> Self {
let everyday = Word::new("everyday");
let every_day = Lrc::new(SequenceExpr::aco("every").t_ws().t_aco("day"));
let every_day = Lrc::new(SequenceExpr::word_seq(&["every", "day"]));

let everyday_bad_after = All::new(vec![
Box::new(SequenceExpr::with(everyday.clone()).t_ws().then_any_word()),
Expand Down
2 changes: 1 addition & 1 deletion harper-core/src/linting/fed_up_with.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct FedUpWith {

impl FedUpWith {
pub fn new(dialect: Dialect) -> Self {
let expr = SequenceExpr::fixed_phrase("fed up of");
let expr = SequenceExpr::word_seq(&["fed", "up", "of"]);

Self { expr, dialect }
}
Expand Down
37 changes: 15 additions & 22 deletions harper-core/src/linting/for_free_of_charge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,21 @@ pub struct ForFreeOfCharge {
impl Default for ForFreeOfCharge {
fn default() -> Self {
Self {
expr: SequenceExpr::aco("for")
.t_ws()
.t_aco("free")
.t_ws_h()
.t_aco("of")
.t_ws_h()
.t_aco("charge")
.then_any_of(vec![
Box::new(SequenceExpr::default().then_kind_any(&[
TokenKind::is_sentence_terminator,
TokenKind::is_comma,
TokenKind::is_quote,
])),
Box::new(SequenceExpr::whitespace().then_kind_any_but_not(
&[
TokenKind::is_conjunction,
TokenKind::is_preposition,
TokenKind::is_verb,
],
TokenKind::is_noun,
)),
]),
expr: SequenceExpr::word_seq(&["for", "free", "of", "charge"]).then_any_of(vec![
Box::new(SequenceExpr::default().then_kind_any(&[
TokenKind::is_sentence_terminator,
TokenKind::is_comma,
TokenKind::is_quote,
])),
Box::new(SequenceExpr::whitespace().then_kind_any_but_not(
&[
TokenKind::is_conjunction,
TokenKind::is_preposition,
TokenKind::is_verb,
],
TokenKind::is_noun,
)),
]),
}
}
}
Expand Down
4 changes: 1 addition & 3 deletions harper-core/src/linting/hereby.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ impl Default for Hereby {
// Require a verb that is not also a noun. Otherwise sentences like
// "I got here by skill" — where "skill" is a noun object of "by" —
// match because "skill" is tagged as both verb and noun.
let pattern = SequenceExpr::aco("here")
.then_whitespace()
.t_aco("by")
let pattern = SequenceExpr::word_seq(&["here", "by"])
.then_whitespace()
.then_kind_is_but_is_not(TokenKind::is_verb, TokenKind::is_noun);

Expand Down
4 changes: 1 addition & 3 deletions harper-core/src/linting/hope_youre.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ impl Default for HopeYoure {

let prep = SequenceExpr::default().t_ws().then_preposition();

let expr = SequenceExpr::aco("hope")
.t_ws()
.t_aco("your")
let expr = SequenceExpr::word_seq(&["hope", "your"])
.t_ws()
.then_adjective()
.then_optional(prep)
Expand Down
2 changes: 1 addition & 1 deletion harper-core/src/linting/it_looks_like_that.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct ItLooksLikeThat {
impl Default for ItLooksLikeThat {
fn default() -> Self {
Self {
expr: SequenceExpr::fixed_phrase("it looks like that")
expr: SequenceExpr::word_seq(&["it", "looks", "like", "that"])
.then_whitespace()
.then_kind_where(|kind| {
// Heuristics on the word after "that" which show "that" was used
Expand Down
2 changes: 1 addition & 1 deletion harper-core/src/linting/its_possessive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ impl Default for ItsPossessive {

map.insert(start_of_chunk_after_conjunction, 2);

let special = SequenceExpr::aco("it's").t_ws().t_aco("various");
let special = SequenceExpr::word_seq(&["it's", "various"]);

map.insert(special, 0);

Expand Down
2 changes: 1 addition & 1 deletion harper-core/src/linting/likewise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ impl Default for Likewise {
fn default() -> Self {
let mut expr = All::default();

expr.add(SequenceExpr::aco("like").then_whitespace().t_aco("wise"));
expr.add(SequenceExpr::word_seq(&["like", "wise"]));
expr.add(SequenceExpr::unless(
SequenceExpr::anything()
.then_whitespace()
Expand Down
4 changes: 1 addition & 3 deletions harper-core/src/linting/no_longer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ pub struct NoLonger {
impl Default for NoLonger {
fn default() -> Self {
Self {
expr: SequenceExpr::aco("not")
.t_ws()
.t_aco("longer")
expr: SequenceExpr::word_seq(&["not", "longer"])
.then_optional(SequenceExpr::default().t_ws().then_kind_any(
&[
TokenKind::is_verb_lemma,
Expand Down
4 changes: 1 addition & 3 deletions harper-core/src/linting/nobody.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ pub struct Nobody {

impl Default for Nobody {
fn default() -> Self {
let pattern = SequenceExpr::aco("no")
.then_whitespace()
.t_aco("body")
let pattern = SequenceExpr::word_seq(&["no", "body"])
.then_whitespace()
.then_verb();
Self { expr: pattern }
Expand Down
4 changes: 1 addition & 3 deletions harper-core/src/linting/not_only_inversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ pub struct NotOnlyInversion {
impl Default for NotOnlyInversion {
fn default() -> Self {
Self {
expr: SequenceExpr::aco("not")
.t_ws()
.t_aco("only")
expr: SequenceExpr::word_seq(&["not", "only"])
.t_ws()
.then_word_set(&["I", "we", "you", "he", "she", "it", "they"])
.t_ws()
Expand Down
3 changes: 2 additions & 1 deletion harper-core/src/linting/oldest_in_the_book.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ impl Default for OldestInTheBook {
Self {
expr: SequenceExpr::fixed_phrase("oldest ")
.then(noun_phrase)
.then_fixed_phrase(" in the books"),
.t_ws()
.then_word_seq(&["in", "the", "books"]),
}
}
}
Expand Down
10 changes: 3 additions & 7 deletions harper-core/src/linting/once_or_twice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,9 @@ pub struct OnceOrTwice {

impl Default for OnceOrTwice {
fn default() -> Self {
let pattern = SequenceExpr::aco("once")
.then_whitespace()
.t_aco("a")
.then_whitespace()
.t_aco("twice");

Self { expr: pattern }
Self {
expr: SequenceExpr::word_seq(&["once", "a", "twice"]),
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion harper-core/src/linting/one_of_the_singular.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ impl<D: Dictionary + 'static> OneOfTheSingular<D> {
.then_zero_or_more_spaced(SequenceExpr::default().then_my_noun_or_adjective());

Self {
expr: SequenceExpr::fixed_phrase("one of the ")
expr: SequenceExpr::word_seq(&["one", "of", "the"])
.t_ws()
.then(SequenceExpr::optional(advs.t_ws()).then(adj_or_nouns)),
dict,
}
Expand Down
2 changes: 1 addition & 1 deletion harper-core/src/linting/pronoun_verb_agreement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ where
.t_ws()
.then(verb_lemma),
),
Box::new(SequenceExpr::aco("it").t_ws().t_aco("don't")),
Box::new(SequenceExpr::word_seq(&["it", "don't"])),
]),
dict,
}
Expand Down
8 changes: 3 additions & 5 deletions harper-core/src/linting/some_without_article.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,9 @@ pub struct SomeWithoutArticle {

impl Default for SomeWithoutArticle {
fn default() -> Self {
let expr = SequenceExpr::any_capitalization_of("the")
.t_ws()
.then_any_capitalization_of("some");

Self { expr }
Self {
expr: SequenceExpr::word_seq(&["the", "some"]),
}
}
}

Expand Down
10 changes: 3 additions & 7 deletions harper-core/src/linting/somewhat_something.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,9 @@ pub struct SomewhatSomething {

impl Default for SomewhatSomething {
fn default() -> Self {
let pattern = SequenceExpr::aco("somewhat")
.then_whitespace()
.t_aco("of")
.then_whitespace()
.t_aco("a");

Self { expr: pattern }
Self {
expr: SequenceExpr::word_seq(&["somewhat", "of", "a"]),
}
}
}

Expand Down
6 changes: 1 addition & 5 deletions harper-core/src/linting/that_which.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ impl Default for ThatWhich {
fn default() -> Self {
let mut pattern = WordExprGroup::default();

let matching_pattern = Lrc::new(
SequenceExpr::any_capitalization_of("that")
.then_whitespace()
.then_any_capitalization_of("that"),
);
let matching_pattern = Lrc::new(SequenceExpr::word_seq(&["that", "that"]));

pattern.add("that", matching_pattern.clone());
pattern.add("That", matching_pattern);
Expand Down
8 changes: 2 additions & 6 deletions harper-core/src/linting/were_where.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,12 @@ impl Default for WereWhere {
// "you where" alone is ambiguous ("I'll show you where to go"), so only flag
// it when followed by a verb, auxiliary, or adjective — confirming a verb slot.
// e.g. "you where going" → "you were going"
let you_where_verb = SequenceExpr::aco("you")
.t_ws()
.t_aco("where")
let you_where_verb = SequenceExpr::word_seq(&["you", "where"])
.t_ws()
.then(UPOSSet::new(&[UPOS::VERB, UPOS::AUX, UPOS::ADJ]));

// "where you ..." can be a typo for "were you ..." when it starts a question.
let where_you_verb = SequenceExpr::aco("where")
.t_ws()
.t_aco("you")
let where_you_verb = SequenceExpr::word_seq(&["where", "you"])
.t_ws()
.then(UPOSSet::new(&[UPOS::VERB, UPOS::AUX, UPOS::ADJ]));

Expand Down
4 changes: 1 addition & 3 deletions harper-core/src/linting/worth_to_do.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ where
{
pub fn new(dict: D) -> Self {
Self {
expr: SequenceExpr::aco("worth")
.t_ws()
.t_aco("to")
expr: SequenceExpr::word_seq(&["worth", "to"])
.t_ws()
.then_verb_lemma(),
dict,
Expand Down
Loading