node/visitor: add GraphVisitor Visitor impl

This commit is contained in:
Paul Stemmet 2022-04-16 13:57:59 +00:00
parent 4d10d0e4b3
commit 88a291e145
Signed by: Paul Stemmet
GPG key ID: EDEA539F594E7E75
2 changed files with 216 additions and 0 deletions

View file

@ -0,0 +1,215 @@
/*
* This Source Code Form is subject to the terms of the
* Mozilla Public License, v. 2.0. If a copy of the MPL
* was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
use crate::node::{
error::{NodeError, NodeResult as Result},
graph::Storage,
nodes::{
alias::AliasNode, mapping::MappingNode, scalar::ScalarNode, sequence::SequenceNode, Node,
NodeData, NodeIndex,
},
visitor::{
transform::{TransformAlias, TransformLeaf, TransformMapping, TransformSequence},
Context, VisitAlias, VisitLeaf, VisitMapping, VisitSequence, Visitor,
},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(in crate::node) struct GraphVisitor;
impl Visitor for GraphVisitor
{
fn visit_leaf<'de>(
&self,
cxt: &mut Context<'de>,
graph: &mut Storage<'de>,
mut node: VisitLeaf<'de>,
) -> Result<NodeIndex>
{
let (scalar, data) = TransformLeaf::new(cxt, &mut node).consume()?;
let id = match cxt.current
{
Some(parent) =>
{
let init = ScalarNode::new_with_data(parent, scalar);
graph.insert(Node::scalar(init), data)
},
None =>
{
let init = ScalarNode::root_with_data(scalar);
graph.insert(Node::scalar(init), data)
},
};
update_context_from_node_data(cxt, &*graph, id)?;
connect_node_index(cxt, graph, id)?;
Ok(id)
}
fn visit_alias<'de>(
&self,
cxt: &mut Context<'de>,
graph: &mut Storage<'de>,
mut node: VisitAlias<'de>,
) -> Result<NodeIndex>
{
let (alias, data) = TransformAlias::new(&*cxt, &mut node).consume()?;
// Alias nodes *cannot* be root nodes
let parent = cxt.current.ok_or(NodeError::UndefinedAlias)?;
let init = AliasNode::new_with_data(parent, alias);
let id = graph.insert(Node::alias(init), data);
update_context_from_node_data(cxt, &*graph, id)?;
connect_node_index(cxt, graph, id)?;
Ok(id)
}
fn visit_sequence<'de>(
&self,
cxt: &mut Context<'de>,
graph: &mut Storage<'de>,
mut node: VisitSequence<'de>,
) -> Result<NodeIndex>
{
let data = TransformSequence::new(&*cxt, &mut node).consume()?;
let id = match cxt.current
{
Some(parent) =>
{
let init = SequenceNode::new_with(parent);
graph.insert(Node::sequence(init), data)
},
None =>
{
let init = SequenceNode::root_with();
graph.insert(Node::sequence(init), data)
},
};
update_context_from_node_data(cxt, &*graph, id)?;
connect_node_index(cxt, graph, id)?;
Ok(id)
}
fn visit_mapping<'de>(
&self,
cxt: &mut Context<'de>,
graph: &mut Storage<'de>,
mut node: VisitMapping<'de>,
) -> Result<NodeIndex>
{
let data = TransformMapping::new(&*cxt, &mut node).consume()?;
let id = match cxt.current
{
Some(parent) =>
{
let init = MappingNode::new_with(parent);
graph.insert(Node::mapping(init), data)
},
None =>
{
let init = MappingNode::root_with();
graph.insert(Node::mapping(init), data)
},
};
update_context_from_node_data(cxt, &*graph, id)?;
connect_node_index(cxt, graph, id)?;
Ok(id)
}
}
/// Update the current context with any additional state
/// that should be stored from the given node_id's data.
///
/// ## Panics
///
/// The given node_id should point to a valid live node
/// in the given Graph. It is considered programmer
/// error to not provide such a node_id, and this
/// function may panic.
fn update_context_from_node_data<'de>(
cxt: &mut Context<'de>,
graph: &Storage<'de>,
node_id: NodeIndex,
) -> Result<()>
{
let node_data = graph.node_data().get(node_id);
// It is a logic error to pass a node_id who's data has been
// deleted
debug_assert!(node_data.is_some());
// Add the node's anchor to our context, replacing the
// existing anchor if one exists.
if let Some(anchor) = node_data.and_then(NodeData::anchor)
{
cxt.aliases.insert(anchor.clone(), node_id);
}
Ok(())
}
/// Connect the given node_id into the provided graph,
/// situating it in the current parent node.
///
/// ## Panics
///
/// It is a logic error to call this function if the
/// current parent node is not either a mapping or
/// sequence node, as they are the only kinds of nodes
/// that _can_ have children. Do so will result in a
/// panic, as is considered programmer error.
fn connect_node_index<'de>(
cxt: &mut Context<'de>,
graph: &mut Storage<'de>,
node_id: NodeIndex,
) -> Result<()>
{
if let Some(parent) = cxt.current
{
match graph.nodes_mut()[parent]
{
// If we're a child of a mapping node, we need to add ourselves to either the
// key or value position
Node::Map(ref mut map) => match cxt.mapping_last_node.take()
{
// Found a key stored, so we're a value node, insert ourselves
Some(key_id) =>
{
map.children_mut().insert(key_id, Some(node_id));
},
// No key found, so we're a key node then; insert ourselves into the
// map, and prime the context for later
None =>
{
map.children_mut().insert(node_id, None);
cxt.mapping_last_node = Some(node_id);
},
},
// Push the node onto the sequence node's children stack
Node::List(ref mut list) => list.children_mut().push(node_id),
// Leaf and Alias nodes are never parent nodes
Node::Leaf(_) | Node::Alias(_) => unreachable!(),
}
}
Ok(())
}

View file

@ -12,6 +12,7 @@ use crate::{
token::Slice, token::Slice,
}; };
mod graph_visitor;
mod transform; mod transform;
pub(in crate::node) trait Visitor pub(in crate::node) trait Visitor