use crate::expression::*; use crate::token::*; #[derive(Debug, Clone)] pub enum ParseError { UnexpectedToken { found: Token, // Own the token, don't borrow it expecting: &'static str, }, UnexpectedEndOfInput { expecting: &'static str, }, } struct ParseContext { tokens: Vec, pos: usize, } impl ParseContext { fn advance(&mut self) -> Result<(), ParseError> { self.pos += 1; if self.pos >= self.tokens.len() { Err(ParseError::UnexpectedEndOfInput { expecting: "more tokens", }) } else { Ok(()) } } fn current(&self) -> Result { self.tokens .get(self.pos) .cloned() .ok_or(ParseError::UnexpectedEndOfInput { expecting: "token" }) } } pub fn parse(tokens: Vec) -> Result { let mut context = ParseContext { tokens: tokens, pos: 0, }; let func = parse_function(&mut context)?; Ok(SelectionValuedExpr::NullaryApplicationS(func)) } fn parse_function(context: &mut ParseContext) -> Result { let func = parse_builtin_function_s(context)?; Ok(SelectionFn::Function { func: func, search_mod: None, result_transform: None, }) } fn parse_builtin_function_s(context: &mut ParseContext) -> Result { let token = context.current()?; match token { Token::Empty => Ok(BuiltinSelectionFn::Empty), Token::EndOfBuffer => Ok(BuiltinSelectionFn::EndOfBuffer), Token::Span => Ok(BuiltinSelectionFn::Span), Token::CharacterOffset => parse_char_offset(context), Token::Number(n) => Ok(BuiltinSelectionFn::Line(n)), Token::Regex(pattern) => Ok(BuiltinSelectionFn::Regex(pattern)), Token::AllMatches => parse_all_matches(context), Token::PositiveLineOffset => parse_relative_line(context), Token::BufferMatch => parse_buffer_match(context), _ => Err(ParseError::UnexpectedToken { found: token, expecting: "selection function", }), } } fn parse_char_offset(context: &mut ParseContext) -> Result { context.advance()?; let token = context.current()?; match token { Token::Number(n) => Ok(BuiltinSelectionFn::CharOffset(n)), _ => Err(ParseError::UnexpectedToken { found: token, expecting: "number", }), } } fn parse_all_matches(context: &mut ParseContext) -> Result { context.advance()?; let token = context.current()?; match token { Token::Regex(pattern) => Ok(BuiltinSelectionFn::AllMatches(pattern)), _ => Err(ParseError::UnexpectedToken { found: token, expecting: "regex", }), } } fn parse_relative_line(context: &mut ParseContext) -> Result { context.advance()?; let token = context.current()?; match token { Token::Number(n) => Ok(BuiltinSelectionFn::RelativeLine(n)), _ => Err(ParseError::UnexpectedToken { found: token, expecting: "number", }), } } fn parse_buffer_match(context: &mut ParseContext) -> Result { context.advance()?; let token = context.current()?; match token { Token::Regex(pattern) => Ok(BuiltinSelectionFn::BufferMatch(pattern)), _ => Err(ParseError::UnexpectedToken { found: token, expecting: "regex", }), } }