1use std::fmt;
16
17#[derive(Debug, Clone, PartialEq)]
23pub enum Token {
24 Name(String),
27 Star,
29 Dot,
31 DotDot,
33
34 At,
37 DoubleColon,
39 Slash,
41 DoubleSlash,
43 Pipe,
45 Plus,
47 Minus,
49 Eq,
51 Ne,
53 Lt,
55 Gt,
57 Le,
59 Ge,
61 Multiply,
63
64 Or,
67 And,
69 Mod,
71 Div,
73 Ancestor,
75 AncestorOrSelf,
77 Attribute,
79 Child,
81 Descendant,
83 DescendantOrSelf,
85 Following,
87 FollowingSibling,
89 Namespace,
91 Parent,
93 Preceding,
95 PrecedingSibling,
97 Self_,
99
100 StringLiteral(String),
103 NumberLiteral(f64),
105
106 LParen,
109 RParen,
111 LBracket,
113 RBracket,
115 LBrace,
117 RBrace,
119 Comma,
121 Dollar,
123
124 Eof,
127}
128
129impl fmt::Display for Token {
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 match self {
132 Token::Name(n) => write!(f, "{}", n),
133 Token::Star => write!(f, "*"),
134 Token::Dot => write!(f, "."),
135 Token::DotDot => write!(f, ".."),
136 Token::At => write!(f, "@"),
137 Token::DoubleColon => write!(f, "::"),
138 Token::Slash => write!(f, "/"),
139 Token::DoubleSlash => write!(f, "//"),
140 Token::Pipe => write!(f, "|"),
141 Token::Plus => write!(f, "+"),
142 Token::Minus => write!(f, "-"),
143 Token::Eq => write!(f, "="),
144 Token::Ne => write!(f, "!="),
145 Token::Lt => write!(f, "<"),
146 Token::Gt => write!(f, ">"),
147 Token::Le => write!(f, "<="),
148 Token::Ge => write!(f, ">="),
149 Token::Multiply => write!(f, "*"),
150 Token::Or => write!(f, "or"),
151 Token::And => write!(f, "and"),
152 Token::Mod => write!(f, "mod"),
153 Token::Div => write!(f, "div"),
154 Token::Ancestor => write!(f, "ancestor"),
155 Token::AncestorOrSelf => write!(f, "ancestor-or-self"),
156 Token::Attribute => write!(f, "attribute"),
157 Token::Child => write!(f, "child"),
158 Token::Descendant => write!(f, "descendant"),
159 Token::DescendantOrSelf => write!(f, "descendant-or-self"),
160 Token::Following => write!(f, "following"),
161 Token::FollowingSibling => write!(f, "following-sibling"),
162 Token::Namespace => write!(f, "namespace"),
163 Token::Parent => write!(f, "parent"),
164 Token::Preceding => write!(f, "preceding"),
165 Token::PrecedingSibling => write!(f, "preceding-sibling"),
166 Token::Self_ => write!(f, "self"),
167 Token::StringLiteral(s) => write!(f, "'{}'", s),
168 Token::NumberLiteral(n) => write!(f, "{}", n),
169 Token::LParen => write!(f, "("),
170 Token::RParen => write!(f, ")"),
171 Token::LBracket => write!(f, "["),
172 Token::RBracket => write!(f, "]"),
173 Token::LBrace => write!(f, "{{"),
174 Token::RBrace => write!(f, "}}"),
175 Token::Comma => write!(f, ","),
176 Token::Dollar => write!(f, "$"),
177 Token::Eof => write!(f, "<EOF>"),
178 }
179 }
180}
181
182#[derive(Debug, Clone)]
190pub struct Lexer {
191 input: Vec<u8>,
193 pos: usize,
195 ch: u8,
197 at_start: bool,
199}
200
201impl Lexer {
202 pub fn new(input: &str) -> Self {
204 let bytes = input.as_bytes().to_vec();
205 let ch = if bytes.is_empty() { 0 } else { bytes[0] };
206 Self {
207 input: bytes,
208 pos: 0,
209 ch,
210 at_start: true,
211 }
212 }
213
214 fn advance(&mut self) {
216 self.pos += 1;
217 self.ch = if self.pos < self.input.len() {
218 self.input[self.pos]
219 } else {
220 0
221 };
222 }
223
224 fn peek(&self) -> u8 {
226 if self.pos + 1 < self.input.len() {
227 self.input[self.pos + 1]
228 } else {
229 0
230 }
231 }
232
233 fn skip_ws(&mut self) {
235 while self.ch != 0
236 && (self.ch == b' ' || self.ch == b'\t' || self.ch == b'\n' || self.ch == b'\r')
237 {
238 self.advance();
239 }
240 }
241
242 fn read_name(&mut self) -> String {
244 let start = self.pos;
245 while self.ch != 0
246 && (self.ch.is_ascii_alphanumeric()
247 || self.ch == b'_'
248 || self.ch == b'-'
249 || self.ch == b'.')
250 {
251 self.advance();
252 }
253 String::from_utf8_lossy(&self.input[start..self.pos]).to_string()
254 }
255
256 fn try_keyword_or_axis(&self, name: &str) -> Option<Token> {
258 match name {
259 "or" => Some(Token::Or),
260 "and" => Some(Token::And),
261 "mod" => Some(Token::Mod),
262 "div" => Some(Token::Div),
263 "ancestor" => Some(Token::Ancestor),
264 "ancestor-or-self" => Some(Token::AncestorOrSelf),
265 "attribute" => Some(Token::Attribute),
266 "child" => Some(Token::Child),
267 "descendant" => Some(Token::Descendant),
268 "descendant-or-self" => Some(Token::DescendantOrSelf),
269 "following" => Some(Token::Following),
270 "following-sibling" => Some(Token::FollowingSibling),
271 "namespace" => Some(Token::Namespace),
272 "parent" => Some(Token::Parent),
273 "preceding" => Some(Token::Preceding),
274 "preceding-sibling" => Some(Token::PrecedingSibling),
275 "self" => Some(Token::Self_),
276 _ => None,
277 }
278 }
279
280 fn read_number(&mut self) -> f64 {
289 let input = &self.input;
290 let len = input.len();
291 let mut cur = self.pos;
292
293 let mut ret = 0.0f64;
295 while cur < len && input[cur].is_ascii_digit() {
296 ret = ret * 10.0 + (input[cur] - b'0') as f64;
297 cur += 1;
298 }
299
300 let mut frac: i32 = 0;
303 if cur < len && input[cur] == b'.' {
304 cur += 1;
305 while cur < len && input[cur] == b'0' {
306 frac += 1;
307 cur += 1;
308 }
309 let max = frac + 20; let mut fraction = 0.0f64;
311 while cur < len && input[cur].is_ascii_digit() && frac < max {
312 let v = (input[cur] - b'0') as f64;
313 fraction = fraction * 10.0 + v;
314 frac += 1;
315 cur += 1;
316 }
317 fraction /= 10f64.powf(frac as f64);
318 ret += fraction;
319 while cur < len && input[cur].is_ascii_digit() {
320 cur += 1;
321 }
322 }
323
324 let mut exponent: i32 = 0;
328 let mut is_exponent_negative = false;
329 if cur < len && (input[cur] == b'e' || input[cur] == b'E') {
330 cur += 1;
331 if cur < len && input[cur] == b'-' {
332 is_exponent_negative = true;
333 cur += 1;
334 } else if cur < len && input[cur] == b'+' {
335 cur += 1;
336 }
337 while cur < len && input[cur].is_ascii_digit() {
338 if exponent < 1000000 {
339 exponent = exponent * 10 + (input[cur] - b'0') as i32;
340 }
341 cur += 1;
342 }
343 }
344 if is_exponent_negative {
345 exponent = -exponent;
346 }
347 ret *= 10f64.powf(exponent as f64);
348
349 self.pos = cur;
350 self.ch = if cur < len { input[cur] } else { 0 };
351 ret
352 }
353
354 fn read_string(&mut self, quote: u8) -> String {
356 self.advance(); let start = self.pos;
358 while self.ch != 0 && self.ch != quote {
359 self.advance();
360 }
361 let s = String::from_utf8_lossy(&self.input[start..self.pos]).to_string();
362 if self.ch == quote {
363 self.advance(); }
365 s
366 }
367
368 pub fn next_token(&mut self) -> Token {
370 self.skip_ws();
371
372 if self.ch == 0 {
373 return Token::Eof;
374 }
375
376 let _was_at_start = self.at_start;
378 self.at_start = false;
379
380 match self.ch {
382 b'(' => {
383 self.advance();
384 return Token::LParen;
385 }
386 b')' => {
387 self.advance();
388 return Token::RParen;
389 }
390 b'[' => {
391 self.advance();
392 return Token::LBracket;
393 }
394 b']' => {
395 self.advance();
396 return Token::RBracket;
397 }
398 b'{' => {
399 self.advance();
400 return Token::LBrace;
401 }
402 b'}' => {
403 self.advance();
404 return Token::RBrace;
405 }
406 b',' => {
407 self.advance();
408 return Token::Comma;
409 }
410 b'$' => {
411 self.advance();
412 return Token::Dollar;
413 }
414 b'|' => {
415 self.advance();
416 return Token::Pipe;
417 }
418 b'+' => {
419 self.advance();
420 return Token::Plus;
421 }
422 b'@' => {
423 self.advance();
424 return Token::At;
425 }
426 b'.' => {
427 if self.peek() == b'.' {
428 self.advance();
429 self.advance();
430 return Token::DotDot;
431 }
432 if self.peek().is_ascii_digit() {
434 return Token::NumberLiteral(self.read_number());
435 }
436 self.advance();
437 return Token::Dot;
438 }
439 b'-' => {
440 self.advance();
441 return Token::Minus;
444 }
445 b'=' => {
446 self.advance();
447 return Token::Eq;
448 }
449 b'!' => {
450 if self.peek() == b'=' {
451 self.advance();
452 self.advance();
453 return Token::Ne;
454 }
455 self.advance();
457 return self.next_token();
458 }
459 b'<' => {
460 self.advance();
461 if self.ch == b'=' {
462 self.advance();
463 return Token::Le;
464 }
465 return Token::Lt;
466 }
467 b'>' => {
468 self.advance();
469 if self.ch == b'=' {
470 self.advance();
471 return Token::Ge;
472 }
473 return Token::Gt;
474 }
475 b'/' => {
476 self.advance();
477 if self.ch == b'/' {
478 self.advance();
479 return Token::DoubleSlash;
480 }
481 return Token::Slash;
482 }
483 b'*' => {
484 self.advance();
485 return Token::Star; }
487 b':' => {
488 if self.peek() == b':' {
489 self.advance();
490 self.advance();
491 return Token::DoubleColon;
492 }
493 self.advance();
498 return self.next_token();
499 }
500 b'\'' | b'"' => {
501 let quote = self.ch;
502 let s = self.read_string(quote);
503 return Token::StringLiteral(s);
504 }
505 _ => {}
506 }
507
508 if self.ch.is_ascii_digit() {
510 return Token::NumberLiteral(self.read_number());
511 }
512
513 if self.ch.is_ascii_alphabetic() || self.ch == b'_' {
515 let name = self.read_name();
516
517 if self.ch == b':' && self.peek() != b':' {
519 self.advance(); if self.ch.is_ascii_alphabetic() || self.ch == b'_' || self.ch == b'*' {
521 if self.ch == b'*' {
522 self.advance();
523 let full = format!("{}:*", name);
524 return Token::Name(full);
525 }
526 let local = self.read_name();
527 return Token::Name(format!("{}:{}", name, local));
528 }
529 return Token::Name(name);
536 }
537
538 if self.ch == b':' && self.peek() == b':' {
542 if let Some(axis) = self.try_keyword_or_axis(&name) {
543 return axis;
544 }
545 return Token::Name(name);
548 }
549
550 if let Some(keyword) = self.try_keyword_or_axis(&name) {
552 return keyword;
553 }
554
555 return Token::Name(name);
556 }
557
558 self.advance();
560 self.next_token()
561 }
562}
563
564#[cfg(test)]
569mod tests {
570 use super::*;
571
572 fn tokenize(s: &str) -> Vec<Token> {
573 let mut lexer = Lexer::new(s);
574 let mut tokens = Vec::new();
575 loop {
576 let tok = lexer.next_token();
577 let is_eof = matches!(tok, Token::Eof);
578 tokens.push(tok);
579 if is_eof {
580 break;
581 }
582 }
583 tokens
584 }
585
586 #[test]
587 fn test_empty() {
588 let tokens = tokenize("");
589 assert_eq!(tokens.len(), 1);
590 assert_eq!(tokens[0], Token::Eof);
591 }
592
593 #[test]
594 fn test_simple_path() {
595 let tokens = tokenize("child::para");
596 assert_eq!(
597 tokens,
598 vec![
599 Token::Child,
600 Token::DoubleColon,
601 Token::Name("para".into()),
602 Token::Eof,
603 ]
604 );
605 }
606
607 #[test]
608 fn test_absolute_path() {
609 let tokens = tokenize("/child::para");
610 assert_eq!(
611 tokens,
612 vec![
613 Token::Slash,
614 Token::Child,
615 Token::DoubleColon,
616 Token::Name("para".into()),
617 Token::Eof,
618 ]
619 );
620 }
621
622 #[test]
623 fn test_short_form() {
624 let tokens = tokenize("para");
625 assert_eq!(tokens, vec![Token::Name("para".into()), Token::Eof]);
626 }
627
628 #[test]
629 fn test_attribute() {
630 let tokens = tokenize("@attr");
631 assert_eq!(
632 tokens,
633 vec![Token::At, Token::Name("attr".into()), Token::Eof]
634 );
635 }
636
637 #[test]
638 fn test_predicate() {
639 let tokens = tokenize("para[1]");
640 assert_eq!(
641 tokens,
642 vec![
643 Token::Name("para".into()),
644 Token::LBracket,
645 Token::NumberLiteral(1.0),
646 Token::RBracket,
647 Token::Eof,
648 ]
649 );
650 }
651
652 #[test]
653 fn test_function_call() {
654 let tokens = tokenize("position()");
655 assert_eq!(
656 tokens,
657 vec![
658 Token::Name("position".into()),
659 Token::LParen,
660 Token::RParen,
661 Token::Eof,
662 ]
663 );
664 }
665
666 #[test]
667 fn test_string_literal() {
668 let tokens = tokenize("'hello'");
669 assert_eq!(
670 tokens,
671 vec![Token::StringLiteral("hello".into()), Token::Eof]
672 );
673 }
674
675 #[test]
676 fn test_number() {
677 let tokens = tokenize("42");
678 assert_eq!(tokens, vec![Token::NumberLiteral(42.0), Token::Eof]);
679 }
680 #[allow(clippy::approx_constant)]
681 #[test]
682 fn test_decimal() {
683 let tokens = tokenize("3.14");
684 assert_eq!(tokens, vec![Token::NumberLiteral(3.14), Token::Eof]);
685 }
686
687 #[test]
688 fn test_operators() {
689 let tokens = tokenize("a = b and c != d or e < f");
690 assert!(tokens.contains(&Token::Eq));
691 assert!(tokens.contains(&Token::And));
692 assert!(tokens.contains(&Token::Ne));
693 assert!(tokens.contains(&Token::Or));
694 assert!(tokens.contains(&Token::Lt));
695 }
696
697 #[test]
698 fn test_union() {
699 let tokens = tokenize("a | b");
700 assert_eq!(
701 tokens,
702 vec![
703 Token::Name("a".into()),
704 Token::Pipe,
705 Token::Name("b".into()),
706 Token::Eof,
707 ]
708 );
709 }
710
711 #[test]
712 fn test_double_slash() {
713 let tokens = tokenize("//para");
714 assert_eq!(
715 tokens,
716 vec![Token::DoubleSlash, Token::Name("para".into()), Token::Eof]
717 );
718 }
719
720 #[test]
721 fn test_qname() {
722 let tokens = tokenize("xslt:template");
723 assert_eq!(
724 tokens,
725 vec![Token::Name("xslt:template".into()), Token::Eof]
726 );
727 }
728
729 #[test]
730 fn test_wildcard() {
731 let tokens = tokenize("*");
732 assert_eq!(tokens, vec![Token::Star, Token::Eof]);
733 }
734
735 #[test]
736 fn test_ns_wildcard() {
737 let tokens = tokenize("ns:*");
738 assert_eq!(tokens, vec![Token::Name("ns:*".into()), Token::Eof]);
739 }
740
741 #[test]
742 fn test_dot_dot() {
743 let tokens = tokenize("..");
744 assert_eq!(tokens, vec![Token::DotDot, Token::Eof]);
745 }
746
747 #[test]
748 fn test_axis_keyword() {
749 let tokens = tokenize("ancestor-or-self::node()");
750 assert_eq!(
751 tokens,
752 vec![
753 Token::AncestorOrSelf,
754 Token::DoubleColon,
755 Token::Name("node".into()),
756 Token::LParen,
757 Token::RParen,
758 Token::Eof,
759 ]
760 );
761 }
762
763 #[test]
764 fn test_complex_expression() {
765 let tokens = tokenize("/html/body//div[@class='main']/p[1]");
766 let names: Vec<String> = tokens
768 .iter()
769 .filter_map(|t| match t {
770 Token::Name(n) => Some(n.clone()),
771 Token::Div => Some("div".to_string()),
772 Token::Mod => Some("mod".to_string()),
773 Token::And => Some("and".to_string()),
774 Token::Or => Some("or".to_string()),
775 _ => None,
776 })
777 .collect();
778 assert_eq!(names, vec!["html", "body", "div", "class", "p"]);
779 }
780
781 #[test]
782 fn test_variable() {
783 let tokens = tokenize("$var");
784 assert_eq!(
785 tokens,
786 vec![Token::Dollar, Token::Name("var".into()), Token::Eof]
787 );
788 }
789}