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}