1use crate::ast::{
8 DecompositionBinding, DestructurePattern, ObjectPatternField, ObjectTypeField,
9 OwnershipModifier, TypeAnnotation, VarKind, VariableDecl,
10};
11use crate::error::{Result, ShapeError};
12use pest::iterators::Pair;
13
14use super::expressions;
15use super::types::parse_type_annotation;
16use super::{Rule, pair_location, pair_span};
17
18pub fn parse_variable_decl(pair: Pair<Rule>) -> Result<VariableDecl> {
20 let pair_loc = pair_location(&pair);
21 let mut inner = pair.into_inner();
22
23 let keyword_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
25 message: "expected variable declaration keyword".to_string(),
26 location: Some(
27 pair_loc
28 .clone()
29 .with_hint("use 'let', 'var', or 'const' to declare a variable"),
30 ),
31 })?;
32 let kind_str = keyword_pair.as_str();
33 let kind = match kind_str {
34 "let" => VarKind::Let,
35 "var" => VarKind::Var,
36 "const" => VarKind::Const,
37 _ => {
38 return Err(ShapeError::ParseError {
39 message: format!("invalid variable declaration kind: '{}'", kind_str),
40 location: Some(
41 pair_location(&keyword_pair).with_hint("use 'let', 'var', or 'const'"),
42 ),
43 });
44 }
45 };
46
47 let next_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
49 message: "expected variable name or pattern after keyword".to_string(),
50 location: Some(
51 pair_loc
52 .clone()
53 .with_hint("provide a variable name, e.g., 'let x = 5'"),
54 ),
55 })?;
56 let (is_mut, pattern_pair) = if next_pair.as_rule() == Rule::var_mut_modifier {
57 let p = inner.next().ok_or_else(|| ShapeError::ParseError {
58 message: "expected variable name or pattern after 'mut'".to_string(),
59 location: Some(pair_loc.with_hint("provide a variable name, e.g., 'let mut x = 5'")),
60 })?;
61 (true, p)
62 } else {
63 (false, next_pair)
64 };
65 let pattern = parse_pattern(pattern_pair)?;
66
67 let mut type_annotation = None;
69 let mut value = None;
70 let mut ownership = OwnershipModifier::Inferred;
71
72 for pair in inner {
73 match pair.as_rule() {
74 Rule::type_annotation => {
75 type_annotation = Some(parse_type_annotation(pair)?);
76 }
77 Rule::ownership_modifier => {
78 ownership = match pair.as_str() {
79 "move" => OwnershipModifier::Move,
80 "clone" => OwnershipModifier::Clone,
81 _ => OwnershipModifier::Inferred,
82 };
83 }
84 Rule::expression => {
85 value = Some(expressions::parse_expression(pair)?);
86 }
87 Rule::table_row_init => {
88 value = Some(parse_table_row_init(pair)?);
89 }
90 _ => {}
91 }
92 }
93
94 Ok(VariableDecl {
95 kind,
96 is_mut,
97 pattern,
98 type_annotation,
99 value,
100 ownership,
101 })
102}
103
104fn parse_table_row_init(pair: Pair<Rule>) -> Result<crate::ast::Expr> {
107 use crate::ast::{Expr, Span};
108 let span = pair_span(&pair);
109 let mut rows = Vec::new();
110
111 for inner in pair.into_inner() {
112 match inner.as_rule() {
113 Rule::array_elements => {
114 let mut elements = Vec::new();
115 for elem_pair in inner.into_inner() {
116 if elem_pair.as_rule() == Rule::array_element {
117 let mut elem_inner = elem_pair.into_inner();
118 if let Some(elem) = elem_inner.next() {
119 elements.push(expressions::parse_expression(elem)?);
120 }
121 }
122 }
123 rows.push(elements);
124 }
125 _ => {}
126 }
127 }
128
129 Ok(Expr::TableRows(rows, Span::new(span.start, span.end)))
130}
131
132pub fn parse_pattern(pair: Pair<Rule>) -> Result<DestructurePattern> {
134 let pair_loc = pair_location(&pair);
135
136 match pair.as_rule() {
137 Rule::destructure_pattern => {
138 let inner = pair
140 .into_inner()
141 .next()
142 .ok_or_else(|| ShapeError::ParseError {
143 message: "expected pattern content".to_string(),
144 location: Some(pair_loc),
145 })?;
146 parse_pattern(inner)
147 }
148 Rule::destructure_ident_pattern => {
149 let ident = pair
150 .into_inner()
151 .next()
152 .ok_or_else(|| ShapeError::ParseError {
153 message: "expected identifier in pattern".to_string(),
154 location: Some(pair_loc),
155 })?;
156 let ident_span = pair_span(&ident);
157 Ok(DestructurePattern::Identifier(
158 ident.as_str().to_string(),
159 ident_span,
160 ))
161 }
162 Rule::destructure_array_pattern => {
163 let mut patterns = Vec::new();
164 for inner in pair.into_inner() {
165 if inner.as_rule() == Rule::destructure_pattern {
166 patterns.push(parse_pattern(inner)?);
167 }
168 }
169 Ok(DestructurePattern::Array(patterns))
170 }
171 Rule::destructure_object_pattern => {
172 let mut fields = Vec::new();
173 for field in pair.into_inner() {
174 if field.as_rule() == Rule::destructure_object_pattern_field {
175 let field_loc = pair_location(&field);
176 let field_str = field.as_str();
177 let mut field_inner = field.into_inner();
178 if field_str.trim_start().starts_with("...") {
179 let ident_pair =
181 field_inner.next().ok_or_else(|| ShapeError::ParseError {
182 message: "expected identifier after '...' in object pattern"
183 .to_string(),
184 location: Some(field_loc),
185 })?;
186 let ident_span = pair_span(&ident_pair);
187 let ident = ident_pair.as_str().to_string();
188 fields.push(ObjectPatternField {
189 key: "...".to_string(),
190 pattern: DestructurePattern::Rest(Box::new(
191 DestructurePattern::Identifier(ident, ident_span),
192 )),
193 });
194 } else {
195 let key_pair =
197 field_inner.next().ok_or_else(|| ShapeError::ParseError {
198 message: "expected field name in object pattern".to_string(),
199 location: Some(field_loc),
200 })?;
201 let key_span = pair_span(&key_pair);
202 let key = key_pair.as_str().to_string();
203 let pattern = if let Some(pattern_pair) = field_inner.next() {
204 parse_pattern(pattern_pair)?
205 } else {
206 DestructurePattern::Identifier(key.clone(), key_span)
207 };
208 fields.push(ObjectPatternField { key, pattern });
209 }
210 }
211 }
212 Ok(DestructurePattern::Object(fields))
213 }
214 Rule::destructure_rest_pattern => {
215 let ident_pair = pair
216 .into_inner()
217 .next()
218 .ok_or_else(|| ShapeError::ParseError {
219 message: "expected identifier after '...' in rest pattern".to_string(),
220 location: Some(pair_loc),
221 })?;
222 let ident_span = pair_span(&ident_pair);
223 let ident = ident_pair.as_str().to_string();
224 Ok(DestructurePattern::Rest(Box::new(
225 DestructurePattern::Identifier(ident, ident_span),
226 )))
227 }
228 Rule::destructure_decomposition_pattern => {
229 let mut bindings = Vec::new();
232 for binding_pair in pair.into_inner() {
233 if binding_pair.as_rule() == Rule::decomposition_binding {
234 let binding_span = pair_span(&binding_pair);
235 let mut binding_inner = binding_pair.into_inner();
236
237 let name_pair = binding_inner.next().ok_or_else(|| ShapeError::ParseError {
238 message: "expected identifier in decomposition binding".to_string(),
239 location: Some(pair_loc.clone()),
240 })?;
241 let name = name_pair.as_str().to_string();
242
243 let type_pair = binding_inner.next().ok_or_else(|| ShapeError::ParseError {
244 message: "expected type annotation in decomposition binding".to_string(),
245 location: Some(pair_loc.clone()),
246 })?;
247 let type_annotation = if type_pair.as_rule() == Rule::decomposition_field_set {
248 let fields = type_pair
250 .into_inner()
251 .filter(|p| p.as_rule() == Rule::ident)
252 .map(|p| ObjectTypeField {
253 name: p.as_str().to_string(),
254 optional: false,
255 type_annotation: TypeAnnotation::Basic("_".into()),
256 annotations: vec![],
257 })
258 .collect();
259 TypeAnnotation::Object(fields)
260 } else {
261 parse_type_annotation(type_pair)?
262 };
263
264 bindings.push(DecompositionBinding {
265 name,
266 type_annotation,
267 span: binding_span,
268 });
269 }
270 }
271
272 if bindings.len() < 2 {
273 return Err(ShapeError::ParseError {
274 message: "decomposition pattern requires at least 2 bindings".to_string(),
275 location: Some(pair_loc),
276 });
277 }
278
279 Ok(DestructurePattern::Decomposition(bindings))
280 }
281 _ => Err(ShapeError::ParseError {
282 message: format!("invalid pattern rule: {:?}", pair.as_rule()),
283 location: Some(pair_loc),
284 }),
285 }
286}