fnotation 0.11.2

A simple lower-house syntax for programming language experimentation
Documentation
use bumpalo::Bump;
use tattle::Reporter;

use crate::{
    grammar::{parse_term, parse_top},
    lexer::lex,
    parser::Prec,
    FNtn, FNtnTop,
};

pub struct ParseConfig<'a> {
    pub precedences: &'a [(&'a str, Prec)],
    pub keywords: &'a [&'a str],
    pub toplevels: &'a [&'a str],
}

impl<'a> ParseConfig<'a> {
    pub const fn new(
        precedences: &'a [(&'a str, Prec)],
        keywords: &'a [&'a str],
        toplevels: &'a [&'a str],
    ) -> Self {
        Self {
            precedences,
            keywords,
            toplevels,
        }
    }

    pub fn is_keyword(&self, s: &str) -> bool {
        self.keywords.contains(&s)
    }

    pub fn is_toplevel(&self, s: &str) -> bool {
        self.toplevels.contains(&s)
    }

    pub fn with_parsed<A, F: FnOnce(&FNtn) -> Option<A>>(
        &self,
        input: &str,
        reporter: Reporter,
        f: F,
    ) -> Option<A> {
        let precedences = self
            .precedences
            .iter()
            .map(|(s, p)| (s.to_string(), *p))
            .collect();
        let Ok(tokens) = lex(input, &self, reporter.clone()) else {
            return None;
        };
        let arena = Bump::new();
        let ast = parse_term(input, reporter.clone(), precedences, tokens, &arena);
        if reporter.errored() {
            None
        } else {
            f(ast)
        }
    }

    pub fn with_parsed_top<A, F: FnOnce(&[FNtnTop]) -> Option<A>>(
        &self,
        input: &str,
        reporter: Reporter,
        f: F,
    ) -> Option<A> {
        let precedences = self
            .precedences
            .iter()
            .map(|(s, p)| (s.to_string(), *p))
            .collect();
        let Ok(tokens) = lex(input, &self, reporter.clone()) else {
            return None;
        };
        if reporter.errored() {
            return None;
        }
        let arena = Bump::new();
        let top = parse_top(input, reporter.clone(), precedences, tokens, &arena);
        if reporter.errored() {
            None
        } else {
            f(&top)
        }
    }
}