rbx-rsml 1.0.1

A lexer and parser for the RSML language.
Documentation
use std::{mem::{self, Discriminant, MaybeUninit}};
use crate::lexer::{Token, TokenKind};

#[macro_export]
macro_rules! token_kind_list {
    ($str:literal, [ $( $name:ident ),* ]) => {
        &TokenKindList::new_with_stringified([$(
            (TokenKind::$name, std::mem::discriminant(&TokenKind::$name))
        ),*], Stringified::Single(String::from($str)))
    };

    ($( $name:ident ),*) => {
        &TokenKindList::new([$(
            (TokenKind::$name, std::mem::discriminant(&TokenKind::$name))
        ),*])
    };

    ([ $( $name:ident ),* ]) => {
        token_kind_list!($( $name ),*)
    };
}

#[derive(Debug)]
pub struct TokenKindList<const N: usize>{
    items: [(TokenKind, Discriminant<TokenKind>); N],
    stringified: Option<Stringified>
}

#[derive(Debug, Clone)]
pub enum Stringified {
    Single(String),
    Many(Vec<String>)
}

impl Stringified {
    fn iter(&self) -> Box<dyn Iterator<Item = &String> + '_> {
        match self {
            Stringified::Single(item) => Box::new(std::iter::once(item)),
            Stringified::Many(items) => Box::new(items.iter())
        }
    }

    fn extend(self, extend_with: Stringified) -> Stringified {
        Self::Many(match (self, extend_with) {
            (Stringified::Single(a), Stringified::Single(b)) => vec![a, b],
            (Stringified::Many(mut a), Stringified::Many(b)) => {
                a.extend(b);
                a
            },
            (Stringified::Many(mut a), Stringified::Single(b)) |
            (Stringified::Single(b), Stringified::Many(mut a)) => {
                a.push(b);
                a
            }
        })
    }

}

impl<'a, const N: usize> TokenKindList<N> {
    pub fn new(items: [(TokenKind, Discriminant<TokenKind>); N]) -> Self {
        Self {
            items,
            stringified: None
        }
    }

    pub fn new_with_stringified(
        items: [(TokenKind, Discriminant<TokenKind>); N],
        stringified: Stringified
    ) -> Self {
        Self {
            items,
            stringified: Some(stringified)
        }
    }

    pub fn has_token(&self, token: &Token) -> bool {
        let discriminant = &token.discriminant();

        self.items.iter().any(|x| &x.1 == discriminant)
    }

    pub fn has_discriminant(&self, discriminant: &Discriminant<TokenKind>) -> bool {
        self.items.iter().any(|x| &x.1 == discriminant)
    }

    pub fn to_string(&'a self) -> Option<String> {
        let stringified = &self.stringified;
        let items = self.items;

        let mut iter: Box<dyn Iterator<Item = &str>> =
            if let Some(stringified) = stringified { Box::new(stringified.iter().map(String::as_str)) }
            else { Box::new(items.iter().map(|x| x.0.name())) };

        let Some(mut current_item) = iter.next() else { return None };

        let mut msg = format!("{}", current_item);

        let Some(next_item) = iter.next() else { return Some(msg) };
        current_item = next_item;

        loop {
            let next_item = iter.next();
            
            if let Some(next_item) = next_item {
                let msg_item = format!(", {}", current_item);
                current_item = next_item;
                msg += &msg_item;

            } else {
                let msg_item = format!(" or {}", current_item);
                msg += &msg_item;
                break
            };
        }

        return Some(msg)
    }

    pub fn with_stringified(&self, stringified: Stringified) -> Self {
        Self {
            items: self.items,
            stringified: Some(stringified)
        }
    }

    pub fn concat<const B: usize>(&self, b: &TokenKindList<B>) -> TokenKindList<{N + B}>
    where
        [(); N + B]:
    {
        TokenKindList::<{N + B}> {
            items: array_concat(&self.items, &b.items),
            stringified: match (&self.stringified, &b.stringified) {
                (Some(a), Some(b)) => Some(a.clone().extend(b.clone())),
                (Some(a), None) => Some(a.clone()),
                (None, Some(b)) => Some(b.clone()),
                (None, None) => None
            }
        }
    }
}

fn array_concat<T, const AN: usize, const BN: usize>(a: &[T; AN], b: &[T; BN]) -> [T; AN + BN]
where T: Copy, [(); AN + BN]: {
    let mut output: [MaybeUninit<T>; AN + BN] =
        unsafe { MaybeUninit::uninit().assume_init() };

    for i in 0..AN {
        output[i] = MaybeUninit::new(a[i]);
    }

    for i in 0..BN {
        output[AN + i] = MaybeUninit::new(b[i]);
    }

    unsafe {
        mem::transmute_copy::<_, [T; AN + BN]>(&output)
    }
}