use super::{Token, TokenKind};
use crate::expression::Composition;
use crate::expression::EvaluationNode;
struct Parser<'a> {
tokens: &'a [Token],
pos: usize,
}
impl<'a> Parser<'a> {
fn new(tokens: &'a [Token]) -> Self {
Self { tokens, pos: 0 }
}
fn peek(&self) -> Option<TokenKind> {
self.tokens.get(self.pos).map(|t| t.kind())
}
fn consume(&mut self) -> TokenKind {
let kind = self.tokens[self.pos].kind();
self.pos += 1;
kind
}
fn parse_expr(&mut self) -> EvaluationNode {
let first = self.parse_term();
if self.peek() != Some(TokenKind::Or) {
return first;
}
let mut children = vec![first];
while self.peek() == Some(TokenKind::Or) {
self.consume(); children.push(self.parse_term());
}
EvaluationNode::Group {
composition: Composition::Or,
negated: false,
children,
}
}
fn parse_term(&mut self) -> EvaluationNode {
let first = self.parse_factor();
if self.peek() != Some(TokenKind::And) {
return first;
}
let mut children = vec![first];
while self.peek() == Some(TokenKind::And) {
self.consume(); children.push(self.parse_factor());
}
EvaluationNode::Group {
composition: Composition::And,
negated: false,
children,
}
}
fn parse_factor(&mut self) -> EvaluationNode {
match self.peek() {
Some(TokenKind::Not) => {
self.consume(); let child = self.parse_factor();
match child {
EvaluationNode::Group {
composition: Composition::And,
children,
..
} => EvaluationNode::Group {
composition: Composition::And,
children,
negated: true,
},
EvaluationNode::Group {
composition: Composition::Or,
children,
..
} => EvaluationNode::Group {
composition: Composition::Or,
children,
negated: true,
},
EvaluationNode::Condition(idx) => EvaluationNode::Group {
composition: Composition::And,
children: vec![EvaluationNode::Condition(idx)],
negated: true,
},
}
}
Some(TokenKind::LParen) => {
self.consume(); let node = self.parse_expr();
self.consume(); node
}
Some(TokenKind::ConditionIndex(idx)) => {
self.consume();
EvaluationNode::Condition(idx)
}
_ => unreachable!("validator guarantees valid token stream"),
}
}
}
pub(crate) fn parse(tokens: &[Token]) -> EvaluationNode {
let mut parser = Parser::new(tokens);
parser.parse_expr()
}