Skip to content
8 changes: 2 additions & 6 deletions harper-core/src/linting/despite_of.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
Token, TokenStringExt,
patterns::{Pattern, SequencePattern},
patterns::{Pattern, new_syntax_experiment::prelude::*},
};

use super::{Lint, LintKind, PatternLinter, Suggestion};
Expand All @@ -11,12 +11,8 @@ pub struct DespiteOf {

impl Default for DespiteOf {
fn default() -> Self {
let pattern = SequencePattern::aco("despite")
.then_whitespace()
.then_exact_word("of");

Self {
pattern: Box::new(pattern),
pattern: Box::new(seq!["despite", WS, exact("of")]),
}
}
}
Expand Down
62 changes: 8 additions & 54 deletions harper-core/src/linting/modal_of.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
Lrc, Token, TokenStringExt,
patterns::{EitherPattern, Pattern, SequencePattern, WordSet},
Token, TokenStringExt,
patterns::{Pattern, new_syntax_experiment::prelude::*},
};

use super::{Lint, LintKind, PatternLinter, Suggestion};
Expand All @@ -21,43 +21,11 @@ impl Default for ModalOf {
words.add(&format!("{}n't", word));
});

let modal_of = Lrc::new(
SequencePattern::default()
.then(words)
.then_whitespace()
.t_aco("of"),
);

let ws_course = Lrc::new(SequencePattern::default().then_whitespace().t_aco("course"));

let modal_of_course = Lrc::new(
SequencePattern::default()
.then(modal_of.clone())
.then(ws_course.clone()),
);

let anyword_might_of = Lrc::new(
SequencePattern::default()
.then_any_word()
.then_whitespace()
.t_aco("might")
.then_whitespace()
.t_aco("of"),
);

let anyword_might_of_course = Lrc::new(
SequencePattern::default()
.then(anyword_might_of.clone())
.then(ws_course.clone()),
);

