crypt-configs 0.1.0

A simple config format
Documentation
//! Parser 
//! Created 6/4/2026 - Nyx

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 {}