summaryrefslogtreecommitdiff
path: root/src/parser.rs
blob: 1475fce16b272e980ccdd90a5017c1fde249d789 (plain)
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
use crate::tokenizer::{self, If, Keyword::*, Loop};

pub type SplitWithMetadata<'a> = Vec<(&'a str, Option<Metadata>)>;

pub const EXPRESSION_DELIMITERS: &[char] = &[
    ';', '{', '}',
];

#[derive(Clone, Copy, Debug)]
pub enum Scope {
    If(If),
    Loop(Loop),
}

#[derive(Debug)]
pub enum Metadata {
    StartScope,
    EndScope,
}

#[derive(Debug)]
pub enum ExprT<'a> {
    StartOrStop(bool),
    Decision((&'a str, Scope)),
    IO(&'a str),
    Process(&'a str),
}

#[derive(Debug)]
pub struct Expr<'a> {
    pub expr: ExprT<'a>,
    pub meta: Option<Metadata>,
}

pub fn delimit(s: &str) -> SplitWithMetadata<'_> {
    s.split_inclusive([
        ';', '{', '}',
    ])
    .fold(Vec::new(), |mut acc, part| {
        if let Some((i, ch)) = part
            .char_indices()
            .next_back()
        {
            acc.push((
                if ch == ';' || ch == '{' || ch == '}' {
                    part[..i].trim()
                } else {
                    part.trim()
                },
                None,
            ));
            match ch {
                '{' => {
                    if let Some((_, meta)) = acc.last_mut() {
                        *meta = Some(Metadata::StartScope);
                    }
                }
                '}' => {
                    if let Some((_, meta)) = acc.last_mut() {
                        *meta = Some(Metadata::EndScope);
                    }
                }
                _ => {}
            }
        }
        acc
    })
}

pub fn process(strs: SplitWithMetadata<'_>) -> Vec<Expr<'_>> {
    let mut exprs = Vec::new();

    for (str, meta) in strs {
        let mut exp: Option<ExprT> = None;

        // TODO: fix one line if else as not delimited by {}
        for s in str.split_whitespace() {
            if let Some(token) = tokenizer::parse(s) {
                exp = match token {
                    If(t) => Some(ExprT::Decision((str, Scope::If(t.to_owned())))),
                    Loop(t) => Some(ExprT::Decision((str, Scope::Loop(t.to_owned())))),
                    Throw => Some(ExprT::IO(str)),
                    IO => Some(ExprT::IO(str)),
                }
            }
        }

        match exp {
            Some(expr) => exprs.push(Expr {
                expr,
                meta,
            }),
            None => exprs.push(Expr {
                expr: ExprT::Process(str),
                meta,
            }),
        }
    }

    exprs
}

pub fn parse(str: &str) -> Vec<Expr<'_>> {
    process(delimit(str))
}