neutralts/
lib.rs

1#![doc = include_str!("../README.md")]
2
3pub mod constants;
4mod default_json;
5pub mod doc;
6pub mod utils;
7
8use crate::constants::*;
9use crate::default_json::*;
10use crate::utils::*;
11
12use chrono::Utc;
13use md5::{Digest, Md5};
14use sha2::Sha256;
15use rand::Rng;
16use regex::Regex;
17use serde_json::json;
18use serde_json::Value;
19use std::env;
20use std::fs;
21use std::path::Path;
22use std::str;
23use std::time::Duration;
24use std::time::Instant;
25use std::time::{SystemTime, UNIX_EPOCH};
26use std::io::Write;
27use std::fs::File;
28
29//  Build-in function layout
30//
31//  .-------------------------------------------------------------> open bif
32//  | .-----------------------------------------------------------> modifier
33//  | |   .-------------------------------------------------------> bif name
34//  | |   |   .---------------------------------------------------> bif name separator
35//  | |   |   |      .--------------------------------------------> bif params
36//  | |   |   |      |       .------------------------------------> params / code separator
37//  | |   |   |      |       |             .----------------------> comment
38//  | |   |   |      |       |             |   .------------------> bif code
39//  | |   |   |      |       |             |   |               .--> close bif
40//  | |   |   |      |       |             |   |               |
41//  v v   v   v      v       v             |   v               v
42//  - - ----- - ------------ -- -----------v------------------ --
43//  {:!snippet; snippet_name >> <div>... {:* ... *:} ...</div> :}
44//  -------------------------------------------------------------
45//          ^  -----------------------------------------------
46//          |                      ^
47//          |                      |
48//          |                      ·------------------------------> bif src
49//          ·-----------------------------------------------------> bif: Build-in function
50
51//  Same level Bif:
52//
53//                  .-----> .-----> {:code;
54//                  |       |           {:code; ... :}
55//                  |       |           {:code; ... :}
56//                  |       |           {:code; ... :}
57//  Level block --> |       ·-----> :}
58//                  |        -----> {:code; ... :}
59//                  |       .-----> {:code;
60//                  |       |           {:code; ... :}
61//                  ·-----> ·-----> :}
62
63//  Flow
64//
65//      .-------------------------------.
66//      │         new Template          │
67//      ·-------------------------------·
68//                     |
69//                     v
70//      .-------------------------------.
71//      │       new BlockParser         │ <------.
72//      |-------------------------------|        |
73//      │      each same level bif      │        |
74//      ·-------------------------------·        |
75//                     |                         |
76//                     v                         |
77//      .-------------------------------.        |
78//      │           new Bif             │        |
79//      |-------------------------------|        |
80//      │         nested bifs? ---------│--------·
81//      ·-------------------------------·
82//                     |
83//                     v
84//          .----------------------.
85//         │       end render       │
86//          ·----------------------·
87
88// Inherit, macro: new_child_parse
89// -------------------------------
90// Inheritance is implemented with this macro. It is also used for the inheritance
91// of the application itself.
92//
93//
94// Block level scope example:
95//    {:code; <--------------------------.
96//        {:* block *:}                  |<---- Block
97//        {:param; name >> value :} <----|----- Set "name" for this block and its children
98//        {:param; name :} <-------------|----- "name" has the value "value".
99//        {:code;                        |
100//            {:* child block *:}        |
101//            {:param; name :} <---------|----- "name" has the value "value".
102//        :}                             |
103//    :} <-------------------------------·
104//    {:param; name :} <----------------------- outside block, no value or a previous value if any.
105//
106//
107// "include" has a block scope, then:
108//    {:code;
109//        {:* include for set "snippet-name" *:}
110//        {:include; snippet.ntpl :}
111//        {:snippet; snippet-name :} {:* Ok, "snippet-name" is set *:}
112//    :}
113//    {:snippet; snippet-name :} {:* Ko, "snippet-name" is not set *:}
114//
115// The modifier scope (+) adds the scope to the current level to make it possible to do this:
116//    {:+bool; something >>
117//        {:include; snippet.ntpl :}
118//    :}
119//    {:snippet; snippet-name :} {:* Ok, "snippet-name" is set *:}
120//
121#[macro_use]
122mod macros {
123    macro_rules! new_child_parse {
124        ($self:expr, $source:expr, $scope:expr) => {{
125            let mut child_inherit = $self.inherit.clone();
126            let shared = &mut $self.shared;
127
128            //  "bif.alias" is used and not "bif.name" because in "var" or "unprintable"
129            // its name is an empty string and could have more meanings.
130            child_inherit.alias = $self.alias.clone();
131
132            if !$self.file_path.is_empty() {
133                child_inherit.current_file = $self.file_path.clone();
134            }
135
136            if !$self.dir.is_empty() {
137                child_inherit.current_dir = $self.dir.clone();
138            }
139
140            // Create a new version of the schema if mod_scope
141            // This is necessary because indirections are used,
142            // and create_block_schema takes care of that.
143            if $scope {
144                $self.inherit.create_block_schema(shared);
145            }
146
147            let mut block = BlockParser::new(shared, &child_inherit);
148            let code = block.parse($source, $self.only);
149
150            // Update this block with the data generated in the child
151            if $scope {
152                // el código que estaba aquí lo he movido a la función
153                // update_indir para evitar un error de prestamo.
154                block.update_indir(&$self.inherit.indir);
155            }
156
157            code
158        }};
159    }
160}
161
162struct BifError {
163    msg: String,
164    name: String,
165    src: String,
166}
167
168// Global shared variables
169struct Shared {
170    schema: Value,
171    lang: String,
172    comments: String,
173    bisf_count: u64,
174    bisf_max: u64,
175    flags: String,
176    exit: bool,
177    has_error: bool,
178    status_code: String,
179    status_text: String,
180    status_param: String,
181    redirect_js: String,
182    filter_all: bool,
183    filter_bifs: bool,
184    cache_prefix: String,
185    cache_dir: String,
186    cache_on_post: bool,
187    cache_on_get: bool,
188    cache_on_cookies: bool,
189    cache_disable: bool,
190    disable_js: bool,
191    already_js: bool,
192    working_dir: String,
193}
194
195impl Shared {
196    fn new(schema: Value) -> Self {
197        let bisf_max = schema["config"]["infinite_loop_max_bifs"].as_u64().unwrap();
198        let comments = get_from_key(&schema["config"], "comments");
199        let lang = get_from_key(&schema["inherit"]["locale"], "current");
200        let filter_all = is_bool_key(&schema["config"], "filter_all");
201        let cache_prefix = get_from_key(&schema["config"], "cache_prefix");
202        let mut cache_dir = get_from_key(&schema["config"], "cache_dir");
203        let working_dir   = env::current_dir().unwrap().to_string_lossy().into_owned();
204        let cache_on_post= is_bool_key(&schema["config"], "cache_on_post");
205        let cache_on_get= is_bool_key(&schema["config"], "cache_on_get");
206        let cache_on_cookies= is_bool_key(&schema["config"], "cache_on_cookies");
207        let cache_disable= is_bool_key(&schema["config"], "cache_disable");
208        let disable_js= is_bool_key(&schema["config"], "disable_js");
209        let mut filter_bifs = false;
210
211        if !cache_disable {
212            filter_bifs = true;
213        }
214
215        if cache_dir.is_empty() {
216            cache_dir = env::temp_dir().to_string_lossy().into_owned();
217        }
218
219        Shared {
220            schema,
221            lang,
222            comments,
223            bisf_count: 0,
224            bisf_max,
225            flags: String::new(),
226            exit: false,
227            has_error: false,
228            status_code: "200".to_string(),
229            status_text: "OK".to_string(),
230            status_param: String::new(),
231            redirect_js: String::new(),
232            filter_all,
233            filter_bifs,
234            cache_prefix,
235            cache_dir,
236            cache_on_post,
237            cache_on_get,
238            cache_on_cookies,
239            cache_disable,
240            disable_js,
241            already_js: false,
242            working_dir,
243        }
244    }
245}
246
247struct BlockInherit {
248    indir: String,
249    last_bif_out: bool,
250    last_coalesce_out: bool,
251    block_count: u64, // u64 is default type in Value nums
252    bif_count: u64,   // u64 is default type in Value nums
253    alias: String,
254    current_file: String,
255    current_dir: String,
256    include_files: Vec<String>,
257    locale_files: Vec<String>,
258    data_files: Vec<String>,
259    in_cache: bool,
260    in_only: bool,
261}
262
263impl Clone for BlockInherit {
264    fn clone(&self) -> Self {
265        BlockInherit {
266            indir: self.indir.clone(),
267            last_bif_out: self.last_bif_out,
268            last_coalesce_out: self.last_coalesce_out,
269            block_count: self.block_count,
270            bif_count: self.bif_count,
271            alias: self.alias.clone(),
272            current_file: self.current_file.clone(),
273            current_dir: self.current_dir.clone(),
274            include_files: self.include_files.clone(),
275            locale_files: self.locale_files.clone(),
276            data_files: self.data_files.clone(),
277            in_cache: self.in_cache,
278            in_only: self.in_only,
279        }
280    }
281}
282
283impl BlockInherit {
284    fn new() -> Self {
285        BlockInherit {
286            indir: "block_0".to_string(),
287            last_bif_out: false,
288            last_coalesce_out: false,
289            block_count: 0,
290            bif_count: 0,
291            alias: String::new(),
292            current_file: String::new(),
293            current_dir: String::new(),
294            include_files: Vec::new(),
295            locale_files: Vec::new(),
296            data_files: Vec::new(),
297            in_cache: false,
298            in_only: false,
299        }
300    }
301
302    // Create version of data for inheritance at the block level.
303    // For performance reasons, instead of inheriting the complete cloned schema,
304    // we inherit a reference to the data in the root schema.
305    // Therefore, this function should be called before creating data
306    // that needs to be inherited to obtain the reference to the storage.
307    fn create_block_schema(&mut self, shared: &mut Shared) -> String {
308        let prev_id = self.indir.clone();
309        let block_id;
310
311        // If this function is called before creating the first block.
312        // It may be necessary to initialize values.
313        // The first block is not 0, is 1.
314        if self.block_count < 1 {
315            block_id = "block_1".to_string();
316        } else {
317            block_id = "block_".to_string() + self.block_count.to_string().as_str();
318        }
319
320        // It can be called several times from the same level, in which case
321        // it does not need to be cloned again.
322        if prev_id != block_id {
323            shared.schema["__indir"][&block_id] = shared.schema["__indir"][&prev_id].clone();
324        }
325
326        self.indir = block_id.clone();
327
328        block_id
329    }
330}
331
332pub struct Template<'a> {
333    raw: String,
334    file_path: &'a str,
335    schema: Value,
336    shared: Shared,
337    time_start: Instant,
338    time_elapsed: Duration,
339    out: String,
340}
341
342/// A struct representing a template that can be rendered.
343///
344/// This struct is used to handle the rendering of templates.
345impl<'a> Template<'a> {
346    /// Constructs a new `Template` instance with default settings.
347    ///
348    /// It allows you to set up a template and schema with different types.
349    pub fn new() -> Result<Self, String> {
350        let default_schema: Value = match serde_json::from_str(DEFAULT) {
351            Ok(value) => value,
352            Err(_) => return Err("const DEFAULT is not a valid JSON string".to_string()),
353        };
354        let shared = Shared::new(default_schema.clone());
355
356        Ok(Template {
357            raw: String::new(),
358            file_path: "",
359            schema: default_schema,
360            shared,
361            time_start: Instant::now(),
362            time_elapsed: Instant::now().elapsed(),
363            out: String::new(),
364        })
365    }
366
367    /// Constructs a new `Template` instance from a file path and a JSON schema.
368    ///
369    /// # Arguments
370    ///
371    /// * `file_path` - A reference to the path of the file containing the template content.
372    /// * `schema` - A JSON value representing the custom schema to be used with the template.
373    ///
374    /// # Returns
375    ///
376    /// A `Result` containing the new `Template` instance or an error message if:
377    /// - The file cannot be read.
378    pub fn from_file_value(file_path: &'a str, schema: Value) -> Result<Self, String> {
379        let raw: String = match fs::read_to_string(file_path) {
380            Ok(s) => s,
381            Err(e) => {
382                eprintln!("Cannot be read: {}", file_path);
383                return Err(e.to_string());
384            }
385        };
386        let mut default_schema: Value = match serde_json::from_str(DEFAULT) {
387            Ok(value) => value,
388            Err(_) => {
389                eprintln!("Internal error in const DEFAULT {}, line: {}", file!(), line!());
390                return Err("const DEFAULT is not a valid JSON string".to_string());
391            }
392        };
393
394        merge_schema(&mut default_schema, &schema);
395        let shared = Shared::new(default_schema.clone());
396
397        Ok(Template {
398            raw,
399            file_path,
400            schema: default_schema,
401            shared,
402            time_start: Instant::now(),
403            time_elapsed: Instant::now().elapsed(),
404            out: String::new(),
405        })
406    }
407
408    /// Sets the source path of the template.
409    ///
410    /// # Arguments
411    ///
412    /// * `file_path` - A reference to the path of the file containing the template content.
413    ///
414    /// # Returns
415    ///
416    /// A `Result` indicating success or an error message if the file cannot be read
417    pub fn set_src_path(&mut self, file_path: &'a str) -> Result<(), String> {
418        self.file_path = file_path;
419        self.raw = match fs::read_to_string(file_path) {
420            Ok(s) => s,
421            Err(e) => {
422                eprintln!("Cannot be read: {}", file_path);
423                return Err(e.to_string());
424            }
425        };
426
427        Ok(())
428    }
429
430    /// Sets the content of the template from a string.
431    ///
432    /// # Arguments
433    ///
434    /// * `source` - A reference to the new string content to be set as the raw content.
435    pub fn set_src_str(&mut self, source: &str) {
436        self.raw = source.to_string();
437    }
438
439    /// Merges the schema from a file with the current template schema.
440    ///
441    /// # Arguments
442    ///
443    /// * `schema_path` - A reference to the path of the file containing the schema content.
444    ///
445    /// # Returns
446    ///
447    /// A `Result` indicating success or an error message if:
448    /// - The file cannot be read.
449    /// - The file's content is not a valid JSON string.
450    pub fn merge_schema_path(&mut self, schema_path: &str) -> Result<(), String> {
451        let schema_str: String = match fs::read_to_string(schema_path) {
452            Ok(s) => s,
453            Err(e) => {
454                eprintln!("Cannot be read: {}", schema_path);
455                return Err(e.to_string());
456            }
457        };
458        let schema_value: Value = match serde_json::from_str(&schema_str) {
459            Ok(value) => value,
460            Err(_) => {
461                return Err("Is not a valid JSON file".to_string());
462            }
463        };
464        merge_schema(&mut self.schema, &schema_value);
465
466        Ok(())
467    }
468
469    /// Merges the schema from a JSON string with the current template schema.
470    ///
471    /// # Arguments
472    ///
473    /// * `schema` - A reference to the JSON string of the schema content.
474    ///
475    /// # Returns
476    ///
477    /// A `Result` indicating success or an error message if:
478    /// - The file's content is not a valid JSON string.
479    pub fn merge_schema_str(&mut self, schema: &str) -> Result<(), String> {
480        let schema_value: Value = match serde_json::from_str(schema) {
481            Ok(value) => value,
482            Err(_) => {
483                return Err("Is not a valid JSON string".to_string());
484            }
485        };
486        merge_schema(&mut self.schema, &schema_value);
487
488        Ok(())
489    }
490
491    /// Merges the provided JSON value with the current schema.
492    ///
493    /// # Arguments
494    ///
495    /// * `schema` - The JSON Value to be merged with the current schema.
496    pub fn merge_schema_value(&mut self, schema: Value) {
497        merge_schema(&mut self.schema, &schema);
498    }
499
500    /// Renders the template content.
501    ///
502    /// This function initializes the rendering process.
503    /// The resulting output is returned as a string.
504    ///
505    /// # Returns
506    ///
507    /// The rendered template content as a string.
508    pub fn render(&mut self) -> String {
509        let inherit = self.init_render();
510        self.out = BlockParser::new(&mut self.shared, &inherit).parse(&self.raw, "");
511
512        while self.out.contains("{:!cache;") {
513            let out;
514            out = BlockParser::new(&mut self.shared, &inherit).parse(&self.out, "!cache");
515            self.out = out;
516        }
517
518        self.ends_render();
519
520        self.out.clone()
521    }
522
523    // Restore vars for render
524    fn init_render(&mut self) -> BlockInherit {
525        self.time_start = Instant::now();
526        self.shared = Shared::new(self.schema.clone());
527
528        if self.shared.comments.contains("remove") {
529            self.raw = remove_comments(&self.raw);
530        }
531
532        // init inherit
533        let mut inherit = BlockInherit::new();
534        let indir = inherit.create_block_schema(&mut self.shared);
535        self.shared.schema["__moveto"] = json!({});
536        self.shared.schema["__error"] = json!([]);
537        self.shared.schema["__indir"] = json!({});
538        self.shared.schema["__indir"][&indir] = self.shared.schema["inherit"].clone();
539        inherit.current_file = self.file_path.to_string();
540
541        // Escape CONTEXT values
542        filter_value(&mut self.shared.schema["data"]["CONTEXT"]);
543
544        // Escape CONTEXT keys names
545        filter_value_keys(&mut self.shared.schema["data"]["CONTEXT"]);
546
547        if !self.file_path.is_empty() {
548            let path = Path::new(&self.file_path);
549
550            if let Some(parent) = path.parent() {
551                inherit.current_dir = parent.display().to_string();
552            }
553        } else {
554            inherit.current_dir = self.shared.working_dir.clone();
555        }
556
557        inherit
558    }
559
560    // Rendering ends
561    fn ends_render(&mut self) {
562        self.set_moveto();
563        self.replacements();
564        self.set_status_code();
565        self.time_elapsed = self.time_start.elapsed();
566    }
567
568    fn set_status_code(&mut self) {
569        let status_code = self.shared.status_code.as_str();
570
571        if ("400"..="599").contains(&status_code) {
572            self.out = format!("{} {}", self.shared.status_code, self.shared.status_text);
573
574            return;
575        }
576
577        if status_code == "301"
578            || status_code == "302"
579            || status_code == "303"
580            || status_code == "307"
581            || status_code == "308"
582        {
583            self.out = format!(
584                "{} {}\n{}",
585                self.shared.status_code, self.shared.status_text, self.shared.status_param
586            );
587
588            return;
589        }
590
591        if !self.shared.redirect_js.is_empty() {
592            self.out = self.shared.redirect_js.clone();
593        }
594    }
595
596    fn set_moveto(&mut self) {
597        if let Value::Object(data_map) = &self.shared.schema["__moveto"] {
598            for (_key, value) in data_map {
599                if let Value::Object(inner_map) = value {
600                    for (inner_key, inner_value) in inner_map {
601                        let mut tag;
602
603                        // although it should be "<tag" or "</tag" it also supports
604                        // "tag", "/tag", "<tag>" and "</tag>
605                        if !inner_key.starts_with("<") {
606                            tag = format!("<{}", inner_key);
607                        } else {
608                            tag = inner_key.to_string();
609                        }
610                        if tag.ends_with(">") {
611                            tag = tag[..tag.len() - 1].to_string();
612                        }
613
614                        // if it does not find it, it does nothing
615                        let position = find_tag_position(&self.out, &tag);
616                        if let Some(pos) = position {
617                            let mut insert = inner_value.as_str().unwrap().to_string();
618                            insert = insert.to_string();
619                            self.out.insert_str(pos, &insert);
620                        }
621                    }
622                }
623            }
624        }
625    }
626
627    fn replacements(&mut self) {
628        let pattern = format!(r"\s*{}", BACKSPACE);
629        let re = Regex::new(&pattern).expect("Failed to create regex with constant pattern");
630        self.out = re.replace_all(&self.out, "").to_string();
631
632        // UNPRINTABLE should be substituted after BACKSPACE
633        self.out = self.out.replace(UNPRINTABLE, "");
634    }
635
636    /// Retrieves the status code.
637    ///
638    /// The status code is "200" unless "exit", "redirect" is used or the
639    /// template contains a syntax error, which will return a status code
640    /// of "500". Although the codes are numeric, a string is returned.
641    ///
642    /// # Returns
643    ///
644    /// A reference to the status code as a string.
645    pub fn get_status_code(&self) -> &String {
646        &self.shared.status_code
647    }
648
649    /// Retrieves the status text.
650    ///
651    /// It will correspond to the one set by the HTTP protocol.
652    ///
653    /// # Returns
654    ///
655    /// A reference to the status text as a string.
656    pub fn get_status_text(&self) -> &String {
657        &self.shared.status_text
658    }
659
660    /// Retrieves the status parameter.
661    ///
662    /// Some statuses such as 301 (redirect) may contain additional data, such
663    /// as the destination URL, and in similar cases “param” will contain
664    /// that value.
665    ///
666    /// # Returns
667    ///
668    /// A reference to the status parameter as a string.
669    pub fn get_status_param(&self) -> &String {
670        &self.shared.status_param
671    }
672
673    /// Checks if there is an error.
674    ///
675    /// If any error has occurred, in the parse or otherwise, it will return true.
676    ///
677    /// # Returns
678    ///
679    /// A boolean indicating whether there is an error.
680    pub fn has_error(&self) -> bool {
681        self.shared.has_error
682    }
683
684    /// Get bifs errors list
685    ///
686    /// # Returns
687    ///
688    /// * `Value`: A clone of the value with the list of errors in the bifs during rendering.
689    pub fn get_error(&self) -> Value {
690        self.shared.schema["__error"].clone()
691    }
692
693    /// Retrieves the time duration for template rendering.
694    ///
695    /// # Returns
696    ///
697    /// The time duration elapsed .
698    pub fn get_time_duration(&self) -> Duration {
699        let duration: std::time::Duration = self.time_elapsed;
700
701        duration
702    }
703}
704
705struct BlockParser<'a> {
706    shared: &'a mut Shared,
707    inherit: BlockInherit,
708    _none: &'a str,
709}
710
711impl Drop for BlockParser<'_> {
712    fn drop(&mut self) {
713        // release memory
714        let block_id = "block_".to_string() + self.inherit.block_count.to_string().as_str();
715
716        // The first main block cannot be deleted
717        if block_id != "block_1" {
718            if block_id == self.inherit.indir && is_defined_key(&self.shared.schema["__indir"], &block_id) {
719                self.shared.schema["__indir"][&block_id] = json!({});
720            }
721        }
722    }
723}
724
725impl<'a> BlockParser<'a> {
726    fn new(shared: &'a mut Shared, inherit: &BlockInherit) -> Self {
727        let mut inherit = inherit.clone();
728        inherit.block_count += 1;
729
730        BlockParser {
731            shared,
732            inherit,
733            _none: "",
734        }
735    }
736
737    fn update_indir(&mut self, indir: &String) {
738        self.shared.schema["__indir"][indir] =
739            self.shared.schema["__indir"][&self.inherit.indir].clone();
740    }
741
742    fn parse(&mut self, raw_source: &'a str, only: &str) -> String {
743        let blocks;
744
745        match extract_blocks(raw_source) {
746            Ok(b) => {
747                blocks = b;
748            }
749            Err(p) => {
750                self.shared.status_code = "500".to_string();
751                self.shared.status_param = format!("Unmatched block at position {}", p);
752                eprintln!("Unmatched block at position {}", p);
753
754                if let Some(text) = STATUS_CODES.get(self.shared.status_code.as_str()) {
755                    self.shared.status_text = text.to_string();
756                } else {
757                    self.shared.status_text = EMPTY_STRING;
758                }
759
760                return EMPTY_STRING;
761            }
762        }
763
764        let mut prev_end = 0;
765        let mut out = String::new();
766        for (start, end) in blocks {
767            let is_comment = raw_source[start..end].starts_with(BIF_COMMENT_OPEN);
768            let is_short_circuit_coalesce =
769                self.inherit.last_coalesce_out && self.inherit.alias == "coalesce";
770
771            if self.shared.exit {
772                return out.clone();
773            }
774
775            if prev_end < start {
776                out += &raw_source[prev_end..start];
777            }
778
779            if !is_comment && !is_short_circuit_coalesce {
780                let mut bif =
781                    Bif::new(&raw_source[start..end], self.shared, &mut self.inherit, only);
782                out += &bif.parse();
783            }
784
785            prev_end = end;
786        }
787        out += &raw_source[prev_end..];
788
789        out.trim().to_string()
790    }
791}
792
793struct Bif<'a> {
794    raw: &'a str,
795    shared: &'a mut Shared,
796    inherit: &'a mut BlockInherit,
797    src: String,
798    name: String,
799    alias: String,
800    code: String,
801    params: String,
802    flags: String,
803    mod_filter: bool,
804    mod_negate: bool,
805    mod_upline: bool,
806    mod_scope: bool,
807    file_path: String,
808    dir: String,
809    out: String,
810    only: &'a str,
811    _none: &'a str,
812}
813
814impl<'a> Bif<'a> {
815    fn new(raw_source: &'a str, shared: &'a mut Shared, inherit: &'a mut BlockInherit, only: &'a str) -> Self {
816        shared.bisf_count += 1;
817        let count = shared.bisf_count;
818        inherit.bif_count = shared.bisf_count;
819
820        if count > shared.bisf_max {
821            panic!(
822                "Infinite loop? {} bifs of {} max have been created.",
823                shared.bisf_max, count
824            );
825        }
826
827        Bif {
828            raw: raw_source, // should not be modified
829            shared,
830            inherit,
831            src: String::new(),
832            name: String::new(),
833            alias: String::new(),
834            code: String::new(),
835            params: String::new(),
836            flags: String::new(),
837            mod_filter: false,
838            mod_negate: false,
839            mod_upline: false,
840            mod_scope: false,
841            file_path: String::new(),
842            dir: String::new(),
843            out: String::new(),
844            only,
845            _none: "",
846        }
847    }
848
849    // Divides the bif into its parts and executes the bif parse function.
850    fn parse(&mut self) -> String {
851        let bif = strip_prefix_suffix(self.raw, BIF_OPEN, BIF_CLOSE);
852        let result;
853
854        if let Some((name, src)) = bif.split_once(BIF_NAME) {
855            self.name = name.to_string();
856            self.src = src.trim().to_string();
857        } else {
858            if !self.only.is_empty() {
859                return self.raw.to_string();
860            }
861
862            let show_error = self.shared.schema["config"]["error"]["show"].as_bool().unwrap();
863            let error_line = format!("The delimiter was not found: {}", self.raw);
864            let error_line = error_line.replace(['\n', '\r'], " ");
865
866            if let Some(Value::Array(errors)) = self.shared.schema.get_mut("__error") {
867                errors.push(json!(error_line));
868            }
869
870            if show_error {
871                eprintln!("{}", error_line);
872            }
873
874            self.shared.has_error = true;
875
876            return EMPTY_STRING;
877        }
878
879        if !self.only.is_empty() && !self.name.contains(self.only) && !self.inherit.in_only {
880            return self.raw.to_string();
881        }
882
883        self.name = self.set_modifiers();
884        self.alias = self.name.clone();
885        self.inherit.in_only = true;
886
887        // exec the function of each bif
888        match &self.name[..] {
889            "" => result = self.parse_bif_var(),
890            "allow" => result = self.parse_bif_allow(),
891            "array" => result = self.parse_bif_array(),
892            "bool" => result = self.parse_bif_bool(),
893            "cache" => result = self.parse_bif_cache(),
894            "coalesce" => result = self.parse_bif_coalesce(),
895            "code" => result = self.parse_bif_code(),
896            "contains" => result = self.parse_bif_contains(),
897            "count" => result = self.parse_bif_count(),
898            "data" => result = self.parse_bif_data(),
899            "date" => result = self.parse_bif_date(),
900            "declare" => result = self.parse_bif_declare(),
901            "defined" => result = self.parse_bif_defined(),
902            "each" => result = self.parse_bif_each(),
903            "else" => result = self.parse_bif_else(),
904            "eval" => result = self.parse_bif_eval(),
905            "exit" => result = self.parse_bif_exit(),
906            "fetch" => result = self.parse_bif_fetch(),
907            "filled" => result = self.parse_bif_filled(),
908            "flg" => result = self.parse_bif_flg(),
909            "for" => result = self.parse_bif_for(),
910            "hash" => result = self.parse_bif_hash(),
911            "include" => result = self.parse_bif_include(),
912            "join" => result = self.parse_bif_join(),
913            "lang" => result = self.parse_bif_lang(),
914            "locale" => result = self.parse_bif_locale(),
915            "moveto" => result = self.parse_bif_moveto(),
916            "neutral" => result = self.parse_bif_neutral(),
917            "param" => result = self.parse_bif_param(),
918            "rand" => result = self.parse_bif_rand(),
919            "redirect" => result = self.parse_bif_redirect(),
920            "replace" => result = self.parse_bif_replace(),
921            "same" => result = self.parse_bif_same(),
922            "snippet" => result = self.parse_bif_snippet(),
923            "snip" => result = self.parse_bif_snippet(),
924            "trans" => result = self.parse_bif_trans(),
925            _ => result = self.parse_bif_unknown(),
926        }
927
928        match result {
929            Ok(()) => (),
930            Err(e) => {
931                let show_error = self.shared.schema["config"]["error"]["show"].as_bool().unwrap();
932                let error_line = format!("Error ({}) {} src: {}", e.name, e.msg, e.src);
933                let error_line = error_line.replace(['\n', '\r'], " ");
934
935                if let Some(Value::Array(errors)) = self.shared.schema.get_mut("__error") {
936                    errors.push(json!(error_line));
937                }
938
939                if show_error {
940                    eprintln!("{}", error_line);
941                }
942
943                self.shared.has_error = true;
944            }
945        }
946
947        self.inherit.last_bif_out = !self.out.is_empty();
948        self.inherit.last_coalesce_out = self.inherit.last_bif_out;
949
950        if self.mod_upline {
951            self.out = BACKSPACE.to_string() + &self.out;
952            self.out.trim().to_string()
953        } else {
954            self.out.trim().to_string()
955        }
956    }
957
958    //  Determines which modifiers are being used
959    //
960    //    .------ modifier
961    //    |
962    //    v
963    //  {:!snippet; ...
964    //
965    fn set_modifiers(&mut self) -> String {
966        let mut index = 0;
967        while index < self.name.len() {
968            let start = &self.name[index..index + 1];
969            if start == BIF_MOD_FILTER
970                || start == BIF_MOD_NEGATE
971                || start == BIF_MOD_UPLINE
972                || start == BIF_MOD_SCOPE
973            {
974                match start {
975                    BIF_MOD_FILTER => self.mod_filter = true,
976                    BIF_MOD_NEGATE => self.mod_negate = true,
977                    BIF_MOD_UPLINE => self.mod_upline = true,
978                    BIF_MOD_SCOPE => self.mod_scope = true,
979                    _ => unreachable!(),
980                }
981                index += 1;
982            } else {
983                break;
984            }
985        }
986
987        self.name[index..].to_string()
988    }
989
990    // Get key from schema data o local data
991    //
992    // {
993    //     "config": {},
994    //     "inherit": {},
995    //     "data": {}  <------------ schema data get from
996    //     "__indir": {
997    //          "X": {
998    //             "data": {} <----- local data get from
999    //     ...
1000    // }
1001    fn get_data(&self, name: &str) -> String {
1002        if name.starts_with("local::") {
1003            let local_name = name.strip_prefix("local::").unwrap_or(name);
1004            get_from_key(
1005                &self.shared.schema["__indir"][&self.inherit.indir]["data"],
1006                local_name,
1007            )
1008        } else {
1009            get_from_key(&self.shared.schema["data"], name)
1010        }
1011    }
1012
1013    // Set key to schema data
1014    //
1015    // {
1016    //     "config": {},
1017    //     "inherit": {},
1018    //     "data": {}  <-------- set to
1019    // }
1020    fn set_data(&mut self, name: &str, value: &str) {
1021        self.shared.schema["data"][name] = json!(value);
1022    }
1023
1024    // Get key from schema locale, an indirection is used instead of its initial position
1025    // {
1026    //     "config": {},
1027    //     "inherit": {
1028    //     "locale": { ------------------.
1029    //        "current": "en",           |
1030    //        "trans": {                 |
1031    //           "es": {}                |
1032    //         }                         | moved on init Template
1033    //     },                            |
1034    //     "data": {},                   |
1035    //     "__indir": {                  |
1036    //          "X": {                   |
1037    //             "locale": { <---------·
1038    //                 "trans": {
1039    //                     "es": {} <----- get from
1040    //     ...
1041    // }
1042    fn get_trans(&self, text: &str) -> String {
1043        get_from_key(
1044            &self.shared.schema["__indir"][&self.inherit.indir]["locale"]["trans"]
1045                [&self.shared.lang],
1046            text,
1047        )
1048    }
1049
1050    /*
1051        dynamic evaluation
1052
1053        This is not allowed: {:;{:;refvarname:}:}
1054        Use instead: {:; {:allow; allowed >> {:;refvarname:} :} :}
1055    */
1056    fn contains_allow(&self, source: &str) -> bool {
1057        for allow in BIF_ALLOWED {
1058            if source.contains(allow) {
1059                return true;
1060            }
1061        }
1062
1063        let source = &remove_comments(source);
1064        !(source.starts_with(BIF_VAR) && source.ends_with(BIF_CLOSE))
1065    }
1066
1067    // Split params/code and parse params if parse is true.
1068    // It is possible that it has no parameters, in which case
1069    // it is all code and the parameters are an empty string.
1070    // To set flags, parameters are required.
1071    //
1072    //                   .------------------------------> params
1073    //                   |       .----------------------> separator
1074    //                   |       |
1075    //                   |       |                 .----> code
1076    //                   |       |                 |
1077    //                   v       v                 v
1078    //              ------------ -- ------------------------------
1079    //  {:!snippet; snippet_name >> <div>... {:* ... *:} ...</div> :}
1080    fn extract_params_code(&mut self, parse: bool) -> bool {
1081        let position = get_code_position(&self.src);
1082        let has_code: bool = position.is_some();
1083
1084        if has_code {
1085            let code_pos = position.unwrap();
1086            self.params = self.src[0..code_pos].trim().to_string();
1087            self.code = self.src[code_pos + BIF_CODE.len()..].trim().to_string();
1088        } else {
1089            self.params = EMPTY_STRING;
1090            self.code = self.src.trim().to_string();
1091        }
1092
1093        if parse && self.params.contains(BIF_OPEN) {
1094            self.shared.flags = EMPTY_STRING;
1095            self.params = new_child_parse!(self, &self.params, false);
1096            self.flags = self.shared.flags.clone();
1097        }
1098
1099        has_code
1100    }
1101
1102    fn extract_args(&mut self) -> Vec<String> {
1103        let mut result: Vec<String> = Vec::new();
1104
1105        let delim;
1106        if let Some(first_char) = self.params.chars().next() {
1107            delim = first_char;
1108        } else {
1109            return vec!["".to_string()];
1110        }
1111
1112        let mut parts = self.params.split(delim);
1113
1114        while let Some(ref mut part) = parts.next() {
1115            let mut arg = part.to_string();
1116
1117            if arg.contains(BIF_OPEN) {
1118                arg = new_child_parse!(self, &arg, false);
1119            }
1120
1121            result.push(arg);
1122        }
1123
1124        result
1125    }
1126
1127    /*
1128        unknown bif
1129    */
1130    fn parse_bif_unknown(&mut self) -> Result<(), BifError> {
1131        self.alias = "unknown".to_string();
1132
1133        Err(BifError {
1134            msg: "unknown bif".to_string(),
1135            name: self.alias.clone(),
1136            src: self.raw.to_string(),
1137        })
1138    }
1139
1140    /*
1141        {:;varname:}
1142        {:;:}
1143    */
1144    fn parse_bif_var(&mut self) -> Result<(), BifError> {
1145        if self.mod_scope {
1146            return Err(BifError {
1147                msg: "modifier not allowed".to_string(),
1148                name: self.alias.clone(),
1149                src: self.raw.to_string(),
1150            });
1151        }
1152
1153        // Unprintable: {:;:} / {:; :}
1154        if self.src.is_empty() {
1155            // "bif.alias" is used and not "bif.name" because in "var" or "unprintable"
1156            // its name is an empty string.
1157            self.alias = "unprintable".to_string();
1158
1159            self.out = UNPRINTABLE.to_string();
1160
1161            return Ok(());
1162        }
1163
1164        // Var: {:;varname:}
1165        self.alias = "var".to_string();
1166        let var_name;
1167
1168        // For security requires {:allow; in some cases.
1169        if self.src.contains(BIF_OPEN) {
1170            if !self.contains_allow(&self.src) {
1171                self.out = EMPTY_STRING;
1172
1173                return Err(BifError {
1174                    msg: "insecure varname".to_string(),
1175                    name: self.alias.clone(),
1176                    src: self.src.clone(),
1177                });
1178            }
1179
1180            var_name = new_child_parse!(self, &self.src, self.mod_scope);
1181        } else {
1182            var_name = self.src.clone();
1183        }
1184
1185        self.out = self.get_data(&var_name).to_string();
1186
1187        if (self.mod_filter || self.shared.filter_all) && !self.mod_negate {
1188            if !var_name.starts_with("CONTEXT->") {
1189                // unescape_chars for prevent double encoding
1190                self.out = unescape_chars(&self.get_data(&var_name), true).to_string();
1191                self.out = escape_chars(&self.out, true).to_string();
1192            }
1193        } else {
1194            if self.shared.filter_bifs {
1195                // Avoid reevaluation in cache
1196                self.out = self.out.replace(BIF_OPEN, BIF_SANITIZE_OPEN);
1197                self.out = self.out.replace(BIF_CLOSE, BIF_SANITIZE_CLOSE);
1198            }
1199        }
1200
1201        if self.mod_negate && !self.shared.filter_bifs && var_name.starts_with("CONTEXT->") {
1202            self.out = unescape_chars(&self.out, true).to_string();
1203        }
1204
1205        Ok(())
1206    }
1207
1208    /*
1209        {:allow; {:flg; partial casein replace :} name >> ... :}
1210    */
1211    fn parse_bif_allow(&mut self) -> Result<(), BifError> {
1212        if self.mod_filter || self.mod_scope {
1213            return Err(BifError {
1214                msg: "modifier not allowed".to_string(),
1215                name: self.alias.clone(),
1216                src: self.raw.to_string(),
1217            });
1218        }
1219
1220        self.extract_params_code(true);
1221        let mut found = String::new();
1222        let words_string = get_from_key(
1223            &self.shared.schema["__indir"][&self.inherit.indir]["declare"],
1224            &self.params,
1225        );
1226
1227        if words_string.is_empty() {
1228            return Err(BifError {
1229                msg: self.params.clone() + " declared is empty",
1230                name: self.alias.clone(),
1231                src: self.raw.to_string(),
1232            });
1233        }
1234
1235        let mut words_list: Vec<&str> = words_string.split_whitespace().collect();
1236        self.code = new_child_parse!(self, &self.code, self.mod_scope);
1237
1238        for word in &mut words_list {
1239            let lower_haystack;
1240            let mut haystack = &self.code;
1241            let mut pattern = word.to_string().clone();
1242
1243            if self.flags.contains("|partial|") || self.flags.contains("|replace|") {
1244                pattern = format!("{}{}{}", "*", pattern, "*");
1245            }
1246
1247            if self.flags.contains("|casein|") {
1248                pattern = pattern.to_lowercase();
1249                lower_haystack = self.code.clone().to_lowercase();
1250                haystack = &lower_haystack;
1251            }
1252
1253            if wildcard_match(haystack, &pattern) {
1254                found = word.to_string();
1255                break;
1256            }
1257        }
1258
1259        if !found.is_empty() ^ self.mod_negate {
1260            if self.flags.contains("|replace|") {
1261                found = found.replace("~", "");
1262                found = found.replace("*", "");
1263                found = found.replace("?", "");
1264                found = found.replace(".", "");
1265                self.out = found.to_string();
1266            } else {
1267                self.out = self.code.to_string();
1268            }
1269        } else {
1270            self.out = EMPTY_STRING;
1271        }
1272
1273        Ok(())
1274    }
1275
1276    /*
1277        {:array; varname >> ... :}
1278    */
1279    fn parse_bif_array(&mut self) -> Result<(), BifError> {
1280        if self.mod_filter {
1281            return Err(BifError {
1282                msg: "modifier not allowed".to_string(),
1283                name: self.alias.clone(),
1284                src: self.raw.to_string(),
1285            });
1286        }
1287
1288        self.extract_params_code(true);
1289
1290        let mut varname = self.params.as_str();
1291        let mut schema = &self.shared.schema["data"];
1292
1293        if varname.starts_with("local::") {
1294            schema = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
1295            varname = varname.strip_prefix("local::").unwrap_or(varname);
1296        }
1297
1298        if is_array_key(schema, varname) ^ self.mod_negate {
1299            if self.code.contains(BIF_OPEN) {
1300                self.code = new_child_parse!(self, &self.code, self.mod_scope);
1301            }
1302            self.out = self.code.to_string();
1303        }
1304
1305        Ok(())
1306    }
1307
1308    /*
1309        {:bool; varname >> ... :}
1310    */
1311    fn parse_bif_bool(&mut self) -> Result<(), BifError> {
1312        if self.mod_filter {
1313            return Err(BifError {
1314                msg: "modifier not allowed".to_string(),
1315                name: self.alias.clone(),
1316                src: self.raw.to_string(),
1317            });
1318        }
1319
1320        self.extract_params_code(true);
1321
1322        let mut varname = self.params.as_str();
1323        let mut schema = &self.shared.schema["data"];
1324
1325        if varname.starts_with("local::") {
1326            schema = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
1327            varname = varname.strip_prefix("local::").unwrap_or(varname);
1328        }
1329
1330        if is_bool_key(schema, varname) ^ self.mod_negate {
1331            if self.code.contains(BIF_OPEN) {
1332                self.code = new_child_parse!(self, &self.code, self.mod_scope);
1333            }
1334            self.out = self.code.to_string();
1335        }
1336
1337        Ok(())
1338    }
1339
1340    /*
1341        {:cache; /expires/id/only_custom_id/ >> ... :} {:* expires in seconds *:}
1342        {:cache; /expires/id/ >> ... :}
1343        {:cache; /expires/ >> ... :}
1344        {:!cache; ... :}
1345    */
1346    fn parse_bif_cache(&mut self) -> Result<(), BifError> {
1347        if self.mod_filter || self.mod_scope {
1348            return Err(BifError {
1349                msg: "modifier not allowed".to_string(),
1350                name: self.alias.clone(),
1351                src: self.raw.to_string(),
1352            });
1353        }
1354
1355        self.extract_params_code(false);
1356
1357        if self.mod_negate {
1358            if self.inherit.in_cache {
1359                self.out = self.raw.to_string();
1360            } else {
1361                // If it is not in a cache block, it is now resolved.
1362                self.out = new_child_parse!(self, &self.code, self.mod_scope);
1363            }
1364            return Ok(());
1365        }
1366
1367        let restore_in_cache = self.inherit.in_cache;
1368        let context = &self.shared.schema["data"]["CONTEXT"];
1369        let has_post = !is_empty_key(context, "POST");
1370        let has_get = !is_empty_key(context, "GET");
1371        let has_cookies = !is_empty_key(context, "COOKIES");
1372
1373        if self.shared.cache_disable || (has_post && !self.shared.cache_on_post) || (has_get && !self.shared.cache_on_get) || (has_cookies && !self.shared.cache_on_cookies) {
1374            if self.code.contains(BIF_OPEN) {
1375                self.code = new_child_parse!(self, &self.code, self.mod_scope);
1376            }
1377            self.out = self.code.clone();
1378            return Ok(());
1379        }
1380
1381        self.inherit.in_cache = true;
1382        let args = self.extract_args();
1383        self.inherit.in_cache = restore_in_cache;
1384
1385        // require expires
1386        let expires = args.get(1)
1387            .cloned()
1388            .ok_or_else(|| {
1389                BifError {
1390                    msg: "arguments 'expires' not found".to_string(),
1391                    name: self.alias.clone(),
1392                    src: self.raw.to_string(),
1393                }
1394            })?;
1395
1396        // optional id
1397        let mut id = args.get(2).cloned().unwrap_or("".to_string());
1398
1399        // optional only_custom_id
1400        let only_custom_id: bool = match args.get(3) {
1401            Some(value) => !matches!(value.as_str(), "false" | "0" | ""),
1402            None => false,
1403        };
1404
1405        if !only_custom_id {
1406            id.push_str(&self.shared.lang);
1407            id.push_str(&expires);
1408            if has_post {
1409                id.push_str(&serde_json::to_string(&self.shared.schema["data"]["CONTEXT"]["POST"]).unwrap());
1410            }
1411            if has_get {
1412                id.push_str(&serde_json::to_string(&self.shared.schema["data"]["CONTEXT"]["GET"]).unwrap());
1413            }
1414            if has_cookies {
1415                id.push_str(&serde_json::to_string(&self.shared.schema["data"]["CONTEXT"]["COOKIES"]).unwrap());
1416            }
1417            id.push_str(&self.get_data("CONTEXT->HOST"));
1418            id.push_str(&self.get_data("CONTEXT->ROUTE"));
1419            id.push_str(&self.code);
1420        }
1421
1422        let mut hasher = Sha256::new();
1423        hasher.update(id.clone());
1424        let cache_id = format!("{:x}", hasher.finalize());
1425        let cache_dir = self.get_cache_dir(&cache_id);
1426        let file = format!("{}/{}-{}", cache_dir, &cache_id, expires);
1427        let file_path = Path::new(&file);
1428
1429        if file_path.exists() && !self.cache_file_expires(file_path, expires.parse::<u64>().unwrap_or(0)) {
1430            if let Ok(content) = fs::read_to_string(file_path) {
1431                self.out = content;
1432            } else {
1433
1434                // The output is created even if there is an error
1435                if self.code.contains(BIF_OPEN) {
1436                    self.inherit.in_cache = true;
1437                    self.out = new_child_parse!(self, &self.code, self.mod_scope);
1438                    self.inherit.in_cache = restore_in_cache;
1439                }
1440                return Err(BifError {
1441                    msg: format!("Failed to read cache {}", file_path.display()),
1442                    name: self.alias.clone(),
1443                    src: self.raw.to_string(),
1444                })
1445            }
1446        } else {
1447            if self.code.contains(BIF_OPEN) {
1448                self.inherit.in_cache = true;
1449                self.code = new_child_parse!(self, &self.code, self.mod_scope);
1450                self.inherit.in_cache = restore_in_cache;
1451            }
1452
1453            // The output is created even if there is an error
1454            self.out = self.code.clone();
1455
1456            // Create cache dir
1457            self.set_cache_dir(&cache_dir)?;
1458
1459            // Write in cache
1460            match File::create(&file_path) {
1461                Ok(mut file) => {
1462                    if let Err(e) = file.write_all(&self.code.as_bytes()) {
1463                        return Err(BifError {
1464                            msg: format!("Failed to write to cache {}: {}", file_path.display(), e.to_string()),
1465                            name: self.alias.clone(),
1466                            src: self.raw.to_string(),
1467                        })
1468                    }
1469                },
1470                Err(e) => {
1471                    return Err(BifError {
1472                        msg: format!("Failed to create file {}: {}", file_path.display(), e.to_string()),
1473                        name: self.alias.clone(),
1474                        src: self.raw.to_string(),
1475                    })
1476                }
1477            }
1478        }
1479
1480        Ok(())
1481    }
1482
1483    fn cache_file_expires(&self, file_path: &Path, expires: u64) -> bool {
1484        let now: u64 = SystemTime::now()
1485            .duration_since(UNIX_EPOCH)
1486            .unwrap()
1487            .as_secs();
1488
1489        let metadata = match fs::metadata(file_path) {
1490            Ok(meta) => meta,
1491            Err(_) => return true,
1492        };
1493
1494        let modified_time = match metadata.modified() {
1495            Ok(time) => time,
1496            Err(_) => return true,
1497        };
1498
1499        let duration_since_epoch = match modified_time.duration_since(UNIX_EPOCH) {
1500            Ok(duration) => duration,
1501            Err(_) => return true,
1502        };
1503
1504        let file_modified_time = duration_since_epoch.as_secs();
1505        let expiration_time = file_modified_time + expires;
1506
1507        if now > expiration_time {
1508            return true
1509        }
1510
1511        false
1512    }
1513
1514    fn set_cache_dir(&self, cache_dir: &str) -> Result<(), BifError> {
1515        let cache_dir_levels = Path::new(&cache_dir);
1516
1517        match fs::create_dir_all(cache_dir_levels) {
1518            Ok(_) => Ok(()),
1519            Err(e) => {
1520                return Err(BifError {
1521                    msg: format!("Failed to create cache directory {}: {}", cache_dir, e.to_string()),
1522                    name: self.alias.clone(),
1523                    src: self.raw.to_string(),
1524                })
1525            }
1526        }
1527    }
1528
1529    fn get_cache_dir(&self, file: &str) -> String {
1530        let mut cache_dir = self.shared.cache_dir.clone();
1531
1532        if !self.shared.cache_prefix.is_empty() {
1533            cache_dir.push_str("/");
1534            cache_dir.push_str(&self.shared.cache_prefix);
1535        }
1536
1537        cache_dir.push_str("/");
1538        cache_dir.push_str(&file[0..3]);
1539
1540        cache_dir.to_string()
1541    }
1542
1543    /*
1544       {:coalesce;
1545           {:code;  :}
1546           {:code; this is output :}
1547           {:code; ... :}
1548       :}
1549    */
1550    fn parse_bif_coalesce(&mut self) -> Result<(), BifError> {
1551        if self.mod_filter || self.mod_negate {
1552            return Err(BifError {
1553                msg: "modifier not allowed".to_string(),
1554                name: self.alias.clone(),
1555                src: self.raw.to_string(),
1556            });
1557        }
1558
1559        // This var so as not to overwrite the original: inherit.last_bif_out
1560        self.inherit.last_coalesce_out = false;
1561        self.out = new_child_parse!(self, &self.src, self.mod_scope);
1562
1563        Ok(())
1564    }
1565
1566    /*
1567        {:code; ...  :}
1568        {:code; {:flags; safe noparse encode_tags encode_tags_after encode_bifs :} >>  <div>...</div>  :}
1569    */
1570    fn parse_bif_code(&mut self) -> Result<(), BifError> {
1571        if self.mod_filter || self.mod_negate {
1572            return Err(BifError {
1573                msg: "modifier not allowed".to_string(),
1574                name: self.alias.clone(),
1575                src: self.raw.to_string(),
1576            });
1577        }
1578
1579        self.extract_params_code(true);
1580
1581        if self.flags.contains("|safe|") {
1582            self.code = escape_chars(&unescape_chars(&self.code, false), false).to_string();
1583            self.code = self.code.replace(BIF_OPEN, BIF_SANITIZE_OPEN);
1584            self.code = self.code.replace(BIF_CLOSE, BIF_SANITIZE_CLOSE);
1585        } else {
1586            if self.flags.contains("|encode_tags|") {
1587                self.code = escape_chars(&unescape_chars(&self.code, false), false).to_string();
1588            }
1589
1590            if self.flags.contains("|encode_bifs|") {
1591                self.code = self.code.replace(BIF_OPEN, BIF_SANITIZE_OPEN);
1592                self.code = self.code.replace(BIF_CLOSE, BIF_SANITIZE_CLOSE);
1593            }
1594
1595            if !self.flags.contains("|noparse|") && self.code.contains(BIF_OPEN) {
1596                self.code = new_child_parse!(self, &self.code, self.mod_scope);
1597            }
1598        }
1599
1600        if self.flags.contains("|encode_tags_after|") {
1601            self.code = escape_chars(&unescape_chars(&self.code, false), false).to_string();
1602        }
1603
1604        self.out = self.code.to_string();
1605
1606        Ok(())
1607    }
1608
1609    /*
1610        {:contains; /haystack/needle/ >> ... :}
1611    */
1612    fn parse_bif_contains(&mut self) -> Result<(), BifError> {
1613        if self.mod_filter {
1614            return Err(BifError {
1615                msg: "modifier not allowed".to_string(),
1616                name: self.alias.clone(),
1617                src: self.raw.to_string(),
1618            });
1619        }
1620
1621        self.extract_params_code(false);
1622        let args = self.extract_args();
1623
1624        let haystack = args.get(1)
1625            .cloned()
1626            .ok_or_else(|| {
1627                BifError {
1628                    msg: "arguments not found".to_string(),
1629                    name: self.alias.clone(),
1630                    src: self.raw.to_string(),
1631                }
1632            })?;
1633
1634        let needle = args.get(2)
1635            .cloned()
1636            .ok_or_else(|| {
1637                BifError {
1638                    msg: "arguments not found".to_string(),
1639                    name: self.alias.clone(),
1640                    src: self.raw.to_string(),
1641                }
1642            })?;
1643
1644        if haystack.contains(&needle) ^ self.mod_negate  {
1645            if self.code.contains(BIF_OPEN) {
1646                self.code = new_child_parse!(self, &self.code, self.mod_scope);
1647            }
1648            self.out = self.code.to_string();
1649        } else {
1650            self.out = EMPTY_STRING;
1651        }
1652
1653        Ok(())
1654    }
1655
1656    /*
1657        {:count; name >> 0 :}
1658        {:count; name :}
1659    */
1660    fn parse_bif_count(&mut self) -> Result<(), BifError> {
1661        if self.mod_filter || self.mod_negate || self.mod_scope {
1662            return Err(BifError {
1663                msg: "modifier not allowed".to_string(),
1664                name: self.alias.clone(),
1665                src: self.raw.to_string(),
1666            });
1667        }
1668
1669        let is_set = self.extract_params_code(true);
1670
1671        if self.code.contains(BIF_OPEN) {
1672            self.code = new_child_parse!(self, &self.code, self.mod_scope);
1673        }
1674
1675        if is_set {
1676            let count_name = self.params.clone();
1677            let count_value = match self.code.parse::<i32>() {
1678                Ok(num) => num,
1679                Err(_) => {
1680                    return Err(BifError {
1681                        msg: "argument is not a number".to_string(),
1682                        name: self.alias.clone(),
1683                        src: self.raw.to_string(),
1684                    });
1685                }
1686            };
1687
1688            self.set_data(&count_name, &count_value.to_string());
1689            self.out = EMPTY_STRING;
1690        } else {
1691            let count_name = self.code.clone();
1692            let count_value = match self.get_data(&count_name).parse::<i32>() {
1693                Ok(num) => num,
1694                Err(_) => {
1695                    return Err(BifError {
1696                        msg: "argument is not a number".to_string(),
1697                        name: self.alias.clone(),
1698                        src: self.raw.to_string(),
1699                    });
1700                }
1701            };
1702            let new_value = count_value + 1;
1703
1704            self.set_data(&count_name, &new_value.to_string());
1705            self.out = count_value.to_string();
1706        }
1707
1708        Ok(())
1709    }
1710
1711    /*
1712        {:data; file-path :} {:* local data *}
1713    */
1714    fn parse_bif_data(&mut self) -> Result<(), BifError> {
1715        if self.mod_filter || self.mod_scope {
1716            return Err(BifError {
1717                msg: "modifier not allowed".to_string(),
1718                name: self.alias.clone(),
1719                src: self.raw.to_string(),
1720            });
1721        }
1722
1723        self.extract_params_code(true);
1724
1725        if self.flags.contains("|inline|") {
1726            let data: Value = match serde_json::from_str(&self.code) {
1727                Ok(value) => value,
1728                Err(_) => {
1729                    return Err(BifError {
1730                        msg: "not a valid JSON file".to_string(),
1731                        name: self.alias.clone(),
1732                        src: self.raw.to_string(),
1733                    })
1734                }
1735            };
1736
1737            let indir = &self.inherit.create_block_schema(self.shared);
1738
1739            // Merge new locale data in curren local data.
1740            merge_schema(
1741                &mut self.shared.schema["__indir"][indir]["data"],
1742                &data["data"],
1743            );
1744
1745            self.out = UNPRINTABLE.to_string();
1746
1747            return Ok(());
1748        }
1749
1750        self.file_path = self.code.clone();
1751
1752        // For security requires {:allow;
1753        if self.file_path.contains(BIF_OPEN) {
1754            if !self.contains_allow(&self.file_path) {
1755                return Err(BifError {
1756                    msg: "insecure file name".to_string(),
1757                    name: self.alias.clone(),
1758                    src: self.raw.to_string(),
1759                });
1760            }
1761            self.file_path = new_child_parse!(self, &self.code, false);
1762        }
1763
1764        if self.file_path.starts_with("#") {
1765            self.file_path.remove(0);
1766            self.file_path = format!("{}{}", self.inherit.current_dir, self.file_path);
1767        }
1768
1769        let path = Path::new(&self.file_path);
1770        if !Path::new(path).exists() {
1771            if self.flags.contains("|require|") {
1772                return Err(BifError {
1773                    msg: "file not found".to_string(),
1774                    name: self.alias.clone(),
1775                    src: self.raw.to_string(),
1776                });
1777            } else {
1778                self.out = EMPTY_STRING;
1779
1780                return Ok(());
1781            }
1782        }
1783
1784        let canonical_path = fs::canonicalize(path)
1785            .unwrap()
1786            .to_string_lossy()
1787            .into_owned();
1788
1789        if self.mod_negate && self.inherit.data_files.contains(&canonical_path) {
1790            self.out = UNPRINTABLE.to_string();
1791
1792            return Ok(());
1793        }
1794
1795        self.inherit.data_files.push(canonical_path);
1796        let file_raw = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
1797
1798        let data: Value = match serde_json::from_str(&file_raw) {
1799            Ok(value) => value,
1800            Err(_) => {
1801                return Err(BifError {
1802                    msg: "not a valid JSON file".to_string(),
1803                    name: self.alias.clone(),
1804                    src: self.raw.to_string(),
1805                })
1806            }
1807        };
1808
1809        let indir = &self.inherit.create_block_schema(self.shared);
1810
1811        // Merge new locale data in curren local data.
1812        merge_schema(
1813            &mut self.shared.schema["__indir"][indir]["data"],
1814            &data["data"],
1815        );
1816
1817        self.out = UNPRINTABLE.to_string();
1818
1819        Ok(())
1820    }
1821
1822    /*
1823        {:date;  :} timestamp
1824        {:date; %Y-%m-%d %H:%M:%S  :} UTC
1825    */
1826    fn parse_bif_date(&mut self) -> Result<(), BifError> {
1827        if self.mod_filter || self.mod_negate || self.mod_scope {
1828            return Err(BifError {
1829                msg: "modifier not allowed".to_string(),
1830                name: self.alias.clone(),
1831                src: self.raw.to_string(),
1832            });
1833        }
1834
1835        self.extract_params_code(true);
1836
1837        let now = Utc::now();
1838
1839        if self.src.contains(BIF_OPEN) {
1840            self.code = new_child_parse!(self, &self.code, self.mod_scope);
1841        } else {
1842            self.code = self.src.trim().to_string();
1843        }
1844
1845        if self.code.is_empty() {
1846            self.out = now.timestamp().to_string();
1847        } else {
1848            self.out = now.format(&self.src).to_string();
1849        }
1850
1851        Ok(())
1852    }
1853
1854    /*
1855        {:declare; name >> words list :}
1856    */
1857    fn parse_bif_declare(&mut self) -> Result<(), BifError> {
1858        if self.mod_filter || self.mod_negate || self.mod_scope {
1859            return Err(BifError {
1860                msg: "modifier not allowed".to_string(),
1861                name: self.alias.clone(),
1862                src: self.raw.to_string(),
1863            });
1864        }
1865
1866        self.extract_params_code(true);
1867
1868        if self.inherit.current_file.contains(SNIPPETS_FILES) {
1869            self.inherit.create_block_schema(self.shared);
1870            if self.code.contains(BIF_OPEN) {
1871                self.code = new_child_parse!(self, &self.code, false);
1872                self.code = self.code.replace(UNPRINTABLE, "");
1873            }
1874            self.shared.schema["__indir"][&self.inherit.indir]["declare"][&self.params] =
1875                json!(&self.code);
1876
1877            self.out = EMPTY_STRING;
1878        } else {
1879            return Err(BifError {
1880                msg: "declare cannot be set here".to_string(),
1881                name: self.alias.clone(),
1882                src: self.raw.to_string(),
1883            });
1884        }
1885
1886        Ok(())
1887    }
1888
1889    /*
1890        {:defined; varname >> ... :}
1891    */
1892    fn parse_bif_defined(&mut self) -> Result<(), BifError> {
1893        if self.mod_filter {
1894            return Err(BifError {
1895                msg: "modifier not allowed".to_string(),
1896                name: self.alias.clone(),
1897                src: self.raw.to_string(),
1898            });
1899        }
1900
1901        self.extract_params_code(true);
1902
1903        let mut varname = self.params.as_str();
1904        let mut schema = &self.shared.schema["data"];
1905
1906        if varname.starts_with("local::") {
1907            schema = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
1908            varname = varname.strip_prefix("local::").unwrap_or(varname);
1909        }
1910
1911        if is_defined_key(schema, varname) ^ self.mod_negate {
1912            if self.code.contains(BIF_OPEN) {
1913                self.code = new_child_parse!(self, &self.code, self.mod_scope);
1914            }
1915            self.out = self.code.to_string();
1916        }
1917
1918        Ok(())
1919    }
1920
1921    /*
1922        {:each; array-name name-for-key name-for-value  >>
1923            {:;name-for-key:}={:;name-for-value:}
1924        :}
1925    */
1926    fn parse_bif_each(&mut self) -> Result<(), BifError> {
1927        if self.mod_filter || self.mod_negate || self.mod_scope {
1928            return Err(BifError {
1929                msg: "modifier not allowed".to_string(),
1930                name: self.alias.clone(),
1931                src: self.raw.to_string(),
1932            });
1933        }
1934
1935        self.extract_params_code(true);
1936        let mut parts = self.params.split_whitespace();
1937
1938        let array_name = match parts.next() {
1939            Some(value) => value.to_string(),
1940            None => {
1941                return Err(BifError {
1942                    msg: "arguments not found".to_string(),
1943                    name: self.alias.clone(),
1944                    src: self.raw.to_string(),
1945                })
1946            }
1947        };
1948
1949        let key_name = match parts.next() {
1950            Some(value) => value.to_string(),
1951            None => {
1952                return Err(BifError {
1953                    msg: "arguments 'key' not found".to_string(),
1954                    name: self.alias.clone(),
1955                    src: self.raw.to_string(),
1956                })
1957            }
1958        };
1959
1960        let val_name = match parts.next() {
1961            Some(value) => value.to_string(),
1962            None => {
1963                return Err(BifError {
1964                    msg: "arguments 'value' not found".to_string(),
1965                    name: self.alias.clone(),
1966                    src: self.raw.to_string(),
1967                })
1968            }
1969        };
1970
1971        let tmp: String = format!("{}{}", "/", array_name);
1972        let mut array = tmp.replace(BIF_ARRAY, "/");
1973        let restore_key = self.get_data(&key_name);
1974        let restore_val = self.get_data(&val_name);
1975
1976        let data_storage;
1977        if array.starts_with("/local::") {
1978            array = array.replace("/local::", "/");
1979            data_storage = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
1980        } else {
1981            data_storage = &self.shared.schema["data"];
1982        }
1983
1984        if let Some(data_value) = data_storage.pointer(&array) {
1985            match data_value.to_owned() {
1986                Value::Object(obj) => {
1987                    for (key, val) in obj.iter() {
1988                        self.parse_bif_each_iter(&key_name, &val_name, key, val);
1989                    }
1990                }
1991                Value::Array(arr) => {
1992                    for (key, val) in arr.iter().enumerate() {
1993                        self.parse_bif_each_iter(&key_name, &val_name, &key.to_string(), val);
1994                    }
1995                }
1996                _ => {}
1997            }
1998        }
1999
2000        self.set_data(&key_name, &restore_key);
2001        self.set_data(&val_name, &restore_val);
2002
2003        Ok(())
2004    }
2005
2006    fn parse_bif_each_iter(&mut self, key_name: &str, val_name: &str, key: &String, val: &Value) {
2007        self.shared.schema["data"][key_name] = json!(key);
2008        self.shared.schema["data"][val_name] = json!(val);
2009        self.out += &new_child_parse!(self, &self.code, false);
2010    }
2011
2012    /*
2013       {:else; ... :}
2014       {:code; :}{:else; this is output :}
2015       {:code; not empty :}{:!else; this is output :}
2016    */
2017    fn parse_bif_else(&mut self) -> Result<(), BifError> {
2018        if self.mod_filter {
2019            return Err(BifError {
2020                msg: "modifier not allowed".to_string(),
2021                name: self.alias.clone(),
2022                src: self.raw.to_string(),
2023            });
2024        }
2025
2026        self.extract_params_code(true);
2027
2028        if self.inherit.last_bif_out ^ self.mod_negate {
2029            self.out = EMPTY_STRING;
2030
2031            return Ok(());
2032        }
2033
2034        if self.code.contains(BIF_OPEN) {
2035            self.code = new_child_parse!(self, &self.code, self.mod_scope);
2036        }
2037
2038        self.out = self.code.to_string();
2039
2040        Ok(())
2041    }
2042
2043    /*
2044        {:eval; code >> ... {:;__eval__:} ... :} {:* embbedding *:}
2045    */
2046    fn parse_bif_eval(&mut self) -> Result<(), BifError> {
2047        if self.mod_filter {
2048            return Err(BifError {
2049                msg: "modifier not allowed".to_string(),
2050                name: self.alias.clone(),
2051                src: self.raw.to_string(),
2052            });
2053        }
2054
2055        self.extract_params_code(false);
2056
2057        if self.params.contains(BIF_OPEN) {
2058            self.params = new_child_parse!(self, &self.params, self.mod_scope);
2059        }
2060
2061        if (self.params != EMPTY_STRING) ^ self.mod_negate {
2062            if self.code.contains(BIF_OPEN) {
2063                let restore_eval = self.get_data("__eval__");
2064                self.set_data("__eval__", &self.params.clone());
2065                self.code = new_child_parse!(self, &self.code, self.mod_scope);
2066                self.set_data("__eval__", &restore_eval);
2067            }
2068            self.out = self.code.clone();
2069        } else {
2070            self.out = EMPTY_STRING;
2071        }
2072
2073        Ok(())
2074    }
2075
2076    /*
2077        {:exit; :}
2078        {:exit; 404 :}
2079        {:!exit; 202 :} {:* only sets the status code :}
2080        {:exit; 301 >> /page :}
2081    */
2082    fn parse_bif_exit(&mut self) -> Result<(), BifError> {
2083        if self.mod_filter || self.mod_scope {
2084            return Err(BifError {
2085                msg: "modifier not allowed".to_string(),
2086                name: self.alias.clone(),
2087                src: self.raw.to_string(),
2088            });
2089        }
2090
2091        if self.inherit.in_cache {
2092            self.out = format!("{}{}{}", "{:!cache;", self.raw.to_string(), ":}");
2093        } else {
2094            self.out = EMPTY_STRING;
2095        }
2096
2097        let has_status_params = self.extract_params_code(true);
2098
2099        if self.code.contains(BIF_OPEN) {
2100            self.code = new_child_parse!(self, &self.src, false);
2101        }
2102
2103        let mut status_code = "200";
2104        let mut status_param = "";
2105
2106        if has_status_params {
2107            if !self.params.is_empty() {
2108                status_code = self.params.as_str();
2109            }
2110            status_param = &self.code;
2111        } else if !self.code.is_empty() {
2112            status_code = self.code.as_str();
2113        }
2114
2115        self.shared.status_code = status_code.to_string();
2116        self.shared.status_param = status_param.to_string();
2117
2118        if let Some(text) = STATUS_CODES.get(status_code) {
2119            self.shared.status_text = text.to_string();
2120        } else {
2121            self.shared.status_text = EMPTY_STRING;
2122        }
2123
2124        self.shared.exit = true ^ self.mod_negate;
2125
2126        Ok(())
2127    }
2128
2129
2130    /*
2131        {:fetch; {:flg; visible click :} url >> ... :}
2132    */
2133    fn parse_bif_fetch(&mut self) -> Result<(), BifError> {
2134        if self.mod_filter || self.mod_negate || self.mod_scope {
2135            return Err(BifError {
2136                msg: "modifier not allowed".to_string(),
2137                name: self.alias.clone(),
2138                src: self.raw.to_string(),
2139            });
2140        }
2141
2142        self.extract_params_code(true);
2143        let args = self.extract_args();
2144
2145        let url = args.get(1)
2146            .cloned()
2147            .ok_or_else(|| {
2148                BifError {
2149                    msg: "argument 'url' not found".to_string(),
2150                    name: self.alias.clone(),
2151                    src: self.raw.to_string(),
2152                }
2153            })?;
2154
2155        let event = args.get(2).cloned().unwrap_or("".to_string());
2156        let wrap = args.get(3).cloned().unwrap_or("".to_string());
2157        let class = args.get(4).cloned().unwrap_or("".to_string());
2158        let id = args.get(5).cloned().unwrap_or("".to_string());
2159        let name = args.get(6).cloned().unwrap_or("".to_string());
2160        let div;
2161
2162        match event.as_str() {
2163            "form" => div = DIV_FETCH_FORM,
2164            "none" => div = DIV_FETCH_NONE,
2165            "visible" => div = DIV_FETCH_VISIBLE,
2166            "click" => div = DIV_FETCH_CLICK,
2167            "auto" => div = DIV_FETCH_AUTO,
2168            _ => div = DIV_FETCH_AUTO,
2169        }
2170
2171        if self.code.contains(BIF_OPEN) {
2172            self.code = new_child_parse!(self, &self.code, self.mod_scope);
2173        }
2174
2175        self.out = div
2176            .replace("{id}", &id)
2177            .replace("{name}", &name)
2178            .replace("{wrap}", &wrap)
2179            .replace("{class}", &class)
2180            .replace("{body}", &self.code)
2181            .replace("{endpoint}", &url);
2182
2183        if !self.shared.disable_js && !self.shared.already_js {
2184            self.out = format!("{}{}{}{}", self.out, "{:!cache;{:moveto;</body>>", NEUTRAL_JS.to_string(), ":}:}");
2185            self.shared.already_js = true;
2186        }
2187
2188        Ok(())
2189    }
2190
2191    /*
2192        {:filled; varname >> ... :}
2193
2194        *** It is only not filled if it has nothing "", if it is not defined
2195        or is null, the rest “false”, “0” etc. is something.
2196    */
2197    fn parse_bif_filled(&mut self) -> Result<(), BifError> {
2198        if self.mod_filter {
2199            return Err(BifError {
2200                msg: "modifier not allowed".to_string(),
2201                name: self.alias.clone(),
2202                src: self.raw.to_string(),
2203            });
2204        }
2205
2206        self.extract_params_code(true);
2207
2208        let mut varname = self.params.as_str();
2209        let mut schema = &self.shared.schema["data"];
2210
2211        if varname.starts_with("local::") {
2212            schema = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
2213            varname = varname.strip_prefix("local::").unwrap_or(varname);
2214        }
2215
2216        if !is_empty_key(schema, varname) ^ self.mod_negate {
2217            if self.code.contains(BIF_OPEN) {
2218                self.code = new_child_parse!(self, &self.code, self.mod_scope);
2219            }
2220
2221            self.out = self.code.to_string();
2222        }
2223
2224        Ok(())
2225    }
2226
2227    /*
2228        {:flg; flag-name1 flag-name2 ... :}
2229        {:code; {:flg; safe :} >>  <div>...</div> :}
2230    */
2231    fn parse_bif_flg(&mut self) -> Result<(), BifError> {
2232        if self.mod_filter || self.mod_negate || self.mod_upline || self.mod_scope {
2233            return Err(BifError {
2234                msg: "modifier not allowed".to_string(),
2235                name: self.alias.clone(),
2236                src: self.raw.to_string(),
2237            });
2238        }
2239
2240        self.extract_params_code(true);
2241
2242        if self.code.contains(BIF_OPEN) {
2243            self.code = new_child_parse!(self, &self.code, false);
2244        }
2245
2246        let flags = format!(" {} ", self.code);
2247        self.shared.flags = flags.replace(" ", "|");
2248        self.out = EMPTY_STRING;
2249
2250        Ok(())
2251    }
2252
2253    /*
2254       {:for; varname 1 10 >>
2255           var is:{:;varname:}
2256       :}
2257    */
2258    fn parse_bif_for(&mut self) -> Result<(), BifError> {
2259        if self.mod_filter || self.mod_negate || self.mod_scope {
2260            return Err(BifError {
2261                msg: "modifier not allowed".to_string(),
2262                name: self.alias.clone(),
2263                src: self.raw.to_string(),
2264            });
2265        }
2266
2267        self.extract_params_code(true);
2268        self.params = self.params.replace("..", " ");
2269        let mut parts = self.params.split_whitespace();
2270
2271        let var_name = match parts.next() {
2272            Some(value) => value.to_string(),
2273            None => {
2274                return Err(BifError {
2275                    msg: "arguments not found".to_string(),
2276                    name: self.alias.clone(),
2277                    src: self.raw.to_string(),
2278                })
2279            }
2280        };
2281
2282        let from = match parts.next() {
2283            Some(value) => match value.parse::<i32>() {
2284                Ok(num) => num,
2285                Err(_) => {
2286                    return Err(BifError {
2287                        msg: "argument is not a number".to_string(),
2288                        name: self.alias.clone(),
2289                        src: self.raw.to_string(),
2290                    })
2291                }
2292            },
2293            None => {
2294                return Err(BifError {
2295                    msg: "arguments 'from' and 'to' not found".to_string(),
2296                    name: self.alias.clone(),
2297                    src: self.raw.to_string(),
2298                })
2299            }
2300        };
2301
2302        let to = match parts.next() {
2303            Some(value) => match value.parse::<i32>() {
2304                Ok(num) => num,
2305                Err(_) => {
2306                    return Err(BifError {
2307                        msg: "argument is not a number".to_string(),
2308                        name: self.alias.clone(),
2309                        src: self.raw.to_string(),
2310                    })
2311                }
2312            },
2313            None => {
2314                return Err(BifError {
2315                    msg: "arguments 'to' not found".to_string(),
2316                    name: self.alias.clone(),
2317                    src: self.raw.to_string(),
2318                })
2319            }
2320        };
2321
2322        let range = if from > to {
2323            (to..=from).rev().collect::<Vec<i32>>()
2324        } else {
2325            (from..=to).collect::<Vec<i32>>()
2326        };
2327
2328        let restore_var = self.get_data(&var_name);
2329        for i in range {
2330            self.set_data(&var_name, &i.to_string());
2331            self.out += &new_child_parse!(self, &self.code, self.mod_scope);
2332        }
2333        self.set_data(&var_name, &restore_var);
2334
2335        Ok(())
2336    }
2337
2338    /*
2339        {:hash;  :}
2340        {:hash; text :}
2341    */
2342    fn parse_bif_hash(&mut self) -> Result<(), BifError> {
2343        if self.mod_filter || self.mod_negate || self.mod_scope {
2344            return Err(BifError {
2345                msg: "modifier not allowed".to_string(),
2346                name: self.alias.clone(),
2347                src: self.raw.to_string(),
2348            });
2349        }
2350
2351        self.code = self.src.trim().to_string();
2352
2353        if self.src.contains(BIF_OPEN) {
2354            self.code = new_child_parse!(self, &self.code, self.mod_scope);
2355        } else {
2356            self.code = self.code.trim().to_string();
2357        }
2358
2359        if self.code.is_empty() {
2360            let mut hasher = Md5::new();
2361            let mut rng = rand::rng();
2362            let rand = rng.random_range(100000000..=999999999).to_string();
2363            hasher.update(&rand);
2364            self.out = format!("{:x}", hasher.finalize())
2365        } else {
2366            let mut hasher = Md5::new();
2367            hasher.update(&self.code);
2368            self.out = format!("{:x}", hasher.finalize());
2369        }
2370
2371        Ok(())
2372    }
2373
2374    /*
2375        {:include; file-path :}
2376        {:include; {:flg; require safe noparse :} >> file-path :}
2377    */
2378    fn parse_bif_include(&mut self) -> Result<(), BifError> {
2379        if self.mod_filter || self.mod_scope {
2380            return Err(BifError {
2381                msg: "modifier not allowed".to_string(),
2382                name: self.alias.clone(),
2383                src: self.raw.to_string(),
2384            });
2385        }
2386
2387        self.extract_params_code(true);
2388        self.file_path = self.code.clone();
2389
2390        // For security requires {:allow;
2391        if self.file_path.contains(BIF_OPEN) {
2392            if !self.contains_allow(&self.file_path) {
2393                return Err(BifError {
2394                    msg: "insecure file name".to_string(),
2395                    name: self.alias.clone(),
2396                    src: self.raw.to_string(),
2397                });
2398            }
2399            self.file_path = new_child_parse!(self, &self.code, false);
2400        }
2401
2402        if self.file_path.starts_with("#") {
2403            self.file_path.remove(0);
2404            self.file_path = format!("{}{}", self.inherit.current_dir, self.file_path);
2405        }
2406
2407        let path = Path::new(&self.file_path);
2408        if !path.exists() {
2409            if self.flags.contains("|require|") {
2410                return Err(BifError {
2411                    msg: "file not found".to_string(),
2412                    name: self.alias.clone(),
2413                    src: self.raw.to_string(),
2414                });
2415            } else {
2416                return Ok(());
2417            }
2418        }
2419
2420        if let Some(parent) = path.parent() {
2421            self.dir = parent.display().to_string();
2422        }
2423
2424        let canonical_path = fs::canonicalize(path)
2425            .unwrap()
2426            .to_string_lossy()
2427            .into_owned();
2428
2429        if self.mod_negate && self.inherit.include_files.contains(&canonical_path) {
2430            self.out = EMPTY_STRING;
2431
2432            return Ok(());
2433        }
2434
2435        if self.flags.contains("|safe|") {
2436            self.code = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
2437            self.code = escape_chars(&unescape_chars(&self.code, false), false).to_string();
2438            self.code = self.code.replace(BIF_OPEN, BIF_SANITIZE_OPEN);
2439            self.code = self.code.replace(BIF_CLOSE, BIF_SANITIZE_CLOSE);
2440            self.out = self.code.clone();
2441
2442            return Ok(());
2443        }
2444
2445        if self.flags.contains("|noparse|") {
2446            self.code = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
2447            self.out = self.code.clone();
2448
2449            return Ok(());
2450        }
2451
2452        self.inherit.include_files.push(canonical_path);
2453
2454        let mut file_raw = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
2455        if self.shared.comments.contains("remove") {
2456            file_raw = remove_comments(&file_raw);
2457        }
2458
2459        self.out = new_child_parse!(self, &file_raw, true);
2460
2461        Ok(())
2462    }
2463
2464    /*
2465        {:join; /array/separator/ :}
2466        {:join; /array/separator/bool true for join keys instead values/ :}
2467        <li>{:join; |array|</li><li>| :}</li>
2468        {:join; /array/ / :}
2469    */
2470    fn parse_bif_join(&mut self) -> Result<(), BifError> {
2471        if self.mod_filter || self.mod_negate || self.mod_scope {
2472            return Err(BifError {
2473                msg: "modifier not allowed".to_string(),
2474                name: self.alias.clone(),
2475                src: self.raw.to_string(),
2476            });
2477        }
2478
2479        self.params = self.src.clone();
2480        let args = self.extract_args();
2481
2482        let mut array_name = args.get(1)
2483            .cloned()
2484            .ok_or_else(|| {
2485                BifError {
2486                    msg: "arguments 'array' not found".to_string(),
2487                    name: self.alias.clone(),
2488                    src: self.raw.to_string(),
2489                }
2490            })?;
2491
2492        let separator = args.get(2)
2493            .cloned()
2494            .ok_or_else(|| {
2495                BifError {
2496                    msg: "arguments 'separator' not found".to_string(),
2497                    name: self.alias.clone(),
2498                    src: self.raw.to_string(),
2499                }
2500            })?;
2501
2502        // optional use keys
2503        let use_keys = args.get(3).cloned().unwrap_or("".to_string());
2504
2505        let keys: bool = match use_keys.as_str() {
2506            "" => false,
2507            "false" => false,
2508            "0" => false,
2509            _ => true,
2510        };
2511
2512        let data_storage;
2513        array_name = format!("{}{}", "/", array_name);
2514        array_name = array_name.replace(BIF_ARRAY, "/");
2515        if array_name.starts_with("/local::") {
2516            array_name = array_name.replace("/local::", "/");
2517            data_storage = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
2518        } else {
2519            data_storage = &self.shared.schema["data"];
2520        }
2521
2522        let mut joined = String::new();
2523        if let Some(data_value) = data_storage.pointer(&array_name) {
2524            match data_value.to_owned() {
2525                Value::Object(obj) => {
2526                    if keys {
2527                        joined = obj
2528                            .keys()
2529                            .map(|k| k.to_string()) // Convertir cada clave a String
2530                            .collect::<Vec<String>>()
2531                            .join(&separator);
2532                    } else {
2533                        joined = obj
2534                            .values()
2535                            .map(|v| match v {
2536                                Value::Object(_) => "".to_string(),
2537                                Value::Array(_) => "".to_string(),
2538                                Value::String(s) => s.to_string(),
2539                                Value::Number(n) => n.to_string(),
2540                                Value::Bool(b) => b.to_string(),
2541                                _ => v.to_string(),
2542                            })
2543                            .collect::<Vec<String>>()
2544                            .join(&separator);
2545                    }
2546                }
2547                Value::Array(arr) => {
2548                    if keys {
2549                        joined = (0..arr.len())
2550                            .map(|i| i.to_string())
2551                            .collect::<Vec<String>>()
2552                            .join(&separator);
2553                    } else {
2554                        joined = arr
2555                            .iter()
2556                            .map(|v| v.as_str().unwrap_or(""))
2557                            .collect::<Vec<&str>>()
2558                            .join(&separator);
2559                    }
2560                }
2561                _ => {}
2562            }
2563        }
2564
2565        self.out = joined.to_string();
2566        Ok(())
2567    }
2568
2569    /*
2570       {:lang; ... :}
2571    */
2572    fn parse_bif_lang(&mut self) -> Result<(), BifError> {
2573        if self.mod_filter || self.mod_negate || self.mod_scope {
2574            return Err(BifError {
2575                msg: "modifier not allowed".to_string(),
2576                name: self.alias.clone(),
2577                src: self.raw.to_string(),
2578            });
2579        }
2580
2581        self.out = self.shared.lang.to_string();
2582
2583        Ok(())
2584    }
2585
2586    /*
2587        {:locale; file-path :}
2588    */
2589    fn parse_bif_locale(&mut self) -> Result<(), BifError> {
2590        if self.mod_filter || self.mod_scope {
2591            return Err(BifError {
2592                msg: "modifier not allowed".to_string(),
2593                name: self.alias.clone(),
2594                src: self.raw.to_string(),
2595            });
2596        }
2597
2598        self.extract_params_code(true);
2599
2600        if self.flags.contains("|inline|") {
2601            // Parse possible bifs included in json
2602            if self.code.contains(BIF_OPEN) {
2603                self.code = new_child_parse!(self, &self.code, false);
2604            }
2605
2606            let locale: Value = match serde_json::from_str(&self.code) {
2607                Ok(value) => value,
2608                Err(_) => {
2609                    return Err(BifError {
2610                        msg: "not a valid JSON string".to_string(),
2611                        name: self.alias.clone(),
2612                        src: self.raw.to_string(),
2613                    })
2614                }
2615            };
2616
2617            let indir = &self.inherit.create_block_schema(self.shared);
2618
2619            // Merge new locale data in curren locale.
2620            merge_schema(&mut self.shared.schema["__indir"][indir]["locale"], &locale);
2621
2622            self.out = EMPTY_STRING;
2623
2624            return Ok(());
2625        }
2626
2627        self.file_path = self.code.clone();
2628
2629        // For security requires {:allow;
2630        if self.file_path.contains(BIF_OPEN) {
2631            if !self.contains_allow(&self.file_path) {
2632                return Err(BifError {
2633                    msg: "insecure file name".to_string(),
2634                    name: self.alias.clone(),
2635                    src: self.raw.to_string(),
2636                });
2637            }
2638            self.file_path = new_child_parse!(self, &self.code, false);
2639        }
2640
2641        if self.file_path.starts_with("#") {
2642            self.file_path.remove(0);
2643            self.file_path = format!("{}{}", self.inherit.current_dir, self.file_path);
2644        }
2645
2646        let path = Path::new(&self.file_path);
2647        if !Path::new(path).exists() {
2648            if self.flags.contains("|require|") {
2649                return Err(BifError {
2650                    msg: "file not found".to_string(),
2651                    name: self.alias.clone(),
2652                    src: self.raw.to_string(),
2653                });
2654            } else {
2655                return Ok(());
2656            }
2657        }
2658
2659        let canonical_path = fs::canonicalize(path)
2660            .unwrap()
2661            .to_string_lossy()
2662            .into_owned();
2663        if self.mod_negate && self.inherit.locale_files.contains(&canonical_path) {
2664            self.out = UNPRINTABLE.to_string();
2665
2666            return Ok(());
2667        }
2668
2669        self.inherit.locale_files.push(canonical_path);
2670        let mut file_raw = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
2671
2672        if !self.flags.contains("|noparse|") {
2673            // Parse possible bifs included in json
2674            if file_raw.contains(BIF_OPEN) {
2675                file_raw = new_child_parse!(self, &file_raw, false);
2676            }
2677        }
2678
2679        let locale: Value = match serde_json::from_str(&file_raw) {
2680            Ok(value) => value,
2681            Err(_) => {
2682                return Err(BifError {
2683                    msg: "not a valid JSON file".to_string(),
2684                    name: self.alias.clone(),
2685                    src: self.raw.to_string(),
2686                })
2687            }
2688        };
2689
2690        let indir = &self.inherit.create_block_schema(self.shared);
2691
2692        // Merge new locale data in curren locale.
2693        merge_schema(&mut self.shared.schema["__indir"][indir]["locale"], &locale);
2694
2695        self.out = UNPRINTABLE.to_string();
2696
2697        Ok(())
2698    }
2699
2700    /*
2701        {:moveto; <tag >> ... :}
2702        {:moveto; </tag >> ... :}
2703    */
2704    fn parse_bif_moveto(&mut self) -> Result<(), BifError> {
2705        if self.mod_filter || self.mod_negate || self.mod_scope {
2706            return Err(BifError {
2707                msg: "modifier not allowed".to_string(),
2708                name: self.alias.clone(),
2709                src: self.raw.to_string(),
2710            });
2711        }
2712
2713        if self.inherit.in_cache {
2714            self.out = format!("{}{}{}", "{:!cache;", self.raw.to_string(), ":}");
2715        } else {
2716            self.out = EMPTY_STRING;
2717        }
2718
2719        self.extract_params_code(true);
2720
2721        if self.code.contains(BIF_OPEN) {
2722            self.code = new_child_parse!(self, &self.code, self.mod_scope);
2723        }
2724
2725        self.moveto(&self.params.clone(), &self.code.clone());
2726
2727        Ok(())
2728    }
2729
2730    fn moveto(&mut self, to: &str, code: &str)  {
2731        let mut moveto = json!({});
2732        let mut hasher = Md5::new();
2733
2734        // the same code moves only once
2735        hasher.update(code.replace("\n", "").replace(" ", ""));
2736        let code_hash = hasher.finalize();
2737        let code_hash = format!("{:x}", code_hash);
2738
2739        moveto[to] = json!(code);
2740        self.shared.schema["__moveto"][&code_hash] = moveto;
2741    }
2742
2743    /*
2744        {:neutral; ... :}
2745    */
2746    fn parse_bif_neutral(&mut self) -> Result<(), BifError> {
2747        if self.mod_filter || self.mod_negate || self.mod_scope {
2748            return Err(BifError {
2749                msg: "modifier not allowed".to_string(),
2750                name: self.alias.clone(),
2751                src: self.raw.to_string(),
2752            });
2753        }
2754
2755        self.out = self.raw.to_string();
2756
2757        Ok(())
2758    }
2759
2760    /*
2761        Play param: {:param; param-name :}
2762        Set param:  {:param; param-name >> content to set :}
2763    */
2764    fn parse_bif_param(&mut self) -> Result<(), BifError> {
2765        if self.mod_filter || self.mod_negate || self.mod_scope {
2766            return Err(BifError {
2767                msg: "modifier not allowed".to_string(),
2768                name: self.alias.clone(),
2769                src: self.raw.to_string(),
2770            });
2771        }
2772
2773        let is_set = self.extract_params_code(true);
2774        if is_set {
2775            if self.inherit.alias == "code" {
2776                if self.code.contains(BIF_OPEN) {
2777                    self.code = new_child_parse!(self, &self.code, self.mod_scope);
2778                }
2779
2780                self.inherit.create_block_schema(self.shared);
2781                self.shared.schema["__indir"][&self.inherit.indir]["params"][&self.params] =
2782                    json!(&self.code);
2783                self.out = EMPTY_STRING;
2784
2785                Ok(())
2786            } else {
2787                Err(BifError {
2788                    msg: "param cannot be set here".to_string(),
2789                    name: self.alias.clone(),
2790                    src: self.raw.to_string(),
2791                })
2792            }
2793        } else {
2794            if self.code.contains(BIF_OPEN) {
2795                self.code = new_child_parse!(self, &self.code, self.mod_scope);
2796            }
2797
2798            self.code = get_from_key(
2799                &self.shared.schema["__indir"][&self.inherit.indir]["params"],
2800                &self.code,
2801            );
2802            self.out = self.code.to_string();
2803
2804            Ok(())
2805        }
2806    }
2807
2808    /*
2809        {:rand;  :}
2810        {:rand; 1..100 :}
2811    */
2812    fn parse_bif_rand(&mut self) -> Result<(), BifError> {
2813        if self.mod_filter || self.mod_negate || self.mod_scope {
2814            return Err(BifError {
2815                msg: "modifier not allowed".to_string(),
2816                name: self.alias.clone(),
2817                src: self.raw.to_string(),
2818            });
2819        }
2820
2821        let mut rng = rand::rng();
2822        self.code = self.src.trim().to_string();
2823
2824        if self.src.contains(BIF_OPEN) {
2825            self.code = new_child_parse!(self, &self.code, self.mod_scope);
2826        } else {
2827            self.code = self.src.trim().to_string();
2828        }
2829
2830        if self.code.is_empty() {
2831            self.out = rng.random_range(100000000..=999999999).to_string();
2832        } else {
2833            // TODO comprobar rangos
2834            self.code = self.code.replace("..", " ");
2835            let mut parts = self.code.split_whitespace();
2836
2837            let from = match parts.next() {
2838                Some(value) => match value.parse::<i32>() {
2839                    Ok(num) => num,
2840                    Err(_) => {
2841                        return Err(BifError {
2842                            msg: "argument is not a number".to_string(),
2843                            name: self.alias.clone(),
2844                            src: self.raw.to_string(),
2845                        })
2846                    }
2847                },
2848                None => {
2849                    return Err(BifError {
2850                        msg: "arguments not found".to_string(),
2851                        name: self.alias.clone(),
2852                        src: self.raw.to_string(),
2853                    })
2854                }
2855            };
2856
2857            let to = match parts.next() {
2858                Some(value) => match value.parse::<i32>() {
2859                    Ok(num) => num,
2860                    Err(_) => {
2861                        return Err(BifError {
2862                            msg: "argument is not a number".to_string(),
2863                            name: self.alias.clone(),
2864                            src: self.raw.to_string(),
2865                        })
2866                    }
2867                },
2868                None => {
2869                    return Err(BifError {
2870                        msg: "arguments not found".to_string(),
2871                        name: self.alias.clone(),
2872                        src: self.raw.to_string(),
2873                    })
2874                }
2875            };
2876
2877            if from > to {
2878                return Err(BifError {
2879                    msg: "from > to".to_string(),
2880                    name: self.alias.clone(),
2881                    src: self.raw.to_string(),
2882                });
2883            }
2884
2885            self.out = rng.random_range(from..=to).to_string();
2886        }
2887
2888        Ok(())
2889    }
2890
2891    /*
2892        {:redirect; 301 >> /page :}
2893        {:redirect; js:reload:top >> (none) :}
2894    */
2895    fn parse_bif_redirect(&mut self) -> Result<(), BifError> {
2896        if self.mod_filter || self.mod_scope || self.mod_negate {
2897            return Err(BifError {
2898                msg: "modifier not allowed".to_string(),
2899                name: self.alias.clone(),
2900                src: self.raw.to_string(),
2901            });
2902        }
2903
2904        if self.inherit.in_cache {
2905            self.out = format!("{}{}{}", "{:!cache;", self.raw.to_string(), ":}");
2906        } else {
2907            self.out = EMPTY_STRING;
2908        }
2909
2910        let status_code;
2911        let has_status_params = self.extract_params_code(true);
2912
2913        if self.code.contains(BIF_OPEN) {
2914            self.code = new_child_parse!(self, &self.src, false);
2915        }
2916
2917        if has_status_params {
2918            // When parameters are required or optional in BIF
2919            status_code = match self.params.as_str() {
2920                "301" => {
2921                    if self.code.is_empty() {
2922                        return Err(BifError {
2923                            msg: "this redirection requires URL".to_string(),
2924                            name: self.alias.clone(),
2925                            src: self.raw.to_string(),
2926                        });
2927                    }
2928
2929                    "301"
2930                }
2931                "302" => {
2932                    if self.code.is_empty() {
2933                        return Err(BifError {
2934                            msg: "this redirection requires URL".to_string(),
2935                            name: self.alias.clone(),
2936                            src: self.raw.to_string(),
2937                        });
2938                    }
2939
2940                    "302"
2941                }
2942                "303" => {
2943                    if self.code.is_empty() {
2944                        return Err(BifError {
2945                            msg: "this redirection requires URL".to_string(),
2946                            name: self.alias.clone(),
2947                            src: self.raw.to_string(),
2948                        });
2949                    }
2950
2951                    "303"
2952                }
2953                "307" => {
2954                    if self.code.is_empty() {
2955                        return Err(BifError {
2956                            msg: "this redirection requires URL".to_string(),
2957                            name: self.alias.clone(),
2958                            src: self.raw.to_string(),
2959                        });
2960                    }
2961
2962                    "307"
2963                }
2964                "308" => {
2965                    if self.code.is_empty() {
2966                        return Err(BifError {
2967                            msg: "this redirection requires URL".to_string(),
2968                            name: self.alias.clone(),
2969                            src: self.raw.to_string(),
2970                        });
2971                    }
2972
2973                    "308"
2974                }
2975                "js:reload:top" => {
2976                    self.shared.redirect_js = REDIR_JS_RELOAD_TOP.to_string();
2977
2978                    "200"
2979                }
2980                "js:reload:self" => {
2981                    self.shared.redirect_js = REDIR_JS_RELOAD_SELF.to_string();
2982
2983                    "200"
2984                }
2985                "js:redirect:top" => {
2986                    if self.code.is_empty() {
2987                        return Err(BifError {
2988                            msg: "this redirection requires URL".to_string(),
2989                            name: self.alias.clone(),
2990                            src: self.raw.to_string(),
2991                        });
2992                    }
2993                    // TODO replace(['%2F','%3A','%3F','%3D','%26'], ['/',':','?','=','&'], url);
2994                    self.shared.redirect_js =
2995                        REDIR_JS_REDIRECT_TOP.replace("{}", &self.code).to_string();
2996
2997                    "200"
2998                }
2999                "js:redirect:self" => {
3000                    if self.code.is_empty() {
3001                        return Err(BifError {
3002                            msg: "this redirection requires URL".to_string(),
3003                            name: self.alias.clone(),
3004                            src: self.raw.to_string(),
3005                        });
3006                    }
3007                    // TODO replace(['%2F','%3A','%3F','%3D','%26'], ['/',':','?','=','&'], url);
3008                    self.shared.redirect_js =
3009                        REDIR_JS_REDIRECT_SELF.replace("{}", &self.code).to_string();
3010
3011                    "200"
3012                }
3013                _ => {
3014                    // Parameters are optional in js:reload:self and js:reload:top
3015                    if !self.code.contains("js:reload:self") || !self.code.contains("js:reload:top")
3016                    {
3017                        return Err(BifError {
3018                            msg: "status code not allowed".to_string(),
3019                            name: self.alias.clone(),
3020                            src: self.raw.to_string(),
3021                        });
3022                    } else {
3023                        "200"
3024                    }
3025                }
3026            };
3027        } else {
3028            // When parameters are not needed in BIF
3029            status_code = match self.code.as_str() {
3030                "js:reload:top" => {
3031                    self.shared.redirect_js = REDIR_JS_RELOAD_TOP.to_string();
3032
3033                    "200"
3034                }
3035                "js:reload:self" => {
3036                    self.shared.redirect_js = REDIR_JS_RELOAD_SELF.to_string();
3037
3038                    "200"
3039                }
3040                _ => {
3041                    return Err(BifError {
3042                        msg: "redirect type not allowed".to_string(),
3043                        name: self.alias.clone(),
3044                        src: self.raw.to_string(),
3045                    })
3046                }
3047            };
3048        }
3049
3050        self.shared.status_param = self.code.to_string();
3051        self.shared.status_code = status_code.to_string();
3052
3053        if let Some(text) = STATUS_CODES.get(status_code) {
3054            self.shared.status_text = text.to_string();
3055        } else {
3056            self.shared.status_text = EMPTY_STRING;
3057        }
3058
3059        self.shared.exit = true ^ self.mod_negate;
3060
3061        Ok(())
3062    }
3063
3064    /*
3065        {:replace; /from/to/ >> ... :}
3066        /from/to/, ~from~to~, |from|to|, ...
3067    */
3068    fn parse_bif_replace(&mut self) -> Result<(), BifError> {
3069        if self.mod_filter || self.mod_negate || self.mod_scope {
3070            return Err(BifError {
3071                msg: "modifier not allowed".to_string(),
3072                name: self.alias.clone(),
3073                src: self.raw.to_string(),
3074            });
3075        }
3076
3077        self.extract_params_code(false);
3078        let args = self.extract_args();
3079
3080        let from = args.get(1)
3081            .cloned()
3082            .ok_or_else(|| {
3083                BifError {
3084                    msg: "arguments not found".to_string(),
3085                    name: self.alias.clone(),
3086                    src: self.raw.to_string(),
3087                }
3088            })?;
3089
3090        let to = args.get(2)
3091            .cloned()
3092            .ok_or_else(|| {
3093                BifError {
3094                    msg: "arguments not found".to_string(),
3095                    name: self.alias.clone(),
3096                    src: self.raw.to_string(),
3097                }
3098            })?;
3099
3100        if self.code.contains(BIF_OPEN) {
3101            self.code = new_child_parse!(self, &self.code, self.mod_scope);
3102        }
3103
3104        self.out = self.code.replace(&from, &to);
3105
3106        Ok(())
3107    }
3108
3109    /*
3110        {:same; /a/b/ >> ... :}
3111    */
3112    fn parse_bif_same(&mut self) -> Result<(), BifError> {
3113        if self.mod_filter {
3114            return Err(BifError {
3115                msg: "modifier not allowed".to_string(),
3116                name: self.alias.clone(),
3117                src: self.raw.to_string(),
3118            });
3119        }
3120
3121        self.extract_params_code(false);
3122        let args = self.extract_args();
3123
3124        let param1 = args.get(1)
3125            .cloned()
3126            .ok_or_else(|| {
3127                BifError {
3128                    msg: "arguments not found".to_string(),
3129                    name: self.alias.clone(),
3130                    src: self.raw.to_string(),
3131                }
3132            })?;
3133
3134        let param2 = args.get(2)
3135            .cloned()
3136            .ok_or_else(|| {
3137                BifError {
3138                    msg: "arguments not found".to_string(),
3139                    name: self.alias.clone(),
3140                    src: self.raw.to_string(),
3141                }
3142            })?;
3143
3144        if (param1 == param2) ^ self.mod_negate  {
3145            if self.code.contains(BIF_OPEN) {
3146                self.code = new_child_parse!(self, &self.code, self.mod_scope);
3147            }
3148            self.out = self.code.to_string();
3149        } else {
3150            self.out = EMPTY_STRING;
3151        }
3152
3153        Ok(())
3154    }
3155
3156    /*
3157        Play snippet:
3158        {:snippet; snippet-name :}
3159
3160        Set snippet:
3161        {:snippet; snippet-name >>
3162            content to set
3163        :}
3164    */
3165    fn parse_bif_snippet(&mut self) -> Result<(), BifError> {
3166        if self.mod_filter || self.mod_negate || self.mod_scope {
3167            return Err(BifError {
3168                msg: "modifier not allowed".to_string(),
3169                name: self.alias.clone(),
3170                src: self.raw.to_string(),
3171            });
3172        }
3173
3174        self.alias = "snippet".to_string();
3175
3176        let is_set = self.extract_params_code(true);
3177        if is_set {
3178            // Set snippets in snippet files and inside snippets
3179            if self.inherit.current_file.contains(SNIPPETS_FILES) || self.inherit.alias == "snippet"
3180            {
3181                if self.flags.contains("|static|") {
3182                    self.code = new_child_parse!(self, &self.code, self.mod_scope);
3183                } else {
3184                    // required regardless of mod_scope or static
3185                    self.inherit.create_block_schema(self.shared);
3186                }
3187                self.shared.schema["__indir"][&self.inherit.indir]["snippets"][&self.params] =
3188                    json!(&self.code);
3189
3190                // The directory inside the snippet is that of the template that created it.
3191                self.shared.schema["__indir"][&self.inherit.indir]["snippets_set_dir"][&self.params] =
3192                    json!(&self.inherit.current_dir);
3193
3194                self.out = EMPTY_STRING;
3195
3196                Ok(())
3197            } else {
3198                Err(BifError {
3199                    msg: "snippet cannot be set here".to_string(),
3200                    name: self.alias.clone(),
3201                    src: self.raw.to_string(),
3202                })
3203            }
3204        } else {
3205            // parse snippet name if need
3206            if self.code.contains(BIF_OPEN) {
3207                self.code = new_child_parse!(self, &self.code, false);
3208            }
3209            let snip_name = self.code.clone();
3210
3211            self.code = get_from_key(
3212                &self.shared.schema["__indir"][&self.inherit.indir]["snippets"],&self.code,
3213            );
3214
3215            if self.code.contains(BIF_OPEN) {
3216
3217                // The directory inside the snippet is that of the template that created it.
3218                let set_dir = get_from_key(
3219                    &self.shared.schema["__indir"][&self.inherit.indir]["snippets_set_dir"],&snip_name,
3220                );
3221
3222                if !set_dir.is_empty() {
3223                    self.inherit.current_dir = set_dir;
3224                }
3225
3226                // auto mod_scope in snippets for snippets inside snippets
3227                self.code = new_child_parse!(self, &self.code, self.code.contains("{:snip"));
3228            }
3229
3230            self.out = self.code.to_string();
3231
3232            Ok(())
3233        }
3234    }
3235
3236    /*
3237       {:trans; ... :}
3238    */
3239    fn parse_bif_trans(&mut self) -> Result<(), BifError> {
3240        if self.mod_filter || self.mod_scope {
3241            return Err(BifError {
3242                msg: "modifier not allowed".to_string(),
3243                name: self.alias.clone(),
3244                src: self.raw.to_string(),
3245            });
3246        }
3247
3248        // For performance, we avoid calling BlockParser::new if it is not necessary
3249        if self.src.contains(BIF_OPEN) {
3250            self.src = new_child_parse!(self, &self.src, self.mod_scope);
3251        }
3252
3253        let trans = self.get_trans(&self.src);
3254
3255        // By default the input text
3256        if trans.is_empty() {
3257            if self.mod_negate {
3258                self.out = EMPTY_STRING;
3259            } else {
3260                self.out = self.src.clone();
3261            }
3262        } else {
3263            self.out = trans;
3264        }
3265
3266        Ok(())
3267    }
3268}