1use std::fmt;
67
68#[derive(Debug, Clone, PartialEq)]
74pub enum Token {
75 Name(String),
78 Star,
80 Dot,
82 DotDot,
84
85 At,
88 DoubleColon,
90 Slash,
92 DoubleSlash,
94 Pipe,
96 Plus,
98 Minus,
100 Eq,
102 Ne,
104 Lt,
106 Gt,
108 Le,
110 Ge,
112 Multiply,
114
115 Or,
118 And,
120 Mod,
122 Div,
124 Ancestor,
126 AncestorOrSelf,
128 Attribute,
130 Child,
132 Descendant,
134 DescendantOrSelf,
136 Following,
138 FollowingSibling,
140 Namespace,
142 Parent,
144 Preceding,
146 PrecedingSibling,
148 Self_,
150
151 StringLiteral(String),
154 NumberLiteral(f64),
156
157 LParen,
160 RParen,
162 LBracket,
164 RBracket,
166 LBrace,
168 RBrace,
170 Comma,
172 Dollar,
174
175 Eof,
178}
179
180impl fmt::Display for Token {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 match self {
183 Token::Name(n) => write!(f, "{}", n),
184 Token::Star => write!(f, "*"),
185 Token::Dot => write!(f, "."),
186 Token::DotDot => write!(f, ".."),
187 Token::At => write!(f, "@"),
188 Token::DoubleColon => write!(f, "::"),
189 Token::Slash => write!(f, "/"),
190 Token::DoubleSlash => write!(f, "//"),
191 Token::Pipe => write!(f, "|"),
192 Token::Plus => write!(f, "+"),
193 Token::Minus => write!(f, "-"),
194 Token::Eq => write!(f, "="),
195 Token::Ne => write!(f, "!="),
196 Token::Lt => write!(f, "<"),
197 Token::Gt => write!(f, ">"),
198 Token::Le => write!(f, "<="),
199 Token::Ge => write!(f, ">="),
200 Token::Multiply => write!(f, "*"),
201 Token::Or => write!(f, "or"),
202 Token::And => write!(f, "and"),
203 Token::Mod => write!(f, "mod"),
204 Token::Div => write!(f, "div"),
205 Token::Ancestor => write!(f, "ancestor"),
206 Token::AncestorOrSelf => write!(f, "ancestor-or-self"),
207 Token::Attribute => write!(f, "attribute"),
208 Token::Child => write!(f, "child"),
209 Token::Descendant => write!(f, "descendant"),
210 Token::DescendantOrSelf => write!(f, "descendant-or-self"),
211 Token::Following => write!(f, "following"),
212 Token::FollowingSibling => write!(f, "following-sibling"),
213 Token::Namespace => write!(f, "namespace"),
214 Token::Parent => write!(f, "parent"),
215 Token::Preceding => write!(f, "preceding"),
216 Token::PrecedingSibling => write!(f, "preceding-sibling"),
217 Token::Self_ => write!(f, "self"),
218 Token::StringLiteral(s) => write!(f, "'{}'", s),
219 Token::NumberLiteral(n) => write!(f, "{}", n),
220 Token::LParen => write!(f, "("),
221 Token::RParen => write!(f, ")"),
222 Token::LBracket => write!(f, "["),
223 Token::RBracket => write!(f, "]"),
224 Token::LBrace => write!(f, "{{"),
225 Token::RBrace => write!(f, "}}"),
226 Token::Comma => write!(f, ","),
227 Token::Dollar => write!(f, "$"),
228 Token::Eof => write!(f, "<EOF>"),
229 }
230 }
231}
232
233#[derive(Debug, Clone)]
241pub struct Lexer {
242 input: Vec<u8>,
244 pos: usize,
246 ch: u8,
248 at_start: bool,
250}
251
252impl Lexer {
253 pub fn new(input: &str) -> Self {
255 let bytes = input.as_bytes().to_vec();
256 let ch = if bytes.is_empty() { 0 } else { bytes[0] };
257 Self {
258 input: bytes,
259 pos: 0,
260 ch,
261 at_start: true,
262 }
263 }
264
265 fn advance(&mut self) {
267 self.pos += 1;
268 self.ch = if self.pos < self.input.len() {
269 self.input[self.pos]
270 } else {
271 0
272 };
273 }
274
275 fn peek(&self) -> u8 {
277 if self.pos + 1 < self.input.len() {
278 self.input[self.pos + 1]
279 } else {
280 0
281 }
282 }
283
284 fn skip_ws(&mut self) {
286 while self.ch != 0
287 && (self.ch == b' ' || self.ch == b'\t' || self.ch == b'\n' || self.ch == b'\r')
288 {
289 self.advance();
290 }
291 }
292
293 fn read_name(&mut self) -> String {
295 let start = self.pos;
296 while self.ch != 0
297 && (self.ch.is_ascii_alphanumeric()
298 || self.ch == b'_'
299 || self.ch == b'-'
300 || self.ch == b'.')
301 {
302 self.advance();
303 }
304 String::from_utf8_lossy(&self.input[start..self.pos]).to_string()
305 }
306
307 fn try_keyword_or_axis(&self, name: &str) -> Option<Token> {
309 match name {
310 "or" => Some(Token::Or),
311 "and" => Some(Token::And),
312 "mod" => Some(Token::Mod),
313 "div" => Some(Token::Div),
314 "ancestor" => Some(Token::Ancestor),
315 "ancestor-or-self" => Some(Token::AncestorOrSelf),
316 "attribute" => Some(Token::Attribute),
317 "child" => Some(Token::Child),
318 "descendant" => Some(Token::Descendant),
319 "descendant-or-self" => Some(Token::DescendantOrSelf),
320 "following" => Some(Token::Following),
321 "following-sibling" => Some(Token::FollowingSibling),
322 "namespace" => Some(Token::Namespace),
323 "parent" => Some(Token::Parent),
324 "preceding" => Some(Token::Preceding),
325 "preceding-sibling" => Some(Token::PrecedingSibling),
326 "self" => Some(Token::Self_),
327 _ => None,
328 }
329 }
330
331 fn read_number(&mut self) -> f64 {
340 let input = &self.input;
341 let len = input.len();
342 let mut cur = self.pos;
343
344 let mut ret = 0.0f64;
346 while cur < len && input[cur].is_ascii_digit() {
347 ret = ret * 10.0 + (input[cur] - b'0') as f64;
348 cur += 1;
349 }
350
351 let mut frac: i32 = 0;
354 if cur < len && input[cur] == b'.' {
355 cur += 1;
356 while cur < len && input[cur] == b'0' {
357 frac += 1;
358 cur += 1;
359 }
360 let max = frac + 20; let mut fraction = 0.0f64;
362 while cur < len && input[cur].is_ascii_digit() && frac < max {
363 let v = (input[cur] - b'0') as f64;
364 fraction = fraction * 10.0 + v;
365 frac += 1;
366 cur += 1;
367 }
368 fraction /= 10f64.powf(frac as f64);
369 ret += fraction;
370 while cur < len && input[cur].is_ascii_digit() {
371 cur += 1;
372 }
373 }
374
375 let mut exponent: i32 = 0;
379 let mut is_exponent_negative = false;
380 if cur < len && (input[cur] == b'e' || input[cur] == b'E') {
381 cur += 1;
382 if cur < len && input[cur] == b'-' {
383 is_exponent_negative = true;
384 cur += 1;
385 } else if cur < len && input[cur] == b'+' {
386 cur += 1;
387 }
388 while cur < len && input[cur].is_ascii_digit() {
389 if exponent < 1000000 {
390 exponent = exponent * 10 + (input[cur] - b'0') as i32;
391 }
392 cur += 1;
393 }
394 }
395 if is_exponent_negative {
396 exponent = -exponent;
397 }
398 ret *= 10f64.powf(exponent as f64);
399
400 self.pos = cur;
401 self.ch = if cur < len { input[cur] } else { 0 };
402 ret
403 }
404
405 fn read_string(&mut self, quote: u8) -> String {
407 self.advance(); let start = self.pos;
409 while self.ch != 0 && self.ch != quote {
410 self.advance();
411 }
412 let s = String::from_utf8_lossy(&self.input[start..self.pos]).to_string();
413 if self.ch == quote {
414 self.advance(); }
416 s
417 }
418
419 pub fn next_token(&mut self) -> Token {
421 self.skip_ws();
422
423 if self.ch == 0 {
424 return Token::Eof;
425 }
426
427 let _was_at_start = self.at_start;
429 self.at_start = false;
430
431 match self.ch {
433 b'(' => {
434 self.advance();
435 return Token::LParen;
436 }
437 b')' => {
438 self.advance();
439 return Token::RParen;
440 }
441 b'[' => {
442 self.advance();
443 return Token::LBracket;
444 }
445 b']' => {
446 self.advance();
447 return Token::RBracket;
448 }
449 b'{' => {
450 self.advance();
451 return Token::LBrace;
452 }
453 b'}' => {
454 self.advance();
455 return Token::RBrace;
456 }
457 b',' => {
458 self.advance();
459 return Token::Comma;
460 }
461 b'$' => {
462 self.advance();
463 return Token::Dollar;
464 }
465 b'|' => {
466 self.advance();
467 return Token::Pipe;
468 }
469 b'+' => {
470 self.advance();
471 return Token::Plus;
472 }
473 b'@' => {
474 self.advance();
475 return Token::At;
476 }
477 b'.' => {
478 if self.peek() == b'.' {
479 self.advance();
480 self.advance();
481 return Token::DotDot;
482 }
483 if self.peek().is_ascii_digit() {
485 return Token::NumberLiteral(self.read_number());
486 }
487 self.advance();
488 return Token::Dot;
489 }
490 b'-' => {
491 self.advance();
492 return Token::Minus;
495 }
496 b'=' => {
497 self.advance();
498 return Token::Eq;
499 }
500 b'!' => {
501 if self.peek() == b'=' {
502 self.advance();
503 self.advance();
504 return Token::Ne;
505 }
506 self.advance();
508 return self.next_token();
509 }
510 b'<' => {
511 self.advance();
512 if self.ch == b'=' {
513 self.advance();
514 return Token::Le;
515 }
516 return Token::Lt;
517 }
518 b'>' => {
519 self.advance();
520 if self.ch == b'=' {
521 self.advance();
522 return Token::Ge;
523 }
524 return Token::Gt;
525 }
526 b'/' => {
527 self.advance();
528 if self.ch == b'/' {
529 self.advance();
530 return Token::DoubleSlash;
531 }
532 return Token::Slash;
533 }
534 b'*' => {
535 self.advance();
536 return Token::Star; }
538 b':' => {
539 if self.peek() == b':' {
540 self.advance();
541 self.advance();
542 return Token::DoubleColon;
543 }
544 self.advance();
549 return self.next_token();
550 }
551 b'\'' | b'"' => {
552 let quote = self.ch;
553 let s = self.read_string(quote);
554 return Token::StringLiteral(s);
555 }
556 _ => {}
557 }
558
559 if self.ch.is_ascii_digit() {
561 return Token::NumberLiteral(self.read_number());
562 }
563
564 if self.ch.is_ascii_alphabetic() || self.ch == b'_' {
566 let name = self.read_name();
567
568 if self.ch == b':' && self.peek() != b':' {
570 self.advance(); if self.ch.is_ascii_alphabetic() || self.ch == b'_' || self.ch == b'*' {
572 if self.ch == b'*' {
573 self.advance();
574 let full = format!("{}:*", name);
575 return Token::Name(full);
576 }
577 let local = self.read_name();
578 return Token::Name(format!("{}:{}", name, local));
579 }
580 return Token::Name(name);
587 }
588
589 if self.ch == b':' && self.peek() == b':' {
593 if let Some(axis) = self.try_keyword_or_axis(&name) {
594 return axis;
595 }
596 return Token::Name(name);
599 }
600
601 if let Some(keyword) = self.try_keyword_or_axis(&name) {
603 return keyword;
604 }
605
606 return Token::Name(name);
607 }
608
609 self.advance();
611 self.next_token()
612 }
613}
614
615#[cfg(test)]
620mod tests {
621 use super::*;
622
623 fn tokenize(s: &str) -> Vec<Token> {
624 let mut lexer = Lexer::new(s);
625 let mut tokens = Vec::new();
626 loop {
627 let tok = lexer.next_token();
628 let is_eof = matches!(tok, Token::Eof);
629 tokens.push(tok);
630 if is_eof {
631 break;
632 }
633 }
634 tokens
635 }
636
637 #[test]
638 fn test_empty() {
639 let tokens = tokenize("");
640 assert_eq!(tokens.len(), 1);
641 assert_eq!(tokens[0], Token::Eof);
642 }
643
644 #[test]
645 fn test_simple_path() {
646 let tokens = tokenize("child::para");
647 assert_eq!(
648 tokens,
649 vec![
650 Token::Child,
651 Token::DoubleColon,
652 Token::Name("para".into()),
653 Token::Eof,
654 ]
655 );
656 }
657
658 #[test]
659 fn test_absolute_path() {
660 let tokens = tokenize("/child::para");
661 assert_eq!(
662 tokens,
663 vec![
664 Token::Slash,
665 Token::Child,
666 Token::DoubleColon,
667 Token::Name("para".into()),
668 Token::Eof,
669 ]
670 );
671 }
672
673 #[test]
674 fn test_short_form() {
675 let tokens = tokenize("para");
676 assert_eq!(tokens, vec![Token::Name("para".into()), Token::Eof]);
677 }
678
679 #[test]
680 fn test_attribute() {
681 let tokens = tokenize("@attr");
682 assert_eq!(
683 tokens,
684 vec![Token::At, Token::Name("attr".into()), Token::Eof]
685 );
686 }
687
688 #[test]
689 fn test_predicate() {
690 let tokens = tokenize("para[1]");
691 assert_eq!(
692 tokens,
693 vec![
694 Token::Name("para".into()),
695 Token::LBracket,
696 Token::NumberLiteral(1.0),
697 Token::RBracket,
698 Token::Eof,
699 ]
700 );
701 }
702
703 #[test]
704 fn test_function_call() {
705 let tokens = tokenize("position()");
706 assert_eq!(
707 tokens,
708 vec![
709 Token::Name("position".into()),
710 Token::LParen,
711 Token::RParen,
712 Token::Eof,
713 ]
714 );
715 }
716
717 #[test]
718 fn test_string_literal() {
719 let tokens = tokenize("'hello'");
720 assert_eq!(
721 tokens,
722 vec![Token::StringLiteral("hello".into()), Token::Eof]
723 );
724 }
725
726 #[test]
727 fn test_number() {
728 let tokens = tokenize("42");
729 assert_eq!(tokens, vec![Token::NumberLiteral(42.0), Token::Eof]);
730 }
731 #[allow(clippy::approx_constant)]
732 #[test]
733 fn test_decimal() {
734 let tokens = tokenize("3.14");
735 assert_eq!(tokens, vec![Token::NumberLiteral(3.14), Token::Eof]);
736 }
737
738 #[test]
739 fn test_operators() {
740 let tokens = tokenize("a = b and c != d or e < f");
741 assert!(tokens.contains(&Token::Eq));
742 assert!(tokens.contains(&Token::And));
743 assert!(tokens.contains(&Token::Ne));
744 assert!(tokens.contains(&Token::Or));
745 assert!(tokens.contains(&Token::Lt));
746 }
747
748 #[test]
749 fn test_union() {
750 let tokens = tokenize("a | b");
751 assert_eq!(
752 tokens,
753 vec![
754 Token::Name("a".into()),
755 Token::Pipe,
756 Token::Name("b".into()),
757 Token::Eof,
758 ]
759 );
760 }
761
762 #[test]
763 fn test_double_slash() {
764 let tokens = tokenize("//para");
765 assert_eq!(
766 tokens,
767 vec![Token::DoubleSlash, Token::Name("para".into()), Token::Eof]
768 );
769 }
770
771 #[test]
772 fn test_qname() {
773 let tokens = tokenize("xslt:template");
774 assert_eq!(
775 tokens,
776 vec![Token::Name("xslt:template".into()), Token::Eof]
777 );
778 }
779
780 #[test]
781 fn test_wildcard() {
782 let tokens = tokenize("*");
783 assert_eq!(tokens, vec![Token::Star, Token::Eof]);
784 }
785
786 #[test]
787 fn test_ns_wildcard() {
788 let tokens = tokenize("ns:*");
789 assert_eq!(tokens, vec![Token::Name("ns:*".into()), Token::Eof]);
790 }
791
792 #[test]
793 fn test_dot_dot() {
794 let tokens = tokenize("..");
795 assert_eq!(tokens, vec![Token::DotDot, Token::Eof]);
796 }
797
798 #[test]
799 fn test_axis_keyword() {
800 let tokens = tokenize("ancestor-or-self::node()");
801 assert_eq!(
802 tokens,
803 vec![
804 Token::AncestorOrSelf,
805 Token::DoubleColon,
806 Token::Name("node".into()),
807 Token::LParen,
808 Token::RParen,
809 Token::Eof,
810 ]
811 );
812 }
813
814 #[test]
815 fn test_complex_expression() {
816 let tokens = tokenize("/html/body//div[@class='main']/p[1]");
817 let names: Vec<String> = tokens
819 .iter()
820 .filter_map(|t| match t {
821 Token::Name(n) => Some(n.clone()),
822 Token::Div => Some("div".to_string()),
823 Token::Mod => Some("mod".to_string()),
824 Token::And => Some("and".to_string()),
825 Token::Or => Some("or".to_string()),
826 _ => None,
827 })
828 .collect();
829 assert_eq!(names, vec!["html", "body", "div", "class", "p"]);
830 }
831
832 #[test]
833 fn test_variable() {
834 let tokens = tokenize("$var");
835 assert_eq!(
836 tokens,
837 vec![Token::Dollar, Token::Name("var".into()), Token::Eof]
838 );
839 }
840}