1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! The matcher module provides a set of token matchers for the Lexxor lexer.
//!
//! Each matcher implements the [Matcher] trait and is responsible for recognizing
//! specific types of tokens in a character stream. The available matchers are:
//!
//! - [ExactMatcher](matcher::exact::ExactMatcher): Matches exact strings from a provided list.
//! - [FloatMatcher](matcher::float::FloatMatcher): Matches floating-point numbers (e.g., 3.14, 0.001).
//! - [IntegerMatcher](matcher::integer::IntegerMatcher): Matches integer numbers (e.g., 42, -7).
//! - [KeywordMatcher](matcher::keyword::KeywordMatcher): Matches specific keywords, ensuring they are not substrings.
//! - [SymbolMatcher](matcher::symbol::SymbolMatcher): Matches non-alphanumeric, non-whitespace symbols (e.g., @, #, $).
//! - [WhitespaceMatcher](matcher::whitespace::WhitespaceMatcher): Matches whitespace characters (spaces, tabs, newlines).
//! - [WordMatcher](matcher::word::WordMatcher): Matches sequences of alphabetic characters (words).
//!
//! Each matcher can be used independently or in combination to build a custom lexer.
///
/// Trait for token matchers used by [`Lexxor`](crate::Lexxor).
///
/// # Overview
///
/// A `Matcher` is responsible for recognizing a particular kind of token in a character stream. Each matcher
/// maintains its own state and is reset before each new tokenization attempt. Lexxor will call `find_match` repeatedly,
/// feeding one character at a time to each matcher, until one returns a successful match or all fail.
///
/// Matchers can be used for words, numbers, symbols, keywords, whitespace, or any custom pattern. They can share
/// context using the provided `ctx` parameter, which is a mutable boxed `HashMap`.
///
/// # Example: Implementing and Using a Matcher
///
/// ```rust
/// use std::collections::HashMap;
/// use lexxor::matcher::{Matcher, MatcherResult};
/// use lexxor::token::{Token, TOKEN_TYPE_WORD};
///
/// #[derive(Debug)]
/// struct SimpleWordMatcher { index: usize, running: bool }
///
/// impl Matcher for SimpleWordMatcher {
/// fn reset(&mut self, _ctx: &mut Box<HashMap<String, i32>>) {
/// self.index = 0;
/// self.running = true;
/// }
/// fn find_match(&mut self, oc: Option<char>, value: &[char], _ctx: &mut Box<HashMap<String, i32>>)
/// -> MatcherResult {
/// match oc {
/// Some(c) if c.is_alphabetic() => {
/// self.index += 1;
/// MatcherResult::Running()
/// }
/// _ if self.index > 0 => {
/// let s: String = value.iter().collect();
/// MatcherResult::Matched(Token {
/// token_type: TOKEN_TYPE_WORD,
/// value: s,
/// line: 1,
/// column: 1,
/// len: self.index,
/// precedence: 0,
/// })
/// }
/// _ => MatcherResult::Failed(),
/// }
/// }
/// fn is_running(&self) -> bool { self.running }
/// fn precedence(&self) -> u8 { 0 }
/// }
///
/// let mut ctx: Box<HashMap<String, i32>> = Box::new(HashMap::new());
/// let mut matcher = SimpleWordMatcher { index: 0, running: true };
/// assert!(matches!(matcher.find_match(Some('w'), &['w'], &mut ctx), MatcherResult::Running()));
/// assert!(matches!(matcher.find_match(Some('o'), &['w','o'], &mut ctx), MatcherResult::Running()));
/// assert!(matches!(matcher.find_match(Some('r'), &['w','o','r'], &mut ctx), MatcherResult::Running()));
/// assert!(matches!(matcher.find_match(Some('d'), &['w','o','r','d'], &mut ctx), MatcherResult::Running()));
/// // None signals the end of input
/// assert!(matches!(matcher.find_match(None, &['w','o','r','d'], &mut ctx), MatcherResult::Matched(_)));
/// ```
use crateToken;
use HashMap;
use Debug;
/// The result of a match
/// All matcher types must also implement [`Debug`],
/// which allows for easy inspection and debugging of matcher state.
/// This is especially useful when writing tests or diagnosing matcher behavior
/// during tokenization.
/// The `exact` module provides the `ExactMatcher`, which matches strings exactly as specified.
/// It allows users to define a list of strings to match against, ensuring that only exact matches
/// are recognized, regardless of their position in the input stream.
/// The float matcher matches floating point numbers. To qualify as floating point, the numbers must
/// start and end with a numeric digit and have a period within them. For example `1.0`. Thus,
/// `.1` and `1.` do not qualify as floating point numbers.
/// The integer matcher matches integer numbers. To qualify as integer the numbers must
/// start and end with a numeric digit.
/// The Keyword matcher is very similar to the [ExactMatcher](exact::ExactMatcher), in that you give it a list of matches
/// to make, and it looks EXACTLY for those matches. The difference between this matcher and the
/// [ExactMatcher](exact::ExactMatcher) is that for `THIS` matcher an exact match must end with a non alpha-numeric
/// character. For example, if you give this matcher "match" as a keyword it will NOT match
/// "matches", "matchers" or "match1", "1matcher", "2match" etc.
/// It will match "match ", " match." "---match---" and so on.
/// The SymbolMatcher matches any series of characters that do NOT match `is_whitespace()` or
/// `c.is_alphanumeric()`. That is, this matcher
/// will match any character that is not a number, letter, or whitespace.
/// The WhitespaceMatcher matches any series of characters that are `is_whitespace()`.
/// The `WordMatcher` is a matcher that matches word tokens in the input stream.