libhanzzok 0.1.5

Hanzzok compiler library
Documentation
use std::{
    collections::HashMap,
    iter::Enumerate,
    ops::{RangeFrom, RangeTo},
    rc::Rc,
    vec::IntoIter,
};

use nom::{
    combinator::{fail, opt},
    InputIter, InputLength, InputTake, Needed, Offset, Slice,
};
use tokenize::HanzzokTokenizer;

use crate::{
    api::BlockConstructorRule,
    core::ast::BlockConstructorForm,
    syntax::{parse::ParseResult, tokenize, Token, TokenKind},
};

use super::satisfy;

#[derive(Clone)]
pub struct HanzzokParser {
    pub(crate) block_constructors: HashMap<
        BlockConstructorForm,
        Vec<(BlockConstructorNameParser, Rc<dyn BlockConstructorRule>)>,
    >,
    pub(crate) offset: usize,
    pub(crate) tokens: Vec<Token>,
}

impl HanzzokParser {
    pub fn create_tracker(&self) -> HanzzokParserTracker {
        HanzzokParserTracker {
            start_offset: self.offset,
            tokens: self.tokens.clone(),
        }
    }
}

pub struct HanzzokParserTracker {
    start_offset: usize,
    tokens: Vec<Token>,
}

impl HanzzokParserTracker {
    pub fn end(self, parser: &HanzzokParser) -> Vec<Token> {
        self.tokens[..(parser.offset - self.start_offset)].to_vec()
    }
}

#[derive(Clone, Debug)]
pub(crate) struct BlockConstructorNameParser {
    pub(crate) name: String,
    kinds: Vec<TokenKind>,
}

impl BlockConstructorNameParser {
    pub(crate) fn parse(&self, mut p: HanzzokParser) -> ParseResult<Vec<Token>> {
        let mut tokens = Vec::new();

        for kind in &self.kinds {
            let res = satisfy(|token| &token.kind == kind)(p)?;
            p = res.0;
            tokens.push(res.1);
        }

        let (p, v) = opt(satisfy(|t| {
            matches!(
                t.kind,
                TokenKind::PunctuationQuotationMark
                    | TokenKind::PunctuationNumberSign
                    | TokenKind::PunctuationLeftParenthesis
                    | TokenKind::PunctuationRightParenthesis
                    | TokenKind::PunctuationHyphenMinus
                    | TokenKind::PunctuationFullStop
                    | TokenKind::PunctuationReverseSolidus
                    | TokenKind::PunctuationLeftSquareBracket
                    | TokenKind::PunctuationRightSquareBracket
                    | TokenKind::PunctuationLeftCurlyBracket
                    | TokenKind::PunctuationVerticalBar
                    | TokenKind::PunctuationRightCurlyBracket
                    | TokenKind::PunctuationsOther(_)
            )
        }))(p)?;
        if v.is_some() {
            return fail(p);
        }

        Ok((p, tokens))
    }
}

impl HanzzokParser {
    pub fn new(
        tokens: Vec<Token>,
        block_constructors: &HashMap<String, Rc<dyn BlockConstructorRule>>,
    ) -> Self {
        HanzzokParser {
            block_constructors: {
                let mut map = HashMap::new();

                for (name, rule) in block_constructors {
                    let group = map.entry(rule.form()).or_insert(Vec::new());
                    group.push((
                        BlockConstructorNameParser {
                            name: name.clone(),
                            kinds: HanzzokTokenizer::from_source(name.as_ref())
                                .map(|token| token.kind)
                                .collect(),
                        },
                        rule.clone(),
                    ))
                }

                map
            },
            offset: 0,
            tokens,
        }
    }
}

impl InputLength for HanzzokParser {
    #[inline]
    fn input_len(&self) -> usize {
        self.tokens.len()
    }
}

impl<'a> InputIter for HanzzokParser {
    type Item = Token;
    type Iter = Enumerate<Self::IterElem>;
    type IterElem = IntoIter<Token>;

    #[inline]
    fn iter_indices(&self) -> Self::Iter {
        self.iter_elements().enumerate()
    }
    #[inline]
    fn iter_elements(&self) -> Self::IterElem {
        self.tokens.clone().into_iter()
    }
    #[inline]
    fn position<P>(&self, predicate: P) -> Option<usize>
    where
        P: Fn(Self::Item) -> bool,
    {
        self.tokens.iter().position(|b| predicate(b.clone()))
    }
    #[inline]
    fn slice_index(&self, count: usize) -> Result<usize, Needed> {
        if self.tokens.len() >= count {
            Ok(count)
        } else {
            Err(Needed::new(count - self.tokens.len()))
        }
    }
}

impl InputTake for HanzzokParser {
    #[inline]
    fn take(&self, count: usize) -> Self {
        HanzzokParser {
            tokens: self.tokens[0..count].to_vec(),
            offset: self.offset,
            block_constructors: self.block_constructors.clone(),
        }
    }
    #[inline]
    fn take_split(&self, count: usize) -> (Self, Self) {
        let (prefix, suffix) = self.tokens.split_at(count);
        (
            HanzzokParser {
                tokens: suffix.to_vec(),
                offset: self.offset + count,
                block_constructors: self.block_constructors.clone(),
            },
            HanzzokParser {
                tokens: prefix.to_vec(),
                offset: self.offset,
                block_constructors: self.block_constructors.clone(),
            },
        )
    }
}

impl Slice<RangeFrom<usize>> for HanzzokParser {
    fn slice(&self, range: RangeFrom<usize>) -> Self {
        HanzzokParser {
            tokens: self.tokens[range.clone()].to_vec(),
            offset: self.offset + range.start,
            block_constructors: self.block_constructors.clone(),
        }
    }
}

impl Slice<RangeTo<usize>> for HanzzokParser {
    fn slice(&self, range: RangeTo<usize>) -> Self {
        HanzzokParser {
            tokens: self.tokens[range].to_vec(),
            offset: self.offset,
            block_constructors: self.block_constructors.clone(),
        }
    }
}

impl Offset for HanzzokParser {
    fn offset(&self, second: &Self) -> usize {
        second.offset - self.offset
    }
}