use crate::{lexer::Token};
#[derive(Debug)]
pub enum Node {
Null,
Assignment(Box<Node>, Box<Node>),
Body(Box<Node>),
Sequence(Box<Node>, Box<Node>),
Value(String),
Identifier(String),
}
pub struct Parser {
tokens: Vec<Token>,
}
impl Parser {
pub fn new(mut tokens: Vec<Token>) -> Self {
tokens.reverse();
Self {
tokens,
}
}
pub fn next(&mut self) {
self.tokens.pop();
}
pub fn peek(&self) -> Result<Token, ParseError> {
match self.tokens.last() {
Some(t) => Ok(t.clone()),
None => Err(ParseError::ReadOutOfBounds)
}
}
}
pub fn parse_expression(
parser: &mut Parser,
current_power: i32,
) -> Result<Box<Node>, ParseError> {
let current = parser.peek()?;
parser.next();
let mut left = null_denotation(parser, current)?;
while let current = parser.peek()? && current.get_infix_binding() > current_power {
parser.next();
left = left_denotation(parser, current, left)?;
}
Ok(left)
}
pub fn null_denotation(
parser: &mut Parser,
current: Token,
) -> Result<Box<Node>, ParseError> {
match current {
Token::LineEnd => Ok(Box::new(Node::Null)),
Token::EOF => Ok(Box::new(Node::Null)),
Token::Identifier(i) => Ok(Box::new(Node::Identifier(i))),
Token::Value(v) => Ok(Box::new(Node::Value(v))),
Token::BodyClose => Ok(Box::new(Node::Null)),
Token::BodyOpen => {
if let Token::BodyClose = parser.peek()? {
parser.next();
Ok(Box::new(Node::Body(Box::new(Node::Null))))
} else {
let inner = parse_expression(parser, 0)?;
let next = parser.peek()?;
if let Token::BodyClose = next {
parser.next();
Ok(Box::new(Node::Body(inner)))
} else {
Err(ParseError::ExpectedClosingBrace(next))
}
}
}
_ => Err(ParseError::NoNUDForToken(current))
}
}
pub fn left_denotation(
parser: &mut Parser,
current: Token,
left: Box<Node>,
) -> Result<Box<Node>, ParseError> {
match current {
Token::Assign => Ok(Box::new(Node::Assignment(left, parse_expression(parser, 2)?))),
Token::LineEnd => {
let right = parse_expression(parser, 0)?;
if let Node::Null = &*right {
Ok(left)
} else if let Node::Null = &*left {
Ok(right)
} else {
Ok(Box::new(Node::Sequence(left, right)))
}
}
_ => Err(ParseError::NoLEDForToken(current))
}
}
#[derive(Debug)]
pub enum ParseError {
ReadOutOfBounds,
NoNUDForToken(Token),
NoLEDForToken(Token),
ExpectedClosingBrace(Token),
Other(std::io::Error)
}
impl From<std::io::Error> for ParseError {
fn from(value: std::io::Error) -> Self {
Self::Other(value)
}
}
impl std::fmt::Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::ReadOutOfBounds => write!(f, "Read out of bounds!"),
Self::NoNUDForToken(t) => write!(f, "No NUD for token: {:?}", t),
Self::NoLEDForToken(t) => write!(f, "No LED for token: {:?}", t),
Self::ExpectedClosingBrace(t) => write!(f, "Expected closing brace: (}}) found: {:?}", t),
Self::Other(e) => write!(f, "{}", e)
}
}
}
impl std::error::Error for ParseError {}