Skip to main content

rl_lang/parser/statements/
variable_declaration.rs

1//! Variable declaration parser (`dec`).
2//!
3//! Handles the `dec` keyword, which introduces a mutable binding.
4//!
5//! ```text
6//! dec int x = 42
7//! dec array[int] xs = [1, 2, 3]
8//! dec (int, string) p = (1, "hi")
9//! dec int x, string y = (1, "hi")
10//! ```
11
12use std::rc::Rc;
13
14use crate::{
15    ast::statements::{Statement, StatementKind, TypeAnnotation},
16    lexer::tokentypes::TokenType,
17    parser::parser_logic::Parser,
18    utils::{errors::Error, span::Span},
19};
20
21impl Parser {
22    /// Parses a `dec` variable declaration.
23    ///
24    /// Called after `dec` has been consumed. Handles two forms:
25    ///
26    /// - **Array declaration** - `dec array[T] name = [items]` or
27    ///   `dec array[T] name = expr` - detected by the `array` keyword followed
28    ///   by `[`. Produces [`StatementKind::Array`] for inline literals or
29    ///   [`StatementKind::VariableDeclaration`] with `TypeAnnotation::Array` for
30    ///   expression initialisers.
31    ///
32    /// - **Scalar declaration** - `dec T name = expr` - produces
33    ///   [`StatementKind::VariableDeclaration`].
34    ///
35    /// # Errors
36    /// Returns an error if the type, name, `=`, or initialiser expression is
37    /// missing or malformed.
38    pub fn parse_variable_declartion(&mut self, start: Span) -> Result<Statement, Error> {
39        #[cfg(feature = "debug")]
40        log::debug!("{:?}", self.peek());
41        #[cfg(feature = "debug")]
42        log::debug!("parsing type");
43
44        // -- tuple: dec (T, T, ...) name = (...) --
45        if self.peek() == TokenType::LeftParen {
46            self.advance();
47            while self.match_type(&[TokenType::Newline]) {}
48            let first_type = self.parse_type(true)?;
49
50            while self.match_type(&[TokenType::Newline]) {}
51            if self.peek() == TokenType::Comma || self.peek() == TokenType::RightParen {
52                let mut types = vec![first_type];
53                while self.match_type(&[TokenType::Comma]) {
54                    while self.match_type(&[TokenType::Newline]) {}
55                    if self.peek() == TokenType::RightParen {
56                        break;
57                    }
58                    types.push(self.parse_type(true)?);
59                }
60                if !self.match_type(&[TokenType::RightParen]) {
61                    return Err(self.err("expected `)` after tuple types", self.peek_span()));
62                }
63                while self.match_type(&[TokenType::Newline]) {}
64                let name = match self.peek() {
65                    TokenType::Identifier(n) => {
66                        self.advance();
67                        n
68                    }
69                    _ => return Err(self.err("expected name after tuple type", self.peek_span())),
70                };
71                while self.match_type(&[TokenType::Newline]) {}
72                if !self.match_type(&[TokenType::Assign]) {
73                    return Err(self.err("expected `=` after name", self.peek_span()));
74                }
75                let value = self.parse_expression()?;
76                let value_id = self.ast_arena.exprs.get(value);
77                let span = start.join(value_id.span);
78                return Ok(Statement::new(
79                    StatementKind::VariableDeclaration {
80                        name,
81                        type_annotation: TypeAnnotation::Tuple(Rc::new(types)),
82                        value,
83                    },
84                    span,
85                ));
86            } else {
87                return Err(self.err("invalid tuple type syntax", self.peek_span()));
88            }
89        }
90
91        // -- destructure: dec T x, T y = (...) --
92        if matches!(
93            self.peek(),
94            TokenType::Int
95                | TokenType::Float
96                | TokenType::Bool
97                | TokenType::String
98                | TokenType::Byte
99                | TokenType::Char
100                | TokenType::Fn
101                | TokenType::Error
102        ) {
103            let saved = self.current;
104            while self.match_type(&[TokenType::Newline]) {}
105            let first_type = self.parse_type(true)?;
106            while self.match_type(&[TokenType::Newline]) {}
107            let first_name = match self.peek() {
108                TokenType::Identifier(n) => {
109                    self.advance();
110                    n
111                }
112                _ => {
113                    self.current = saved;
114                    return self.parse_variable_declartion_scalar(start);
115                }
116            };
117            while self.match_type(&[TokenType::Newline]) {}
118            if self.peek() == TokenType::Comma {
119                let mut bindings = vec![(first_type, first_name)];
120                while self.match_type(&[TokenType::Comma]) {
121                    while self.match_type(&[TokenType::Newline]) {}
122                    let t = self.parse_type(true)?;
123                    while self.match_type(&[TokenType::Newline]) {}
124                    let n = match self.peek() {
125                        TokenType::Identifier(n) => {
126                            self.advance();
127                            n
128                        }
129                        _ => {
130                            return Err(
131                                self.err("expected name in destructure binding", self.peek_span())
132                            );
133                        }
134                    };
135                    bindings.push((t, n));
136                }
137                while self.match_type(&[TokenType::Newline]) {}
138                if !self.match_type(&[TokenType::Assign]) {
139                    return Err(
140                        self.err("expected `=` after destructure bindings", self.peek_span())
141                    );
142                }
143                while self.match_type(&[TokenType::Newline]) {}
144                let value = self.parse_expression()?;
145                let value_id = self.ast_arena.exprs.get(value);
146                let span = start.join(value_id.span);
147                return Ok(Statement::new(
148                    StatementKind::DestructureDeclaration { bindings, value },
149                    span,
150                ));
151            } else {
152                while self.match_type(&[TokenType::Newline]) {}
153                if !self.match_type(&[TokenType::Assign]) {
154                    return Err(self.err("expected `=` after name", self.peek_span()));
155                }
156                while self.match_type(&[TokenType::Newline]) {}
157                let value = self.parse_expression()?;
158                let value_id = self.ast_arena.exprs.get(value);
159                let span = start.join(value_id.span);
160                return Ok(Statement::new(
161                    StatementKind::VariableDeclaration {
162                        name: first_name,
163                        type_annotation: first_type,
164                        value,
165                    },
166                    span,
167                ));
168            }
169        }
170
171        // -- map: dec map[K,V] name = {...} --
172        if self.match_type(&[TokenType::Map]) && self.peek() == TokenType::LeftBracket {
173            self.advance();
174            while self.match_type(&[TokenType::Newline]) {}
175            let key_type = self.parse_param_type()?;
176
177            while self.match_type(&[TokenType::Newline]) {}
178            if !self.match_type(&[TokenType::Comma]) {
179                return Err(self.err(
180                    "expected `,` between map key and value types",
181                    self.peek_span(),
182                ));
183            }
184
185            while self.match_type(&[TokenType::Newline]) {}
186            let value_type = self.parse_param_type()?;
187
188            while self.match_type(&[TokenType::Newline]) {}
189            if !self.match_type(&[TokenType::RightBracket]) {
190                return Err(self.err("expected `]` after type", self.peek_span()));
191            }
192
193            while self.match_type(&[TokenType::Newline]) {}
194            let name = match self.peek() {
195                TokenType::Identifier(n) => {
196                    self.advance();
197                    n
198                }
199                _ => return Err(self.err("expected name after map type", self.peek_span())),
200            };
201
202            while self.match_type(&[TokenType::Newline]) {}
203            if !self.match_type(&[TokenType::Assign]) {
204                return Err(self.err("expected `=` after name", self.peek_span()));
205            }
206
207            let annoation_type = TypeAnnotation::Map(Box::new(key_type), Box::new(value_type));
208
209            while self.match_type(&[TokenType::Newline]) {}
210            if self.peek() == TokenType::LeftBrace {
211                self.advance();
212                let mut entries = Vec::new();
213                while self.match_type(&[TokenType::Newline]) {}
214
215                while self.peek() != TokenType::RightBrace {
216                    let key = self.parse_expression()?;
217                    while self.match_type(&[TokenType::Newline]) {}
218                    if !self.match_type(&[TokenType::Colon]) {
219                        return Err(self.err("expected `:` after map key", self.peek_span()));
220                    }
221                    while self.match_type(&[TokenType::Newline]) {}
222                    let value = self.parse_expression()?;
223                    entries.push((key, value));
224                    while self.match_type(&[TokenType::Newline]) {}
225                    if self.peek() == TokenType::RightBrace {
226                        break;
227                    }
228                    if !self.match_type(&[TokenType::Comma]) {
229                        return Err(self.err("expected ',' between map entries", self.peek_span()));
230                    }
231                    while self.match_type(&[TokenType::Newline]) {}
232                }
233                self.match_type(&[TokenType::RightBrace]);
234                let span = start.join(self.previous_span());
235                return Ok(Statement::new(
236                    StatementKind::Map {
237                        name,
238                        type_annotation: annoation_type,
239                        entries,
240                    },
241                    span,
242                ));
243            } else {
244                let value = self.parse_expression()?;
245                let value_id = self.ast_arena.exprs.get(value);
246                let span = start.join(value_id.span);
247                return Ok(Statement::new(
248                    StatementKind::VariableDeclaration {
249                        name,
250                        type_annotation: annoation_type,
251                        value,
252                    },
253                    span,
254                ));
255            }
256        }
257
258        // -- set: dec set[T] name = {...} --
259        if self.match_type(&[TokenType::Set]) && self.peek() == TokenType::LeftBracket {
260            self.advance();
261            while self.match_type(&[TokenType::Newline]) {}
262            let annoation_type = self.parse_param_type()?;
263            while self.match_type(&[TokenType::Newline]) {}
264            if !self.match_type(&[TokenType::RightBracket]) {
265                return Err(self.err("expected `]` after type", self.peek_span()));
266            }
267
268            while self.match_type(&[TokenType::Newline]) {}
269            let name = match self.peek() {
270                TokenType::Identifier(n) => {
271                    self.advance();
272                    n
273                }
274                _ => return Err(self.err("expected name after set type", self.peek_span())),
275            };
276
277            while self.match_type(&[TokenType::Newline]) {}
278            if !self.match_type(&[TokenType::Assign]) {
279                return Err(self.err("expected `=` after name", self.peek_span()));
280            }
281
282            while self.match_type(&[TokenType::Newline]) {}
283            if self.peek() == TokenType::LeftBrace {
284                self.advance();
285                let mut items = Vec::new();
286                while self.match_type(&[TokenType::Newline]) {}
287
288                while self.peek() != TokenType::RightBrace {
289                    let value = self.parse_expression()?;
290                    items.push(value);
291                    while self.match_type(&[TokenType::Newline]) {}
292                    if self.peek() == TokenType::RightBrace {
293                        break;
294                    }
295                    if !self.match_type(&[TokenType::Comma]) {
296                        return Err(self.err("expected `,` between set items", self.peek_span()));
297                    }
298                    while self.match_type(&[TokenType::Newline]) {}
299                }
300                self.match_type(&[TokenType::RightBrace]);
301                let span = start.join(self.previous_span());
302                return Ok(Statement::new(
303                    StatementKind::Set {
304                        name,
305                        type_annotation: annoation_type,
306                        items,
307                    },
308                    span,
309                ));
310            } else {
311                while self.match_type(&[TokenType::Newline]) {}
312                let value = self.parse_expression()?;
313                let value_id = self.ast_arena.exprs.get(value);
314                let span = start.join(value_id.span);
315                return Ok(Statement::new(
316                    StatementKind::ConstantDeclaration {
317                        name,
318                        type_annotation: TypeAnnotation::Set(Box::new(annoation_type)),
319                        value,
320                    },
321                    span,
322                ));
323            }
324        }
325
326        // -- array: dec array[T] name = [...] --
327        if self.match_type(&[TokenType::Array]) && self.peek() == TokenType::LeftBracket {
328            self.advance();
329            while self.match_type(&[TokenType::Newline]) {}
330            let annoation_type = self.parse_param_type()?;
331
332            while self.match_type(&[TokenType::Newline]) {}
333            if !self.match_type(&[TokenType::RightBracket]) {
334                return Err(self.err("expected `]` after type", self.peek_span()));
335            }
336
337            while self.match_type(&[TokenType::Newline]) {}
338            let name = match self.peek() {
339                TokenType::Identifier(n) => {
340                    self.advance();
341                    n
342                }
343                _ => return Err(self.err("expected name after array type", self.peek_span())),
344            };
345
346            while self.match_type(&[TokenType::Newline]) {}
347            if !self.match_type(&[TokenType::Assign]) {
348                return Err(self.err("expected `=` after name", self.peek_span()));
349            }
350
351            while self.match_type(&[TokenType::Newline]) {}
352            if self.peek() == TokenType::LeftBracket {
353                self.advance();
354                let mut items = Vec::new();
355                while self.match_type(&[TokenType::Newline]) {}
356
357                while self.peek() != TokenType::RightBracket {
358                    let value = self.parse_expression()?;
359                    items.push(value);
360                    while self.match_type(&[TokenType::Newline]) {}
361                    if self.peek() == TokenType::RightBracket {
362                        break;
363                    }
364                    if !self.match_type(&[TokenType::Comma]) {
365                        return Err(self.err("expected ',' between list items", self.peek_span()));
366                    }
367                    while self.match_type(&[TokenType::Newline]) {}
368                }
369                self.match_type(&[TokenType::RightBracket]);
370                let span = start.join(self.previous_span());
371                return Ok(Statement::new(
372                    StatementKind::Array {
373                        name,
374                        type_annotation: annoation_type,
375                        value: items,
376                    },
377                    span,
378                ));
379            } else {
380                while self.match_type(&[TokenType::Newline]) {}
381                let value = self.parse_expression()?;
382                let value_id = self.ast_arena.exprs.get(value);
383                let span = start.join(value_id.span);
384                return Ok(Statement::new(
385                    StatementKind::VariableDeclaration {
386                        name,
387                        type_annotation: TypeAnnotation::Array(Box::new(annoation_type)),
388                        value,
389                    },
390                    span,
391                ));
392            }
393        }
394
395        self.parse_variable_declartion_scalar(start)
396    }
397
398    fn parse_variable_declartion_scalar(&mut self, start: Span) -> Result<Statement, Error> {
399        let var_type = self.parse_type(true)?;
400        while self.match_type(&[TokenType::Newline]) {}
401        let name = match self.peek() {
402            TokenType::Identifier(n) => {
403                self.advance();
404                n
405            }
406            _ => return Err(self.err("expected name after type", self.peek_span())),
407        };
408
409        while self.match_type(&[TokenType::Newline]) {}
410        if !self.match_type(&[TokenType::Assign]) {
411            return Err(self.err("expected `=` after name", self.peek_span()));
412        }
413
414        while self.match_type(&[TokenType::Newline]) {}
415        let value = self.parse_expression()?;
416        let value_id = self.ast_arena.exprs.get(value);
417        let span = start.join(value_id.span);
418
419        Ok(Statement::new(
420            StatementKind::VariableDeclaration {
421                name,
422                type_annotation: var_type,
423                value,
424            },
425            span,
426        ))
427    }
428}