Skip to main content

rl_lang/parser/statements/
const_declaration.rs

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