python_ast/parser/
mod.rs

1use crate::{dump, Module, Name, *};
2
3use pyo3::prelude::*;
4
5use std::path::MAIN_SEPARATOR;
6
7/// Takes a string of Python code and emits a Python struct that represents the AST.
8fn parse_to_py(
9    input: impl AsRef<str>,
10    filename: impl AsRef<str>,
11    py: Python<'_>,
12) -> PyResult<PyObject> {
13    let pymodule_code = include_str!("__init__.py");
14
15    // We want to call tokenize.tokenize from Python.
16    let pymodule = PyModule::from_code(py, pymodule_code, "__init__.py", "parser")?;
17    let t = pymodule.getattr("parse")?;
18    assert!(t.is_callable());
19    let args = (input.as_ref(), filename.as_ref());
20
21    let py_tree = t.call1(args)?;
22    log::debug!("py_tree: {}", dump(py_tree, Some(4))?);
23
24    Ok(py_tree.into())
25}
26
27/// Takes a string of bytes and returns the Python-tokenized version of it.
28/// use python_ast::parse;
29///
30/// ```Rust
31/// fn read_python_file(input: std::path::Path) {
32///    let py = read_to_string(input).unwrap();
33///    let ast = parse(&py, "__main__").unwrap();
34///
35///    println!("{:?}", ast);
36///}
37/// ```
38pub fn parse(input: impl AsRef<str>, filename: impl AsRef<str>) -> PyResult<Module> {
39    let filename = filename.as_ref();
40    let mut module: Module = Python::with_gil(|py| {
41        let py_tree = parse_to_py(input, filename, py)?;
42        py_tree.extract(py)
43    })?;
44    module.filename = Some(filename.into());
45
46    if let Some(name_str) = filename.replace(MAIN_SEPARATOR, "__").strip_suffix(".py") {
47        module.name =
48            Some(Name::try_from(name_str).unwrap_or_else(|_| panic!("Invalid name {}", name_str)));
49    }
50
51    println!("module: {:#?}", module);
52    for item in module.__dir__() {
53        println!("module.__dir__: {:#?}", item.as_ref());
54    }
55    Ok(module)
56}