1use crate::common::*;
8use crate::error::Error;
9
10pub fn analyze(program: Vec<Declaration>) -> Vec<Declaration>
11{
12 let mut analyzer = Analyzer {
13 is_naked_then_branch: false,
14 is_naked_else_branch: false,
15 is_in_block: false,
16 };
17 program
18 .into_iter()
19 .map(|x| x.analyze(&mut analyzer))
20 .collect()
21}
22
23struct Analyzer
24{
25 is_naked_then_branch: bool,
26 is_naked_else_branch: bool,
27 is_in_block: bool,
28}
29
30trait Analyzable
31{
32 fn analyze(self, analyzer: &mut Analyzer) -> Self;
33}
34
35impl Analyzable for Declaration
36{
37 fn analyze(self, analyzer: &mut Analyzer) -> Self
38 {
39 match self
40 {
41 Declaration::Constant {
42 name: _,
43 value: _,
44 value_type: _,
45 flags: _,
46 depth: _,
47 location_of_declaration: _,
48 location_of_type: _,
49 } => self,
50 Declaration::Function {
51 name,
52 parameters,
53 body,
54 return_type,
55 flags,
56 location_of_declaration,
57 location_of_return_type,
58 } =>
59 {
60 let body = match body
61 {
62 Ok(body) => Ok(body.analyze(analyzer)),
63 Err(poison) => Err(poison),
64 };
65 Declaration::Function {
66 name,
67 parameters,
68 body,
69 return_type,
70 flags,
71 location_of_declaration,
72 location_of_return_type,
73 }
74 }
75 Declaration::FunctionHead {
76 name: _,
77 parameters: _,
78 return_type: _,
79 flags: _,
80 location_of_declaration: _,
81 location_of_return_type: _,
82 } => self,
83 Declaration::Structure {
84 name: _,
85 members: _,
86 structural_type: _,
87 flags: _,
88 depth: _,
89 location_of_declaration: _,
90 } => self,
91 Declaration::Import { .. } => self,
92 Declaration::Poison(_) => self,
93 }
94 }
95}
96
97impl Analyzable for FunctionBody
98{
99 fn analyze(self, analyzer: &mut Analyzer) -> Self
100 {
101 analyzer.is_in_block = false;
103
104 let statements = self
105 .statements
106 .into_iter()
107 .map(|x| x.analyze(analyzer))
108 .collect();
109
110 FunctionBody {
111 statements,
112 return_value: self.return_value,
113 return_value_identifier: self.return_value_identifier,
114 }
115 }
116}
117
118impl Analyzable for Block
119{
120 fn analyze(self, analyzer: &mut Analyzer) -> Self
121 {
122 let (others, last) = {
123 let mut statements = self.statements;
124 let last = statements.pop();
125 let others = statements;
126 (others, last)
127 };
128 let statements = match last
129 {
130 Some(last) =>
131 {
132 let mut statements: Vec<Statement> = others
133 .into_iter()
134 .map(|statement| {
135 analyzer.is_in_block = true;
136 let statement = statement.analyze(analyzer);
137 match statement
138 {
139 Statement::Loop { location } => Statement::Poison(
140 Poison::Error(Error::NonFinalLoopStatement {
141 location,
142 location_of_block: self.location.clone(),
143 }),
144 ),
145 Statement::Poison(_) => statement,
146 _ => statement,
147 }
148 })
149 .collect();
150 analyzer.is_in_block = true;
151 let last = last.analyze(analyzer);
152 analyzer.is_in_block = false;
153 statements.push(last);
154 statements
155 }
156 None => Vec::new(),
157 };
158
159 Block {
160 statements,
161 location: self.location,
162 }
163 }
164}
165
166impl Analyzable for Statement
167{
168 fn analyze(self, analyzer: &mut Analyzer) -> Self
169 {
170 if analyzer.is_naked_then_branch || analyzer.is_naked_else_branch
171 {
172 match &self
173 {
174 Statement::Goto { .. } => (),
175 Statement::Block(..) => (),
176 Statement::If { .. } if analyzer.is_naked_else_branch => (),
177 Statement::Poison(_poison) => (),
178 statement =>
179 {
180 return Statement::Poison(Poison::Error(
181 Error::MissingBraces {
182 location: statement.location().clone(),
183 },
184 ));
185 }
186 }
187 }
188
189 match self
190 {
191 Statement::Declaration { .. } => self,
192 Statement::Assignment { .. } => self,
193 Statement::MethodCall { .. } => self,
194 Statement::Loop { location } =>
195 {
196 if analyzer.is_in_block
197 {
198 Statement::Loop { location }
199 }
200 else
201 {
202 Statement::Poison(Poison::Error(
203 Error::MisplacedLoopStatement { location },
204 ))
205 }
206 }
207 Statement::Goto { .. } => self,
208 Statement::Label { .. } => self,
209 Statement::If {
210 condition,
211 then_branch,
212 else_branch,
213 location,
214 } =>
215 {
216 analyzer.is_in_block = false;
217
218 analyzer.is_naked_then_branch = true;
219 let then_branch = Box::new(then_branch.analyze(analyzer));
220 analyzer.is_naked_then_branch = false;
221
222 let else_branch = else_branch.map(|x| {
223 analyzer.is_naked_else_branch = true;
224 let branch = x.branch.analyze(analyzer);
225 analyzer.is_naked_else_branch = false;
226
227 Else {
228 branch: Box::new(branch),
229 location_of_else: x.location_of_else,
230 }
231 });
232
233 Statement::If {
234 condition,
235 then_branch,
236 else_branch,
237 location,
238 }
239 }
240 Statement::Block(block) =>
241 {
242 analyzer.is_naked_then_branch = false;
243 analyzer.is_naked_else_branch = false;
244 let block = block.analyze(analyzer);
245 Statement::Block(block)
246 }
247 Statement::Poison(_) => self,
248 }
249 }
250}