r7rs-parser 0.1.0

Simple Scheme R7RS parser & lexer
Documentation
use std::fmt;

use crate::{
    expr::{Expr, Interner, NoIntern},
    lexer::{
        lexical_error::LexicalError,
        scanner::{Position, Scanner, TokenKind},
    },
};

use self::syntax_error::SyntaxError;

pub mod syntax_error;

pub struct Parser<'a, I: Interner = NoIntern> {
    symbols: &'a mut I,
    scanner: Scanner<'a>,
}

impl<'a, I: Interner> Parser<'a, I> {
    pub fn new(symbols: &'a mut I, source: &'a str, fold_case: bool) -> Self {
        Self {
            symbols,
            scanner: Scanner::new(source, fold_case, true),
        }
    }

    pub fn finished(&self) -> bool {
        !self.scanner.has_next()
    }

    pub fn parse(&mut self, prescan: bool) -> Result<Box<Expr<I>>, ParseError> {
        let token = self.scanner.token();
        let pos = token.pos;
        let res;
        match token.kind {
            TokenKind::Error => {
                let err = token.error_val.unwrap();
                self.scanner.next();

                return Err(ParseError::Lexical(pos, err));
            }

            TokenKind::Eof => {
                return Err(ParseError::Syntax(pos, SyntaxError::Empty));
            }

            TokenKind::HashSemi => {
                self.scanner.next();
                self.parse(true)?;

                return self.parse(true);
            }

            TokenKind::Ident => {
                let s = if self.scanner.fold_case {
                    token.str_val.to_lowercase()
                } else {
                    token.str_val.clone()
                };
                res = Box::new(Expr::Symbol(self.symbols.intern(&s)));
            }

            TokenKind::TrueLit => res = Box::new(Expr::Bool(true)),

            TokenKind::FalseLit => res = Box::new(Expr::Bool(false)),

            TokenKind::Int => {
                res = Box::new(Expr::Fixnum(token.int_val));
            }

            TokenKind::BigInt => {
                res = Box::new(Expr::BigInt(token.big_int_val.clone()));
            }

            TokenKind::Rat => res = Box::new(Expr::Rational(token.rat_val)),
            TokenKind::Float => {
                res = Box::new(Expr::Float(token.float_val));
            }

            TokenKind::BigRat => res = Box::new(Expr::BigRational(token.big_rat_val.clone())),

            TokenKind::Complex => res = Box::new(Expr::Complex(token.complex_val)),

            TokenKind::Char => {
                res = Box::new(Expr::Char(char::from_u32(token.int_val as u32).unwrap()))
            }

            TokenKind::String => res = Box::new(Expr::Str(token.str_val.clone())),

            TokenKind::LParent => {
                self.scanner.next();
                let mut exprs = vec![];
                while !self
                    .scanner
                    .has_token(&[TokenKind::Eof, TokenKind::RParent, TokenKind::Dot])
                {
                    exprs.push(self.parse(true)?);
                }

                if self.scanner.has_token(&[TokenKind::Dot]) {
                    self.scanner.next();

                    res = Expr::from_slice(exprs, self.parse(true)?);
                } else {
                    res = Expr::from_slice(exprs, Box::new(Expr::Null));
                }

                if !self.scanner.has_token(&[TokenKind::RParent]) {
                    return Err(ParseError::Syntax(
                        self.position(),
                        SyntaxError::ClosingParenthesisMissing,
                    ));
                }
            }

            TokenKind::RParent => {
                self.scanner.next();
                return Err(ParseError::Syntax(
                    pos,
                    SyntaxError::UnexpectedClosingParenthesis,
                ));
            }

            TokenKind::HashLParen => {
                self.scanner.next();

                let mut exprs = vec![];

                while !self
                    .scanner
                    .has_token(&[TokenKind::Eof, TokenKind::RParent])
                {
                    exprs.push(self.parse(true)?.datum());
                }

                if !self.scanner.has_token(&[TokenKind::RParent]) {
                    return Err(ParseError::Syntax(
                        self.position(),
                        SyntaxError::ClosingParenthesisMissing,
                    ));
                }
                res = Box::new(Expr::ImmutableVector(exprs.into_boxed_slice()))
            }

            TokenKind::HashGLParen => {
                self.scanner.next();

                let mut exprs = vec![];

                while !self
                    .scanner
                    .has_token(&[TokenKind::Eof, TokenKind::RParent])
                {
                    exprs.push(self.parse(true)?.datum());
                }

                if !self.scanner.has_token(&[TokenKind::RParent]) {
                    return Err(ParseError::Syntax(
                        self.position(),
                        SyntaxError::ClosingParenthesisMissing,
                    ));
                }
                res = Box::new(Expr::GrowableVector(exprs.into_boxed_slice()))
            }

            TokenKind::U8LParen => {
                self.scanner.next();

                let mut bytes = vec![];

                while !self
                    .scanner
                    .has_token(&[TokenKind::Eof, TokenKind::RParent])
                {
                    let number = self.scanner.token().int_val;
                    if number > 0 && number <= 255 {
                        bytes.push(number as u8);
                    } else {
                        return Err(ParseError::Syntax(
                            self.position(),
                            SyntaxError::NotAByteValue,
                        ));
                    }
                }

                if !self.scanner.has_token(&[TokenKind::RParent]) {
                    return Err(ParseError::Syntax(
                        self.position(),
                        SyntaxError::ClosingParenthesisMissing,
                    ));
                }
                res = Box::new(Expr::ByteVector(bytes.into_boxed_slice()))
            }

            TokenKind::Quote => {
                self.scanner.next();

                res = Expr::from_slice(
                    vec![
                        Box::new(Expr::Symbol(self.symbols.intern("quote"))),
                        self.parse(true)?,
                    ],
                    Box::new(Expr::Null),
                );
            }

            TokenKind::BackQuote => {
                self.scanner.next();

                res = Expr::from_slice(
                    vec![
                        Box::new(Expr::Symbol(self.symbols.intern("quasiquote"))),
                        self.parse(true)?,
                    ],
                    Box::new(Expr::Null),
                );
            }

            TokenKind::Comma => {
                self.scanner.next();

                res = Expr::from_slice(
                    vec![
                        Box::new(Expr::Symbol(self.symbols.intern("unquote"))),
                        self.parse(true)?,
                    ],
                    Box::new(Expr::Null),
                );
            }

            TokenKind::CommaAt => {
                self.scanner.next();

                res = Expr::from_slice(
                    vec![
                        Box::new(Expr::Symbol(self.symbols.intern("unquote-splicing"))),
                        self.parse(true)?,
                    ],
                    Box::new(Expr::Null),
                );
            }
            TokenKind::Dot => {
                self.scanner.next();
                return Err(ParseError::Syntax(pos, SyntaxError::UnexpectedDot));
            }
        }

        if prescan {
            self.scanner.next();
        }

        Ok(Box::new(Expr::Syntax(pos, res)))
    }

    pub fn position(&self) -> Position {
        self.scanner.token().pos
    }
}

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ParseError {
    Lexical(Position, LexicalError),
    Syntax(Position, SyntaxError),
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Lexical(pos, err) => {
                write!(f, "error {} at {}", pos, err)
            }

            Self::Syntax(pos, err) => {
                write!(f, "error {} at {}", pos, err)
            }
        }
    }
}