use std::sync::Arc;
use gramatika::{Parse, ParseStreamer, Span, Spanned, Token as _};
use crate::{
common::{AttributeList, TypeDecl},
expr::Expr,
token::{operator, punct, Token, TokenKind},
ParseStream,
};
#[derive(Clone, DebugLisp)]
pub struct VarDecl {
pub attributes: Option<AttributeList>,
pub storage: Token,
pub storage_qualifiers: Option<Arc<[Token]>>,
pub name: Token,
pub ty: Option<TypeDecl>,
pub assignment: Option<Expr>,
pub semicolon: Token,
}
impl Parse for VarDecl {
type Stream = ParseStream;
fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
let storage = input.consume_kind(TokenKind::Keyword)?;
assert!(matches!(
storage.as_matchable(),
(TokenKind::Keyword, "let" | "const" | "override" | "var", _)
));
let storage_qualifiers = if input.check(operator![<]) {
input.consume(operator![<])?;
let mut qual = vec![input.consume_kind(TokenKind::Keyword)?];
if input.check(punct![,]) {
input.consume(punct![,])?;
qual.push(input.consume_kind(TokenKind::Keyword)?);
}
input.consume(operator![>])?;
Some(qual.into())
} else {
None
};
let name = input.consume_kind(TokenKind::Ident)?;
let ty = if input.check(punct![:]) {
Some(input.parse::<TypeDecl>()?)
} else {
None
};
let assignment = if input.check(operator![=]) {
input.next().unwrap();
Some(input.parse::<Expr>()?)
} else {
None
};
let semicolon = input.consume(punct![;])?;
Ok(Self {
attributes: None,
storage,
storage_qualifiers,
name,
ty,
assignment,
semicolon,
})
}
}
impl Spanned for VarDecl {
fn span(&self) -> Span {
self.storage.span().through(self.semicolon.span())
}
}