mirror of https://github.com/astral-sh/ruff
131 lines
4.3 KiB
Rust
131 lines
4.3 KiB
Rust
use anyhow::Result;
|
|
use tree_sitter::{Parser, Query, QueryCursor};
|
|
|
|
enum Action {
|
|
Up,
|
|
Down,
|
|
Right,
|
|
}
|
|
|
|
fn main() -> Result<()> {
|
|
let src = r#"
|
|
def double(x):
|
|
# Return a double.
|
|
return x * 2
|
|
|
|
x = double(1)
|
|
y = (f"{x}" "b")
|
|
"#;
|
|
let mut parser = Parser::new();
|
|
parser
|
|
.set_language(tree_sitter_python::language())
|
|
.expect("Error loading Python grammar");
|
|
let parse_tree = parser.parse(src, None);
|
|
|
|
if let Some(parse_tree) = &parse_tree {
|
|
// Check for comments.
|
|
let query = Query::new(tree_sitter_python::language(), "(comment) @capture")?;
|
|
let mut query_cursor = QueryCursor::new();
|
|
let all_matches = query_cursor.matches(&query, parse_tree.root_node(), src.as_bytes());
|
|
|
|
for each_match in all_matches {
|
|
for capture in each_match.captures.iter() {
|
|
let range = capture.node.range();
|
|
let text = &src[range.start_byte..range.end_byte];
|
|
let line = range.start_point.row;
|
|
let col = range.start_point.column;
|
|
println!(
|
|
"[Line: {}, Col: {}] Offending source code: `{}`",
|
|
line, col, text
|
|
);
|
|
}
|
|
}
|
|
|
|
// Check for string concatenations.
|
|
let query = Query::new(
|
|
tree_sitter_python::language(),
|
|
"(concatenated_string) @capture",
|
|
)?;
|
|
let mut query_cursor = QueryCursor::new();
|
|
let all_matches = query_cursor.matches(&query, parse_tree.root_node(), src.as_bytes());
|
|
|
|
for each_match in all_matches {
|
|
for capture in each_match.captures.iter() {
|
|
let range = capture.node.range();
|
|
let text = &src[range.start_byte..range.end_byte];
|
|
let line = range.start_point.row;
|
|
let col = range.start_point.column;
|
|
println!(
|
|
"[Line: {}, Col: {}] Offending source code: `{}`",
|
|
line, col, text
|
|
);
|
|
}
|
|
}
|
|
|
|
// Walk the tree.
|
|
let mut cursor = parse_tree.walk();
|
|
let mut action = Action::Down;
|
|
loop {
|
|
match action {
|
|
Action::Up => {
|
|
if cursor.goto_next_sibling() {
|
|
action = Action::Right;
|
|
} else if cursor.goto_parent() {
|
|
action = Action::Up;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
Action::Down => {
|
|
let range = cursor.node().range();
|
|
let text = &src[range.start_byte..range.end_byte];
|
|
let line = range.start_point.row;
|
|
let col = range.start_point.column;
|
|
println!(
|
|
"[Line: {}, Col: {}] {}: `{}`",
|
|
line,
|
|
col,
|
|
cursor.node().kind(),
|
|
text
|
|
);
|
|
|
|
if cursor.goto_first_child() {
|
|
action = Action::Down;
|
|
} else if cursor.goto_next_sibling() {
|
|
action = Action::Right;
|
|
} else if cursor.goto_parent() {
|
|
action = Action::Up;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
Action::Right => {
|
|
let range = cursor.node().range();
|
|
let text = &src[range.start_byte..range.end_byte];
|
|
let line = range.start_point.row;
|
|
let col = range.start_point.column;
|
|
println!(
|
|
"[Line: {}, Col: {}] {}: `{}`",
|
|
line,
|
|
col,
|
|
cursor.node().kind(),
|
|
text
|
|
);
|
|
|
|
if cursor.goto_first_child() {
|
|
action = Action::Down;
|
|
} else if cursor.goto_next_sibling() {
|
|
action = Action::Right;
|
|
} else if cursor.goto_parent() {
|
|
action = Action::Up;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|