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
use super::{context::Context, node::Node};

pub trait Branch<BranchNodes>
where
    BranchNodes: Node,
{
    fn push<CanBeNode: Into<BranchNodes>>(&mut self, node: CanBeNode);
    fn get_maybe_nodes() -> Vec<MaybeNode<BranchNodes>>;
    fn get_fallback_node() -> Option<DefinitelyNode<BranchNodes>>;
    fn get_outer_token_length(&self) -> usize;

    fn parse_branch(input: &str, mut branch: Self) -> Option<Self>
    where
        Self: Sized + Deserializer + Node,
    {
        let mut current_position = 0;
        let mut fallback_position = 0;
        let fallback_node = Self::get_fallback_node();
        let maybe_nodes = Self::get_maybe_nodes();
        while current_position < input.len() {
            let slice = &input[current_position..];
            current_position += slice.chars().next().unwrap().len_utf8();
            if maybe_nodes.is_empty() {
                match fallback_node.as_ref() {
                    Some(fallback_node) => {
                        branch.push(fallback_node(slice));
                        current_position = branch.len() - branch.get_outer_token_length();
                        fallback_position = current_position;
                    }
                    None => return None,
                }
                continue;
            }
            for parser in &maybe_nodes {
                if let Some(node) = parser(slice, branch.context()) {
                    if fallback_position != current_position - 1 {
                        match &fallback_node {
                            Some(fallback_node) => branch.push(fallback_node(
                                &input[fallback_position..current_position - 1],
                            )),
                            None => return None,
                        }
                    }
                    branch.push(node);
                    current_position = branch.len() - branch.get_outer_token_length();
                    fallback_position = current_position;
                }
            }
        }
        if fallback_position < input.len() {
            match fallback_node {
                Some(fallback_node) => branch.push(fallback_node(&input[fallback_position..])),
                None => return None,
            }
        }

        Some(branch)
    }
}

pub type MaybeNode<BranchNodes> = Box<dyn Fn(&str, Option<Context>) -> Option<BranchNodes>>;
pub type DefinitelyNode<BranchNodes> = Box<dyn Fn(&str) -> BranchNodes>;

pub trait FallbackNode {
    fn fallback_node<BranchNodes>() -> DefinitelyNode<BranchNodes>
    where
        Self: Into<BranchNodes>;
}

pub trait Deserializer {
    fn deserialize_with_context(input: &str, ctx: Option<Context>) -> Option<Self>
    where
        Self: Sized;

    fn deserialize(input: &str) -> Option<Self>
    where
        Self: Sized,
    {
        Self::deserialize_with_context(input, None)
    }
}