summaryrefslogtreecommitdiff
path: root/src/ast.rs
blob: fb648e08d0d2f27393a4a91eb65ccc76a838eff2 (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
use crate::tokenizer::If;
use std::iter::Peekable;

use crate::parser::{Expr, ExprT, Metadata, Scope};

#[derive(Clone, Debug)]
pub enum DepthExpr<'a> {
    Decision {
        cond: Box<&'a str>, // TODO: take DepthExpr
        t: Scope,
        then_branch: Box<Vec<DepthExpr<'a>>>,
        else_branch: Option<Box<Vec<DepthExpr<'a>>>>,
    },
    IO(&'a str),
    Process(&'a str),
}

pub fn parse<'a>(vec: &Vec<Expr<'a>>) -> Vec<DepthExpr<'a>> {
    let mut exprs: Vec<DepthExpr<'a>> = Vec::new();

    let mut it = vec
        .iter()
        .peekable();

    while let Some(e) = it.next() {
        match e.expr {
            ExprT::Decision((cond, scope)) => {
                let then_branch = parse(&entire_scopes(&mut it));

                let else_branch = if let Some(n) = it.peek() {
                    match n.expr {
                        ExprT::Decision((_, scope)) => {
                            if let Scope::If(If::Else) = scope {
                                it.next();
                                Some(Box::new(parse(&entire_scopes(&mut it))))
                            } else {
                                None
                            }
                        }
                        _ => None,
                    }
                } else {
                    None
                };

                exprs.push(DepthExpr::Decision {
                    cond: Box::new(cond),
                    t: scope,
                    then_branch: Box::new(then_branch),
                    else_branch,
                });
            }
            ExprT::IO(s) => {
                if !s.is_empty() {
                    exprs.push(DepthExpr::IO(s))
                }
            }
            ExprT::Process(s) => {
                if !s.is_empty() {
                    exprs.push(DepthExpr::Process(s))
                }
            }
            ExprT::StartOrStop(_) => {}
        }
    }

    exprs
}

fn entire_scopes<'a>(it: &mut Peekable<std::slice::Iter<'_, Expr<'a>>>) -> Vec<Expr<'a>> {
    let mut exprs: Vec<Expr<'a>> = Vec::new();
    let mut scope_count: u32 = 1; // assume we already entered the scope

    for i in it {
        if let Some(meta) = i.meta {
            match meta {
                Metadata::StartScope => {
                    scope_count = scope_count
                        .checked_add(1)
                        .expect("Scopes nested too deep")
                }
                Metadata::EndScope => {
                    scope_count = scope_count
                        .checked_sub(1)
                        .expect("Closed not opened scope")
                }
            }
        }
        exprs.push(*i);
        if scope_count == 0 {
            break;
        }
    }

    exprs
}