use anyhow::{Context, Result};
use log::{debug, info};
use rustpython_parser::{ast, Parse};
use std::fs;
use std::path::Path;
pub fn parse_file(path: &Path) -> Result<ast::Suite> {
info!("Parsing Python file: {}", path.display());
let source = fs::read_to_string(path)
.with_context(|| format!("Failed to read Python file: {}", path.display()))?;
parse_source(&source)
.with_context(|| format!("Failed to parse Python file: {}", path.display()))
}
pub fn parse_source(source: &str) -> Result<ast::Suite> {
debug!("Parsing Python source code");
let ast = ast::Suite::parse(source, "<string>")
.map_err(|e| anyhow::anyhow!("Python parsing error: {}", e))?;
debug!("Successfully parsed Python source code");
Ok(ast)
}
pub fn extract_functions(ast: &ast::Suite) -> Vec<&ast::Stmt> {
let mut functions = Vec::new();
for stmt in ast {
match stmt {
ast::Stmt::FunctionDef(_) => {
functions.push(stmt);
}
_ => {}
}
}
debug!("Extracted {} functions", functions.len());
functions
}
pub fn extract_classes(ast: &ast::Suite) -> Vec<&ast::Stmt> {
let mut classes = Vec::new();
for stmt in ast {
match stmt {
ast::Stmt::ClassDef(_) => {
classes.push(stmt);
}
_ => {}
}
}
debug!("Extracted {} classes", classes.len());
classes
}
pub fn extract_imports(ast: &ast::Suite) -> Vec<&ast::Stmt> {
let mut imports = Vec::new();
for stmt in ast {
match stmt {
ast::Stmt::Import(_) => {
imports.push(stmt);
}
_ => {}
}
}
debug!("Extracted {} imports", imports.len());
imports
}
pub fn extract_from_imports(ast: &ast::Suite) -> Vec<&ast::Stmt> {
let mut imports = Vec::new();
for stmt in ast {
match stmt {
ast::Stmt::ImportFrom(_) => {
imports.push(stmt);
}
_ => {}
}
}
debug!("Extracted {} from imports", imports.len());
imports
}
pub fn extract_module_vars(ast: &ast::Suite) -> Vec<&ast::Stmt> {
let mut vars = Vec::new();
for stmt in ast {
match stmt {
ast::Stmt::Assign(_) => {
vars.push(stmt);
}
_ => {}
}
}
debug!("Extracted {} module variables", vars.len());
vars
}