Skip to content

Commit

Permalink
Merge pull request #137 from PlasmaFAIR/better_parallel_performance
Browse files Browse the repository at this point in the history
Better parallel performance
  • Loading branch information
LiamPattinson authored Nov 22, 2024
2 parents d63c249 + e7ef084 commit eb90255
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 101 deletions.
45 changes: 7 additions & 38 deletions fortitude/src/ast.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,9 @@
use anyhow::Context;
use lazy_static::lazy_static;
use ruff_diagnostics::Edit;
use ruff_source_file::SourceFile;
use ruff_text_size::{TextRange, TextSize};
/// Contains methods to parse Fortran code into a tree-sitter Tree and utilites to simplify the
/// navigation of a Tree.
use std::sync::Mutex;
use tree_sitter::{Language, Node, Parser, Tree, TreeCursor};

lazy_static! {
static ref PARSER: Mutex<Parser> = {
let parser = Mutex::new(Parser::new());
parser
.lock()
.unwrap()
.set_language(&tree_sitter_fortran::LANGUAGE.into())
.expect("Error loading Fortran grammar");
parser
};
}

/// Parse a Fortran string and return the root note to the AST.
pub fn parse<S: AsRef<str>>(source: S) -> anyhow::Result<Tree> {
PARSER
.lock()
.unwrap()
.parse(source.as_ref(), None)
.context("Failed to parse")
}

/// Access the language of the parser.
pub fn language() -> Language {
PARSER.lock().unwrap().language().unwrap()
}
use tree_sitter::{Node, TreeCursor};

pub struct DepthFirstIterator<'a> {
cursor: TreeCursor<'a>,
Expand All @@ -59,15 +30,18 @@ impl<'a> Iterator for DepthFirstIterator<'a> {

pub struct DepthFirstIteratorExcept<'a> {
cursor: TreeCursor<'a>,
exceptions: Vec<u16>,
exceptions: Vec<String>, // TODO Use kind ids instead
}

impl<'a> Iterator for DepthFirstIteratorExcept<'a> {
type Item = Node<'a>;

fn next(&mut self) -> Option<Self::Item> {
// ignore exception list if we're at a depth of 0
if (self.cursor.depth() == 0 || !self.exceptions.contains(&self.cursor.node().kind_id()))
if (self.cursor.depth() == 0
|| !self
.exceptions
.contains(&self.cursor.node().kind().to_string()))
&& self.cursor.goto_first_child()
{
return Some(self.cursor.node());
Expand Down Expand Up @@ -149,14 +123,9 @@ impl FortitudeNode<'_> for Node<'_> {
where
I: IntoIterator<Item = &'tree str>,
{
let lang = language();
let exception_ids: Vec<_> = exceptions
.into_iter()
.map(|x| lang.id_for_node_kind(x, true))
.collect();
DepthFirstIteratorExcept {
cursor: self.walk(),
exceptions: exception_ids,
exceptions: exceptions.into_iter().map(|x| x.to_string()).collect(),
}
}

Expand Down
11 changes: 9 additions & 2 deletions fortitude/src/check.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::ast::{parse, FortitudeNode};
use crate::ast::FortitudeNode;
use crate::cli::{CheckArgs, GlobalConfigArgs, FORTRAN_EXTS};
use crate::message::DiagnosticMessage;
use crate::printer::{Flags as PrinterFlags, Printer};
Expand All @@ -20,6 +20,7 @@ use std::path::{Path, PathBuf};
use std::process::ExitCode;
use strum::IntoEnumIterator;
use toml::Table;
use tree_sitter::Parser;
use walkdir::WalkDir;

// These are just helper structs to let us quickly work out if there's
Expand Down Expand Up @@ -245,7 +246,13 @@ pub(crate) fn check_file(
}

// Perform AST analysis
let tree = parse(file.source_text())?;
let mut parser = Parser::new();
parser
.set_language(&tree_sitter_fortran::LANGUAGE.into())
.context("Error loading Fortran grammar")?;
let tree = parser
.parse(file.source_text(), None)
.context("Failed to parse")?;
for node in tree.root_node().named_descendants() {
if let Some(rules) = ast_entrypoints.get(node.kind()) {
for rule in rules {
Expand Down
14 changes: 1 addition & 13 deletions fortitude/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ mod test;
mod text_helpers;
pub use crate::registry::clap_completion::RuleParser;
pub use crate::rule_selector::clap_completion::RuleSelectorParser;
use ast::{parse, FortitudeNode};

use ruff_diagnostics::{Diagnostic, DiagnosticKind};
use ruff_source_file::{OneIndexed, SourceFile};
use ruff_text_size::{TextRange, TextSize};
Expand Down Expand Up @@ -91,18 +91,6 @@ pub trait AstRule {

/// Return list of tree-sitter node types on which a rule should trigger.
fn entrypoints() -> Vec<&'static str>;

/// Apply a rule over some text, generating all violations raised as a result.
fn apply(source: &SourceFile) -> anyhow::Result<Vec<Diagnostic>> {
let entrypoints = Self::entrypoints();
Ok(parse(source.source_text())?
.root_node()
.named_descendants()
.filter(|x| entrypoints.contains(&x.kind()))
.filter_map(|x| Self::check(&Settings::default(), &x, source))
.flatten()
.collect())
}
}

/// Simplify making a `SourceFile` in tests
Expand Down
48 changes: 0 additions & 48 deletions fortitude/src/rules/style/relational_operators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,51 +56,3 @@ impl AstRule for DeprecatedRelationalOperator {
vec!["relational_expression"]
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{test_file, FromStartEndLineCol};
use pretty_assertions::assert_eq;

#[test]
fn test_relational_symbol() -> anyhow::Result<()> {
let source = test_file(
"
program test
if (0 .gt. 1) error stop
if (1 .le. 0) error stop
if (a.eq.b.and.a.ne.b) error stop
if (1 == 2) error stop ! OK
if (2 /= 2) error stop ! OK
end program test
",
);
let expected: Vec<_> = [
(2, 8, 2, 12, ".gt.", ">"),
(3, 8, 3, 12, ".le.", "<="),
(4, 7, 4, 11, ".eq.", "=="),
(4, 18, 4, 22, ".ne.", "/="),
]
.iter()
.map(
|(start_line, start_col, end_line, end_col, symbol, new_symbol)| {
Diagnostic::from_start_end_line_col(
DeprecatedRelationalOperator {
symbol: symbol.to_string(),
new_symbol: new_symbol.to_string(),
},
&source,
*start_line,
*start_col,
*end_line,
*end_col,
)
},
)
.collect();
let actual = DeprecatedRelationalOperator::apply(&source)?;
assert_eq!(actual, expected);
Ok(())
}
}

0 comments on commit eb90255

Please sign in to comment.