lex_core/lex/ast/elements/
annotation.rs1use super::super::range::{Position, Range};
53use super::super::traits::{AstNode, Container, Visitor, VisualStructure};
54use super::container::GeneralContainer;
55use super::content_item::ContentItem;
56use super::data::Data;
57use super::label::Label;
58use super::parameter::Parameter;
59use super::typed_content::ContentElement;
60use std::fmt;
61
62#[derive(Debug, Clone, PartialEq)]
64pub struct Annotation {
65 pub data: Data,
66 pub children: GeneralContainer,
67 pub location: Range,
68}
69
70impl Annotation {
71 fn default_location() -> Range {
72 Range::new(0..0, Position::new(0, 0), Position::new(0, 0))
73 }
74 pub fn new(label: Label, parameters: Vec<Parameter>, children: Vec<ContentElement>) -> Self {
75 let data = Data::new(label, parameters);
76 Self::from_data(data, children)
77 }
78 pub fn marker(label: Label) -> Self {
79 Self::from_data(Data::new(label, Vec::new()), Vec::new())
80 }
81 pub fn with_parameters(label: Label, parameters: Vec<Parameter>) -> Self {
82 Self::from_data(Data::new(label, parameters), Vec::new())
83 }
84 pub fn from_data(data: Data, children: Vec<ContentElement>) -> Self {
85 Self {
86 data,
87 children: GeneralContainer::from_typed(children),
88 location: Self::default_location(),
89 }
90 }
91
92 pub fn at(mut self, location: Range) -> Self {
94 self.location = location;
95 self
96 }
97
98 pub fn header_location(&self) -> &Range {
100 &self.data.location
101 }
102
103 pub fn body_location(&self) -> Option<Range> {
105 Range::bounding_box(self.children.iter().map(|item| item.range()))
106 }
107}
108
109impl AstNode for Annotation {
110 fn node_type(&self) -> &'static str {
111 "Annotation"
112 }
113 fn display_label(&self) -> String {
114 if self.data.parameters.is_empty() {
115 self.data.label.value.clone()
116 } else {
117 format!(
118 "{} ({} params)",
119 self.data.label.value,
120 self.data.parameters.len()
121 )
122 }
123 }
124 fn range(&self) -> &Range {
125 &self.location
126 }
127
128 fn accept(&self, visitor: &mut dyn Visitor) {
129 visitor.visit_annotation(self);
130 super::super::traits::visit_children(visitor, &self.children);
131 visitor.leave_annotation(self);
132 }
133}
134
135impl VisualStructure for Annotation {
136 fn is_source_line_node(&self) -> bool {
137 true
138 }
139
140 fn has_visual_header(&self) -> bool {
141 true
142 }
143}
144
145impl Container for Annotation {
146 fn label(&self) -> &str {
147 &self.data.label.value
148 }
149 fn children(&self) -> &[ContentItem] {
150 &self.children
151 }
152 fn children_mut(&mut self) -> &mut Vec<ContentItem> {
153 self.children.as_mut_vec()
154 }
155}
156
157impl fmt::Display for Annotation {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 write!(
160 f,
161 "Annotation('{}', {} params, {} items)",
162 self.data.label.value,
163 self.data.parameters.len(),
164 self.children.len()
165 )
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use super::*;
172 use crate::lex::ast::elements::paragraph::Paragraph;
173 use crate::lex::ast::elements::typed_content::ContentElement;
174
175 #[test]
176 fn test_annotation_header_and_body_locations() {
177 let header_range = Range::new(0..4, Position::new(0, 0), Position::new(0, 4));
178 let child_range = Range::new(10..20, Position::new(1, 0), Position::new(2, 0));
179 let label = Label::new("note".to_string()).at(header_range.clone());
180 let data = Data::new(label, Vec::new()).at(header_range.clone());
181 let child = ContentElement::Paragraph(
182 Paragraph::from_line("body".to_string()).at(child_range.clone()),
183 );
184
185 let annotation = Annotation::from_data(data, vec![child]).at(Range::new(
186 0..25,
187 Position::new(0, 0),
188 Position::new(2, 0),
189 ));
190
191 assert_eq!(annotation.header_location().span, header_range.span);
192 assert_eq!(annotation.body_location().unwrap().span, child_range.span);
193 }
194}