amarok_parser/builders/
statements.rs1use amarok_syntax::{Diagnostic, Spanned, Statement};
2use pest::iterators::Pair;
3
4use crate::grammar::Rule;
5
6use super::expressions::build_expression;
7use super::helpers::{collect_path_segments, find_child, span_of};
8
9pub(crate) fn build_assignment_statement(pair: Pair<Rule>) -> Result<Statement, Diagnostic> {
10 let outer_span = span_of(&pair);
12 let mut inner = pair.into_inner();
13
14 let name_pair = inner
15 .next()
16 .ok_or_else(|| Diagnostic::new("Assignment missing identifier.").with_span(outer_span))?;
17 if name_pair.as_rule() != Rule::identifier {
18 return Err(Diagnostic::new(format!(
19 "Assignment expected identifier, got {:?}",
20 name_pair.as_rule()
21 ))
22 .with_span(span_of(&name_pair)));
23 }
24 let name = name_pair.as_str().to_string();
25
26 let expression_pair = inner
27 .find(|p| p.as_rule() == Rule::expression)
28 .ok_or_else(|| Diagnostic::new("Assignment missing expression.").with_span(outer_span))?;
29
30 let value = build_expression(expression_pair)?;
31
32 Ok(Statement::Assignment { name, value })
33}
34
35pub(crate) fn build_expression_statement(pair: Pair<Rule>) -> Result<Statement, Diagnostic> {
36 let expression_pair = find_child(pair, Rule::expression, "Expression statement")?;
38
39 Ok(Statement::Expression {
40 expression: build_expression(expression_pair)?,
41 })
42}
43
44pub(crate) fn build_block_statement(pair: Pair<Rule>) -> Result<Statement, Diagnostic> {
45 let mut statements: Vec<Spanned<Statement>> = Vec::new();
47
48 for item in pair.into_inner() {
49 statements.push(super::build_statement(item)?);
51 }
52
53 Ok(Statement::Block { statements })
54}
55
56pub(crate) fn build_if_statement(pair: Pair<Rule>) -> Result<Statement, Diagnostic> {
57 let outer_span = span_of(&pair);
59 let mut inner = pair.into_inner();
60
61 let condition_pair = inner
62 .find(|p| p.as_rule() == Rule::expression)
63 .ok_or_else(|| {
64 Diagnostic::new("If statement missing condition expression.").with_span(outer_span)
65 })?;
66 let condition = build_expression(condition_pair)?;
67
68 let then_block_pair = inner
69 .find(|p| p.as_rule() == Rule::block_statement)
70 .ok_or_else(|| Diagnostic::new("If statement missing then block.").with_span(outer_span))?;
71 let then_branch = extract_block_statements(then_block_pair)?;
72
73 let mut else_branch: Vec<Spanned<Statement>> = Vec::new();
74 for item in inner {
75 if item.as_rule() == Rule::else_clause {
76 else_branch = extract_else_clause(item)?;
77 }
78 }
79
80 Ok(Statement::If {
81 condition,
82 then_branch,
83 else_branch,
84 })
85}
86
87fn extract_else_clause(pair: Pair<Rule>) -> Result<Vec<Spanned<Statement>>, Diagnostic> {
88 extract_block_statements(find_child(pair, Rule::block_statement, "Else clause")?)
90}
91
92fn extract_block_statements(block_pair: Pair<Rule>) -> Result<Vec<Spanned<Statement>>, Diagnostic> {
93 let mut statements = Vec::new();
95 for item in block_pair.into_inner() {
96 statements.push(super::build_statement(item)?);
97 }
98 Ok(statements)
99}
100
101pub(crate) fn build_while_statement(pair: Pair<Rule>) -> Result<Statement, Diagnostic> {
102 let outer_span = span_of(&pair);
104 let mut inner = pair.into_inner();
105
106 let condition_pair = inner
107 .find(|p| p.as_rule() == Rule::expression)
108 .ok_or_else(|| {
109 Diagnostic::new("While statement missing condition expression.").with_span(outer_span)
110 })?;
111 let condition = build_expression(condition_pair)?;
112
113 let body_block_pair = inner
114 .find(|p| p.as_rule() == Rule::block_statement)
115 .ok_or_else(|| {
116 Diagnostic::new("While statement missing body block.").with_span(outer_span)
117 })?;
118 let body = extract_block_statements(body_block_pair)?;
119
120 Ok(Statement::While { condition, body })
121}
122
123pub(crate) fn build_function_definition(pair: Pair<Rule>) -> Result<Statement, Diagnostic> {
124 let outer_span = span_of(&pair);
126 let mut inner = pair.into_inner();
127
128 let name_pair = inner
129 .find(|p| p.as_rule() == Rule::identifier)
130 .ok_or_else(|| {
131 Diagnostic::new("Function definition missing name.").with_span(outer_span)
132 })?;
133 let name = name_pair.as_str().to_string();
134
135 let mut parameters: Vec<String> = Vec::new();
136 let mut body: Vec<Spanned<Statement>> = Vec::new();
137
138 for item in inner {
139 match item.as_rule() {
140 Rule::parameter_list => {
141 parameters = item
142 .into_inner()
143 .filter(|p| p.as_rule() == Rule::identifier)
144 .map(|p| p.as_str().to_string())
145 .collect();
146 }
147 Rule::block_statement => {
148 body = extract_block_statements(item)?;
149 }
150 _ => {}
151 }
152 }
153
154 Ok(Statement::FunctionDefinition {
155 name,
156 parameters,
157 body,
158 })
159}
160
161pub(crate) fn build_return_statement(pair: Pair<Rule>) -> Result<Statement, Diagnostic> {
162 let expression_pair = pair.into_inner().find(|p| p.as_rule() == Rule::expression);
164 let value = match expression_pair {
165 Some(p) => Some(build_expression(p)?),
166 None => None,
167 };
168
169 Ok(Statement::Return { value })
170}
171
172pub(crate) fn build_use_statement(pair: Pair<Rule>) -> Result<Statement, Diagnostic> {
173 let path_pair = find_child(pair, Rule::path, "Use statement")?;
175 let path = collect_path_segments(path_pair, "Use statement")?;
176
177 Ok(Statement::Use { path })
178}