Skip to main content

jjpwrgem_parse/
ast.rs

1use core::range::Range;
2
3use visitor::AstVisitor;
4
5use crate::{Result, tokens::TokenStream, traverse::parse_tokens};
6
7#[derive(Debug, Clone, Default, PartialEq, Eq)]
8pub struct ObjectEntries(pub(crate) Vec<(Range<usize>, Value)>);
9
10impl ObjectEntries {
11    pub(crate) fn new() -> Self {
12        Self(Vec::new())
13    }
14
15    pub(crate) fn push(&mut self, key_range: Range<usize>, v: Value) {
16        self.0.push((key_range, v));
17    }
18
19    pub(crate) fn is_empty(&self) -> bool {
20        self.0.is_empty()
21    }
22
23    pub(crate) fn find<'a>(&'a self, source: &str, key: &str) -> Option<&'a Value> {
24        self.0
25            .iter()
26            .find(|(kr, _)| &source[*kr] == key)
27            .map(|(_, v)| v)
28    }
29}
30
31#[derive(Debug, PartialEq, Eq, Clone)]
32pub enum Value {
33    Null(Range<usize>),
34    /// excludes surrounding quotes
35    String(Range<usize>),
36    Number {
37        mantissa: Range<usize>,
38        exponent: Option<Range<usize>>,
39    },
40    Object(Range<usize>, ObjectEntries),
41    Array(Range<usize>, Vec<Value>),
42    Boolean(Range<usize>, bool),
43}
44
45impl Value {
46    pub fn range(&self) -> Range<usize> {
47        match self {
48            Value::Null(r)
49            | Value::String(r)
50            | Value::Boolean(r, _)
51            | Value::Object(r, _)
52            | Value::Array(r, _) => *r,
53            Value::Number { mantissa, exponent } => {
54                mantissa.start..exponent.map_or(mantissa.end, |e| e.end)
55            }
56        }
57    }
58
59    pub(crate) fn to_f64(&self, source: &str) -> Option<f64> {
60        let Value::Number { mantissa, exponent } = self else {
61            return None;
62        };
63        let m = &source[*mantissa];
64        if let Some(exponent) = exponent {
65            let e = &source[*exponent];
66            format!("{m}e{e}").parse().ok()
67        } else {
68            m.parse().ok()
69        }
70    }
71}
72
73#[derive(Debug, Clone, PartialEq, Eq)]
74pub struct Document<S> {
75    pub(crate) source: S,
76    pub(crate) root: Value,
77}
78
79impl<S: AsRef<str>> Document<S> {
80    pub fn parse(source: S) -> Result<Self> {
81        let root = {
82            let text = source.as_ref();
83            parse_at(text, 0..text.len())?.root
84        };
85        Ok(Self { source, root })
86    }
87
88    pub fn root(&self) -> &Value {
89        &self.root
90    }
91
92    pub fn slice(&self, range: Range<usize>) -> &str {
93        &self.source.as_ref()[range]
94    }
95
96    pub fn get_object_value<'a>(&self, entries: &'a ObjectEntries, key: &str) -> Option<&'a Value> {
97        entries.find(self.source.as_ref(), key)
98    }
99
100    pub fn as_str<'a>(&'a self, value: &Value) -> Option<&'a str> {
101        match value {
102            Value::String(r) => Some(self.slice(*r)),
103            _ => None,
104        }
105    }
106
107    pub fn parse_f64(&self, value: &Value) -> Option<f64> {
108        value.to_f64(self.source.as_ref())
109    }
110}
111
112pub(crate) fn parse_at(full_source: &str, range: Range<usize>) -> Result<Document<&str>> {
113    let mut ast = AstVisitor::new();
114    parse_tokens(
115        &mut TokenStream::new_at_range(full_source, range),
116        full_source,
117        true,
118        &mut ast,
119    )?;
120    let root = ast
121        .finish()
122        .expect("visitor should error if empty or unfinished");
123    Ok(Document {
124        source: full_source,
125        root,
126    })
127}
128
129mod visitor {
130    use core::range::Range;
131
132    use crate::{
133        ast::{ObjectEntries, Value},
134        traverse::Visitor,
135    };
136
137    #[derive(Debug, Default)]
138    pub struct AstVisitor {
139        stack: Vec<AstFrame>,
140        result: Option<Value>,
141    }
142
143    #[derive(Debug)]
144    enum AstFrame {
145        Object {
146            open_range: Range<usize>,
147            entries: ObjectEntries,
148            current_key: Option<Range<usize>>,
149        },
150        Array {
151            open_range: Range<usize>,
152            items: Vec<Value>,
153        },
154    }
155
156    impl AstVisitor {
157        pub fn new() -> Self {
158            Self {
159                stack: Vec::new(),
160                result: None,
161            }
162        }
163
164        fn last_emitted_mut(&mut self) -> &mut Value {
165            match self.stack.last_mut() {
166                None => self.result.as_mut().expect("must have emitted a value"),
167                Some(AstFrame::Array { items, .. }) => items.last_mut().expect("must have item"),
168                Some(AstFrame::Object { entries, .. }) => {
169                    &mut entries.0.last_mut().expect("must have entry").1
170                }
171            }
172        }
173
174        fn emit_value(&mut self, value: Value) {
175            match self.stack.last_mut() {
176                None => {
177                    self.result = Some(value);
178                }
179                Some(frame) => match frame {
180                    AstFrame::Array { items, .. } => items.push(value),
181                    AstFrame::Object {
182                        entries,
183                        current_key,
184                        ..
185                    } => {
186                        let k = current_key
187                            .take()
188                            .expect("the traverser should not emit a value before the key");
189                        entries.push(k, value);
190                    }
191                },
192            }
193        }
194
195        pub fn finish(self) -> Option<Value> {
196            self.result
197        }
198    }
199
200    impl<'a> Visitor<'a> for AstVisitor {
201        fn on_object_open(&mut self, range: Range<usize>) {
202            self.stack.push(AstFrame::Object {
203                open_range: range,
204                entries: ObjectEntries::new(),
205                current_key: None,
206            });
207        }
208
209        fn on_object_key(&mut self, range: Range<usize>, _key: &'a str) {
210            if let Some(AstFrame::Object { current_key, .. }) = self.stack.last_mut() {
211                *current_key = Some(range);
212            } else {
213                unreachable!("must be in object for object key")
214            }
215        }
216
217        fn on_object_close(&mut self, close_range: Range<usize>) {
218            let frame = self
219                .stack
220                .pop()
221                .expect("traverser will not emit unbalanced brackets");
222            if let AstFrame::Object {
223                open_range,
224                entries,
225                ..
226            } = frame
227            {
228                self.emit_value(Value::Object(open_range.start..close_range.end, entries));
229            } else {
230                unreachable!("must be an object to close object")
231            }
232        }
233
234        fn on_array_open(&mut self, range: Range<usize>) {
235            self.stack.push(AstFrame::Array {
236                open_range: range,
237                items: Vec::new(),
238            });
239        }
240
241        fn on_array_close(&mut self, close_range: Range<usize>) {
242            let frame = self
243                .stack
244                .pop()
245                .expect("traverser will not emit unbalanced brackets");
246            if let AstFrame::Array { open_range, items } = frame {
247                self.emit_value(Value::Array(open_range.start..close_range.end, items));
248            } else {
249                unreachable!("must be an array to close array")
250            }
251        }
252
253        fn on_null(&mut self, range: Range<usize>) {
254            self.emit_value(Value::Null(range));
255        }
256
257        fn on_string(&mut self, range: Range<usize>, _s: &'a str) {
258            self.emit_value(Value::String(range));
259        }
260
261        fn on_mantissa(&mut self, range: Range<usize>, _mantissa: &'a str) {
262            self.emit_value(Value::Number {
263                mantissa: range,
264                exponent: None,
265            });
266        }
267
268        fn on_exponent(&mut self, range: Range<usize>, _exponent: &'a str) {
269            let Value::Number { exponent, .. } = self.last_emitted_mut() else {
270                unreachable!("exponent must follow mantissa")
271            };
272            *exponent = Some(range);
273        }
274
275        fn on_boolean(&mut self, range: Range<usize>, b: bool) {
276            self.emit_value(Value::Boolean(range, b));
277        }
278
279        fn on_object_key_val_delim(&mut self) {}
280        fn on_item_delim(&mut self) {}
281    }
282}
283
284#[cfg(test)]
285mod tests {
286    use super::*;
287
288    fn range_of(source: &str, needle: &str) -> Range<usize> {
289        let start = source.find(needle).expect("needle in source");
290        start..start + needle.len()
291    }
292
293    fn make_obj(entries: Vec<(&str, Value)>, source: &str) -> Value {
294        let entries = entries
295            .into_iter()
296            .map(|(k, v)| (range_of(source, k), v))
297            .collect::<Vec<_>>();
298        Value::Object(0..source.len(), ObjectEntries(entries))
299    }
300
301    #[test]
302    fn empty_object() {
303        let doc = Document::parse("{}").unwrap();
304        assert_eq!(doc.root(), &Value::Object(0..2, ObjectEntries::new()));
305    }
306
307    #[test]
308    fn one_key_value_pair() {
309        let json = r#"{"hi":"bye"}"#;
310        let doc = Document::parse(json).unwrap();
311        assert_eq!(
312            doc.root(),
313            &make_obj(vec![("hi", Value::String(range_of(json, "bye")))], json)
314        );
315    }
316
317    #[rstest_reuse::template]
318    #[rstest::rstest]
319    #[case("null", |s: &str| Value::Null(range_of(s, "null")))]
320    #[case("true", |s: &str| Value::Boolean(range_of(s, "true"), true))]
321    #[case("false", |s: &str| Value::Boolean(range_of(s, "false"), false))]
322    #[case("\"burger\"", |s: &str| Value::String(range_of(s, "burger")))]
323    fn primitive_template(#[case] primitive: &str, #[case] expected: fn(&str) -> Value) {}
324
325    #[rstest_reuse::apply(primitive_template)]
326    fn primitive_object_value(#[case] primitive: &str, #[case] expected: fn(&str) -> Value) {
327        let json = format!(
328            r#"{{
329                "rust": {primitive}
330            }}"#
331        );
332        let doc = Document::parse(&json).unwrap();
333        let want = make_obj(vec![("rust", expected(&json))], &json);
334        assert_eq!(doc.root(), &want);
335    }
336
337    #[rstest_reuse::apply(primitive_template)]
338    fn primitives(#[case] json: &str, #[case] expected: fn(&str) -> Value) {
339        let doc = Document::parse(json).unwrap();
340        assert_eq!(doc.root(), &expected(json));
341    }
342}