tangibl/
tangibl.rs

1use crate::{
2    ast::{
3        BooleanMethod, BooleanMethodKind, Command, Condition, Conditional, ConditionalKind, Flow,
4        FlowKind, IntegerMethod, IntegerMethodKind, Start, Value,
5    },
6    parser::Parser,
7};
8use std::collections::VecDeque;
9use topcodes::TopCode;
10
11pub fn parse(topcodes: &Vec<TopCode>) -> Option<Start> {
12    Parser::new(topcodes).parse()
13}
14
15pub fn start() -> TangiblStartBuilder {
16    TangiblStartBuilder::default()
17}
18
19pub fn flow() -> TangiblFlowBuilder {
20    TangiblFlowBuilder::default()
21}
22
23#[derive(Default, Debug)]
24pub struct TangiblStartBuilder {
25    /// The main flow for the program. As if it were the 'main' function of many common languages.
26    flow_builder: TangiblFlowBuilder,
27}
28
29impl TangiblStartBuilder {
30    pub fn with_command(&mut self, command: Command) -> &mut Self {
31        self.flow_builder.with_command(command);
32        self
33    }
34
35    pub fn with_conditional(
36        &mut self,
37        conditional_kind: ConditionalKind,
38        alternate: Option<Flow>,
39    ) -> &mut Self {
40        self.flow_builder.with_conditional(Conditional {
41            kind: conditional_kind,
42            alternate: alternate.map(Box::new),
43        });
44        self
45    }
46
47    pub fn with_boolean_method(
48        &mut self,
49        boolean_method_kind: BooleanMethodKind,
50        condition: Option<Condition>,
51        body: Option<Flow>,
52    ) -> &mut Self {
53        self.flow_builder
54            .with_boolean_method(boolean_method_kind, condition, body);
55        self
56    }
57
58    pub fn with_integer_method(
59        &mut self,
60        integer_method_kind: IntegerMethodKind,
61        value: Option<Value>,
62        body: Option<Flow>,
63    ) -> &mut Self {
64        self.flow_builder
65            .with_integer_method(integer_method_kind, value, body);
66        self
67    }
68
69    pub fn build(&mut self) -> Start {
70        Start {
71            next: self.flow_builder.build(),
72        }
73    }
74}
75
76#[derive(Default, Debug)]
77pub struct TangiblFlowBuilder {
78    nodes: VecDeque<Flow>,
79}
80
81impl TangiblFlowBuilder {
82    pub fn with_command(&mut self, command: Command) -> &mut Self {
83        self.with_flow(Flow::new(FlowKind::Command(command)));
84        self
85    }
86
87    pub fn with_conditional(&mut self, conditional: Conditional) -> &mut Self {
88        self.with_flow(Flow::new(FlowKind::Conditional(conditional)));
89        self
90    }
91
92    pub fn with_boolean_method(
93        &mut self,
94        boolean_method_kind: BooleanMethodKind,
95        condition: Option<Condition>,
96        body: Option<Flow>,
97    ) -> &mut Self {
98        self.with_flow(Flow::new(FlowKind::BooleanMethod(BooleanMethod {
99            kind: boolean_method_kind,
100            condition,
101            body: body.map(Box::new),
102        })));
103        self
104    }
105
106    pub fn with_integer_method(
107        &mut self,
108        integer_method_kind: IntegerMethodKind,
109        value: Option<Value>,
110        body: Option<Flow>,
111    ) -> &mut Self {
112        self.with_flow(Flow::new(FlowKind::IntegerMethod(IntegerMethod {
113            kind: integer_method_kind,
114            value,
115            body: body.map(Box::new),
116        })));
117        self
118    }
119
120    pub fn build(&mut self) -> Option<Flow> {
121        let mut current = None;
122        while let Some(mut node) = self.nodes.pop_back() {
123            match current {
124                None => current = Some(node),
125                Some(_) => {
126                    node.next = current.map(Box::new);
127                    current = Some(node);
128                }
129            }
130        }
131        current
132    }
133
134    fn with_flow(&mut self, flow: Flow) -> &mut Self {
135        self.nodes.push_back(flow);
136        self
137    }
138}