1use std::sync::Arc;
2
3use gramatika::{Parse, ParseStreamer, Span, Spanned, Token as _};
4
5use crate::{
6 common::{AttributeList, TypeDecl},
7 expr::Expr,
8 token::{operator, punct, Token, TokenKind},
9 ParseStream,
10};
11
12#[derive(Clone, DebugLisp)]
13pub struct VarDecl {
14 pub attributes: Option<AttributeList>,
15 pub storage: Token,
16 pub storage_qualifiers: Option<Arc<[Token]>>,
17 pub name: Token,
18 pub ty: Option<TypeDecl>,
19 pub assignment: Option<Expr>,
20 pub semicolon: Token,
21}
22
23impl Parse for VarDecl {
24 type Stream = ParseStream;
25
26 fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
27 let storage = input.consume_kind(TokenKind::Keyword)?;
28 assert!(matches!(
29 storage.as_matchable(),
30 (TokenKind::Keyword, "let" | "const" | "override" | "var", _)
31 ));
32
33 let storage_qualifiers = if input.check(operator![<]) {
34 input.consume(operator![<])?;
35 let mut qual = vec![input.consume_kind(TokenKind::Keyword)?];
36 if input.check(punct![,]) {
37 input.consume(punct![,])?;
38 qual.push(input.consume_kind(TokenKind::Keyword)?);
39 }
40 input.consume(operator![>])?;
41 Some(qual.into())
42 } else {
43 None
44 };
45
46 let name = input.consume_kind(TokenKind::Ident)?;
47 let ty = if input.check(punct![:]) {
48 Some(input.parse::<TypeDecl>()?)
49 } else {
50 None
51 };
52
53 let assignment = if input.check(operator![=]) {
54 input.next().unwrap();
55
56 Some(input.parse::<Expr>()?)
57 } else {
58 None
59 };
60
61 let semicolon = input.consume(punct![;])?;
62
63 Ok(Self {
64 attributes: None,
65 storage,
66 storage_qualifiers,
67 name,
68 ty,
69 assignment,
70 semicolon,
71 })
72 }
73}
74
75impl Spanned for VarDecl {
76 fn span(&self) -> Span {
77 self.storage.span().through(self.semicolon.span())
78 }
79}