Skip to main content

regast_syntax/print/
json.rs

1use std::convert::Infallible;
2
3use serde_json::{Value, json};
4
5use super::{JsonShape, kind_name, rep_name};
6use crate::{AstKind, Cursor, Flow, GroupKind, Pattern, Visitor, visit};
7
8impl Pattern {
9    #[must_use]
10    pub fn to_json(&self, shape: JsonShape) -> Value {
11        match shape {
12            JsonShape::Tree => json!({
13                "schema_version": 1,
14                "pattern": self.source(),
15                "shape": "tree",
16                "root": run_visitor(self, TreeJson::default()),
17            }),
18            JsonShape::Arena => json!({
19                "schema_version": 1,
20                "pattern": self.source(),
21                "shape": "arena",
22                "root": self.root_id().0,
23                "nodes": run_visitor(self, ArenaJson::default()),
24            }),
25        }
26    }
27}
28
29fn run_visitor<V>(pattern: &Pattern, visitor: V) -> V::Output
30where
31    V: Visitor<Err = Infallible>,
32{
33    match visit(pattern, visitor) {
34        Ok(output) => output,
35        Err(error) => match error {},
36    }
37}
38
39#[derive(Default)]
40struct TreeJson {
41    stack: Vec<Value>,
42    root: Option<Value>,
43}
44
45impl Visitor for TreeJson {
46    type Output = Value;
47    type Err = Infallible;
48
49    fn enter(&mut self, node: Cursor<'_>) -> Result<Flow, Self::Err> {
50        self.stack.push(node_json(node));
51        Ok(Flow::Continue)
52    }
53
54    fn leave(&mut self, _node: Cursor<'_>) -> Result<(), Self::Err> {
55        let completed = self.stack.pop().expect("enter precedes leave");
56        if let Some(parent) = self.stack.last_mut() {
57            let object = parent.as_object_mut().expect("node JSON is an object");
58            object
59                .entry("children")
60                .or_insert_with(|| Value::Array(Vec::new()))
61                .as_array_mut()
62                .expect("children is an array")
63                .push(completed);
64        } else {
65            self.root = Some(completed);
66        }
67        Ok(())
68    }
69
70    fn finish(self) -> Result<Self::Output, Self::Err> {
71        Ok(self.root.expect("pattern always has a root"))
72    }
73}
74
75#[derive(Default)]
76struct ArenaJson {
77    nodes: Vec<Value>,
78}
79
80impl Visitor for ArenaJson {
81    type Output = Vec<Value>;
82    type Err = Infallible;
83
84    fn enter(&mut self, node: Cursor<'_>) -> Result<Flow, Self::Err> {
85        self.nodes.push(json!({
86            "id": node.id().0,
87            "span": [node.span().start, node.span().end],
88            "parent": node.parent().map(|parent| parent.id().0),
89            "kind": kind_name(node.kind()),
90            "children": node.children().map(|child| child.id().0).collect::<Vec<_>>(),
91            "text": node.text(),
92        }));
93        Ok(Flow::Continue)
94    }
95
96    fn finish(mut self) -> Result<Self::Output, Self::Err> {
97        self.nodes.sort_by_key(|node| node["id"].as_u64());
98        Ok(self.nodes)
99    }
100}
101
102fn node_json(cursor: Cursor<'_>) -> Value {
103    let mut value = json!({
104        "id": cursor.id().0,
105        "kind": kind_name(cursor.kind()),
106        "span": [cursor.span().start, cursor.span().end],
107        "text": cursor.text(),
108    });
109    let object = value.as_object_mut().expect("object literal");
110    match cursor.kind() {
111        AstKind::Literal { c, escaped } => {
112            object.insert("c".into(), json!(c));
113            object.insert("escaped".into(), json!(escaped));
114        }
115        AstKind::Class { negated, set, .. } => {
116            object.insert("negated".into(), json!(negated));
117            object.insert("set".into(), json!(set));
118        }
119        AstKind::Group { kind, .. } => add_group_fields(object, kind),
120        AstKind::Repeat { kind, greedy, .. } => {
121            object.insert("rep".into(), json!(rep_name(*kind)));
122            object.insert("greedy".into(), json!(greedy));
123        }
124        AstKind::Anchor { kind } => {
125            object.insert("anchor".into(), json!(kind));
126        }
127        AstKind::Empty | AstKind::Dot | AstKind::Alt { .. } | AstKind::Concat { .. } => {}
128    }
129    value
130}
131
132fn add_group_fields(object: &mut serde_json::Map<String, Value>, kind: &GroupKind) {
133    match kind {
134        GroupKind::Capture { index, name } => {
135            object.insert("capture".into(), json!(index));
136            object.insert("name".into(), json!(name));
137        }
138        GroupKind::NonCapture => {
139            object.insert("capture".into(), Value::Null);
140        }
141    }
142}