ielr 0.1.1

Table generation backend for LR parser generators
Documentation
/*
 * Copyright 2022 Arnaud Golfouse
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

//! Structures to build your [`Grammar`].
//!
//! The [`Grammar`] will then be used as input to
//! [`compute_table`](crate::compute_table).
//!
//! # Note on conflicts and their resolution
//!
//! When trying to write a LR(1) grammar, one almost always stumble upon _conflicts_:
//! places in the grammar where the parser generator thinks there is an ambiguity.
//! Those will be reported when calling the [`compute_table`](crate::compute_table)
//! function: it will return [`Error::Conflict`](crate::output::Error::Conflict).
//!
//! It should be noted that conflicts are usually resolved when dealing with
//! expressions (aka `E + E`, is it left or right associative ?). In most other cases,
//! the actual grammar should be changed in order to avoid the conflict.
//!
//! This crate provides two ways of dealing with such conflicts:
//! - **conflict resolution**: by using the [`Grammar::add_conflict_solution`] method,
//! you can resolve specific conflict. In a parser generator, those may be added in
//! bulk when resolving conflicts related to expressions precedence.
//!
//! See [ConflictSolution] for an example.
//! - **precedence annotations**: you can set the precedence of a particular
//! expression, by using [`Production::set_left_precedence`] and
//! [`Production::set_right_precedence`]:
//! ```rust
//! # use ielr::input::{Node, Grammar, Token, Symbol};
//! let expr = Node(0);
//! let plus = Token::new(1).unwrap();
//! let times = Token::new(2).unwrap();
//! let mut grammar = Grammar::new();
//! let add_prod = grammar.add_production(expr, vec![Symbol::Node(expr), Symbol::Token(plus), Symbol::Node(expr)]).unwrap();
//! let mul_prod = grammar.add_production(expr, vec![Symbol::Node(expr), Symbol::Token(times), Symbol::Node(expr)]).unwrap();
//! let precedence_family = grammar.add_precedence_family();
//! grammar
//!     .get_production_mut(add_prod)
//!     .unwrap()
//!     .set_left_precedence(precedence_family, 1)
//!     .set_right_precedence(precedence_family, 2);
//! grammar
//!     .get_production_mut(mul_prod)
//!     .unwrap()
//!     .set_left_precedence(precedence_family, 3)
//!     .set_right_precedence(precedence_family, 4);
//! ```
//!
//! ## Remark
//! On big grammars (like Rust's 😉), precedence annotations slow the generator
//! considerably. In should be fine on small/medium grammars though.

mod conflict_solutions;
mod grammar;

use crate::indices::NonZero;

pub use self::{
    conflict_solutions::{ConflictSolution, ConflictingAction},
    grammar::{
        AddProductionError, Grammar, PrecedenceFamilyToken, PrecedenceLevel, ProdIdx, Production,
    },
};

use std::fmt;

/// A token of the grammar.
///
/// Also called a terminal in some literature.
///
/// A token is a single 'word' in the text. For example, in the following Rust code:
/// ```
/// let x: i32 = 1 + 2;
/// ```
/// The list of tokens (excluding whitespace) would be
/// `["let", "x", ":", "i32", "=", "1", "+", "2", ";"]`.
pub type Token = NonZero<crate::indices::PlainToken>;

/// A node of the grammar.
///
/// Also called a non-terminal in some literature.
///
/// A node is a lexical element of the text, made of tokens (a node may contain 0, 1 or
/// more tokens). For example, in the following Rust code:
/// ```
/// let x: i32 = 1 + 2;
/// ```
/// The grammar would look like this:
/// ```text
/// Statement → 'let' Pattern ':' Type '=' Expression ';'
/// ```
/// As such, the nodes would be `"x"`, `"i32"`, `"1 + 2"` and the whole statement (and
/// maybe other sub-nodes).
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Node(pub crate::indices::PlainNode);

/// A symbol of the grammar, either a [`Token`] or a [`Node`].
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Symbol {
    /// See [`Token`].
    Token(Token),
    /// See [`Node`].
    Node(Node),
}

impl fmt::Debug for Node {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Node({:?})", self.0)
    }
}

impl fmt::Debug for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Token(arg0) => f.debug_tuple("Token").field(&arg0.get()).finish(),
            Self::Node(arg0) => f.debug_tuple("Node").field(&arg0.0).finish(),
        }
    }
}