use sexp::{Sexp, SourcePosition}; use crate::asm::data::{Mask, Rd, RdData, RdObj, Wr}; use crate::asm::error::CrsnError; use crate::asm::parse::parse_data::{parse_rd, parse_wr}; use crate::asm::parse::ParserContext; use crate::asm::parse::sexp_expect::expect_string_atom; /// Utility for argument parsing pub struct TokenParser<'a> { orig_len: usize, args: Vec, start_pos: &'a SourcePosition, pub pcx: &'a ParserContext<'a>, } impl<'a> IntoIterator for TokenParser<'a> { type Item = Sexp; type IntoIter = std::vec::IntoIter; fn into_iter(mut self) -> Self::IntoIter { // The vec is reversed so we can call "pop", but here we will iterate it as slice so it // must be reversed to its original direction. self.args.reverse(); self.args.into_iter() } } impl<'a> TokenParser<'a> { /// Create a new argument parser pub fn new(mut args: Vec, start_pos: &'a SourcePosition, pcx: &'a ParserContext) -> Self { args.reverse(); Self { orig_len: args.len(), start_pos, args, pcx, } } pub fn have_more(&self) -> bool { self.len() > 0 } /// Get remaining items count pub fn len(&self) -> usize { self.args.len() } /// Get len before parsing started pub fn orig_len(&self) -> usize { self.orig_len } /// Check if parsing started pub fn parsing_started(&self) -> bool { self.args.len() != self.orig_len } /// Get the next entry pub fn next(&mut self) -> Option { self.args.pop() } /// Get the next entry, or raise an error pub fn next_or_err(&mut self) -> Result { match self.next() { None => { Err(CrsnError::Parse("Unexpected end of token list".into(), self.start_pos.clone())) } Some(removed) => Ok(removed) } } /// Look at the next entry pub fn peek(&mut self) -> Option<&Sexp> { self.args.last() } /// Get the next string entry pub fn next_string(&mut self) -> Result<(String, SourcePosition), CrsnError> { let next = self.next_or_err()?; let esa = expect_string_atom(next)?; Ok(esa) } /// Get the next entry as read location pub fn next_rd(&mut self) -> Result { let next = self.next_or_err()?; parse_rd(next, self.pcx) } /// Get the next entry as an object location pub fn next_rdobj(&mut self) -> Result { match parse_rd(self.next_or_err()?, self.pcx)? { Rd(RdData::RegObject(reg), Mask::FULL) => { Ok(RdObj::new(reg)) } other => { Err(CrsnError::Parse( format!("Not a valid object handle syntax: {:?}", other).into(), self.start_pos.clone(), )) } } } /// Get the next entry as write location pub fn next_wr(&mut self) -> Result { parse_wr(self.next_or_err()?, self.pcx) } }