unidok-parser 0.2.0

Parser for the Unidok document format
Documentation
use detached_str::StrSlice;
use unidok_repr::ast::macros::MacroArgs;

use crate::parsing_mode::ParsingMode;
use crate::utils::{ParseLineBreak, ParseLineEnd, ParseSpaces};
use crate::{Indents, Input, Parse};

pub(super) fn get_parsing_mode(
    name: &str,
    args: &Option<MacroArgs>,
    input: &Input,
) -> Option<Option<ParsingMode>> {
    Some(match name {
        "PASS" => match &args {
            None => Some(ParsingMode::new_all()),
            Some(MacroArgs::TokenTrees(tts)) => {
                let mut pm = ParsingMode::new_nothing();
                for tt in tts {
                    let word = &input[tt.as_atom()?.as_word()?];
                    match ParsingMode::parse_param(word) {
                        Some(param) => pm = pm.set(param),
                        _ => return None,
                    }
                }
                Some(pm)
            }
            _ => return None,
        },
        "NOPASS" => match &args {
            None => Some(ParsingMode::new_nothing()),
            Some(MacroArgs::TokenTrees(tts)) => {
                let mut pm = ParsingMode::new_all();
                for tt in tts {
                    let word = &input[tt.as_atom()?.as_word()?];
                    match ParsingMode::parse_param(word) {
                        Some(param) => pm = pm.unset(param),
                        _ => return None,
                    }
                }
                Some(pm)
            }
            _ => return None,
        },
        _ => None,
    })
}

pub(crate) struct ParseMacroName;

impl Parse for ParseMacroName {
    type Output = StrSlice;

    fn parse(&mut self, input: &mut Input) -> Option<Self::Output> {
        fn is_macro_char(c: char) -> bool {
            c.is_ascii_uppercase() || c.is_ascii_digit() || c == '_'
        }

        if let Some(mat) = input.rest().find(|c| !is_macro_char(c)) {
            let rest = &input.rest()[mat..];
            if rest.starts_with(char::is_alphanumeric) {
                None
            } else {
                let len = input.len() - rest.len();
                Some(input.bump(len))
            }
        } else {
            Some(input.bump(input.len()))
        }
    }
}

pub(crate) struct ParseOpeningBrace<'a>(pub(crate) Indents<'a>);

impl Parse for ParseOpeningBrace<'_> {
    type Output = ();

    fn parse(&mut self, input: &mut Input) -> Option<Self::Output> {
        let mut input = input.start();

        input.parse('{')?;
        input.parse_i(ParseSpaces);
        input.parse(ParseLineEnd)?;
        input.try_parse(ParseLineBreak(self.0));

        input.apply();
        Some(())
    }
}

pub(crate) struct ParseClosingBrace<'a>(pub(crate) Indents<'a>);

impl Parse for ParseClosingBrace<'_> {
    type Output = ();

    fn parse(&mut self, input: &mut Input) -> Option<Self::Output> {
        let mut input = input.start();

        input.parse_i(ParseSpaces);
        input.parse('}')?;
        input.parse_i(ParseSpaces);
        input.parse(ParseLineEnd)?;
        input.try_parse(ParseLineBreak(self.0));

        input.apply();
        Some(())
    }
}