use crate::{
nodes::expression::{DeflatedLeftParen, DeflatedRightParen},
nodes::op::DeflatedComma,
tokenizer::whitespace_parser::{Config, WhitespaceError},
Codegen, CodegenState, EmptyLine, LeftParen, RightParen,
};
use std::ops::Deref;
pub trait WithComma<'r, 'a> {
fn with_comma(self, comma: DeflatedComma<'r, 'a>) -> Self;
}
pub trait ParenthesizedNode<'a> {
fn lpar(&self) -> &Vec<LeftParen<'a>>;
fn rpar(&self) -> &Vec<RightParen<'a>>;
fn parenthesize<F>(&self, state: &mut CodegenState<'a>, f: F)
where
F: FnOnce(&mut CodegenState<'a>),
{
for lpar in self.lpar() {
lpar.codegen(state);
}
f(state);
for rpar in self.rpar() {
rpar.codegen(state);
}
}
fn with_parens(self, left: LeftParen<'a>, right: RightParen<'a>) -> Self;
}
impl<'a, T: ParenthesizedNode<'a>> ParenthesizedNode<'a> for Box<T> {
fn lpar(&self) -> &Vec<LeftParen<'a>> {
self.deref().lpar()
}
fn rpar(&self) -> &Vec<RightParen<'a>> {
self.deref().rpar()
}
fn parenthesize<F>(&self, state: &mut CodegenState<'a>, f: F)
where
F: FnOnce(&mut CodegenState<'a>),
{
self.deref().parenthesize(state, f)
}
fn with_parens(self, left: LeftParen<'a>, right: RightParen<'a>) -> Self {
Self::new((*self).with_parens(left, right))
}
}
pub trait ParenthesizedDeflatedNode<'r, 'a> {
fn lpar(&self) -> &Vec<DeflatedLeftParen<'r, 'a>>;
fn rpar(&self) -> &Vec<DeflatedRightParen<'r, 'a>>;
fn with_parens(
self,
left: DeflatedLeftParen<'r, 'a>,
right: DeflatedRightParen<'r, 'a>,
) -> Self;
}
impl<'r, 'a, T: ParenthesizedDeflatedNode<'r, 'a>> ParenthesizedDeflatedNode<'r, 'a> for Box<T> {
fn lpar(&self) -> &Vec<DeflatedLeftParen<'r, 'a>> {
self.deref().lpar()
}
fn rpar(&self) -> &Vec<DeflatedRightParen<'r, 'a>> {
self.deref().rpar()
}
fn with_parens(
self,
left: DeflatedLeftParen<'r, 'a>,
right: DeflatedRightParen<'r, 'a>,
) -> Self {
Self::new((*self).with_parens(left, right))
}
}
pub trait WithLeadingLines<'a> {
fn leading_lines(&mut self) -> &mut Vec<EmptyLine<'a>>;
}
pub type Result<T> = std::result::Result<T, WhitespaceError>;
pub trait Inflate<'a>
where
Self: Sized,
{
type Inflated;
fn inflate(self, config: &Config<'a>) -> Result<Self::Inflated>;
}
impl<'a, T: Inflate<'a>> Inflate<'a> for Option<T> {
type Inflated = Option<T::Inflated>;
fn inflate(self, config: &Config<'a>) -> Result<Self::Inflated> {
self.map(|x| x.inflate(config)).transpose()
}
}
impl<'a, T: Inflate<'a> + ?Sized> Inflate<'a> for Box<T> {
type Inflated = Box<T::Inflated>;
fn inflate(self, config: &Config<'a>) -> Result<Self::Inflated> {
match (*self).inflate(config) {
Ok(a) => Ok(Box::new(a)),
Err(e) => Err(e),
}
}
}
impl<'a, T: Inflate<'a>> Inflate<'a> for Vec<T> {
type Inflated = Vec<T::Inflated>;
fn inflate(self, config: &Config<'a>) -> Result<Self::Inflated> {
self.into_iter().map(|item| item.inflate(config)).collect()
}
}
#[cfg(feature = "py")]
pub mod py {
use pyo3::{types::PyAny, types::PyTuple, IntoPy, PyObject, PyResult, Python};
pub trait TryIntoPy<T>: Sized {
fn try_into_py(self, py: Python) -> PyResult<T>;
}
impl TryIntoPy<PyObject> for bool {
fn try_into_py(self, py: Python) -> PyResult<PyObject> {
Ok(self.into_py(py))
}
}
impl<T: TryIntoPy<PyObject>> TryIntoPy<PyObject> for Box<T>
where
T: TryIntoPy<PyObject>,
{
fn try_into_py(self, py: Python) -> PyResult<PyObject> {
(*self).try_into_py(py)
}
}
impl<T> TryIntoPy<PyObject> for Option<T>
where
T: TryIntoPy<PyObject>,
{
fn try_into_py(self, py: Python) -> PyResult<PyObject> {
Ok(match self {
None => py.None(),
Some(x) => x.try_into_py(py)?,
})
}
}
impl<T> TryIntoPy<PyObject> for Vec<T>
where
T: TryIntoPy<PyObject>,
{
fn try_into_py(self, py: Python) -> PyResult<PyObject> {
let converted = self
.into_iter()
.map(|x| x.try_into_py(py))
.collect::<PyResult<Vec<_>>>()?
.into_iter();
Ok(PyTuple::new(py, converted).into())
}
}
impl TryIntoPy<PyObject> for PyTuple {
fn try_into_py(self, py: Python) -> PyResult<PyObject> {
Ok(self.into_py(py))
}
}
impl<'a> TryIntoPy<PyObject> for &'a str {
fn try_into_py(self, py: Python) -> PyResult<PyObject> {
Ok(self.into_py(py))
}
}
impl<T> TryIntoPy<PyObject> for &'_ T
where
T: AsRef<PyAny>,
{
fn try_into_py(self, py: Python) -> PyResult<PyObject> {
Ok(self.into_py(py))
}
}
}