use anyhow::{Result, bail}; use crate::{cli::CliArgs, common::loc::LocBox, lerror, parser::{Delimiter, ast::{expr::Expr, literal::Literal}}, tokeniser::Token}; use super::{ast::{typ::Type, TokenType}, expr::parse_expr, utils, Keyword, Punctuation}; pub fn parse_type(tokens: &mut Vec) -> Result> { let mut ref_cnt = Vec::new(); let mut loc = None; while let Some(tok) = utils::check_consume(tokens, TokenType::Punct(Punctuation::Ampersand)) { if let None = loc { loc = Some(tok.loc().clone()); } if let Some(tok) = utils::check_consume(tokens, TokenType::Keyword(Keyword::Mut)) { ref_cnt.push(tok.clone()); } else { ref_cnt.push(tok.clone()); } } let mut typ; if let Some(start) = utils::check_consume(tokens, TokenType::Delim(super::Delimiter::SquareL)) { if let None = loc { loc = Some(start.loc().clone()); } let itm_typ = parse_type(tokens)?; if let Some(_) = utils::check_consume(tokens, TokenType::Punct(Punctuation::Semi)) { let count = parse_expr(tokens, 0, false, &CliArgs::default())?.unwrap(); match count.inner() { Expr::Literal(_, Literal::Number(_)) | Expr::Path(_) => (), _ => { lerror!(count.loc(), "Only literal numbers are allowed in sized arrays"); bail!("") } } typ = Type::SizedArray { inner: Box::new(itm_typ.inner().clone()), count: count }; } else { typ = Type::UnsizedArray { inner: Box::new(itm_typ.inner().clone()), }; } _ = utils::check_consume_or_err(tokens, TokenType::Delim(Delimiter::SquareR), "")?; } else { let ident = utils::check_consume_or_err(tokens, TokenType::ident(""), "a")?; typ = Type::Owned(ident.tt().unwrap_ident()); if let None = loc { loc = Some(ident.loc().clone()); } } while let Some(reft) = ref_cnt.pop() { match reft.tt() { TokenType::Keyword(Keyword::Mut) => { typ = Type::Ref { inner: Box::new(typ), mutable: true } }, TokenType::Punct(Punctuation::Ampersand) => { typ = Type::Ref { inner: Box::new(typ), mutable: false } } _ => unreachable!() } } Ok(LocBox::new(&loc.unwrap(), typ)) }