use crate::{
ast::{Column, Expr, UnOp},
value::Value,
};
use super::{lexer::Token, Parser, ParserError};
fn descape_string(s: &str) -> String {
(s[1..s.len() - 1].to_string()).replace("''", "'")
}
impl<'a> Parser<'a> {
pub(super) fn parse_column(&mut self) -> Result<Column, ParserError> {
let first = self.try_consume_symbol()?;
if self.try_consume_dot().is_ok() {
let column = self.try_consume_symbol()?;
Ok(Column(first.to_string(), column.to_string()))
} else {
Ok(Column("".to_string(), first.to_string()))
}
}
fn try_consume_atom(&mut self) -> Result<Expr, ParserError> {
match self.peek()? {
Token::Int(i) => {
let _ = self.lexer.next().unwrap();
Ok(Expr::Literal(Value::Int(i.parse().unwrap())))
}
Token::Question => {
let _ = self.lexer.next().unwrap();
Ok(Expr::Binding(self.try_consume_int()?))
}
Token::String(s) => {
let _ = self.lexer.next().unwrap();
Ok(Expr::Literal(Value::String(descape_string(&s))))
}
Token::Null => {
let _ = self.lexer.next().unwrap();
Ok(Expr::Literal(Value::Null))
}
Token::Symbol(_) => {
let col = self.parse_column().map(|c| Expr::Column(c))?;
if let Ok(Token::Arrow) = self.peek() {
let _ = self.lexer.next().unwrap();
let table = self.try_consume_mapping()?;
let rhs = match self.peek()? {
Token::OpenParen => Some({
let _ = self.lexer.next().unwrap();
let v = self.parse_expr_list()?;
self.try_consume_close_paren()?;
self.try_consume_arrow()?;
v
}),
Token::Arrow => {
let _ = self.lexer.next().unwrap();
None
}
token => Err(ParserError::Unexpected(token))?,
};
let expr = self.parse_expr()?;
Ok(Expr::Edge(vec![col], table, rhs, Box::new(expr)))
} else {
Ok(col)
}
}
Token::Not => {
let _ = self.lexer.next().unwrap();
self.try_consume_atom()
.map(|c| Expr::Unary(UnOp::Not, Box::new(c)))
}
Token::OpenParen => {
let _ = self.lexer.next().unwrap();
let inner = self.parse_expr_list()?;
self.try_consume_close_paren()?;
if let Ok(Token::Arrow) = self.peek() {
let _ = self.lexer.next().unwrap();
let table = self.try_consume_mapping()?;
let rhs = match self.peek()? {
Token::OpenParen => Some({
let _ = self.lexer.next().unwrap();
let v = self.parse_expr_list()?;
self.try_consume_close_paren()?;
self.try_consume_arrow()?;
v
}),
Token::Arrow => {
let _ = self.lexer.next().unwrap();
None
}
token => Err(ParserError::Unexpected(token))?,
};
let expr = self.parse_expr()?;
if inner.is_empty()
|| rhs.as_ref().map(|rhs| rhs.is_empty()).unwrap_or_default()
{
return Err(ParserError::EdgeNoExpressions);
}
Ok(Expr::Edge(inner, table, rhs, Box::new(expr)))
} else if inner.len() == 1 {
Ok(inner[0].clone())
} else {
return Err(ParserError::UnexpectedEndOfEdge);
}
}
token => Err(ParserError::Unexpected(token)),
}
}
pub(super) fn parse_expr(&mut self) -> Result<Expr, ParserError> {
let mut atoms = Vec::new();
let mut bin_operators = Vec::new();
atoms.push(self.try_consume_atom()?);
while let Ok(binop) = self.try_consume_binary_operator() {
bin_operators.push(binop);
atoms.push(self.try_consume_atom()?);
}
while let Some((i, op)) = bin_operators
.iter()
.copied()
.enumerate()
.min_by(|a, b| a.1.precedence().cmp(&b.1.precedence()))
{
let lhs = i;
let rhs = i + 1;
bin_operators.remove(i);
atoms[lhs] = Expr::Bin(
Box::new(atoms[lhs].clone()),
op,
Box::new(atoms.remove(rhs)),
);
}
Ok(atoms.pop().unwrap())
}
pub(super) fn parse_expr_list(&mut self) -> Result<Vec<Expr>, ParserError> {
self.make_parse_list(Self::parse_expr)
}
}