neutralts/
block_parser.rs

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