diff options
Diffstat (limited to 'rprt-engine/src/parser.rs')
| -rw-r--r-- | rprt-engine/src/parser.rs | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/rprt-engine/src/parser.rs b/rprt-engine/src/parser.rs new file mode 100644 index 0000000..44feda0 --- /dev/null +++ b/rprt-engine/src/parser.rs @@ -0,0 +1,123 @@ +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<Token>, + 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<Token, ParseError> { + self.tokens + .get(self.pos) + .cloned() + .ok_or(ParseError::UnexpectedEndOfInput { expecting: "token" }) + } +} + +pub fn parse(tokens: Vec<Token>) -> Result<SelectionValuedExpr, ParseError> { + 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<SelectionFn, ParseError> { + 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<BuiltinSelectionFn, ParseError> { + 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<BuiltinSelectionFn, ParseError> { + 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<BuiltinSelectionFn, ParseError> { + 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<BuiltinSelectionFn, ParseError> { + 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<BuiltinSelectionFn, ParseError> { + context.advance()?; + let token = context.current()?; + match token { + Token::Regex(pattern) => Ok(BuiltinSelectionFn::BufferMatch(pattern)), + _ => Err(ParseError::UnexpectedToken { + found: token, + expecting: "regex", + }), + } +} |
