pymeta 0.1.0-alpha.1

Metaprogramming Rust in Python!
Documentation
use super::PY_MARKER;
use crate::utils::rust_token::{CSpan, Punct, Token, TokenBuffer};
use proc_macro2::Delimiter;
use std::rc::Rc;

pub(crate) trait PunctEx {
    fn as_str(&self) -> &'static str;
}
impl PunctEx for Punct {
    fn as_str(&self) -> &'static str {
        match self.inner().as_char() {
            '!' => "!",
            '#' => "#",
            '$' => "$",
            '%' => "%",
            '&' => "&",
            '\'' => "'",
            '*' => "*",
            '+' => "+",
            ',' => ",",
            '-' => "-",
            '.' => ".",
            '/' => "/",
            ':' => ":",
            ';' => ";",
            '<' => "<",
            '=' => "=",
            '>' => ">",
            '?' => "?",
            '@' => "@",
            '^' => "^",
            '|' => "|",
            '~' => "~",
            _ => unreachable!(),
        }
    }
}

pub(super) trait TokenOptionEx {
    fn eq_punct(&self, c: char) -> bool;
    fn eq_group(&self, delimiter: Delimiter) -> bool;
}
impl TokenOptionEx for Option<&Token> {
    fn eq_punct(&self, c: char) -> bool {
        match self {
            Some(t) => t.eq_punct(c),
            None => false,
        }
    }

    fn eq_group(&self, delimiter: Delimiter) -> bool {
        match self {
            Some(t) => t.eq_group(delimiter),
            None => false,
        }
    }
}

pub(super) trait TokenBufferEx {
    fn is_current_py_marker_escaped(&self) -> bool;
    fn is_py_marker_escape(&self) -> bool;
    fn py_marker_escape_span(&self) -> Rc<CSpan>;
    fn skip_py_marker_escape(&mut self);
    fn read_unescaped_py_marker_escape(&mut self) -> Rc<Punct>;
    fn is_py_marker_start(&self) -> bool;
    fn is_py_marker_end(&self) -> bool;
    fn is_indent_block(&self) -> bool;
}
impl TokenBufferEx for TokenBuffer {
    fn is_current_py_marker_escaped(&self) -> bool {
        assert!(self.current().eq_punct(PY_MARKER));
        self.peek(-1).eq_punct('<') && self.peek(1).eq_punct('>')
    }

    fn is_py_marker_escape(&self) -> bool {
        self.peek(1).eq_punct(PY_MARKER) && self.seeked(1).unwrap().is_current_py_marker_escaped()
    }

    fn py_marker_escape_span(&self) -> Rc<CSpan> {
        let start = self.current().unwrap().span();
        let end = self.peek(2).unwrap().span();
        Rc::new(CSpan::from(
            start
                .inner()
                .join(end.inner())
                .unwrap_or_else(|| self.peek(1).unwrap().span().inner()),
        ))
    }

    fn skip_py_marker_escape(&mut self) {
        self.seek(3).unwrap();
    }

    fn read_unescaped_py_marker_escape(&mut self) -> Rc<Punct> {
        let mut punct = self.peek(1).unwrap().clone().punct().unwrap();
        Rc::make_mut(&mut punct).set_span(self.py_marker_escape_span().inner());
        self.skip_py_marker_escape();
        punct
    }

    fn is_py_marker_start(&self) -> bool {
        self.current().eq_punct(PY_MARKER) && !self.is_current_py_marker_escaped()
    }

    fn is_py_marker_end(&self) -> bool {
        self.current().eq_punct(PY_MARKER) && !self.is_current_py_marker_escaped()
    }

    fn is_indent_block(&self) -> bool {
        self.current().eq_punct(':') && self.peek(1).eq_group(Delimiter::Brace)
    }
}

pub(super) trait DelimiterEx {
    fn left_str(self) -> Option<&'static str>;
    fn right_str(self) -> Option<&'static str>;
    fn left_right_str(self) -> Option<&'static str>;
}
impl DelimiterEx for Delimiter {
    fn left_str(self) -> Option<&'static str> {
        match self {
            Delimiter::Parenthesis => Some("("),
            Delimiter::Brace => Some("{"),
            Delimiter::Bracket => Some("["),
            Delimiter::None => None,
        }
    }

    fn right_str(self) -> Option<&'static str> {
        match self {
            Delimiter::Parenthesis => Some(")"),
            Delimiter::Brace => Some("}"),
            Delimiter::Bracket => Some("]"),
            Delimiter::None => None,
        }
    }

    fn left_right_str(self) -> Option<&'static str> {
        match self {
            Delimiter::Parenthesis => Some("()"),
            Delimiter::Brace => Some("{}"),
            Delimiter::Bracket => Some("[]"),
            Delimiter::None => None,
        }
    }
}