penne/analyzer/
syntax.rs

1//
2// Part of penne
3// Copyright (c) 2020 Sander in 't Veld
4// License: MIT
5//
6
7use 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		// We are a function body, not a block.
102		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}