| Crates.io | python-ast |
| lib.rs | python-ast |
| version | 1.0.2 |
| created_at | 2023-10-27 08:00:00.259165+00 |
| updated_at | 2025-08-06 00:11:28.742392+00 |
| description | A library for compiling Python to Rust |
| homepage | |
| repository | https://github.com/rexlunae/python-ast-rs.git |
| max_upload_size | |
| id | 1015718 |
| size | 480,217 |
A Rust library for parsing Python code into Abstract Syntax Trees (AST) and experimentally transpiling Python to Rust. This library leverages Python's own ast module via PyO3 to ensure compatibility with the reference Python implementation.
Add this to your Cargo.toml:
[dependencies]
python-ast = "1.0.0"
use python_ast::parse;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Parse Python source code
let python_code = "def hello():\n return 'world'";
// Parse into AST
let ast = parse(python_code, "example.py")?;
println!("Parsed {} statements", ast.raw.body.len());
println!("AST: {:#?}", ast);
Ok(())
}
use python_ast::{parse, CodeGen, CodeGenContext, PythonOptions, SymbolTableScopes};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let python_code = r#"
def fibonacci(n):
"""Calculate the nth Fibonacci number."""
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
"#;
// Parse Python code
let ast = parse(python_code, "fibonacci.py")?;
// Generate Rust code (experimental)
let options = PythonOptions::default();
let symbols = SymbolTableScopes::new();
let context = CodeGenContext::Module("fibonacci".to_string());
match ast.to_rust(context, options, symbols) {
Ok(rust_code) => {
println!("Generated Rust code:");
println!("{}", rust_code);
/* Output would be:
use stdpython::*;
#[doc = "Calculate the nth Fibonacci number."]
pub fn fibonacci(n: impl Into<PyObject>) -> impl Into<PyObject> {
"Calculate the nth Fibonacci number.";
if ((n) <= (1)) {
return n
};
return (fibonacci((n) - (1))) + (fibonacci((n) - (2)));
}
*/
}
Err(e) => {
println!("Code generation failed: {}", e);
}
}
Ok(())
}
src/parser/): Python AST extraction via PyO3src/ast/tree/): Rust representations of Python AST nodessrc/codegen/): Experimental Python-to-Rust transpilersrc/traits.rs, src/macros.rs): Helper traits and macrosThe library automatically extracts and converts Python docstrings:
def calculate_area(radius):
"""Calculate the area of a circle.
Args:
radius: The radius of the circle
Returns:
The area of the circle
"""
return 3.14159 * radius * radius
Becomes:
use std::ops::Mul;
/// Calculate the area of a circle.
///
/// # Arguments
/// radius: The radius of the circle
///
/// # Returns
/// The area of the circle
pub fn calculate_area<T>(radius: T) -> T
where
T: Copy + Mul<Output = T> + From<f64>,
{
// Generated from Python AST: return 3.14159 * radius * radius
T::from(3.14159) * radius * radius
}
Run the test suite:
# Run all integration tests
cargo test
# Run unit tests.
cargo test --lib
# Run specific test categories
cargo test ast::tree # AST node tests
cargo test parser # Parser tests
cargo test --lib --quiet # Library tests only
Current Test Status: 122/129 tests passing
git clone https://github.com/rexlunae/python-ast-rs.git
cd python-ast-rs
# Build the library
cargo build
# Run examples
cargo run --bin readme_example
impl Into<PyObject>, impl AsRef<str>impl IntoIterator<Item = impl Into<PyObject>>impl IntoIterator<Item = (impl AsRef<str>, impl Into<PyObject>)>The long-term goal is to create a fully-compiled Python-like language that:
Currently, this should be viewed as a proof of concept and research tool rather than a production-ready solution.
use python_ast::parse;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Parse a simple function
let ast = parse("def hello(): return 'world'", "hello.py")?;
// Parse a class with methods
let ast = parse(r#"
class Calculator:
def add(self, a, b):
return a + b
"#, "calc.py")?;
// Parse control flow
let ast = parse(r#"
for i in range(10):
if i % 2 == 0:
print(i)
"#, "loop.py")?;
Ok(())
}
The library generates highly generic Rust code using trait bounds for maximum flexibility:
use python_ast::{parse, CodeGen, CodeGenContext, PythonOptions, SymbolTableScopes};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let python_code = r#"
def process_data(name, values, *args, **kwargs):
"""Process data with flexible parameter types."""
return f"Processing {name} with {len(values)} items"
"#;
let ast = parse(python_code, "example.py")?;
let options = PythonOptions::default();
let symbols = SymbolTableScopes::new();
let context = CodeGenContext::Module("example".to_string());
match ast.to_rust(context, options, symbols) {
Ok(rust_code) => {
println!("Generated generic Rust code:");
println!("{}", rust_code);
/* Output includes generic parameters like:
pub fn process_data(
name: impl Into<PyObject>,
values: impl Into<PyObject>,
args: impl IntoIterator<Item = impl Into<PyObject>>,
kwargs: impl IntoIterator<Item = (impl AsRef<str>, impl Into<PyObject>)>
) -> impl Into<PyObject> { ... }
*/
}
Err(e) => {
println!("Code generation failed: {}", e);
}
}
Ok(())
}
use python_ast::{parse, StatementType, ExprType};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let ast = parse("x = [1, 2, 3]", "list.py")?;
match &ast.raw.body[0].statement {
StatementType::Assign(assign) => {
println!("Assignment to: {:?}", assign.targets);
match &assign.value {
ExprType::List(elements) => {
println!("List with {} elements", elements.len());
}
_ => {}
}
}
_ => {}
}
Ok(())
}
Licensed under the Apache License, Version 2.0. See LICENSE for details.
Note: This library is experimental and under active development. While basic parsing works reliably, advanced features and code generation should be used with caution in production environments.