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-asciidoc/tests/test_sources/comment.adoc
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// This is a comment with a typo: spelll
// Another line of comment.
// Another line of the same comment.
2 changes: 1 addition & 1 deletion harper-asciidoc/tests/test_sources/table.adoc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
|===
| Cell 1 | Cell 2 with typo: errorr
| Cell 1 | Cell 2, but with a typo: errorr
|===
2 changes: 1 addition & 1 deletion harper-comments/tests/language_support_sources/basic.clj
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@

;;;; Frob Grovel

;;; This section of code has some important implications:
;;; This section of the code has some important implications:
;;; 1. Foo.
;;; 2. Bar.
;;; 3. Baz.
Expand Down
10 changes: 5 additions & 5 deletions harper-comments/tests/language_support_sources/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ impl TestStruct {
/// It has another [link](https://example.com) embedded inside
fn test_function() {}

/// This is some gibberish to try to trigger a lint for sentences that continue for too long
/// This is some gibberish to try to trigger a lint for the sentences that continue for too long
///
/// This is some gibberish to try to trigger a lint for sentences that continue for too long
/// This is some gibberish to try to trigger a lint for the sentences that continue for too long
///
/// This is some gibberish to try to trigger a lint for sentences that continue for too long
/// This is some gibberish to try to trigger a lint for the sentences that continue for too long
///
/// This is some gibberish to try to trigger a lint for sentences that continue for too long
/// This is some gibberish to try to trigger a lint for the sentences that continue for too long
///
/// This is some gibberish to try to trigger a lint for sentences that continue for too long
/// This is some gibberish to try to trigger a lint for the sentences that continue for too long
}

10 changes: 5 additions & 5 deletions harper-comments/tests/language_support_sources/clean.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ contract TestContract {
*/
function testFunction2(uint256 p) external {}

// This is some gibberish to try to trigger a lint for sentences that continue for too long
// This is some gibberish to try to trigger a lint for the sentences that continue for too long
//
// This is some gibberish to try to trigger a lint for sentences that continue for too long
// This is some gibberish to try to trigger a lint for the sentences that continue for too long
//
// This is some gibberish to try to trigger a lint for sentences that continue for too long
// This is some gibberish to try to trigger a lint for the sentences that continue for too long
//
// This is some gibberish to try to trigger a lint for sentences that continue for too long
// This is some gibberish to try to trigger a lint for the sentences that continue for too long
//
// This is some gibberish to try to trigger a lint for sentences that continue for too long
// This is some gibberish to try to trigger a lint for the sentences that continue for too long
}
73 changes: 73 additions & 0 deletions harper-core/src/linting/weir_rules/MissingDeterminer.weir
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
expr techNoun [bug, case, change, comment, feature, fix, log, note, problem, reason, report, repro, reproduction, request, response, scenario, screenshot, solution, step, summary, test, ticket, answer, example, explanation, idea, issue, update]
expr requestNounHead @techNoun
expr requestBareNounPhrase [@requestNounHead, (ADJ @requestNounHead), (ADJ ADJ @requestNounHead), (ADV ADJ @requestNounHead), (ADV ADJ ADJ @requestNounHead), (@requestNounHead @requestNounHead), (ADJ @requestNounHead @requestNounHead), (ADV ADJ @requestNounHead @requestNounHead)]
expr narrativeNoun [portrait, nest, glass, hand, coin, toy, victor]
expr narrativeBareNounPhrase [@narrativeNoun, (ADJ @narrativeNoun)]

expr requestMissingDet <([get, provide, give, send, share, attach, include, add, need, want, see, submit, create, report, file, reproduce] @requestBareNounPhrase), ( )>
expr narrativeVerbObjectMissingDet <([painted, built, dropped, raised, found, hid, cheered] @narrativeBareNounPhrase), ( )>
expr narrativePrepObjectMissingDet <([in, on] [studio, tree, floor]), ( )>

expr main [@requestMissingDet, @narrativeVerbObjectMissingDet, @narrativePrepObjectMissingDet]

let message "Add a determiner before this noun phrase."
let description "Detects likely missing determiners in common request phrases and offers to insert one where necessary."
let kind "Grammar"
let becomes [" the ", " a ", " an "]

