neum_parse/
parse.rs

1use crate::file_error;
2use crate::lexer::Token;
3use regex::Regex;
4use std::collections::HashMap;
5use std::ops::Range;
6
7#[derive(Debug, Clone)]
8pub struct Name {
9    pub regex: Regex,
10    pub variables: Vec<String>,
11}
12
13pub fn parse(
14    tokens: Vec<(Token, Range<usize>)>,
15    file: String,
16    content: String,
17) -> Vec<(Name, Vec<Token>)> {
18    let mut list = Vec::new();
19    let mut token = tokens.iter();
20    while let Some(next) = token.next() {
21        match next.0 {
22            Token::String(_) => {
23                let mut name = vec![next.clone()];
24                let mut last = next;
25                for i in token.by_ref() {
26                    last = i;
27                    if i.0 != Token::ConvertTo {
28                        name.push(i.clone());
29                    } else {
30                        break;
31                    }
32                }
33
34                let mut variables: Vec<String> = Vec::new();
35                let mut regex = "^".to_string();
36                let mut name_iter = name.iter();
37                while let Some(i) = name_iter.next() {
38                    regex.push_str(
39                        match &i.0 {
40                            Token::ReplacementStart => {
41                                let next = name_iter.next().unwrap_or_else(|| {
42                                    file_error!(
43                                        file,
44                                        content.clone(),
45                                        i.1.end..i.1.end + 1,
46                                        "Unexpected end of file"
47                                    )
48                                });
49                                if let Token::String(x) = &next.0 {
50                                    if variables.contains(x) {
51                                        file_error!(
52                                            file,
53                                            content.clone(),
54                                            next.1,
55                                            "Cant have 2 varibales that have the same name"
56                                        )
57                                    }
58                                    variables.push(x.to_string());
59                                    let next_name = name_iter.next().unwrap_or_else(|| {
60                                        file_error!(
61                                            file,
62                                            content.clone(),
63                                            next.1.end..next.1.end + 1,
64                                            "Unexpected end of file"
65                                        )
66                                    });
67                                    if next_name.0 != Token::ReplacementEnd {
68                                        file_error!(
69                                            file,
70                                            content.clone(),
71                                            next_name.1,
72                                            "Unexpected token in name"
73                                        );
74                                    }
75                                } else if Token::ReplacementEnd == next.0 {
76                                    if variables.contains(&"".to_string()) {
77                                        file_error!(
78                                            file,
79                                            content.clone(),
80                                            next.1,
81                                            "Cant have 2 varibales that have the same name"
82                                        )
83                                    }
84                                    variables.push("".to_string())
85                                } else {
86                                    file_error!(
87                                        file,
88                                        content.clone(),
89                                        next.1,
90                                        "Unexpected token, expected a string"
91                                    )
92                                }
93
94                                "(.*)".to_string()
95                            }
96                            Token::Add => "+".to_string(),
97                            Token::Subtract => r"\-".to_string(),
98                            Token::Times => r"\*".to_string(),
99                            Token::Divide => "/".to_string(),
100                            Token::Number(x) => regex::escape(x.to_string().as_str()),
101                            Token::String(x) => regex::escape(x),
102                            _ => file_error!(file, content, i.1, "Unexpected token in name"),
103                        }
104                        .as_str(),
105                    );
106                }
107
108                regex.push('$');
109
110                let first = &token
111                    .next()
112                    .unwrap_or_else(|| {
113                        file_error!(
114                            file,
115                            content.clone(),
116                            last.1.end..last.1.end + 1,
117                            "Unexpected end of file"
118                        )
119                    })
120                    .0;
121                let mut convert_to = Vec::new();
122                let go_to = match first {
123                    Token::MultiEqualStart => Token::MultiEqualEnd,
124                    _ => {
125                        convert_to.push(first.clone());
126                        Token::NewLine
127                    }
128                };
129                let mut broke = false;
130                for i in token.by_ref() {
131                    last = i;
132                    if i.0 != go_to {
133                        if !matches!(
134                            i.0,
135                            Token::ReplacementStart
136                                | Token::ReplacementEnd
137                                | Token::Add
138                                | Token::Subtract
139                                | Token::Times
140                                | Token::Divide
141                                | Token::Number(_)
142                                | Token::String(_)
143                                | Token::SemiColon
144                                | Token::NewLine
145                        ) {
146                            file_error!(file, content, i.1, "Unexpected token in converts to");
147                        }
148                        convert_to.push(i.0.clone());
149                    } else {
150                        broke = true;
151                        break;
152                    }
153                }
154                if !broke {
155                    file_error!(
156                        file,
157                        content.clone(),
158                        last.1.end..last.1.end + 1,
159                        "Unexpected end of file"
160                    )
161                }
162                list.push((
163                    Name {
164                        regex: Regex::new(&regex)
165                            .expect("Internal error, could not make regex from input"),
166                        variables,
167                    },
168                    convert_to,
169                ));
170            }
171            _ => {
172                file_error!(file, content, next.1, "Unexpected Token");
173            }
174        }
175    }
176    list
177}
178
179pub fn converts(parsed: Vec<(Name, Vec<Token>)>, input: String) -> Option<String> {
180    for i in parsed {
181        if let Some(caps) = i.0.regex.captures(&input) {
182            let mut caps_iter = caps.iter();
183            caps_iter.next();
184            let mut variables = HashMap::new();
185            for x in i.0.variables {
186                variables.insert(
187                    x,
188                    caps_iter
189                        .next()
190                        .unwrap_or_else(|| {
191                            panic!("Internal Error\ninput: {input}\nregex: {:?}", i.0.regex)
192                        })
193                        .unwrap_or_else(|| {
194                            panic!("Internal Error\ninput: {input}\nregex: {}", i.0.regex)
195                        })
196                        .as_str()
197                        .to_string(),
198                );
199            }
200            let mut returns = String::new();
201            let mut returns_iter = i.1.iter();
202            while let Some(x) = returns_iter.next() {
203                returns.push_str(
204                    match x {
205                        Token::ReplacementStart => {
206                            let next = returns_iter
207                                .next()
208                                .expect("Should never happen but failed to get value");
209                            if next == &Token::ReplacementEnd {
210                                (*variables.get("").unwrap_or_else(|| {
211                                    panic!("Internal Error\nCould not find variable \"\" in {:?}",
212                                           i.1)
213                                })).clone().to_string()
214                            } else {
215                                let mut next_value = false;
216                                let value = match next {
217                                    Token::String(w) => (*variables.get(w).unwrap_or_else(|| {
218                                        panic!("Internal Error\nCould not find variable \"{}\" in {:?}", w, i.1)})).to_string().clone(),
219                                    Token::Number(n) => n.to_string(),
220                                    Token::Add => {
221                                        next_value = true;
222                                        (*variables.get("").unwrap_or_else(|| {
223                                            panic!("Internal Error\nCould not find variable \"\" in {:?}", i.1)})).to_string().clone()
224                                    },
225                                    Token::Subtract => {
226                                        next_value = true;
227                                        (*variables.get("").unwrap_or_else(|| {
228                                            panic!("Internal Error\nCould not find variable \"\" in {:?}", i.1)})).to_string().clone()
229                                    },
230                                    Token::Times => {
231                                        next_value = true;
232                                        (*variables.get("").unwrap_or_else(|| {
233                                            panic!("Internal Error\nCould not find variable \"\" in {:?}", i.1)})).to_string().clone()
234                                    },
235                                    Token::Divide => {
236                                        next_value = true;
237                                        (*variables.get("").unwrap_or_else(|| {
238                                            panic!("Internal Error\nCould not find variable \"\" in {:?}", i.1)})).to_string().clone()
239                                    },
240                                    _ => panic!("Internal Error\nDont know what {:?} is in {:?}", next, i.1),
241                                };
242                                if returns_iter.len() > 0 {
243                                    let mut int_value = value.parse::<f64>().unwrap_or_else(|_| {panic!("Internal Error\nCant do multipul things to a string, \"{}\", in {:?}", value, i.1)});
244                                    if next_value {
245                                        let next_value = match returns_iter
246                                            .next()
247                                            .expect("Internal Error\nCould nothing after a \"+\" \"-\" \"*\" \"/\"") {
248                                                Token::String(w) => variables.get(w).unwrap_or_else(|| {
249                                                    panic!("Internal Error\nCould not find variable \"{}\" in {:?}", w, i.1)})
250                                                    .parse::<f64>().unwrap_or_else(|_| {
251                                                    panic!("Internal Error\nCould not convert variable \"{}\" in {:?} to f64", w, i.1)}),
252                                                Token::Number(w) => *w,
253                                                _ => panic!("Internal Error\nCould not find out what char is requested for"),
254                                            };
255                                        match next {
256                                            Token::Add => int_value+=next_value,
257                                            Token::Subtract => int_value-=next_value,
258                                            Token::Times => int_value*=next_value,
259                                            Token::Divide => int_value/=next_value,
260                                            _ => panic!("Internal Error\nUsed a token not able to use in replacement"),
261                                        }
262                                    }
263                                    while let Some(y) = returns_iter.next() {
264                                        if y == &Token::ReplacementEnd {
265                                            break;
266                                        }
267                                        let next = match returns_iter
268                                            .next()
269                                            .expect("Internal Error\nCould nothing after a \"+\" \"-\" \"*\" \"/\"") {
270                                                Token::String(w) => variables.get(w).unwrap_or_else(|| {
271                                                    panic!("Internal Error\nCould not find variable \"{}\" in {:?}", w, i.1)})
272                                                    .parse::<f64>().unwrap_or_else(|_| {
273                                                    panic!("Internal Error\nCould not convert variable \"{}\" in {:?} to f64", w, i.1)}),
274                                                Token::Number(w) => *w,
275                                                _ => panic!("Internal Error\nCould not find out what char is requested for"),
276                                            };
277                                        match y {
278                                            Token::Add => int_value+=next,
279                                            Token::Subtract => int_value-=next,
280                                            Token::Times => int_value*=next,
281                                            Token::Divide => int_value/=next,
282                                            _ => panic!("Internal Error\nUsed a token not able to use in replacement"),
283                                        }
284                                    }
285                                    int_value.to_string()
286                                }
287                                else {
288                                    value
289                                }
290                            }
291                        }
292                        Token::Add => "+".to_string(),
293                        Token::Subtract => r"\-".to_string(),
294                        Token::Times => r"\*".to_string(),
295                        Token::Divide => "/".to_string(),
296                        Token::Number(x) => x.to_string(),
297                        Token::String(x) => x.clone(),
298                        Token::SemiColon => ";".to_string(),
299                        Token::NewLine => ";".to_string(),
300                        _ => "".to_string(),
301                    }
302                    .as_str(),
303                )
304            }
305            if !returns.ends_with(';') {
306                returns.push(';');
307            }
308            return Some(returns);
309        }
310    }
311    None
312}