lexi_matic/
lib.rs

1#![doc = include_str!("../README.md")]
2use std::fmt;
3
4use regex_automata::{dfa::Automaton, util::start::Config, PatternID};
5
6pub use lexi_matic_derive::Lexer;
7#[doc(hidden)]
8pub use regex_automata::dfa::dense::DFA;
9
10#[derive(Debug)]
11pub struct Error(pub usize);
12
13impl fmt::Display for Error {
14    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15        write!(f, "lexical error at {}", self.0)
16    }
17}
18
19impl std::error::Error for Error {}
20
21pub trait Lexer<'a>: Sized {
22    type Iterator: IntoIterator<Item = Result<(usize, Self, usize), Error>>;
23    fn lex(input: &'a str) -> Self::Iterator;
24}
25
26#[doc(hidden)]
27pub fn dfa_search_next(dfa: &DFA<&[u32]>, input: &str) -> Option<(PatternID, usize)> {
28    let start = dfa
29        .start_state(&Config::new().anchored(regex_automata::Anchored::Yes))
30        .unwrap();
31    let mut state = start;
32    let mut matched = (start, 0);
33    'search: {
34        for (i, b) in input.as_bytes().iter().copied().enumerate() {
35            state = dfa.next_state(state, b);
36            if dfa.is_match_state(state) {
37                matched = (state, i);
38            } else if dfa.is_dead_state(state) {
39                break 'search;
40            }
41        }
42        state = dfa.next_eoi_state(state);
43        if dfa.is_match_state(state) {
44            matched = (state, input.len());
45        }
46    }
47    if matched.1 != 0 {
48        Some((dfa.match_pattern(matched.0, 0), matched.1))
49    } else {
50        None
51    }
52}