use super::nfa::Nfa; use super::rules::{Alias, Associativity, Rule, Symbol}; use hashbrown::HashMap; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub(crate) enum VariableType { Hidden, Auxiliary, Anonymous, Named, } // Input grammar #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) struct Variable { pub name: String, pub kind: VariableType, pub rule: Rule, } #[derive(Debug, PartialEq, Eq)] pub(crate) struct InputGrammar { pub name: String, pub variables: Vec, pub extra_tokens: Vec, pub expected_conflicts: Vec>, pub external_tokens: Vec, pub variables_to_inline: Vec, pub supertype_symbols: Vec, pub word_token: Option, } // Extracted lexical grammar #[derive(Debug, PartialEq, Eq)] pub(crate) struct LexicalVariable { pub name: String, pub kind: VariableType, pub implicit_precedence: i32, pub start_state: u32, } #[derive(Debug, Default, PartialEq, Eq)] pub(crate) struct LexicalGrammar { pub nfa: Nfa, pub variables: Vec, } // Extracted syntax grammar #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub(crate) struct ProductionStep { pub symbol: Symbol, pub precedence: i32, pub associativity: Option, pub alias: Option, pub field_name: Option, } #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) struct Production { pub steps: Vec, pub dynamic_precedence: i32, } #[derive(Default)] pub(crate) struct InlinedProductionMap { pub productions: Vec, pub production_map: HashMap<(*const Production, u32), Vec>, } #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) struct SyntaxVariable { pub name: String, pub kind: VariableType, pub productions: Vec, } #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) struct ExternalToken { pub name: String, pub kind: VariableType, pub corresponding_internal_token: Option, } #[derive(Debug, Default)] pub(crate) struct SyntaxGrammar { pub variables: Vec, pub extra_tokens: Vec, pub expected_conflicts: Vec>, pub external_tokens: Vec, pub supertype_symbols: Vec, pub variables_to_inline: Vec, pub word_token: Option, } #[cfg(test)] impl ProductionStep { pub(crate) fn new(symbol: Symbol) -> Self { Self { symbol, precedence: 0, associativity: None, alias: None, field_name: None, } } pub(crate) fn with_prec(self, precedence: i32, associativity: Option) -> Self { Self { symbol: self.symbol, precedence, associativity, alias: self.alias, field_name: self.field_name, } } pub(crate) fn with_alias(self, value: &str, is_named: bool) -> Self { Self { symbol: self.symbol, precedence: self.precedence, associativity: self.associativity, alias: Some(Alias { value: value.to_string(), is_named, }), field_name: self.field_name, } } pub(crate) fn with_field_name(self, name: &str) -> Self { Self { symbol: self.symbol, precedence: self.precedence, associativity: self.associativity, alias: self.alias, field_name: Some(name.to_string()), } } } impl Production { pub fn first_symbol(&self) -> Option { self.steps.first().map(|s| s.symbol.clone()) } } impl Default for Production { fn default() -> Self { Production { dynamic_precedence: 0, steps: Vec::new(), } } } #[cfg(test)] impl Variable { pub fn named(name: &str, rule: Rule) -> Self { Self { name: name.to_string(), kind: VariableType::Named, rule, } } pub fn auxiliary(name: &str, rule: Rule) -> Self { Self { name: name.to_string(), kind: VariableType::Auxiliary, rule, } } pub fn hidden(name: &str, rule: Rule) -> Self { Self { name: name.to_string(), kind: VariableType::Hidden, rule, } } pub fn anonymous(name: &str, rule: Rule) -> Self { Self { name: name.to_string(), kind: VariableType::Anonymous, rule, } } } impl VariableType { pub fn is_visible(&self) -> bool { *self == VariableType::Named || *self == VariableType::Anonymous } } impl LexicalGrammar { pub fn variable_indices_for_nfa_states<'a>( &'a self, state_ids: &'a Vec, ) -> impl Iterator + 'a { let mut prev = None; state_ids.iter().filter_map(move |state_id| { let variable_id = self.variable_index_for_nfa_state(*state_id); if prev != Some(variable_id) { prev = Some(variable_id); prev } else { None } }) } pub fn variable_index_for_nfa_state(&self, state_id: u32) -> usize { self.variables .iter() .position(|v| v.start_state >= state_id) .unwrap() } } impl SyntaxVariable { pub fn is_auxiliary(&self) -> bool { self.kind == VariableType::Auxiliary } } impl InlinedProductionMap { pub fn inlined_productions<'a>( &'a self, production: &Production, step_index: u32, ) -> Option + 'a> { self.production_map .get(&(production as *const Production, step_index)) .map(|production_indices| { production_indices .iter() .cloned() .map(move |index| &self.productions[index]) }) } }