rpg_compiler/type_checker/
mod.rs

1use std::collections::HashMap;
2use crate::node::{Node, NodeType, parse_dyn_node};
3use crate::node;
4use crate::compile_error;
5
6// TODO: type check shift() & create_potion()
7pub struct TypeChecker<'a> {
8    nodes: &'a Vec<Box<dyn Node + Send + Sync>>,
9    var_map: HashMap<usize, NodeType>
10}
11impl<'a> TypeChecker<'a> {
12    pub fn new(nodes: &'a Vec<Box<dyn Node + Send + Sync>>) -> Self {
13        Self {
14            nodes,
15            var_map: HashMap::new()
16        }
17    }
18    pub fn check_types(&mut self) {
19        self.check_node_types(self.nodes)
20    }
21    fn check_node_types(&mut self, nodes: &'a Vec<Box<dyn Node + Send + Sync>>) {
22        nodes.iter().for_each(|node| {
23            let node = &**node;
24            match node.get_type() {
25                NodeType::Char => {
26                    let node: &node::Char = parse_dyn_node(node);
27                    self.var_map.insert(node.id, NodeType::Char);
28                }
29                NodeType::Zombie => {
30                    let node: &node::Zombie = parse_dyn_node(node);
31                    self.var_map.insert(node.id, NodeType::Zombie);
32                }
33                NodeType::Merchant => {
34                    let node: &node::Merchant = parse_dyn_node(node);
35                    self.var_map.insert(node.id, NodeType::Merchant);
36                }
37                NodeType::Potion => {
38                    let node: &node::Potion = parse_dyn_node(node);
39                    self.var_map.insert(node.id, NodeType::Potion);
40                }
41                NodeType::SpellBook => {
42                    let node: &node::SpellBook = parse_dyn_node(node);
43                    self.var_map.insert(node.id, NodeType::SpellBook);
44                }
45                NodeType::FnBuys => {
46                    let node: &node::FnBuys = parse_dyn_node(node);
47                    if let Some(user) = self.var_map.get(&node.user) {
48                        if let Some(item) = self.var_map.get(&node.item) {
49                            if let Some(merchant) = self.var_map.get(&node.merchant) {
50                                if user == &NodeType::Char || user == &NodeType::Zombie {
51                                    if item == &NodeType::Potion || item == &NodeType::SpellBook {
52                                        if !(merchant == &NodeType::Merchant) {
53                                            compile_error!("Only merchants can sell items.")
54                                        }
55                                    } else {
56                                        compile_error!("Only potions and spellbooks can be bought from a merchant.")
57                                    }
58                                } else {
59                                    compile_error!("The one buying must be an actor.")
60                                }
61                            } else {
62                                compile_error!("No merchant found while buying.")
63                            }
64                        } else {
65                            compile_error!("Item you are trying to buy was not found.")
66                        }
67                    } else {
68                        compile_error!("Actor that is trying to buy not found.")
69                    }
70                    
71                }
72                NodeType::FnAttacks => {
73                    let node: &node::FnAttacks = parse_dyn_node(node);
74                    if let Some(attacked) = self.var_map.get(&node.attacked) {
75                        if let Some(attacker) = self.var_map.get(&node.attacker) {
76                            if attacked == &NodeType::Char || attacked == &NodeType::Zombie {
77                                if !(attacker == &NodeType::Char || attacker == &NodeType::Zombie) {
78                                    compile_error!("The one attacking is not an actor.")
79                                }
80                            } else {
81                                compile_error!("The one being attacked is not an actor.")
82                            }
83                        } else {
84                            compile_error!("Attacking actor could not be found.")
85                        }
86                    } else {
87                        compile_error!("Actor being attacked could not be found.")
88                    }
89                }
90                NodeType::FnUses => {
91                    let node: &node::FnUses = parse_dyn_node(node);
92                    if let Some(user) = self.var_map.get(&node.user) {
93                        if let Some(potion) = self.var_map.get(&node.item) {
94                            if user == &NodeType::Char || user == &NodeType::Zombie {
95                                if !(potion == &NodeType::Potion) {
96                                    compile_error!("The item being used is not a potion.")
97                                }
98                            } else {
99                                compile_error!("The user of the potion is not an actor.")
100                            }
101                        } else {
102                            compile_error!("The potion being used was not defined.")
103                        }
104                    } else {
105                        compile_error!("The actor using the potion was not defined.");
106                    }
107                }
108                NodeType::FnShouts => {
109                    let node: &node::FnShouts = parse_dyn_node(node);
110                    if let Some(shouter) = self.var_map.get(&node.user) {
111                        if !(shouter == &NodeType::Char || shouter == &NodeType::Zombie) {
112                            compile_error!("The one shouting is not an actor.")
113                        }
114                    } else {
115                        compile_error!("The actor shouting was not defined.")
116                    }
117                }
118                NodeType::FnShoutsSpeak => {
119                    let node: &node::FnShoutsSpeak = parse_dyn_node(node);
120                    if let Some(shouter) = self.var_map.get(&node.user) {
121                        if let Some(spellbook) = self.var_map.get(&node.spell_book) {
122                            if shouter == &NodeType::Char || shouter == &NodeType::Zombie {
123                                if !(spellbook == &NodeType::SpellBook) {
124                                    compile_error!("The actor is not using a spellbook to shout.")
125                                }
126                            } else {
127                                compile_error!("The one shouting is not an actor.")
128                            }
129                        } else {
130                            compile_error!("The spellbook used for speaking was not defined.")
131                        }
132                    } else {
133                        compile_error!("The actor shouting was not defined.")
134                    }
135                }
136                NodeType::FnWhispers => {
137                    let node: &node::FnWhispers = parse_dyn_node(node);
138                    if let Some(whisperer) = self.var_map.get(&node.user) {
139                        if !(whisperer == &NodeType::Char || whisperer == &NodeType::Zombie) {
140                            compile_error!("The one shouting is not an actor.")
141                        }
142                    } else {
143                        compile_error!("The actor shouting was not defined.")
144                    }
145                }
146                NodeType::FnWhispersSpeak => {
147                    let node: &node::FnWhispersSpeak = parse_dyn_node(node);
148                    if let Some(whisperer) = self.var_map.get(&node.user) {
149                        if let Some(spellbook) = self.var_map.get(&node.spell_book) {
150                            if whisperer == &NodeType::Char || whisperer == &NodeType::Zombie {
151                                if !(spellbook == &NodeType::SpellBook) {
152                                    compile_error!("The actor is not using a spellbook to shout.")
153                                }
154                            } else {
155                                compile_error!("The one shouting is not an actor.")
156                            }
157                        } else {
158                            compile_error!("The spellbook used for speaking was not defined.")
159                        }
160                    } else {
161                        compile_error!("The actor shouting was not defined.")
162                    }
163                }
164                NodeType::FnUsesCasting => {
165                    // TODO
166                }
167                NodeType::FnBody => {
168                    let node: &node::FnBody = parse_dyn_node(node);
169                    self.check_node_types(&node.body);
170                }
171            }
172        });
173    }
174}