Skip to main content

rbx_rsml/macros/
mod.rs

1mod macros_lexer;
2use std::{collections::HashMap, fmt::Debug};
3
4use guarded::guarded_unwrap;
5use macro_token_iterator::MacroArgs;
6pub use macros_lexer::lex_rsml_macros;
7
8mod macros_parser;
9pub use macros_parser::parse_rsml_macros;
10
11mod macro_token_iterator;
12pub use macro_token_iterator::MacroTokenIterator;
13
14use crate::{lex_rsml, Token};
15
16pub type TokenPair<TokenType = Token> = (TokenType, String);
17
18#[derive(Debug, Clone)]
19pub struct Macro {
20    pub token_pairs: Vec<TokenPair>,
21    arg_places: Option<HashMap<usize, usize>>
22}
23impl<'a> Macro {
24    fn new(body: String, args: Option<HashMap<&'a str, usize>>) -> Self {
25        let mut lexer: logos::Lexer<'_, Token> = lex_rsml(&body);
26        
27        let mut token_pairs: Vec<TokenPair> = vec![];
28
29        if let Some(args) = args {
30            let mut token_pairs_idx = 0usize;
31            let mut arg_places: HashMap<usize, usize> = HashMap::new();
32
33            loop {
34                let token = guarded_unwrap!(guarded_unwrap!(lexer.next(), break), continue);
35                let token_slice = lexer.slice();
36
37                if matches!(token, Token::ArgIdentifier) {
38                    if let Some(Ok(next_token)) = lexer.next() {
39                        let next_token_slice = lexer.slice();
40
41                        if matches!(next_token, Token::Text) {
42                            if let Some(arg_idx) = args.get(next_token_slice) {
43                                arg_places.insert(token_pairs_idx, *arg_idx);
44
45                            } else {
46                                token_pairs.push((Token::Nil, "nil".to_string()));
47                                token_pairs_idx += 1;
48                            }
49
50                        } else {
51                            token_pairs.push((token, token_slice.to_string()));
52                            token_pairs.push((next_token, next_token_slice.to_string()));
53                            token_pairs_idx += 2;
54                        }
55                    }
56
57                } else {
58                    token_pairs.push((token, token_slice.to_string()));
59                    token_pairs_idx += 1;
60                }
61            }
62
63            Self {
64                token_pairs,
65                arg_places: Some(arg_places)
66            }
67            
68        } else {
69            loop {
70                let token = guarded_unwrap!(guarded_unwrap!(lexer.next(), break), continue);
71                let slice = lexer.slice().to_string();
72                token_pairs.push((token, slice));
73            }
74
75            Self {
76                token_pairs,
77                arg_places: None
78            }
79        }
80    }
81
82    pub fn iter(
83        &'a self,
84        args_tokens: Option<Vec<Vec<(Token, &'a str)>>>
85    ) -> MacroTokenIterator<'a> {
86        if let Some(args_tokens) = args_tokens {
87            if let Some(arg_places) = &self.arg_places {
88                let args = Some(MacroArgs {
89                    args_tokens, arg_places
90                });
91
92                return MacroTokenIterator::new(&self.token_pairs, args)
93            }
94        }
95
96        MacroTokenIterator::new(&self.token_pairs, None)
97    }
98}
99
100#[derive(Debug, Clone)]
101pub struct MacroGroup(HashMap<String, HashMap<usize, Macro>>);
102
103impl<'a> MacroGroup {
104    pub fn new() -> Self {
105        MacroGroup(HashMap::new())
106    }
107
108    fn insert(&mut self, name: &str, body: String, args: Option<HashMap<&'a str, usize>>) {
109        let macro_map = self.0.entry(name.into()).or_insert(HashMap::new());
110        if let Some(some_args) = &args {
111            macro_map.insert(
112                some_args.len(),
113                Macro::new(body, args)
114            );
115        } else {
116            macro_map.insert(0, Macro::new(body, None));
117        };
118    }
119
120    pub fn get(&self, macro_name: &str, args_len: usize) -> Option<&Macro> {
121        let macro_data = guarded_unwrap!(self.0.get(macro_name), return None);
122
123        macro_data.get(&args_len)
124    }
125}
126
127
128