test "would it be possible to get reproducible example of this?" "would it be possible to get a reproducible example of this?"
test "Would it be possible to get reproducible bug report?" "Would it be possible to get a reproducible bug report?"
test "Please provide detailed reproduction of this issue." "Please provide a detailed reproduction of this issue."
test "Can you send minimal test case?" "Can you send a minimal test case?"
test "We need quick response." "We need a quick response."
test "I can attach short log." "I can attach a short log."
test "Please share minimal repro." "Please share a minimal repro."
test "Could you submit small change?" "Could you submit a small change?"
test "Please provide reproducible example, thanks." "Please provide a reproducible example, thanks."
test "We should create clear summary." "We should create a clear summary."
test "Please provide the report." "Please provide the report."
test "Please provide your report." "Please provide your report."
test "Please provide another report." "Please provide another report."
test "Please provide more detailed report." "Please provide a more detailed report."
test "We can file short ticket." "We can file a short ticket."
test "Could you reproduce minimal scenario?" "Could you reproduce a minimal scenario?"
test "Please send clear explanation." "Please send a clear explanation."
test "We need simple fix." "We need a simple fix."
test "I want quick update." "I want a quick update."
test "Could you share detailed response?" "Could you share a detailed response?"
test "Please attach short screenshot." "Please attach a short screenshot."
test "We should include short note." "We should include a short note."
test "Please give minimal reproduction." "Please give a minimal reproduction."
test "Can you add brief comment?" "Can you add a brief comment?"
test "We want new feature." "We want a new feature."
test "They need clear solution." "They need a clear solution."

allows "Please provide an example of this."
allows "Please provide the example."
allows "Please provide your example."
allows "Please provide another example."
test "We want detailed explanation." "We want a detailed explanation."
test "We need quick answer." "We need a quick answer."
test "Please send clear update." "Please send a clear update."
test "Please provide brief summary." "Please provide a brief summary."

test "The artist painted portrait in studio." "The artist painted a portrait in the studio."
test "The bird built nest in tree." "The bird built a nest in the tree."
test "The child dropped glass on floor." "The child dropped the glass on the floor."
test "The student raised hand quietly." "The student raised a hand quietly."
test "The child found coin outside." "The child found a coin outside."
test "The child hid toy nearby." "The child hid a toy nearby."
test "The crowd cheered victor loudly." "The crowd cheered the victor loudly."

allows "Let's do this for good measure."
allows "This is a test to make sure we don't split up paragraphs on newlines."
allows "This URL is used by the console to properly generate URLs when using the Artisan command line tool."
allows "The timezone is set to \"UTC\" by default as it is suitable for most use cases."
allows "This option can be set to any locale for which you plan to have translation strings."
allows "Use it to show ownership."
allows "This rule attempts to find common errors with redundancy and contractions that may lead to confusion for readers."
allows "ACF is a powerful tool that allows you to add custom fields to your content, providing greater flexibility in how you manage and display information."
allows "Historical records, colonial archives (however problematic their provenance), and oral histories from surviving communities, even if fragmented and distorted, provide crucial data points."
allows "Traditional cartography relies on observable features – mountains, rivers, coastlines – to create representations of space."
allows "My grandfather built timepieces to mark the passage of moments."
allows "I made a note to encourage Eleanor to share more stories with him; reminiscing often proved beneficial for patients struggling with respiratory distress."
72 changes: 50 additions & 22 deletions harper-core/src/weir/ast.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use harper_brill::UPOS;
use hashbrown::HashMap;
use is_macro::Is;
use itertools::Itertools;

use crate::expr::{Expr, Filter, FirstMatchOf, SequenceExpr, UnlessStep};
use crate::patterns::{AnyPattern, DerivedFrom, UPOSSet, WhitespacePattern, Word};
use crate::{CharString, Punctuation, Token};
use crate::{CharString, CharStringExt, Lrc, Punctuation, Token};

use super::Error;

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Ast {
Expand Down Expand Up @@ -62,6 +65,18 @@ impl Ast {
_ => None,
})
}

/// Iterate through all the expressions in the tree, starting with the one first declared in the
/// tree.
pub fn iter_exprs(&self) -> impl Iterator<Item = (&str, &AstExprNode)> {
self.stmts.iter().filter_map(|stmt| {
if let AstStmtNode::SetExpr { name, value } = stmt {
Some((name.as_str(), value))
} else {
None
}
})
}
}

