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
//! An API for AST representation.

use std::fmt::{Display, Formatter};
use crate::units::Position;

/// Represents a node in an AST
///
/// Used to represent a template code for further evaluation.
///
/// Example:
/// `(plus 1 2)` can be represented as:
/// ```text
///     AnonymousNode {
///         starts_at: 0,
///         children: vec![
///              NamedNode {
///                  identifier: "plus".to_string(),
///                  starts_at: 1,
///                  children: vec![
///                      NamedNode {
///                          identifier: "1".to_string(),
///                          starts_at: 6,
///                          children: vec![],
///                      },
///                      NamedNode {
///                          identifier: "2".to_string(),
///                          starts_at: 8,
///                          children: vec![],
///                      },
///                  ],
///              },
///         ]
///     };
/// ```
///
#[derive(Clone, Debug, PartialEq)]
pub enum SyntaxNode {
    NamedNode {
        identifier: String,
        starts_at: Position,
        children: Vec<SyntaxNode>,
    },
    AnonymousNode {
        starts_at: Position,
        children: Vec<SyntaxNode>,
    },
}

impl SyntaxNode {
    pub fn is_anonymous(&self) -> bool {
        matches!(*self, SyntaxNode::AnonymousNode { .. })
    }

    pub fn add_child(self, child: SyntaxNode) -> SyntaxNode {
        let mut parent = self;
        match parent {
            SyntaxNode::AnonymousNode { ref mut children, .. } => children.push(child),
            SyntaxNode::NamedNode { ref mut children, .. } => children.push(child),
        };
        parent
    }

    pub fn with_identifier(self, new_identifier: &str, identifier_starts_at: Position) -> SyntaxNode {
        match self {
            SyntaxNode::AnonymousNode { children, .. } =>
                SyntaxNode::NamedNode {
                    identifier: new_identifier.to_string(),
                    children,
                    starts_at: identifier_starts_at,
                },

            SyntaxNode::NamedNode { children, .. } =>
                SyntaxNode::NamedNode {
                    identifier: new_identifier.to_string(),
                    children,
                    starts_at: identifier_starts_at,
                },
        }
    }
}

impl Display for SyntaxNode {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            SyntaxNode::AnonymousNode { children, starts_at } =>
                write!(f, "AnonymousNode at {} ({} children)", starts_at, children.len()),
            SyntaxNode::NamedNode { identifier, children, starts_at} =>
                write!(f, "SyntaxNode \"{}\" at {} ({} children)", identifier, starts_at, children.len())
        }
    }
}