use std::{iter::Peekable, slice::Iter};
use crate::{
errors::DiagnosticBuilder,
lexer::{Token, TokenKind},
session::Session,
};
use super::parser::{
parse_binary_literal, parse_float_literal, parse_hexadecimal_literal, parse_integer_literal,
};
pub type ExpResult<'a> = Result<Option<ExpNode>, DiagnosticBuilder<'a>>;
pub type TokenIter<'a> = Peekable<Iter<'a, Token>>;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Value {
Int(i32),
Double(f64),
Bool(bool),
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum UnOp {
Negate,
Flip,
Not,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum BinOp {
Add,
Sub,
Mult,
Div,
Mod,
And,
Or,
Eq,
Ne,
Gt,
Lt,
Gte,
Lte,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ExpNode {
BinOp(Box<ExpNode>, BinOp, Box<ExpNode>),
UnOp(UnOp, Box<ExpNode>),
Constant(Value),
}
macro_rules! gen_binop {
($tokens:ident, $session:ident, $func_name:ident, $token_kind:expr, $op_kind:expr) => {{
Self::skip_whitespace($tokens);
if let Some(mut lhs) = Self::$func_name($tokens, $session)? {
Self::skip_whitespace($tokens);
while let Some(&token) = $tokens.peek() {
if token.kind == $token_kind {
$tokens.next();
if let Some(rhs) = Self::$func_name($tokens, $session)? {
lhs = ExpNode::BinOp(Box::new(lhs), $op_kind, Box::new(rhs));
} else {
let db = $session
.struct_span_error(token.as_span(), "trailing operator".to_string());
return Err(db);
}
}
else {
break;
}
}
Ok(Some(lhs))
} else {
Ok(None)
}
}};
}
pub struct ExpressionParser {}
impl ExpressionParser {
pub fn parse_expression<'a>(
tokens: &mut TokenIter,
session: &'a Session,
nested: bool,
) -> ExpResult<'a> {
let parsed = Self::parse_logical_or(tokens, session)?;
if !nested {
while let Some(token) = tokens.next() {
if token.kind != TokenKind::Whitespace {
let db = session.struct_span_error(
token.as_span(),
"trailing token in expression".to_string(),
);
return Err(db);
}
}
}
Ok(parsed)
}
fn skip_whitespace(tokens: &mut TokenIter) {
while let Some(token) = tokens.peek() {
if token.kind != TokenKind::Whitespace {
break;
} else {
tokens.next();
}
}
}
fn parse_logical_or<'a>(tokens: &mut TokenIter, session: &'a Session) -> ExpResult<'a> {
gen_binop!(
tokens,
session,
parse_logical_and,
TokenKind::OperatorOr,
BinOp::Or
)
}
fn parse_logical_and<'a>(tokens: &mut TokenIter, session: &'a Session) -> ExpResult<'a> {
gen_binop!(
tokens,
session,
parse_equality_exp,
TokenKind::OperatorAnd,
BinOp::And
)
}
fn parse_equality_exp<'a>(tokens: &mut TokenIter, session: &'a Session) -> ExpResult<'a> {
Self::skip_whitespace(tokens);
if let Some(mut lhs) = Self::parse_relational_exp(tokens, session)? {
Self::skip_whitespace(tokens);
while let Some(&&token) = tokens.peek() {
let op = match token.kind {
TokenKind::OperatorEquals => BinOp::Eq,
TokenKind::OperatorNotEquals => BinOp::Ne,
_ => {
break;
}
};
tokens.next();
if let Some(rhs) = Self::parse_relational_exp(tokens, session)? {
lhs = ExpNode::BinOp(Box::new(lhs), op, Box::new(rhs));
} else {
let db =
session.struct_span_error(token.as_span(), "trailing operator".to_string());
return Err(db);
}
}
Ok(Some(lhs))
} else {
Ok(None)
}
}
fn parse_relational_exp<'a>(tokens: &mut TokenIter, session: &'a Session) -> ExpResult<'a> {
Self::skip_whitespace(tokens);
if let Some(mut lhs) = Self::parse_additive_exp(tokens, session)? {
Self::skip_whitespace(tokens);
while let Some(&&token) = tokens.peek() {
let op = match token.kind {
TokenKind::OperatorGreaterThan => BinOp::Gt,
TokenKind::OperatorLessThan => BinOp::Lt,
TokenKind::OperatorGreaterEquals => BinOp::Gte,
TokenKind::OperatorLessEquals => BinOp::Lte,
_ => {
break;
}
};
tokens.next();
if let Some(rhs) = Self::parse_additive_exp(tokens, session)? {
lhs = ExpNode::BinOp(Box::new(lhs), op, Box::new(rhs));
} else {
let db =
session.struct_span_error(token.as_span(), "trailing operator".to_string());
return Err(db);
}
}
Ok(Some(lhs))
} else {
Ok(None)
}
}
fn parse_additive_exp<'a>(tokens: &mut TokenIter, session: &'a Session) -> ExpResult<'a> {
Self::skip_whitespace(tokens);
if let Some(mut lhs) = Self::parse_term(tokens, session)? {
Self::skip_whitespace(tokens);
while let Some(&&token) = tokens.peek() {
let op = match token.kind {
TokenKind::OperatorPlus => BinOp::Add,
TokenKind::OperatorMinus => BinOp::Sub,
_ => {
break;
}
};
tokens.next();
if let Some(rhs) = Self::parse_term(tokens, session)? {
lhs = ExpNode::BinOp(Box::new(lhs), op, Box::new(rhs));
} else {
let db =
session.struct_span_error(token.as_span(), "trailing operator".to_string());
return Err(db);
}
}
Ok(Some(lhs))
} else {
Ok(None)
}
}
fn parse_term<'a>(tokens: &mut TokenIter, session: &'a Session) -> ExpResult<'a> {
Self::skip_whitespace(tokens);
if let Some(mut lhs) = Self::parse_factor(tokens, session)? {
Self::skip_whitespace(tokens);
while let Some(&&token) = tokens.peek() {
let op = match token.kind {
TokenKind::OperatorMultiply => BinOp::Mult,
TokenKind::OperatorDivide => BinOp::Div,
_ => {
break;
}
};
tokens.next();
if let Some(rhs) = Self::parse_factor(tokens, session)? {
lhs = ExpNode::BinOp(Box::new(lhs), op, Box::new(rhs));
} else {
let db =
session.struct_span_error(token.as_span(), "trailing operator".to_string());
return Err(db);
}
}
Ok(Some(lhs))
} else {
Ok(None)
}
}
fn parse_factor<'a>(tokens: &mut TokenIter, session: &'a Session) -> ExpResult<'a> {
Self::skip_whitespace(tokens);
if let Some(&token) = tokens.next() {
match token.kind {
TokenKind::SymbolLeftParen => {
let inner_expression = Self::parse_expression(tokens, session, true)?;
Self::skip_whitespace(tokens);
if let Some(next) = tokens.next() {
if next.kind != TokenKind::SymbolRightParen {
println!("Token was: {:?}", next);
let db = session.struct_span_error(
next.as_span(),
"expected closing )".to_string(),
);
Err(db)
} else {
Ok(inner_expression)
}
} else {
let db = session
.struct_span_error(token.as_span(), "missing closing )".to_string());
Err(db)
}
}
TokenKind::OperatorNegate
| TokenKind::OperatorCompliment
| TokenKind::OperatorMinus => {
let op = match token.kind {
TokenKind::OperatorNegate => UnOp::Not,
TokenKind::OperatorCompliment => UnOp::Flip,
TokenKind::OperatorMinus => UnOp::Negate,
_ => unreachable!(),
};
if let Some(factor) = Self::parse_factor(tokens, session)? {
Ok(Some(ExpNode::UnOp(op, Box::new(factor))))
} else {
let db = session.struct_span_error(
token.as_span(),
"operator with no expression".to_string(),
);
Err(db)
}
}
TokenKind::LiteralInteger | TokenKind::LiteralHex | TokenKind::LiteralBinary => {
let value_snippet = session.span_to_snippet(&token.as_span());
let value_str = value_snippet.as_slice();
if let Ok(value) = match token.kind {
TokenKind::LiteralInteger => parse_integer_literal(value_str),
TokenKind::LiteralHex => parse_hexadecimal_literal(value_str),
TokenKind::LiteralBinary => parse_binary_literal(value_str),
_ => unreachable!(),
} {
Ok(Some(ExpNode::Constant(Value::Int(value))))
} else {
let db = session.struct_span_error(
token.as_span(),
"literal too large to be stored".to_string(),
);
Err(db)
}
}
TokenKind::LiteralFloat => {
let value_snippet = session.span_to_snippet(&token.as_span());
let value_str = value_snippet.as_slice();
if let Ok(value) = parse_float_literal(value_str) {
Ok(Some(ExpNode::Constant(Value::Double(value))))
} else {
let db = session.struct_bug(format!("error parsing float {}", value_str));
Err(db)
}
}
TokenKind::LiteralTrue | TokenKind::LiteralFalse => Ok(Some(ExpNode::Constant(
Value::Bool(token.kind == TokenKind::LiteralTrue),
))),
_ => {
let mut db = session
.struct_error("expected parenthesis, constant, or operator".to_string());
db.span_label(token.as_span(), "found invalid token".to_string());
Err(db)
}
}
} else {
Ok(None)
}
}
}