1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
//! The syntax tree.
use std::any::Any;
use std::fmt::Debug;
use crate::layout::Layout;
use super::span::SpanVec;
/// A collection of nodes which form a tree together with the nodes' children.
pub type SyntaxTree = SpanVec<SyntaxNode>;
/// A syntax node, which encompasses a single logical entity of parsed source
/// code.
#[derive(Debug, Clone)]
pub enum SyntaxNode {
/// Whitespace containing less than two newlines.
Spacing,
/// A forced line break.
Linebreak,
/// Italics were enabled / disabled.
ToggleItalic,
/// Bolder was enabled / disabled.
ToggleBolder,
/// Plain text.
Text(String),
/// Lines of raw text.
Raw(Vec<String>),
/// A paragraph of child nodes.
Par(SyntaxTree),
/// A dynamic node, created through function invocations in source code.
Dyn(Box<dyn DynamicNode>),
}
impl SyntaxNode {
/// Create a `Dyn` variant from an unboxed dynamic node.
pub fn boxed<T: DynamicNode + 'static>(node: T) -> SyntaxNode {
SyntaxNode::Dyn(Box::new(node))
}
}
impl PartialEq for SyntaxNode {
fn eq(&self, other: &SyntaxNode) -> bool {
use SyntaxNode::*;
match (self, other) {
(Spacing, Spacing) => true,
(Linebreak, Linebreak) => true,
(ToggleItalic, ToggleItalic) => true,
(ToggleBolder, ToggleBolder) => true,
(Text(a), Text(b)) => a == b,
(Raw(a), Raw(b)) => a == b,
(Par(a), Par(b)) => a == b,
(Dyn(a), Dyn(b)) => a == b,
_ => false,
}
}
}
/// Dynamic syntax nodes.
///
/// *Note*: This is automatically implemented for all types which are
/// `Debug + Clone + PartialEq`, `Layout` and `'static`.
pub trait DynamicNode: Debug + Layout {
/// Convert into a `dyn Any`.
fn as_any(&self) -> &dyn Any;
/// Check for equality with another dynamic node.
fn dyn_eq(&self, other: &dyn DynamicNode) -> bool;
/// Clone into a boxed node trait object.
fn box_clone(&self) -> Box<dyn DynamicNode>;
}
impl dyn DynamicNode {
/// Downcast this dynamic node to a concrete node.
pub fn downcast<T: DynamicNode + 'static>(&self) -> Option<&T> {
self.as_any().downcast_ref::<T>()
}
}
impl PartialEq for dyn DynamicNode {
fn eq(&self, other: &Self) -> bool {
self.dyn_eq(other)
}
}
impl Clone for Box<dyn DynamicNode> {
fn clone(&self) -> Self {
self.box_clone()
}
}
impl<T> DynamicNode for T
where
T: Debug + PartialEq + Clone + Layout + 'static,
{
fn as_any(&self) -> &dyn Any {
self
}
fn dyn_eq(&self, other: &dyn DynamicNode) -> bool {
match other.as_any().downcast_ref::<Self>() {
Some(other) => self == other,
None => false,
}
}
fn box_clone(&self) -> Box<dyn DynamicNode> {
Box::new(self.clone())
}
}
|