Try out tree-sitter
This commit is contained in:
130
examples/parse_python.rs
Normal file
130
examples/parse_python.rs
Normal file
@@ -0,0 +1,130 @@
|
||||
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(())
|
||||
}
|
||||
Reference in New Issue
Block a user