diff options
author | JSDurand <mmemmew@gmail.com> | 2023-07-18 11:55:03 +0800 |
---|---|---|
committer | JSDurand <mmemmew@gmail.com> | 2023-07-18 11:58:00 +0800 |
commit | 5a5f7e5be9498af219a36401b1d2a13b553402e8 (patch) | |
tree | 87a0351dc00cda0555193421979a4a312185fe25 /chain/src/item/default | |
parent | 9a5359bcc8d47de7222d07035ae99459d49e810e (diff) |
Fix a bug of unnecessarily cloning nodes.
* chain/src/item/default/splone.rs: Previously when we split nodes, we
always clone the parent if the labels differ. This turns out to be
incorrect if the new label is open whereas the old label is closed.
In that case, the old parent should not contain the new node as a
child, as a closed node should not contain an open node.
I am not yet entirely sure this fix is correct, so more test await
us.
Diffstat (limited to 'chain/src/item/default')
-rw-r--r-- | chain/src/item/default/extract.rs | 16 | ||||
-rw-r--r-- | chain/src/item/default/mod.rs | 3 | ||||
-rw-r--r-- | chain/src/item/default/splone.rs | 26 |
3 files changed, 41 insertions, 4 deletions
diff --git a/chain/src/item/default/extract.rs b/chain/src/item/default/extract.rs index 96f5119..b99c541 100644 --- a/chain/src/item/default/extract.rs +++ b/chain/src/item/default/extract.rs @@ -188,11 +188,25 @@ impl DefaultForest<ForestLabel<GrammarLabel>> { 1 => { let child = *roots_stack.first().unwrap(); - builder.add_vertex(self.vertex_label(child)?.ok_or(Error::NodeNoLabel(child))?); + // Make this a plain node. + // + // This situation will be handled properly in + // later codes. + + let plain_child_label = ForestLabel::new( + self.vertex_label(child)? + .ok_or(Error::NodeNoLabel(child))? + .label(), + ForestLabelType::Plain, + ); + + builder.add_vertex(plain_child_label); } _ => { let builder_root = builder.add_vertex(original_root_label); + // The clone indices have to be preserved so that + // we can track those nodes later. for child in roots_stack.iter().copied() { let child_node = builder.add_vertex( self.vertex_label(child)?.ok_or(Error::NodeNoLabel(child))?, diff --git a/chain/src/item/default/mod.rs b/chain/src/item/default/mod.rs index 0781dd2..7369c6f 100644 --- a/chain/src/item/default/mod.rs +++ b/chain/src/item/default/mod.rs @@ -1,3 +1,4 @@ +#![debugger_visualizer(gdb_script_file = "printer.py")] //! This module provides a default implementation of iten derivation //! forest. @@ -72,6 +73,8 @@ impl From<ForestLabelError> for Error { } } +// FIXME: Provide a better Debug implementation. + /// A default implementation of forest. #[derive(Debug, Clone, Graph)] pub struct DefaultForest<T: GraphLabel> { diff --git a/chain/src/item/default/splone.rs b/chain/src/item/default/splone.rs index 09fca0b..c73bd9f 100644 --- a/chain/src/item/default/splone.rs +++ b/chain/src/item/default/splone.rs @@ -290,7 +290,8 @@ impl DefaultForest<ForestLabel<GrammarLabel>> { /// /// 2. Preserve the old children as specified by `edge_index + 1`. /// - /// 3. For each parent, clone the parent. Replace the original + /// 3. If the new node is closed or if the new node is not cloned, + /// then for each parent, clone the parent. Replace the original /// child of the parent, which pointed to the old node, by this /// new node. Other children are inherited from the old parent. /// @@ -305,15 +306,16 @@ impl DefaultForest<ForestLabel<GrammarLabel>> { completingp: bool, ) -> Result<usize, Error> { let end = new_label.label().end(); + let new_node_is_clone = new_label.clone_index().is_some(); let mut builder = PLGBuilderMut::from_graph_mut(&mut self.graph); let new_node = builder.add_vertex(new_label); - let new_packed = if new_label.clone_index().is_some() { + let new_packed = if new_node_is_clone { let packed = builder .query_label(ForestLabel::new(new_label.label(), ForestLabelType::Packed)) - .unwrap(); + .unwrap_or_else(|| panic!("A cloned node {new_node} without packed nodes")); builder.add_edge(packed, new_node, new_label)?; @@ -328,6 +330,24 @@ impl DefaultForest<ForestLabel<GrammarLabel>> { builder.add_edge(new_node, child, new_label)?; } + // NOTE: If the label of the parent is closed while the node + // label is open ended, we need to use an opened parent + // instead. + // + // To be specific, we only need to split the parent if the new + // label is closed. This can be seen from the fact that this + // function only deals with the situation that the new label + // and the old label are different. In this situation, if the + // new label is closed, it means we are closing a node under + // an open node, and we need to clone that parent indeed. On + // the other hand, if we are opening a node under a closed + // node, that parent does not need to connect to this new + // node. + + if end.is_none() && new_node_is_clone { + return Ok(new_node); + } + let parents: Vec<_> = { if let Some(label) = self.vertex_label(node)? { if label.clone_index().is_some() { |