jawk/
processor.rs

1use std::collections::HashMap;
2use std::ops::Deref;
3use std::prelude::v1::Result as StdResult;
4use std::rc::Rc;
5
6use indexmap::IndexMap;
7use regex::Regex;
8use std::fmt::Error as FormatError;
9use std::io::Error as IoError;
10use thiserror::Error;
11
12use crate::json_value::JsonValue;
13use crate::reader::Location;
14use crate::regex_cache::{RegexCache, RegexCompile};
15use crate::selection::Get;
16
17use regex::Error as RegexError;
18
19#[derive(Debug, Error)]
20pub enum ProcessError {
21    #[error("{0}")]
22    Format(#[from] FormatError),
23    #[error("{0}")]
24    Io(#[from] IoError),
25    #[error("{0}")]
26    InvalidInputError(&'static str),
27}
28
29#[derive(Default)]
30pub struct Titles {
31    titles: Vec<Rc<String>>,
32}
33
34impl Titles {
35    pub fn with_title(&self, title: &Rc<String>) -> Self {
36        let mut titles = self.titles.clone();
37        titles.push(title.clone());
38        Titles { titles }
39    }
40
41    pub fn len(&self) -> usize {
42        self.titles.len()
43    }
44
45    pub fn to_list(&self) -> Vec<Option<JsonValue>> {
46        let mut lst = Vec::with_capacity(self.titles.len());
47        for str in &self.titles {
48            let value = Some(str.deref().clone().into());
49            lst.push(value);
50        }
51        lst
52    }
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, Hash)]
56pub enum ContextKey {
57    Value(JsonValue),
58    Results(Vec<Option<JsonValue>>),
59}
60
61#[derive(Clone)]
62pub struct InputContext {
63    pub start_location: Location,
64    pub end_location: Location,
65    pub file_index: u64,
66    pub index: u64,
67}
68
69pub struct Context {
70    input: Rc<JsonValue>,
71    results: Vec<(Rc<String>, Option<JsonValue>)>,
72    parent_inputs: Vec<Rc<JsonValue>>,
73    variables: Rc<HashMap<String, JsonValue>>,
74    definitions: Rc<HashMap<String, Rc<dyn Get>>>,
75    input_context: Option<Rc<InputContext>>,
76    regex_cache: RegexCache,
77}
78
79impl Context {
80    pub fn new_empty() -> Self {
81        Context {
82            input: Rc::new(JsonValue::Null),
83            results: Vec::new(),
84            parent_inputs: Vec::new(),
85            variables: Rc::new(HashMap::new()),
86            definitions: Rc::new(HashMap::new()),
87            input_context: None,
88            regex_cache: RegexCache::new(0),
89        }
90    }
91    pub fn new_with_no_context(input: JsonValue) -> Self {
92        Context {
93            input: Rc::new(input),
94            results: Vec::new(),
95            parent_inputs: Vec::new(),
96            variables: Rc::new(HashMap::new()),
97            definitions: Rc::new(HashMap::new()),
98            input_context: None,
99            regex_cache: RegexCache::new(0),
100        }
101    }
102    pub fn new_with_input(
103        input: JsonValue,
104        start_location: Location,
105        end_location: Location,
106        file_index: u64,
107        index: u64,
108        regex_cache: &RegexCache,
109    ) -> Self {
110        let input_context = InputContext {
111            start_location,
112            end_location,
113            file_index,
114            index,
115        };
116        Context {
117            input: Rc::new(input),
118            results: Vec::new(),
119            parent_inputs: Vec::new(),
120            variables: Rc::new(HashMap::new()),
121            definitions: Rc::new(HashMap::new()),
122            input_context: Some(Rc::new(input_context)),
123            regex_cache: regex_cache.clone(),
124        }
125    }
126    pub fn with_inupt(&self, value: JsonValue) -> Self {
127        let input = Rc::new(value);
128        let mut parent_inputs = Vec::with_capacity(self.parent_inputs.len() + 1);
129        parent_inputs.push(self.input.clone());
130        for i in &self.parent_inputs {
131            parent_inputs.push(i.clone());
132        }
133        Context {
134            input,
135            results: Vec::new(),
136            parent_inputs,
137            variables: self.variables.clone(),
138            definitions: self.definitions.clone(),
139            input_context: self.input_context.clone(),
140            regex_cache: self.regex_cache.clone(),
141        }
142    }
143    pub fn with_result(&self, title: &Rc<String>, result: Option<JsonValue>) -> Self {
144        let mut results = self.results.clone();
145        results.push((title.clone(), result));
146        Context {
147            input: self.input().clone(),
148            results,
149            parent_inputs: Vec::new(),
150            variables: self.variables.clone(),
151            definitions: self.definitions.clone(),
152            input_context: self.input_context.clone(),
153            regex_cache: self.regex_cache.clone(),
154        }
155    }
156    pub fn with_variable(&self, name: String, value: JsonValue) -> Self {
157        let mut variables = HashMap::with_capacity(self.variables.len() + 1);
158        for (k, v) in &*self.variables {
159            variables.insert(k.clone(), v.clone());
160        }
161        variables.insert(name, value);
162        Context {
163            input: self.input().clone(),
164            results: self.results.clone(),
165            parent_inputs: Vec::new(),
166            variables: Rc::new(variables),
167            definitions: self.definitions.clone(),
168            input_context: self.input_context.clone(),
169            regex_cache: self.regex_cache.clone(),
170        }
171    }
172    pub fn with_variables(&self, variables: &Rc<HashMap<String, JsonValue>>) -> Self {
173        Context {
174            input: self.input().clone(),
175            results: self.results.clone(),
176            parent_inputs: Vec::new(),
177            variables: variables.clone(),
178            definitions: self.definitions.clone(),
179            input_context: self.input_context.clone(),
180            regex_cache: self.regex_cache.clone(),
181        }
182    }
183    pub fn with_definition(&self, name: String, definition: &Rc<dyn Get>) -> Self {
184        let mut definitions = HashMap::with_capacity(self.definitions.len() + 1);
185        for (k, d) in &*self.definitions {
186            definitions.insert(k.clone(), d.clone());
187        }
188        definitions.insert(name, definition.clone());
189        Context {
190            input: self.input().clone(),
191            results: self.results.clone(),
192            parent_inputs: Vec::new(),
193            variables: self.variables.clone(),
194            definitions: Rc::new(definitions),
195            input_context: self.input_context.clone(),
196            regex_cache: self.regex_cache.clone(),
197        }
198    }
199    pub fn with_definitions(&self, definitions: &Rc<HashMap<String, Rc<dyn Get>>>) -> Self {
200        Context {
201            input: self.input().clone(),
202            results: self.results.clone(),
203            parent_inputs: Vec::new(),
204            variables: self.variables.clone(),
205            definitions: definitions.clone(),
206            input_context: self.input_context.clone(),
207            regex_cache: self.regex_cache.clone(),
208        }
209    }
210    pub fn build(&self) -> JsonValue {
211        if self.results.is_empty() {
212            self.input().deref().clone()
213        } else {
214            let mut mp = IndexMap::new();
215            for (title, value) in &self.results {
216                if let Some(value) = value {
217                    mp.insert(title.deref().clone(), value.clone());
218                }
219            }
220            JsonValue::Object(mp)
221        }
222    }
223    pub fn to_list(&self) -> Vec<Option<JsonValue>> {
224        self.results.iter().map(|i| i.1.clone()).collect()
225    }
226
227    pub fn get_variable_value(&self, name: &String) -> Option<&JsonValue> {
228        self.variables.get(name)
229    }
230
231    pub fn get_definition(&self, name: &String) -> Option<&Rc<dyn Get>> {
232        self.definitions.get(name)
233    }
234
235    pub fn get_selected(&self, name: &String) -> Option<JsonValue> {
236        for (title, result) in &self.results {
237            if &**title == name {
238                return result.clone();
239            }
240        }
241        None
242    }
243
244    pub fn input(&self) -> &Rc<JsonValue> {
245        &self.input
246    }
247
248    pub fn parent_input(&self, count: usize) -> &JsonValue {
249        if count == 0 {
250            self.input()
251        } else {
252            self.parent_inputs
253                .get(count - 1)
254                .unwrap_or_else(|| self.input())
255        }
256    }
257
258    pub fn key(&self) -> ContextKey {
259        if self.results.is_empty() {
260            ContextKey::Value(self.input().deref().clone())
261        } else {
262            ContextKey::Results(self.to_list())
263        }
264    }
265
266    pub fn input_context(&self) -> Option<Rc<InputContext>> {
267        self.input_context.clone()
268    }
269}
270
271impl RegexCompile for Context {
272    fn compile_regex(&self, regex: &str) -> Rc<StdResult<Regex, RegexError>> {
273        self.regex_cache.compile_regex(regex)
274    }
275}
276
277#[derive(Debug, PartialEq)]
278pub enum ProcessDecision {
279    Continue,
280    Break,
281}
282
283pub type Result<T> = std::result::Result<T, ProcessError>;
284
285pub trait Process {
286    fn start(&mut self, titles_so_far: Titles) -> Result<()>;
287    fn process(&mut self, context: Context) -> Result<ProcessDecision>;
288    fn complete(&mut self) -> Result<()>;
289}