use proc_macro2::TokenStream;
use quote::quote;
use pyo3::types::{PyAnyMethods, PyTypeMethods};
use crate::{CodeGen, CodeGenContext, PythonOptions, SymbolTableScopes, ExprType};
pub trait PythonOperator: Clone + std::fmt::Debug {
fn to_rust_op(&self) -> Result<TokenStream, Box<dyn std::error::Error>>;
fn precedence(&self) -> u8 {
0 }
fn is_unknown(&self) -> bool;
}
pub trait BinaryOperation: Clone + std::fmt::Debug {
type OperatorType: PythonOperator;
fn operator(&self) -> &Self::OperatorType;
fn left(&self) -> &ExprType;
fn right(&self) -> &ExprType;
fn generate_rust_code(
&self,
ctx: CodeGenContext,
options: PythonOptions,
symbols: SymbolTableScopes,
) -> Result<TokenStream, Box<dyn std::error::Error>> {
let left = self.left()
.clone()
.to_rust(ctx.clone(), options.clone(), symbols.clone())?;
let right = self.right()
.clone()
.to_rust(ctx, options, symbols)?;
let op = self.operator().to_rust_op()?;
Ok(quote!((#left) #op (#right)))
}
}
pub trait PyAttributeExtractor {
fn extract_attr_with_context(&self, attr: &str, context: &str) -> pyo3::PyResult<pyo3::Bound<'_, pyo3::PyAny>>;
fn extract_type_name(&self, context: &str) -> pyo3::PyResult<String>;
}
impl<'py> PyAttributeExtractor for pyo3::Bound<'py, pyo3::PyAny> {
fn extract_attr_with_context(&self, attr: &str, context: &str) -> pyo3::PyResult<pyo3::Bound<'_, pyo3::PyAny>> {
use crate::Node;
self.getattr(attr).map_err(|_| {
pyo3::exceptions::PyAttributeError::new_err(
self.error_message("<unknown>", format!("error getting {}", context))
)
})
}
fn extract_type_name(&self, context: &str) -> pyo3::PyResult<String> {
use crate::Node;
let type_name = self.get_type().name().map_err(|_| {
pyo3::exceptions::PyTypeError::new_err(
self.error_message("<unknown>", format!("extracting type name for {}", context))
)
})?;
type_name.extract()
}
}
pub trait PositionInfo {
fn position_info(&self) -> (Option<usize>, Option<usize>, Option<usize>, Option<usize>);
fn has_position(&self) -> bool {
let (lineno, col_offset, _, _) = self.position_info();
lineno.is_some() && col_offset.is_some()
}
}
pub trait DebugInfo {
fn debug_description(&self) -> String;
fn node_type(&self) -> &'static str;
}
pub trait ChainableOperation {
type Operand;
type Operator;
fn operands(&self) -> Vec<&Self::Operand>;
fn operators(&self) -> Vec<&Self::Operator>;
fn generate_chained_rust(
&self,
ctx: CodeGenContext,
options: PythonOptions,
symbols: SymbolTableScopes,
) -> Result<TokenStream, Box<dyn std::error::Error>>;
}
pub trait FromPythonString: Sized {
fn from_python_string(s: &str) -> Option<Self>;
fn unknown() -> Self;
fn parse_or_unknown(s: &str) -> Self {
Self::from_python_string(s).unwrap_or_else(Self::unknown)
}
}
pub trait ErrorContext {
fn with_context(&self, operation: &str) -> String;
}
impl<T: std::fmt::Debug> ErrorContext for T {
fn with_context(&self, operation: &str) -> String {
format!("Error during {}: {:?}", operation, self)
}
}