neutralts/
block_parser.rs

1use serde_json::json;
2use crate::{
3    constants::*,
4    utils::*,
5    shared::Shared,
6    bif::Bif
7};
8
9pub(crate) struct BlockInherit {
10    pub(crate) indir: String,
11    pub(crate) last_bif_out: bool,
12    pub(crate) last_coalesce_out: bool,
13    pub(crate) block_count: u64, // u64 is default type in Value nums
14    pub(crate) bif_count: u64,   // u64 is default type in Value nums
15    pub(crate) alias: String,
16    pub(crate) current_file: String,
17    pub(crate) current_dir: String,
18    pub(crate) include_files: Vec<String>,
19    pub(crate) locale_files: Vec<String>,
20    pub(crate) data_files: Vec<String>,
21    pub(crate) in_cache: bool,
22    pub(crate) in_only: bool,
23}
24
25impl Clone for BlockInherit {
26    fn clone(&self) -> Self {
27        BlockInherit {
28            indir: self.indir.clone(),
29            last_bif_out: self.last_bif_out,
30            last_coalesce_out: self.last_coalesce_out,
31            block_count: self.block_count,
32            bif_count: self.bif_count,
33            alias: self.alias.clone(),
34            current_file: self.current_file.clone(),
35            current_dir: self.current_dir.clone(),
36            include_files: self.include_files.clone(),
37            locale_files: self.locale_files.clone(),
38            data_files: self.data_files.clone(),
39            in_cache: self.in_cache,
40            in_only: self.in_only,
41        }
42    }
43}
44
45impl BlockInherit {
46    pub(crate) fn new() -> Self {
47        BlockInherit {
48            indir: "block_0".to_string(),
49            last_bif_out: false,
50            last_coalesce_out: false,
51            block_count: 0,
52            bif_count: 0,
53            alias: String::new(),
54            current_file: String::new(),
55            current_dir: String::new(),
56            include_files: Vec::new(),
57            locale_files: Vec::new(),
58            data_files: Vec::new(),
59            in_cache: false,
60            in_only: false,
61        }
62    }
63
64    // Create version of data for inheritance at the block level.
65    // For performance reasons, instead of inheriting the complete cloned schema,
66    // we inherit a reference to the data in the root schema.
67    // Therefore, this function should be called before creating data
68    // that needs to be inherited to obtain the reference to the storage.
69    pub(crate) fn create_block_schema(&mut self, shared: &mut Shared) -> String {
70        let prev_id = self.indir.clone();
71        let block_id;
72
73        // If this function is called before creating the first block.
74        // It may be necessary to initialize values.
75        // The first block is not 0, is 1.
76        if self.block_count < 1 {
77            block_id = "block_1".to_string();
78        } else {
79            block_id = "block_".to_string() + self.block_count.to_string().as_str();
80        }
81
82        // It can be called several times from the same level, in which case
83        // it does not need to be cloned again.
84        if prev_id != block_id {
85            shared.schema["__indir"][&block_id] = shared.schema["__indir"][&prev_id].clone();
86        }
87
88        self.indir = block_id.clone();
89
90        block_id
91    }
92}
93
94
95pub(crate) struct BlockParser<'a> {
96    shared: &'a mut Shared,
97    inherit: BlockInherit,
98    _none: &'a str,
99}
100
101impl Drop for BlockParser<'_> {
102    fn drop(&mut self) {
103        // release memory
104        let block_id = "block_".to_string() + self.inherit.block_count.to_string().as_str();
105
106        // The first main block cannot be deleted
107        if block_id != "block_1" {
108            if block_id == self.inherit.indir && is_defined_key(&self.shared.schema["__indir"], &block_id) {
109                self.shared.schema["__indir"][&block_id] = json!({});
110            }
111        }
112    }
113}
114
115impl<'a> BlockParser<'a> {
116    pub(crate) fn new(shared: &'a mut Shared, inherit: &BlockInherit) -> Self {
117        let mut inherit = inherit.clone();
118        inherit.block_count += 1;
119
120        BlockParser {
121            shared,
122            inherit,
123            _none: "",
124        }
125    }
126
127    pub(crate) fn update_indir(&mut self, indir: &String) {
128        self.shared.schema["__indir"][indir] =
129            self.shared.schema["__indir"][&self.inherit.indir].clone();
130    }
131
132    pub(crate) fn parse(&mut self, raw_source: &'a str, only: &str) -> String {
133        let blocks;
134
135        match extract_blocks(raw_source) {
136            Ok(b) => {
137                blocks = b;
138            }
139            Err(p) => {
140                self.shared.status_code = "500".to_string();
141                self.shared.status_param = format!("Unmatched block at position {}", p);
142                eprintln!("Unmatched block at position {}", p);
143
144                if let Some(text) = STATUS_CODES.get(self.shared.status_code.as_str()) {
145                    self.shared.status_text = text.to_string();
146                } else {
147                    self.shared.status_text = EMPTY_STRING;
148                }
149
150                return EMPTY_STRING;
151            }
152        }
153
154        let mut prev_end = 0;
155        let mut out = String::new();
156        for (start, end) in blocks {
157            let is_comment = raw_source[start..end].starts_with(BIF_COMMENT_OPEN);
158            let is_short_circuit_coalesce =
159                self.inherit.last_coalesce_out && self.inherit.alias == "coalesce";
160
161            if self.shared.exit {
162                return out.clone();
163            }
164
165            if prev_end < start {
166                out += &raw_source[prev_end..start];
167            }
168
169            if !is_comment && !is_short_circuit_coalesce {
170                let mut bif =
171                    Bif::new(&raw_source[start..end], self.shared, &mut self.inherit, only);
172                out += &bif.parse();
173            }
174
175            prev_end = end;
176        }
177        out += &raw_source[prev_end..];
178
179        out.trim().to_string()
180    }
181}