use sexp::Sexp; use crate::asm::data::{Mask, Rd, RdData, RdObj, Wr}; 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, 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, pcx: &'a ParserContext) -> Self { args.reverse(); Self { orig_len: args.len(), 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() } /// 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) -> anyhow::Result { let next = self.next(); let esa = expect_string_atom(next)?; Ok(esa) } /// Get the next entry as read location pub fn next_rd(&mut self) -> anyhow::Result { parse_rd(self.next(), self.pcx) } /// Get the next entry as read location pub fn next_rdobj(&mut self) -> anyhow::Result { match parse_rd(self.next(), self.pcx)? { Rd(RdData::ObjectPtr(reg), Mask::FULL) => { return Ok(RdObj::new(reg)); } other => { anyhow::bail!("Not a valid object handle syntax: {:?}", other); } } } /// Get the next entry as write location pub fn next_wr(&mut self) -> anyhow::Result { parse_wr(self.next(), self.pcx) } }