1use chrono::Local;
4use crate::{
5 json, Value,
6 block_parser::BlockInherit,
7 constants::*,
8 shared::Shared,
9 utils::*,
10};
11
12mod constants;
13mod parse_bif_allow;
14mod parse_bif_array;
15mod parse_bif_bool;
16mod parse_bif_cache;
17mod parse_bif_coalesce;
18mod parse_bif_code;
19mod parse_bif_contains;
20mod parse_bif_count;
21mod parse_bif_data;
22mod parse_bif_date;
23mod parse_bif_declare;
24mod parse_bif_defined;
25mod parse_bif_each;
26mod parse_bif_else;
27mod parse_bif_eval;
28mod parse_bif_exit;
29mod parse_bif_fetch;
30mod parse_bif_filled;
31mod parse_bif_flg;
32mod parse_bif_for;
33mod parse_bif_hash;
34mod parse_bif_include;
35mod parse_bif_join;
36mod parse_bif_lang;
37mod parse_bif_locale;
38mod parse_bif_moveto;
39mod parse_bif_neutral;
40mod parse_bif_param;
41mod parse_bif_rand;
42mod parse_bif_redirect;
43mod parse_bif_replace;
44mod parse_bif_same;
45mod parse_bif_snippet;
46mod parse_bif_sum;
47mod parse_bif_trans;
48mod parse_bif_unknown;
49mod parse_bif_var;
50mod parse_bif_obj;
51mod parse_bif_debug;
52
53mod exec_python;
54pub use exec_python::PythonExecutor;
55
56pub(crate) struct BifError {
57 pub(crate) msg: String,
58 pub(crate) file: String,
59 pub(crate) name: String,
60 pub(crate) src: String,
61}
62
63pub(crate) struct Bif<'a> {
64 pub(crate) raw: &'a str,
65 pub(crate) shared: &'a mut Shared,
66 pub(crate) inherit: &'a mut BlockInherit,
67 pub(crate) src: String,
68 pub(crate) name: String,
69 pub(crate) alias: String,
70 pub(crate) code: String,
71 pub(crate) params: String,
72 pub(crate) flags: String,
73 pub(crate) mod_filter: bool,
74 pub(crate) mod_negate: bool,
75 pub(crate) mod_upline: bool,
76 pub(crate) mod_scope: bool,
77 pub(crate) file_path: String,
78 pub(crate) dir: String,
79 pub(crate) out: String,
80 pub(crate) only: &'a str,
81 _none: &'a str,
82}
83
84impl<'a> Bif<'a> {
85 pub(crate) fn new(
86 raw_source: &'a str,
87 shared: &'a mut Shared,
88 inherit: &'a mut BlockInherit,
89 only: &'a str,
90 ) -> Self {
91 shared.bisf_count += 1;
92 let count = shared.bisf_count;
93 inherit.bif_count = shared.bisf_count;
94
95 if count > shared.bisf_max {
96 panic!(
97 "Infinite loop? {} bifs of {} max have been created.",
98 shared.bisf_max, count
99 );
100 }
101
102 Bif {
103 raw: raw_source, shared,
105 inherit,
106 src: String::new(),
107 name: String::new(),
108 alias: String::new(),
109 code: String::new(),
110 params: String::new(),
111 flags: String::new(),
112 mod_filter: false,
113 mod_negate: false,
114 mod_upline: false,
115 mod_scope: false,
116 file_path: String::new(),
117 dir: String::new(),
118 out: String::new(),
119 only,
120 _none: "",
121 }
122 }
123
124 pub(crate) fn parse(&mut self) -> String {
126 let bif = strip_prefix_suffix(self.raw, BIF_OPEN, BIF_CLOSE);
127 let result;
128
129 if let Some((name, src)) = bif.split_once(BIF_NAME) {
130 self.name = name.to_string();
131 self.src = src.trim().to_string();
132 } else {
133 if !self.only.is_empty() {
134 return self.raw.to_string();
135 }
136
137 let show_error = self.shared.schema["config"]["error"]["show"]
138 .as_bool()
139 .unwrap();
140 let error_line = format!("The delimiter was not found: {}", self.raw);
141 let error_line = error_line.replace(['\n', '\r'], " ");
142
143 if let Some(Value::Array(errors)) = self.shared.schema.get_mut("__error") {
144 errors.push(json!(error_line));
145 }
146
147 if show_error {
148 eprintln!("{}", error_line);
149 }
150
151 self.shared.has_error = true;
152
153 return EMPTY_STRING;
154 }
155
156 if !self.only.is_empty() && !self.name.contains(self.only) && !self.inherit.in_only {
157 return self.raw.to_string();
158 }
159
160 self.name = self.set_modifiers();
161 self.alias = self.name.clone();
162 self.inherit.in_only = true;
163
164 match &self.name[..] {
166 "" => result = self.parse_bif_var(),
167 "allow" => result = self.parse_bif_allow(),
168 "array" => result = self.parse_bif_array(),
169 "bool" => result = self.parse_bif_bool(),
170 "cache" => result = self.parse_bif_cache(),
171 "coalesce" => result = self.parse_bif_coalesce(),
172 "code" => result = self.parse_bif_code(),
173 "contains" => result = self.parse_bif_contains(),
174 "count" => result = self.parse_bif_count(),
175 "data" => result = self.parse_bif_data(),
176 "date" => result = self.parse_bif_date(),
177 "declare" => result = self.parse_bif_declare(),
178 "defined" => result = self.parse_bif_defined(),
179 "each" => result = self.parse_bif_each(),
180 "else" => result = self.parse_bif_else(),
181 "eval" => result = self.parse_bif_eval(),
182 "exit" => result = self.parse_bif_exit(),
183 "fetch" => result = self.parse_bif_fetch(),
184 "filled" => result = self.parse_bif_filled(),
185 "flg" => result = self.parse_bif_flg(),
186 "for" => result = self.parse_bif_for(),
187 "hash" => result = self.parse_bif_hash(),
188 "include" => result = self.parse_bif_include(),
189 "join" => result = self.parse_bif_join(),
190 "lang" => result = self.parse_bif_lang(),
191 "locale" => result = self.parse_bif_locale(),
192 "moveto" => result = self.parse_bif_moveto(),
193 "neutral" => result = self.parse_bif_neutral(),
194 "param" => result = self.parse_bif_param(),
195 "rand" => result = self.parse_bif_rand(),
196 "redirect" => result = self.parse_bif_redirect(),
197 "replace" => result = self.parse_bif_replace(),
198 "same" => result = self.parse_bif_same(),
199 "snippet" => result = self.parse_bif_snippet(),
200 "snip" => result = self.parse_bif_snippet(),
201 "sum" => result = self.parse_bif_sum(),
202 "trans" => result = self.parse_bif_trans(),
203 "obj" => result = self.parse_bif_obj(),
204 "debug" => result = self.parse_bif_debug(),
205 _ => result = self.parse_bif_unknown(),
206 }
207
208 match result {
209 Ok(()) => (),
210 Err(e) => {
211 let show_error = self.shared.schema["config"]["error"]["show"]
212 .as_bool()
213 .unwrap();
214
215 let datetime = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
216
217 let error_line = format!(
218 "[{}] Error ({}) {} file~: ({}) src: {}",
219 datetime,
220 e.name,
221 e.msg,
222 e.file,
223 e.src
224 );
225
226 let error_line = error_line.replace(['\n', '\r'], " ");
227
228 if let Some(Value::Array(errors)) = self.shared.schema.get_mut("__error") {
229 errors.push(json!(error_line));
230 }
231
232 if show_error {
233 eprintln!("{}", error_line);
234 }
235
236 self.shared.has_error = true;
237 }
238 }
239
240 self.inherit.last_bif_out = !self.out.is_empty();
241 self.inherit.last_coalesce_out = self.inherit.last_bif_out;
242
243 if self.mod_upline {
244 self.out = BACKSPACE.to_string() + &self.out;
245 self.out.trim().to_string()
246 } else {
247 self.out.trim().to_string()
248 }
249 }
250
251 pub(crate) fn set_modifiers(&mut self) -> String {
259 let mut index = 0;
260 while index < self.name.len() {
261 let start = &self.name[index..index + 1];
262 if start == BIF_MOD_FILTER
263 || start == BIF_MOD_NEGATE
264 || start == BIF_MOD_UPLINE
265 || start == BIF_MOD_SCOPE
266 {
267 match start {
268 BIF_MOD_FILTER => self.mod_filter = true,
269 BIF_MOD_NEGATE => self.mod_negate = true,
270 BIF_MOD_UPLINE => self.mod_upline = true,
271 BIF_MOD_SCOPE => self.mod_scope = true,
272 _ => unreachable!(),
273 }
274 index += 1;
275 } else {
276 break;
277 }
278 }
279
280 self.name[index..].to_string()
281 }
282
283 pub(crate) fn get_data(&self, name: &str) -> String {
295 if name.starts_with("local::") {
296 let local_name = name.strip_prefix("local::").unwrap_or(name);
297 get_from_key(
298 &self.shared.schema["__indir"][&self.inherit.indir]["data"],
299 local_name,
300 )
301 } else {
302 get_from_key(&self.shared.schema["data"], name)
303 }
304 }
305
306 pub(crate) fn set_data(&mut self, name: &str, value: &str) {
314 self.shared.schema["data"][name] = json!(value);
315 }
316
317 pub(crate) fn get_trans(&self, text: &str) -> String {
336 get_from_key(
337 &self.shared.schema["__indir"][&self.inherit.indir]["locale"]["trans"]
338 [&self.shared.lang],
339 text,
340 )
341 }
342
343 pub(crate) fn contains_allow(&self, source: &str) -> bool {
350 for allow in BIF_ALLOWED {
351 if source.contains(allow) {
352 return true;
353 }
354 }
355
356 let source = &remove_comments(source);
357 !(source.starts_with(BIF_VAR) && source.ends_with(BIF_CLOSE))
358 }
359
360 pub(crate) fn extract_params_code(&mut self, parse: bool) -> bool {
374 let position = get_code_position(&self.src);
375 let has_code: bool = position.is_some();
376
377 if has_code {
378 let code_pos = position.unwrap();
379 self.params = self.src[0..code_pos].trim().to_string();
380 self.code = self.src[code_pos + BIF_CODE.len()..].trim().to_string();
381 } else {
382 self.params = EMPTY_STRING;
383 self.code = self.src.trim().to_string();
384 }
385
386 if parse && self.params.contains(BIF_OPEN) {
387 self.shared.flags = EMPTY_STRING;
388 self.params = new_child_parse!(self, &self.params, false);
389 self.flags = self.shared.flags.clone();
390 }
391
392 has_code
393 }
394
395 pub(crate) fn extract_args(&mut self) -> Vec<String> {
406 let mut result: Vec<String> = Vec::new();
407
408 let delim;
409 if let Some(first_char) = self.params.chars().next() {
410 delim = first_char;
411 } else {
412 return vec!["".to_string()];
413 }
414
415 let mut parts = self.params.split(delim);
416
417 while let Some(ref mut part) = parts.next() {
418 let mut arg = part.to_string();
419
420 if arg.contains(BIF_OPEN) {
421 arg = new_child_parse!(self, &arg, false);
422 }
423
424 result.push(arg);
425 }
426
427 result
428 }
429
430 pub(crate) fn bif_error(&self, msg: &str) -> BifError {
431 BifError {
432 msg: msg.to_string(),
433 name: self.alias.clone(),
434 file: self.inherit.current_file.clone(),
435 src: self.raw.to_string(),
436 }
437 }
438
439}