/// A node that represents an expression that can be used to search through natural language.
Expand All @@ -78,53 +93,66 @@ pub enum AstExprNode {
Seq(Vec<AstExprNode>),
Arr(Vec<AstExprNode>),
Filter(Vec<AstExprNode>),
ExprRef(CharString),
Anything,
}

impl AstExprNode {
/// Create an actual expression that fulfills the pattern matching contract defined by this tree.
pub fn to_expr(&self) -> Box<dyn Expr> {
///
/// Requires a map of all expressions currently in the context.
pub fn to_expr(
&self,
ctx_exprs: &HashMap<String, Lrc<Box<dyn Expr>>>,
) -> Result<Box<dyn Expr>, Error> {
match self {
AstExprNode::Anything => Box::new(AnyPattern),
AstExprNode::Progressive => {
Box::new(|tok: &Token, _: &[char]| tok.kind.is_verb_progressive_form())
}
AstExprNode::UPOSSet(upos) => Box::new(UPOSSet::new(upos)),
AstExprNode::Whitespace => Box::new(WhitespacePattern),
AstExprNode::Word(word) => Box::new(Word::from_chars(word)),
AstExprNode::DerivativeOf(word) => Box::new(DerivedFrom::new_from_chars(word)),
AstExprNode::Not(ast_node) => Box::new(UnlessStep::new(
ast_node.to_expr(),
AstExprNode::Anything => Ok(Box::new(AnyPattern)),
AstExprNode::Progressive => Ok(Box::new(|tok: &Token, _: &[char]| {
tok.kind.is_verb_progressive_form()
})),
AstExprNode::UPOSSet(upos) => Ok(Box::new(UPOSSet::new(upos))),
AstExprNode::Whitespace => Ok(Box::new(WhitespacePattern)),
AstExprNode::Word(word) => Ok(Box::new(Word::from_chars(word))),
AstExprNode::DerivativeOf(word) => Ok(Box::new(DerivedFrom::new_from_chars(word))),
AstExprNode::Not(ast_node) => Ok(Box::new(UnlessStep::new(
ast_node.to_expr(ctx_exprs)?,
|_tok: &Token, _: &[char]| true,
)),
)) as Box<dyn Expr>),
AstExprNode::Seq(children) => {
let mut expr = SequenceExpr::default();

for node in children {
expr = expr.then_boxed(node.to_expr());
expr = expr.then_boxed(node.to_expr(ctx_exprs)?);
}

Box::new(expr)
Ok(Box::new(expr))
}
AstExprNode::Arr(children) => {
let mut expr = FirstMatchOf::default();

for node in children {
expr.add_boxed(node.to_expr());
expr.add_boxed(node.to_expr(ctx_exprs)?);
}

Box::new(expr)
}
AstExprNode::Filter(children) => {
Box::new(Filter::new(children.iter().map(|n| n.to_expr()).collect()))
Ok(Box::new(expr))
}
AstExprNode::Filter(children) => Ok(Box::new(Filter::new(
children
.iter()
.map(|n| n.to_expr(ctx_exprs))
.process_results(|iter| iter.collect())?,
))),
AstExprNode::Punctuation(punct) => {
let punct = *punct;

Box::new(move |tok: &Token, _: &[char]| {
Ok(Box::new(move |tok: &Token, _: &[char]| {
tok.kind.as_punctuation().is_some_and(|p| *p == punct)
})
}))
}
AstExprNode::ExprRef(name) => ctx_exprs
.get(&name.to_string())
.map(|e| Box::new(e.clone()) as Box<dyn Expr>)
.ok_or_else(|| Error::UnableToResolveExpr(name.to_string())),
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion harper-core/src/weir/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub enum Error {
UnmatchedBrace,
#[error("Expected a comma here.")]
ExpectedComma,
#[error("Expected a valid keyword.")]
#[error("Expected a valid keyword. Got: {0}")]
UnexpectedToken(String),
#[error("Expected a value to be defined.")]
ExpectedVariableUndefined,
Expand All @@ -20,4 +20,6 @@ pub enum Error {
InvalidReplacementStrategy,
#[error("Expected a variable type other than the one provided.")]
ExpectedDifferentVariableType,
#[error("Unable to resolve expression reference {0}")]
UnableToResolveExpr(String),
}
Loading