shape_ast/parser/
items.rs1use 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 _ => {}
88 }
89 }
90
91 Ok(VariableDecl {
92 kind,
93 is_mut,
94 pattern,
95 type_annotation,
96 value,
97 ownership,
98 })
99}
100
101pub fn parse_pattern(pair: Pair<Rule>) -> Result<DestructurePattern> {
103 let pair_loc = pair_location(&pair);
104
105 match pair.as_rule() {
106 Rule::destructure_pattern => {
107 let inner = pair
109 .into_inner()
110 .next()
111 .ok_or_else(|| ShapeError::ParseError {
112 message: "expected pattern content".to_string(),
113 location: Some(pair_loc),
114 })?;
115 parse_pattern(inner)
116 }
117 Rule::destructure_ident_pattern => {
118 let ident = pair
119 .into_inner()
120 .next()
121 .ok_or_else(|| ShapeError::ParseError {
122 message: "expected identifier in pattern".to_string(),
123 location: Some(pair_loc),
124 })?;
125 let ident_span = pair_span(&ident);
126 Ok(DestructurePattern::Identifier(
127 ident.as_str().to_string(),
128 ident_span,
129 ))
130 }
131 Rule::destructure_array_pattern => {
132 let mut patterns = Vec::new();
133 for inner in pair.into_inner() {
134 if inner.as_rule() == Rule::destructure_pattern {
135 patterns.push(parse_pattern(inner)?);
136 }
137 }
138 Ok(DestructurePattern::Array(patterns))
139 }
140 Rule::destructure_object_pattern => {
141 let mut fields = Vec::new();
142 for field in pair.into_inner() {
143 if field.as_rule() == Rule::destructure_object_pattern_field {
144 let field_loc = pair_location(&field);
145 let field_str = field.as_str();
146 let mut field_inner = field.into_inner();
147 if field_str.trim_start().starts_with("...") {
148 let ident_pair =
150 field_inner.next().ok_or_else(|| ShapeError::ParseError {
151 message: "expected identifier after '...' in object pattern"
152 .to_string(),
153 location: Some(field_loc),
154 })?;
155 let ident_span = pair_span(&ident_pair);
156 let ident = ident_pair.as_str().to_string();
157 fields.push(ObjectPatternField {
158 key: "...".to_string(),
159 pattern: DestructurePattern::Rest(Box::new(
160 DestructurePattern::Identifier(ident, ident_span),
161 )),
162 });
163 } else {
164 let key_pair =
166 field_inner.next().ok_or_else(|| ShapeError::ParseError {
167 message: "expected field name in object pattern".to_string(),
168 location: Some(field_loc),
169 })?;
170 let key_span = pair_span(&key_pair);
171 let key = key_pair.as_str().to_string();
172 let pattern = if let Some(pattern_pair) = field_inner.next() {
173 parse_pattern(pattern_pair)?
174 } else {
175 DestructurePattern::Identifier(key.clone(), key_span)
176 };
177 fields.push(ObjectPatternField { key, pattern });
178 }
179 }
180 }
181 Ok(DestructurePattern::Object(fields))
182 }
183 Rule::destructure_rest_pattern => {
184 let ident_pair = pair
185 .into_inner()
186 .next()
187 .ok_or_else(|| ShapeError::ParseError {
188 message: "expected identifier after '...' in rest pattern".to_string(),
189 location: Some(pair_loc),
190 })?;
191 let ident_span = pair_span(&ident_pair);
192 let ident = ident_pair.as_str().to_string();
193 Ok(DestructurePattern::Rest(Box::new(
194 DestructurePattern::Identifier(ident, ident_span),
195 )))
196 }
197 Rule::destructure_decomposition_pattern => {
198 let mut bindings = Vec::new();
201 for binding_pair in pair.into_inner() {
202 if binding_pair.as_rule() == Rule::decomposition_binding {
203 let binding_span = pair_span(&binding_pair);
204 let mut binding_inner = binding_pair.into_inner();
205
206 let name_pair = binding_inner.next().ok_or_else(|| ShapeError::ParseError {
207 message: "expected identifier in decomposition binding".to_string(),
208 location: Some(pair_loc.clone()),
209 })?;
210 let name = name_pair.as_str().to_string();
211
212 let type_pair = binding_inner.next().ok_or_else(|| ShapeError::ParseError {
213 message: "expected type annotation in decomposition binding".to_string(),
214 location: Some(pair_loc.clone()),
215 })?;
216 let type_annotation = if type_pair.as_rule() == Rule::decomposition_field_set {
217 let fields = type_pair
219 .into_inner()
220 .filter(|p| p.as_rule() == Rule::ident)
221 .map(|p| ObjectTypeField {
222 name: p.as_str().to_string(),
223 optional: false,
224 type_annotation: TypeAnnotation::Basic("_".into()),
225 annotations: vec![],
226 })
227 .collect();
228 TypeAnnotation::Object(fields)
229 } else {
230 parse_type_annotation(type_pair)?
231 };
232
233 bindings.push(DecompositionBinding {
234 name,
235 type_annotation,
236 span: binding_span,
237 });
238 }
239 }
240
241 if bindings.len() < 2 {
242 return Err(ShapeError::ParseError {
243 message: "decomposition pattern requires at least 2 bindings".to_string(),
244 location: Some(pair_loc),
245 });
246 }
247
248 Ok(DestructurePattern::Decomposition(bindings))
249 }
250 _ => Err(ShapeError::ParseError {
251 message: format!("invalid pattern rule: {:?}", pair.as_rule()),
252 location: Some(pair_loc),
253 }),
254 }
255}