Self {
pattern: Box::new(EitherPattern::new(vec![
Box::new(anyword_might_of_course),
Box::new(modal_of_course),
Box::new(anyword_might_of),
Box::new(modal_of),
])),
pattern: Box::new(choice![
seq![WORD, WS, "might", WS, "of", not_ahead![WS, "course"]],
seq![words, WS, "of", not_ahead![WS, "course"]],
]),
}
}
}
Expand All @@ -69,20 +37,7 @@ impl PatternLinter for ModalOf {

fn match_to_lint(&self, matched_toks: &[Token], source_chars: &[char]) -> Option<Lint> {
let modal_index = match matched_toks.len() {
// Without context, always an error from the start
3 => 0,
5 => {
// False positives: modal _ of _ course / adj. _ might _ of / art. _ might _ of
let w3_text = matched_toks
.last()
.unwrap()
.span
.get_content(source_chars)
.iter()
.collect::<String>();
if w3_text.as_str() != "of" {
return None;
}
let w1_kind = &matched_toks.first().unwrap().kind;
// the might of something, great might of something
if w1_kind.is_adjective() || w1_kind.is_determiner() {
Expand All @@ -91,9 +46,8 @@ impl PatternLinter for ModalOf {
// not a false positive, skip context before
2
}
// False positive: <word> _ might _ of _ course
7 => return None,
_ => unreachable!(),
// Without context, always an error from the start
_ => 0,
};

let span_modal_of = matched_toks[modal_index..modal_index + 3].span().unwrap();
Expand Down
4 changes: 2 additions & 2 deletions harper-core/src/linting/no_oxford_comma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ impl Linter for NoOxfordComma {

if let Some(match_len) = match_len {
let lint = self.match_to_lint(
&sentence[tok_cursor..tok_cursor + match_len.get()],
&sentence[tok_cursor..tok_cursor + match_len],
document.get_source(),
);

lints.extend(lint);
tok_cursor += match_len.get();
tok_cursor += match_len;
} else {
tok_cursor += 1;
}
Expand Down
4 changes: 2 additions & 2 deletions harper-core/src/linting/oxford_comma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,12 @@ impl Linter for OxfordComma {

if let Some(match_len) = match_len {
let lint = self.match_to_lint(
&sentence[tok_cursor..tok_cursor + match_len.get()],
&sentence[tok_cursor..tok_cursor + match_len],
document.get_source(),
);

lints.extend(lint);
tok_cursor += match_len.get();
tok_cursor += match_len;
} else {
tok_cursor += 1;
}
Expand Down
5 changes: 2 additions & 3 deletions harper-core/src/linting/pattern_linter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,10 @@ pub fn run_on_chunk(linter: &impl PatternLinter, chunk: &[Token], source: &[char
let match_len = linter.pattern().matches(&chunk[tok_cursor..], source);

if let Some(match_len) = match_len {
let lint =
linter.match_to_lint(&chunk[tok_cursor..tok_cursor + match_len.get()], source);
let lint = linter.match_to_lint(&chunk[tok_cursor..tok_cursor + match_len], source);

lints.extend(lint);
tok_cursor += match_len.get();
tok_cursor += match_len;
} else {
tok_cursor += 1;
}
Expand Down
8 changes: 3 additions & 5 deletions harper-core/src/patterns/all.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::num::NonZeroUsize;

use crate::Token;

use super::Pattern;
Expand All @@ -24,14 +22,14 @@ impl All {
}

impl Pattern for All {
fn matches(&self, tokens: &[Token], source: &[char]) -> Option<NonZeroUsize> {
fn matches(&self, tokens: &[Token], source: &[char]) -> Option<usize> {
let mut max = 0;

for pattern in &self.children {
let len = pattern.matches(tokens, source)?;
max = max.max(len.get());
max = max.max(len);
}

NonZeroUsize::new(max)
Some(max)
}
}
6 changes: 2 additions & 4 deletions harper-core/src/patterns/any_capitalization.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::num::NonZeroUsize;

use crate::{CharString, Token};

use super::Pattern;
Expand All @@ -23,7 +21,7 @@ impl AnyCapitalization {
}

impl Pattern for AnyCapitalization {
fn matches(&self, tokens: &[Token], source: &[char]) -> Option<NonZeroUsize> {
fn matches(&self, tokens: &[Token], source: &[char]) -> Option<usize> {
let tok = tokens.first()?;

if !tok.kind.is_word() {
Expand All @@ -41,6 +39,6 @@ impl Pattern for AnyCapitalization {
.zip(&self.word)
.all(|(a, b)| a.eq_ignore_ascii_case(b));

NonZeroUsize::new(if partial_match { 1 } else { 0 })
if partial_match { Some(1) } else { None }
}
}
7 changes: 3 additions & 4 deletions harper-core/src/patterns/any_pattern.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use std::num::NonZeroUsize;

use crate::Token;

use super::Pattern;

/// A [`Pattern`] that will match any single token.
#[derive(Clone, Copy)]
pub struct AnyPattern;

impl Pattern for AnyPattern {
fn matches(&self, tokens: &[Token], _source: &[char]) -> Option<NonZeroUsize> {
NonZeroUsize::new(if tokens.is_empty() { 0 } else { 1 })
fn matches(&self, tokens: &[Token], _source: &[char]) -> Option<usize> {
if tokens.is_empty() { None } else { Some(1) }
}
}
22 changes: 13 additions & 9 deletions harper-core/src/patterns/either_pattern.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::num::NonZeroUsize;

use crate::Token;

use super::Pattern;
Expand All @@ -21,17 +19,23 @@ impl EitherPattern {
}

impl Pattern for EitherPattern {
fn matches(&self, tokens: &[Token], source: &[char]) -> Option<NonZeroUsize> {
let mut longest = 0;
fn matches(&self, tokens: &[Token], source: &[char]) -> Option<usize> {
let mut longest = None;

for pattern in self.patterns.iter() {
let match_len = pattern.matches(tokens, source).map_or(0, NonZeroUsize::get);

if match_len > longest {
longest = match_len
let Some(match_len) = pattern.matches(tokens, source) else {
continue;
};

if let Some(longest_len) = longest {
if match_len > longest_len {
longest = Some(match_len);
}
} else {
longest = Some(match_len);
}
}

NonZeroUsize::new(longest)
longest
}
}
4 changes: 1 addition & 3 deletions harper-core/src/patterns/exact_phrase.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::num::NonZeroUsize;

use crate::{Document, Token, TokenKind};

use super::{AnyCapitalization, Pattern, SequencePattern};
Expand Down Expand Up @@ -46,7 +44,7 @@ impl ExactPhrase {
}

impl Pattern for ExactPhrase {
fn matches(&self, tokens: &[Token], source: &[char]) -> Option<NonZeroUsize> {
fn matches(&self, tokens: &[Token], source: &[char]) -> Option<usize> {
self.inner.matches(tokens, source)
}
}
12 changes: 5 additions & 7 deletions harper-core/src/patterns/implies_quantity.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::num::NonZeroUsize;

use crate::{Token, TokenKind};

use super::Pattern;
Expand Down Expand Up @@ -38,12 +36,12 @@ impl ImpliesQuantity {
}

impl Pattern for ImpliesQuantity {
fn matches(&self, tokens: &[Token], source: &[char]) -> Option<NonZeroUsize> {
NonZeroUsize::new(if Self::implies_plurality(tokens, source).is_some() {
1
fn matches(&self, tokens: &[Token], source: &[char]) -> Option<usize> {
if Self::implies_plurality(tokens, source).is_some() {
Some(1)
} else {
0
})
None
}
}
}

Expand Down
4 changes: 1 addition & 3 deletions harper-core/src/patterns/indefinite_article.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::num::NonZeroUsize;

use crate::Token;

use super::{Pattern, WordSet};
Expand All @@ -17,7 +15,7 @@ impl Default for IndefiniteArticle {
}

impl Pattern for IndefiniteArticle {
fn matches(&self, tokens: &[Token], source: &[char]) -> Option<NonZeroUsize> {
fn matches(&self, tokens: &[Token], source: &[char]) -> Option<usize> {
self.inner.matches(tokens, source)
}
}
12 changes: 5 additions & 7 deletions harper-core/src/patterns/invert.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::num::NonZeroUsize;

use crate::Token;

use super::Pattern;
Expand All @@ -18,11 +16,11 @@ impl Invert {
}

impl Pattern for Invert {
fn matches(&self, tokens: &[Token], source: &[char]) -> Option<NonZeroUsize> {
NonZeroUsize::new(if self.inner.matches(tokens, source).is_some() {
0
fn matches(&self, tokens: &[Token], source: &[char]) -> Option<usize> {
if self.inner.matches(tokens, source).is_some() {
None
} else {
1
})
Some(1)
}
}
}
Loading
Loading