//! Syntax tree definitions with change metadata.
#![allow(clippy::mutable_key_type)] // Hash for Syntax doesn't use mutable fields.
use std::{cell::Cell, env, fmt, hash::Hash, num::NonZeroU32};
use line_numbers::LinePositions;
use line_numbers::SingleLineSpan;
use typed_arena::Arena;
use self::Syntax::*;
use crate::lines::split_on_newlines;
use crate::words::split_words_and_numbers;
use crate::{
diff::changes::ChangeKind,
diff::changes::{ChangeKind::*, ChangeMap},
diff::myers_diff,
hash::DftHashMap,
lines::is_all_whitespace,
};
/// A Debug implementation that does not recurse into the
/// corresponding node mentioned for Unchanged. Otherwise we will
/// infinitely loop on unchanged nodes, which both point to the other.
impl<'a> fmt::Debug for ChangeKind<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let desc = match self {
Unchanged(node) => format!("Unchanged(ID: {})", node.id()),
ReplacedComment(lhs_node, rhs_node) | ReplacedString(lhs_node, rhs_node) => {
let change_kind = if let ReplacedComment(_, _) = self {
"ReplacedComment"
} else {
"ReplacedString"
};
format!(
"{}(lhs ID: {}, rhs ID: {})",
change_kind,
lhs_node.id(),
rhs_node.id()
)
}
Novel => "Novel".to_owned(),
};
f.write_str(&desc)
}
}
pub(crate) type SyntaxId = NonZeroU32;
/// Fields that are common to both `Syntax::List` and `Syntax::Atom`.
pub(crate) struct SyntaxInfo<'a> {
/// The previous node with the same parent as this one.
previous_sibling: Cell<Option<&'a Syntax<'a>>>