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