use std::convert::Infallible;
use serde_json::{Value, json};
use super::{JsonShape, kind_name, rep_name};
use crate::{AstKind, Cursor, Flow, GroupKind, Pattern, Visitor, visit};
impl Pattern {
#[must_use]
pub fn to_json(&self, shape: JsonShape) -> Value {
match shape {
JsonShape::Tree => json!({
"schema_version": 1,
"pattern": self.source(),
"shape": "tree",
"root": run_visitor(self, TreeJson::default()),
}),
JsonShape::Arena => json!({
"schema_version": 1,
"pattern": self.source(),
"shape": "arena",
"root": self.root_id().0,
"nodes": run_visitor(self, ArenaJson::default()),
}),
}
}
}
fn run_visitor<V>(pattern: &Pattern, visitor: V) -> V::Output
where
V: Visitor<Err = Infallible>,
{
match visit(pattern, visitor) {
Ok(output) => output,
Err(error) => match error {},
}
}
#[derive(Default)]
struct TreeJson {
stack: Vec<Value>,
root: Option<Value>,
}
impl Visitor for TreeJson {
type Output = Value;
type Err = Infallible;
fn enter(&mut self, node: Cursor<'_>) -> Result<Flow, Self::Err> {
self.stack.push(node_json(node));
Ok(Flow::Continue)
}
fn leave(&mut self, _node: Cursor<'_>) -> Result<(), Self::Err> {
let completed = self.stack.pop().expect("enter precedes leave");
if let Some(parent) = self.stack.last_mut() {
let object = parent.as_object_mut().expect("node JSON is an object");
object
.entry("children")
.or_insert_with(|| Value::Array(Vec::new()))
.as_array_mut()
.expect("children is an array")
.push(completed);
} else {
self.root = Some(completed);
}
Ok(())
}
fn finish(self) -> Result<Self::Output, Self::Err> {
Ok(self.root.expect("pattern always has a root"))
}
}
#[derive(Default)]
struct ArenaJson {
nodes: Vec<Value>,
}
impl Visitor for ArenaJson {
type Output = Vec<Value>;
type Err = Infallible;
fn enter(&mut self, node: Cursor<'_>) -> Result<Flow, Self::Err> {
self.nodes.push(json!({
"id": node.id().0,
"span": [node.span().start, node.span().end],
"parent": node.parent().map(|parent| parent.id().0),
"kind": kind_name(node.kind()),
"children": node.children().map(|child| child.id().0).collect::<Vec<_>>(),
"text": node.text(),
}));
Ok(Flow::Continue)
}
fn finish(mut self) -> Result<Self::Output, Self::Err> {
self.nodes.sort_by_key(|node| node["id"].as_u64());
Ok(self.nodes)
}
}
fn node_json(cursor: Cursor<'_>) -> Value {
let mut value = json!({
"id": cursor.id().0,
"kind": kind_name(cursor.kind()),
"span": [cursor.span().start, cursor.span().end],
"text": cursor.text(),
});
let object = value.as_object_mut().expect("object literal");
match cursor.kind() {
AstKind::Literal { c, escaped } => {
object.insert("c".into(), json!(c));
object.insert("escaped".into(), json!(escaped));
}
AstKind::Class { negated, set, .. } => {
object.insert("negated".into(), json!(negated));
object.insert("set".into(), json!(set));
}
AstKind::Group { kind, .. } => add_group_fields(object, kind),
AstKind::Repeat { kind, greedy, .. } => {
object.insert("rep".into(), json!(rep_name(*kind)));
object.insert("greedy".into(), json!(greedy));
}
AstKind::Anchor { kind } => {
object.insert("anchor".into(), json!(kind));
}
AstKind::Empty | AstKind::Dot | AstKind::Alt { .. } | AstKind::Concat { .. } => {}
}
value
}
fn add_group_fields(object: &mut serde_json::Map<String, Value>, kind: &GroupKind) {
match kind {
GroupKind::Capture { index, name } => {
object.insert("capture".into(), json!(index));
object.insert("name".into(), json!(name));
}
GroupKind::NonCapture => {
object.insert("capture".into(), Value::Null);
}
}
}