use std::collections::HashMap; use crate::{ ast::{Expr, ExprMake, Literal, NumberLiteral}, lexer::{Ident, NumberSuffix, Spanned, Token}, unwrap_match, }; use super::{Parser, ParserError}; impl<'a> Parser<'a> { pub fn ask_expr(&mut self) -> Result, ParserError> { let Spanned(token, _) = self.tokens.peek()?; Ok(match token { Token::StringLiteral(_) | Token::NumberLiteral(_) | Token::CharLiteral(_) => { self._ask_literal()?.map(Expr::Literal) } Token::Ident(Ident::Make) => { self.eat(); self._ask_struct_init()?.map(Box::new).map(Expr::Make) } _ => return Err(self.expected("an expression")), }) } pub fn _ask_number_literal(&mut self) -> Result, ParserError> { match self.tokens.next()? { Spanned(Token::NumberLiteral(number), mut span) => { let lit = if let Spanned(Token::NumberSuffix(_), sp) = self.tokens.peek()? { span += sp; use NumberLiteral::*; match unwrap_match!( self.tokens.next()?, Spanned(Token::NumberSuffix(suffering), _) => suffering) // eat suffix { NumberSuffix::Ptr => Ptr(number as usize), NumberSuffix::U8 => U8(number as u8), NumberSuffix::I8 => I8(number as i8), NumberSuffix::U16 => U16(number as u16), NumberSuffix::I16 => I16(number as i16), NumberSuffix::U32 => U32(number as u32), NumberSuffix::I32 => I32(number as i32), NumberSuffix::U64 => U64(number as u64), NumberSuffix::I64 => I64(number), _ => return Err(self.expected("a non-floating number suffix")) } } else { NumberLiteral::Infer(number) }; Ok(Spanned(lit, span)) } _ => Err(self.expected("a number literal")), } } pub fn _ask_literal(&mut self) -> Result, ParserError> { if let Spanned(Token::NumberLiteral(_), _) = self.tokens.peek()? { return Ok(self._ask_number_literal()?.map(Literal::Number)); }; let Spanned(token, span) = self.tokens.next()?; Ok(match token { Token::StringLiteral(string) => Spanned(Literal::String(string), span), Token::CharLiteral(chr) => Spanned(Literal::Char(chr), span), _ => return Err(self.expected("a literal")), }) } fn _ask_struct_init(&mut self) -> Result, ParserError> { let Spanned(name, nSp) = self.ask_ident()?; let Spanned(_, _) = self.get_real( |token| matches!(token, Token::LeftCurly), "an opening curly brace (`{`)", )?; let mut params = HashMap::::new(); loop { match self.tokens.peek()?.0 { Token::Ident(_) => { let Spanned(ident, _) = self.ask_ident().unwrap(); self.get_real(|token| matches!(token, Token::Colon), "a colon")?; let Spanned(value, _) = self.ask_expr()?; params.insert(ident, value); match self.tokens.peek()?.0 { Token::Comma => self.eat(), Token::RightCurly => {}, _ => return Err(self.expected("a comma or a closing curly brace")) } } Token::RightCurly => break, _ => return Err(self.expected("an identifier or a closing curly brace (`}`)")), } } if let Spanned(Token::RightCurly, ccSp) = self.tokens.next()? { return Ok(Spanned(ExprMake { name, params }, nSp + ccSp)); }; Err(self.expected("closing curly braces")) } }