rusty_lr_parser 4.0.0

grammar line parser for rusty_lr
Documentation
use std::collections::BTreeSet;

use super::token::TokenMapped;
use crate::parser::location::Located;
use crate::parser::location::Location;
use proc_macro2::TokenStream;

#[derive(Clone)]
pub struct CustomReduceAction {
    pub body: TokenStream,
    idents_used: BTreeSet<String>,
}

impl CustomReduceAction {
    fn fetch_idents(set: &mut BTreeSet<String>, ts: TokenStream) {
        for token in ts {
            match token {
                proc_macro2::TokenTree::Group(g) => {
                    Self::fetch_idents(set, g.stream());
                }
                proc_macro2::TokenTree::Ident(i) => {
                    set.insert(i.to_string());
                }
                _ => {}
            }
        }
    }
    pub fn new(body: TokenStream) -> Self {
        let mut idents_used = BTreeSet::new();
        Self::fetch_idents(&mut idents_used, body.clone());
        Self { body, idents_used }
    }
    fn contains_ident(&self, name: &str) -> bool {
        self.idents_used.contains(name)
    }
}

pub enum ReduceAction {
    /// reduce action that is function-like TokenStream
    Custom(CustomReduceAction),
    /// reduce action that is auto-generated, and simply returns the i'th token itself
    Identity(usize), // index of the token in the rule
}

impl ReduceAction {
    pub fn new_custom(body: TokenStream) -> Self {
        ReduceAction::Custom(CustomReduceAction::new(body))
    }
    pub fn is_identity(&self) -> bool {
        matches!(self, ReduceAction::Identity(_))
    }
    pub fn is_custom(&self) -> bool {
        matches!(self, ReduceAction::Custom(_))
    }
}

pub struct Rule {
    pub tokens: Vec<TokenMapped>,
    /// reduce action called when this rule is reduced
    pub reduce_action: Option<ReduceAction>,
    /// span of '|' or ':' before this production rule
    pub separator_location: Location,
    /// %prec definition
    pub prec: Option<Located<rusty_lr_core::rule::Precedence>>,
    /// %dprec definition
    pub dprec: Option<Located<usize>>,

    /// in `Grammar::build_grammar()`, some production rules will be optimized out and deleted
    pub(crate) is_used: bool,
}

impl Rule {
    pub fn location(&self) -> Location {
        let begin = self.separator_location.clone();
        if let Some(token) = self.tokens.last() {
            let end = &token.location;
            begin.merge(&end)
        } else {
            begin
        }
    }
    pub fn reduce_action_contains_ident(&self, name: &str) -> bool {
        match self.reduce_action.as_ref() {
            Some(ReduceAction::Custom(custom)) => custom.contains_ident(name),
            Some(ReduceAction::Identity(identity_idx)) => {
                self.tokens[*identity_idx]
                    .mapto
                    .as_ref()
                    .map(|m| m.value().as_str())
                    == Some(name)
            }
            None => false,
        }
    }
}

pub struct NonTerminalInfo {
    pub name: Located<String>,

    /// Name of auto generated rule are in the format of `__AutoRule ...`
    /// So we need other abbreviation for auto generated rules.
    pub pretty_name: String,

    /// The rule type of this non-terminal
    pub ruletype: Option<TokenStream>,

    /// Whether the rule type of this non-terminal should be boxed in the Data enum
    pub ruletype_boxed: bool,

    /// Every set of production rules
    pub rules: Vec<Rule>,

    /// If this non-terminal is auto-generated by other patterns,
    /// the location of that pattern is stored here for error reporting.
    pub(crate) root_location: Option<Location>,

    /// protected from optimization removal
    pub(crate) protected: bool,

    /// if this non-terminal is auto-generated, the pattern that generated this rule.
    /// This field is used in rusty_lr_core/tree.rs to unwrap left/right recursion parsing tree into flat array.
    pub(crate) nonterm_type: Option<rusty_lr_core::parser::nonterminal::NonTerminalType>,
}

impl NonTerminalInfo {
    pub fn is_auto_generated(&self) -> bool {
        self.root_location.is_some()
    }
    /// only for auto-generated rules
    /// returns the location of the pattern that generated this rule
    pub fn root_location(&self) -> Option<Location> {
        self.root_location
    }

    /// if this non-terminal is protected from optimization; will not be automatically deleted
    pub(crate) fn is_protected(&self) -> bool {
        self.protected
    }
}