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(®ex)
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}