use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct AstNode {
pub node_type: NodeType,
pub text: String,
pub children: Vec<AstNode>,
pub position: Option<Position>,
pub attributes: HashMap<String, String>,
pub attribute_keys: Vec<String>,
}
impl AstNode {
pub fn new(node_type: NodeType, text: impl Into<String>) -> Self {
Self {
node_type,
text: text.into(),
children: Vec::new(),
position: None,
attributes: HashMap::new(),
attribute_keys: Vec::new(),
}
}
pub fn add_child(mut self, child: AstNode) -> Self {
self.children.push(child);
self
}
pub fn with_position(mut self, position: Position) -> Self {
self.position = Some(position);
self
}
pub fn with_attribute(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
let key = key.into();
if !self.attributes.contains_key(&key) {
self.attribute_keys.push(key.clone());
}
self.attributes.insert(key, value.into());
self
}
pub fn document() -> Self {
Self::new(NodeType::Document, "")
}
pub fn text(text: impl Into<String>) -> Self {
Self::new(NodeType::PlainText, text)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Position {
pub start: usize,
pub end: usize,
pub line: usize,
pub column: usize,
}
impl Position {
pub fn new(start: usize, end: usize, line: usize, column: usize) -> Self {
Self {
start,
end,
line,
column,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum NodeType {
Document,
Paragraph,
SimpleLine,
EmptyLine,
Section,
PlainText,
PlainTextSpecialChars,
PlainTextEmphasis,
ShortBreak,
Break,
ShortEmphasisModerate,
ShortEmphasisStrong,
ShortEmphasisNone,
ShortEmphasisReduced,
TextModifier,
ShortIpa,
BareIpa,
ShortSub,
Audio,
Mark,
Emphasis,
Voice,
Lang,
Rate,
Pitch,
Volume,
Whisper,
Excited,
Disappointed,
Newscaster,
Dj,
Date,
Time,
Number,
Ordinal,
Characters,
Fraction,
Telephone,
Unit,
Address,
Interjection,
Expletive,
Ipa,
Sub,
}
impl NodeType {
pub fn is_emphasis(&self) -> bool {
matches!(
self,
NodeType::ShortEmphasisModerate
| NodeType::ShortEmphasisStrong
| NodeType::ShortEmphasisNone
| NodeType::ShortEmphasisReduced
| NodeType::Emphasis
)
}
pub fn is_break(&self) -> bool {
matches!(self, NodeType::ShortBreak | NodeType::Break)
}
pub fn is_modifier(&self) -> bool {
matches!(
self,
NodeType::Emphasis
| NodeType::Voice
| NodeType::Lang
| NodeType::Rate
| NodeType::Pitch
| NodeType::Volume
| NodeType::Whisper
| NodeType::Excited
| NodeType::Disappointed
| NodeType::Newscaster
| NodeType::Dj
| NodeType::Date
| NodeType::Time
| NodeType::Number
| NodeType::Ordinal
| NodeType::Characters
| NodeType::Fraction
| NodeType::Telephone
| NodeType::Unit
| NodeType::Address
| NodeType::Interjection
| NodeType::Expletive
| NodeType::Ipa
| NodeType::Sub
)
}
}