1use std::fmt;
4
5#[derive(Clone, Debug, PartialEq)]
11pub enum Keyword {
12 Source, Target, Triple, Datalayout, Define,
23 Declare,
25 Type, Private,
31 Internal,
33 External,
35 Weak,
37 WeakOdr,
39 Linkonce,
41 LinkonceOdr,
43 Common,
45 AvailableExternally,
47
48 Void,
51 Half,
53 Bfloat,
55 Float,
57 Double,
59 Fp128,
61 X86Fp80,
63 Label,
65 Metadata,
67 Ptr,
69
70 Global,
73 Constant,
75
76 Inbounds,
79 Exact,
81 Nuw,
83 Nsw,
85 Volatile,
87 Tail,
89 Musttail,
91 Notail,
93 Fast,
95 Nnan,
97 Ninf,
99 Nsz,
101 Arcp,
103 Contract,
105 Afn,
107 Reassoc,
109
110 Add,
113 Sub,
115 Mul,
117 Udiv,
119 Sdiv,
121 Urem,
123 Srem,
125 And,
127 Or,
129 Xor,
131 Shl,
133 Lshr,
135 Ashr,
137 Fadd,
139 Fsub,
141 Fmul,
143 Fdiv,
145 Frem,
147 Fneg,
149 Icmp,
151 Fcmp,
153 Alloca,
155 Load,
157 Store,
159 Getelementptr,
161 Trunc,
163 Zext,
165 Sext,
167 Fptrunc,
169 Fpext,
171 Fptoui,
173 Fptosi,
175 Uitofp,
177 Sitofp,
179 Ptrtoint,
181 Inttoptr,
183 Bitcast,
185 Addrspacecast,
187 Freeze,
189 Select,
191 Phi,
193 Extractvalue,
195 Insertvalue,
197 Extractelement,
199 Insertelement,
201 Shufflevector,
203 Call,
205 Ret,
207 Br,
209 Switch,
211 Unreachable,
213
214 Eq,
217 Ne,
219 Ugt,
221 Uge,
223 Ult,
225 Ule,
227 Sgt,
229 Sge,
231 Slt,
233 Sle,
235 False,
238 Oeq,
240 Ogt,
242 Oge,
244 Olt,
246 Ole,
248 One,
250 Ord,
252 Uno,
254 Ueq,
256 Une,
258 True,
260
261 Zeroinitializer,
264 Undef,
266 Poison,
268 Null,
270 Align,
272 To,
274 X, Vscale, }
279
280#[derive(Clone, Debug, PartialEq)]
286pub enum Token {
287 LocalIdent(String),
289 GlobalIdent(String),
291 IntType(u32),
293 IntLit(i64),
295 UIntLit(u64),
297 FloatLit(f64),
299 StringLit(String),
301 Kw(Keyword),
303 Equal,
305 Comma,
307 Colon,
309 Star,
311 LParen,
313 RParen,
315 LBracket,
317 RBracket,
319 LBrace,
321 RBrace,
323 LAngle,
325 RAngle,
327 Ellipsis,
329 Bang,
331 Hash,
333 Eof,
335}
336
337#[derive(Clone, Debug)]
343pub struct LexError {
344 pub line: usize,
346 pub col: usize,
348 pub message: String,
350}
351
352impl fmt::Display for LexError {
353 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354 write!(
355 f,
356 "lex error at {}:{}: {}",
357 self.line, self.col, self.message
358 )
359 }
360}
361
362pub struct Lexer<'src> {
368 src: &'src [u8],
370 pos: usize,
372 line: usize,
374 col: usize,
376 peeked: Option<Result<Token, LexError>>,
378}
379
380impl<'src> Lexer<'src> {
381 pub fn new(src: &'src str) -> Self {
383 Lexer {
384 src: src.as_bytes(),
385 pos: 0,
386 line: 1,
387 col: 1,
388 peeked: None,
389 }
390 }
391
392 fn peek_ch(&self) -> Option<u8> {
397 self.src.get(self.pos).copied()
398 }
399
400 fn peek_ch2(&self) -> Option<u8> {
401 self.src.get(self.pos + 1).copied()
402 }
403
404 fn advance(&mut self) -> Option<u8> {
405 let ch = self.src.get(self.pos).copied()?;
406 self.pos += 1;
407 if ch == b'\n' {
408 self.line += 1;
409 self.col = 1;
410 } else {
411 self.col += 1;
412 }
413 Some(ch)
414 }
415
416 fn skip_whitespace_and_comments(&mut self) {
417 loop {
418 while matches!(self.peek_ch(), Some(b' ' | b'\t' | b'\r' | b'\n')) {
419 self.advance();
420 }
421 if self.peek_ch() == Some(b';') {
422 while !matches!(self.peek_ch(), None | Some(b'\n')) {
423 self.advance();
424 }
425 } else {
426 break;
427 }
428 }
429 }
430
431 fn make_err(&self, msg: impl Into<String>) -> LexError {
432 LexError {
433 line: self.line,
434 col: self.col,
435 message: msg.into(),
436 }
437 }
438
439 pub fn peek(&mut self) -> Result<&Token, &LexError> {
445 if self.peeked.is_none() {
446 self.peeked = Some(self.next_token());
447 }
448 match self.peeked.as_ref().unwrap() {
449 Ok(t) => Ok(t),
450 Err(e) => Err(e),
451 }
452 }
453
454 #[allow(clippy::should_implement_trait)]
456 pub fn next(&mut self) -> Result<Token, LexError> {
457 if let Some(t) = self.peeked.take() {
458 return t;
459 }
460 self.next_token()
461 }
462
463 pub fn eat(&mut self, expected: &Token) -> bool {
465 match self.peek() {
466 Ok(t) if t == expected => {
467 let _ = self.next();
468 true
469 }
470 _ => false,
471 }
472 }
473
474 pub fn eat_kw(&mut self, kw: Keyword) -> bool {
476 self.eat(&Token::Kw(kw))
477 }
478
479 pub fn expect(&mut self, expected: &Token) -> Result<(), LexError> {
481 let tok = self.next()?;
482 if tok == *expected {
483 Ok(())
484 } else {
485 Err(self.make_err(format!("expected {:?}, got {:?}", expected, tok)))
486 }
487 }
488
489 pub fn expect_kw(&mut self, kw: &Keyword) -> Result<(), LexError> {
491 let tok = self.next()?;
492 if tok == Token::Kw(kw.clone()) {
493 Ok(())
494 } else {
495 Err(self.make_err(format!("expected keyword {:?}, got {:?}", kw, tok)))
496 }
497 }
498
499 pub fn expect_local_ident(&mut self) -> Result<String, LexError> {
501 match self.next()? {
502 Token::LocalIdent(s) => Ok(s),
503 t => Err(self.make_err(format!("expected local ident, got {:?}", t))),
504 }
505 }
506
507 pub fn expect_global_ident(&mut self) -> Result<String, LexError> {
509 match self.next()? {
510 Token::GlobalIdent(s) => Ok(s),
511 t => Err(self.make_err(format!("expected global ident, got {:?}", t))),
512 }
513 }
514
515 pub fn expect_int_lit(&mut self) -> Result<i64, LexError> {
517 match self.next()? {
518 Token::IntLit(n) => Ok(n),
519 Token::UIntLit(n) => Ok(n as i64),
520 t => Err(self.make_err(format!("expected integer literal, got {:?}", t))),
521 }
522 }
523
524 pub fn expect_uint_lit(&mut self) -> Result<u64, LexError> {
526 match self.next()? {
527 Token::IntLit(n) => Ok(n as u64),
528 Token::UIntLit(n) => Ok(n),
529 t => Err(self.make_err(format!("expected integer literal, got {:?}", t))),
530 }
531 }
532
533 pub fn expect_string_lit(&mut self) -> Result<String, LexError> {
535 match self.next()? {
536 Token::StringLit(s) => Ok(s),
537 t => Err(self.make_err(format!("expected string literal, got {:?}", t))),
538 }
539 }
540
541 pub fn current_line(&self) -> usize {
543 self.line
544 }
545 pub fn current_col(&self) -> usize {
547 self.col
548 }
549
550 fn next_token(&mut self) -> Result<Token, LexError> {
555 self.skip_whitespace_and_comments();
556
557 let start_line = self.line;
558 let start_col = self.col;
559
560 let ch = match self.peek_ch() {
561 None => return Ok(Token::Eof),
562 Some(c) => c,
563 };
564
565 match ch {
566 b'%' => {
567 self.advance();
568 let name = self.read_ident_or_int()?;
569 Ok(Token::LocalIdent(name))
570 }
571 b'@' => {
572 self.advance();
573 let name = self.read_ident_or_int()?;
574 Ok(Token::GlobalIdent(name))
575 }
576 b'"' => {
577 self.advance();
578 let s = self.read_string_literal()?;
579 Ok(Token::StringLit(s))
580 }
581 b'-' | b'0'..=b'9' => self.lex_number(),
582 b'=' => {
583 self.advance();
584 Ok(Token::Equal)
585 }
586 b',' => {
587 self.advance();
588 Ok(Token::Comma)
589 }
590 b':' => {
591 self.advance();
592 Ok(Token::Colon)
593 }
594 b'*' => {
595 self.advance();
596 Ok(Token::Star)
597 }
598 b'(' => {
599 self.advance();
600 Ok(Token::LParen)
601 }
602 b')' => {
603 self.advance();
604 Ok(Token::RParen)
605 }
606 b'[' => {
607 self.advance();
608 Ok(Token::LBracket)
609 }
610 b']' => {
611 self.advance();
612 Ok(Token::RBracket)
613 }
614 b'{' => {
615 self.advance();
616 Ok(Token::LBrace)
617 }
618 b'}' => {
619 self.advance();
620 Ok(Token::RBrace)
621 }
622 b'<' => {
623 self.advance();
624 Ok(Token::LAngle)
625 }
626 b'>' => {
627 self.advance();
628 Ok(Token::RAngle)
629 }
630 b'!' => {
631 self.advance();
632 Ok(Token::Bang)
633 }
634 b'#' => {
635 self.advance();
636 Ok(Token::Hash)
637 }
638 b'.' => {
639 if self.src.get(self.pos + 1) == Some(&b'.')
640 && self.src.get(self.pos + 2) == Some(&b'.')
641 {
642 self.advance();
643 self.advance();
644 self.advance();
645 Ok(Token::Ellipsis)
646 } else {
647 Err(LexError {
648 line: start_line,
649 col: start_col,
650 message: "unexpected '.'".into(),
651 })
652 }
653 }
654 _ if ch.is_ascii_alphabetic() || ch == b'_' || ch == b'$' => {
655 let word = self.read_word();
656 Ok(self.classify_word(&word))
657 }
658 _ => {
659 self.advance();
660 Err(LexError {
661 line: start_line,
662 col: start_col,
663 message: format!("unexpected character {:?}", ch as char),
664 })
665 }
666 }
667 }
668
669 fn read_word(&mut self) -> String {
674 let mut s = String::new();
675 while let Some(c) = self.peek_ch() {
676 if c.is_ascii_alphanumeric() || c == b'_' || c == b'.' || c == b'$' {
677 self.advance();
678 s.push(c as char);
679 } else {
680 break;
681 }
682 }
683 s
684 }
685
686 fn read_ident_or_int(&mut self) -> Result<String, LexError> {
688 if self.peek_ch() == Some(b'"') {
689 self.advance();
690 self.read_string_literal()
691 } else if self.peek_ch().map_or(false, |c| c.is_ascii_digit()) {
692 let mut s = String::new();
693 while let Some(c) = self.peek_ch() {
694 if c.is_ascii_digit() {
695 self.advance();
696 s.push(c as char);
697 } else {
698 break;
699 }
700 }
701 Ok(s)
702 } else {
703 let mut s = String::new();
704 while let Some(c) = self.peek_ch() {
705 if c.is_ascii_alphanumeric() || c == b'_' || c == b'.' || c == b'$' || c == b'-' {
706 self.advance();
707 s.push(c as char);
708 } else {
709 break;
710 }
711 }
712 Ok(s)
713 }
714 }
715
716 fn read_string_literal(&mut self) -> Result<String, LexError> {
717 let mut s = String::new();
718 loop {
719 match self.peek_ch() {
720 None => return Err(self.make_err("unterminated string")),
721 Some(b'"') => {
722 self.advance();
723 break;
724 }
725 Some(b'\\') => {
726 self.advance();
727 let h1 = self.advance().ok_or_else(|| self.make_err("bad escape"))?;
728 let h2 = self.advance().ok_or_else(|| self.make_err("bad escape"))?;
729 let hex_str = format!("{}{}", h1 as char, h2 as char);
730 let byte = u8::from_str_radix(&hex_str, 16)
731 .map_err(|_| self.make_err(format!("invalid hex escape \\{}", hex_str)))?;
732 s.push(byte as char);
733 }
734 Some(c) => {
735 self.advance();
736 s.push(c as char);
737 }
738 }
739 }
740 Ok(s)
741 }
742
743 fn lex_number(&mut self) -> Result<Token, LexError> {
748 let negative = self.peek_ch() == Some(b'-');
749 if negative {
750 self.advance();
751 }
752
753 if self.peek_ch() == Some(b'0') && matches!(self.peek_ch2(), Some(b'x') | Some(b'X')) {
755 self.advance(); self.advance(); let mut hex = String::new();
758 while let Some(c) = self.peek_ch() {
759 if c.is_ascii_hexdigit() {
760 self.advance();
761 hex.push(c as char);
762 } else {
763 break;
764 }
765 }
766 let bits = u64::from_str_radix(&hex, 16).map_err(|_| self.make_err("bad hex float"))?;
767 let f = f64::from_bits(bits);
768 return Ok(Token::FloatLit(if negative { -f } else { f }));
769 }
770
771 let mut digits = String::new();
773 while let Some(c) = self.peek_ch() {
774 if c.is_ascii_digit() {
775 self.advance();
776 digits.push(c as char);
777 } else {
778 break;
779 }
780 }
781
782 let is_float = matches!(self.peek_ch(), Some(b'.') | Some(b'e') | Some(b'E'));
784 if is_float {
785 let mut s = if negative {
786 format!("-{}", digits)
787 } else {
788 digits
789 };
790 if self.peek_ch() == Some(b'.') {
791 self.advance();
792 s.push('.');
793 while let Some(c) = self.peek_ch() {
794 if c.is_ascii_digit() {
795 self.advance();
796 s.push(c as char);
797 } else {
798 break;
799 }
800 }
801 }
802 if matches!(self.peek_ch(), Some(b'e') | Some(b'E')) {
803 self.advance();
804 s.push('e');
805 if matches!(self.peek_ch(), Some(b'+') | Some(b'-')) {
806 let sign = self.advance().unwrap();
807 s.push(sign as char);
808 }
809 while let Some(c) = self.peek_ch() {
810 if c.is_ascii_digit() {
811 self.advance();
812 s.push(c as char);
813 } else {
814 break;
815 }
816 }
817 }
818 let f: f64 = s
819 .parse()
820 .map_err(|_| self.make_err(format!("bad float: {}", s)))?;
821 Ok(Token::FloatLit(f))
822 } else {
823 let n: u64 = digits
825 .parse()
826 .map_err(|_| self.make_err(format!("bad int: {}", digits)))?;
827 if negative {
828 if n > (i64::MAX as u64) + 1 {
830 return Err(self.make_err(format!("integer -{} out of i64 range", n)));
831 }
832 Ok(Token::IntLit((n as i64).wrapping_neg()))
833 } else if n <= i64::MAX as u64 {
834 Ok(Token::IntLit(n as i64))
835 } else {
836 Ok(Token::UIntLit(n))
837 }
838 }
839 }
840
841 fn classify_word(&self, word: &str) -> Token {
846 if let Some(bits_str) = word.strip_prefix('i') {
848 if !bits_str.is_empty() && bits_str.chars().all(|c| c.is_ascii_digit()) {
849 if let Ok(bits) = bits_str.parse::<u32>() {
850 return Token::IntType(bits);
851 }
852 }
853 }
854
855 let kw = match word {
856 "source_filename" => Keyword::Source,
857 "target" => Keyword::Target,
858 "triple" => Keyword::Triple,
859 "datalayout" => Keyword::Datalayout,
860 "define" => Keyword::Define,
861 "declare" => Keyword::Declare,
862 "type" => Keyword::Type,
863 "private" => Keyword::Private,
864 "internal" => Keyword::Internal,
865 "external" => Keyword::External,
866 "weak" => Keyword::Weak,
867 "weak_odr" => Keyword::WeakOdr,
868 "linkonce" => Keyword::Linkonce,
869 "linkonce_odr" => Keyword::LinkonceOdr,
870 "common" => Keyword::Common,
871 "available_externally" => Keyword::AvailableExternally,
872 "void" => Keyword::Void,
873 "half" => Keyword::Half,
874 "bfloat" => Keyword::Bfloat,
875 "float" => Keyword::Float,
876 "double" => Keyword::Double,
877 "fp128" => Keyword::Fp128,
878 "x86_fp80" => Keyword::X86Fp80,
879 "label" => Keyword::Label,
880 "metadata" => Keyword::Metadata,
881 "ptr" => Keyword::Ptr,
882 "global" => Keyword::Global,
883 "constant" => Keyword::Constant,
884 "inbounds" => Keyword::Inbounds,
885 "exact" => Keyword::Exact,
886 "nuw" => Keyword::Nuw,
887 "nsw" => Keyword::Nsw,
888 "volatile" => Keyword::Volatile,
889 "tail" => Keyword::Tail,
890 "musttail" => Keyword::Musttail,
891 "notail" => Keyword::Notail,
892 "fast" => Keyword::Fast,
893 "nnan" => Keyword::Nnan,
894 "ninf" => Keyword::Ninf,
895 "nsz" => Keyword::Nsz,
896 "arcp" => Keyword::Arcp,
897 "contract" => Keyword::Contract,
898 "afn" => Keyword::Afn,
899 "reassoc" => Keyword::Reassoc,
900 "add" => Keyword::Add,
901 "sub" => Keyword::Sub,
902 "mul" => Keyword::Mul,
903 "udiv" => Keyword::Udiv,
904 "sdiv" => Keyword::Sdiv,
905 "urem" => Keyword::Urem,
906 "srem" => Keyword::Srem,
907 "and" => Keyword::And,
908 "or" => Keyword::Or,
909 "xor" => Keyword::Xor,
910 "shl" => Keyword::Shl,
911 "lshr" => Keyword::Lshr,
912 "ashr" => Keyword::Ashr,
913 "fadd" => Keyword::Fadd,
914 "fsub" => Keyword::Fsub,
915 "fmul" => Keyword::Fmul,
916 "fdiv" => Keyword::Fdiv,
917 "frem" => Keyword::Frem,
918 "fneg" => Keyword::Fneg,
919 "icmp" => Keyword::Icmp,
920 "fcmp" => Keyword::Fcmp,
921 "alloca" => Keyword::Alloca,
922 "load" => Keyword::Load,
923 "store" => Keyword::Store,
924 "getelementptr" => Keyword::Getelementptr,
925 "trunc" => Keyword::Trunc,
926 "zext" => Keyword::Zext,
927 "sext" => Keyword::Sext,
928 "fptrunc" => Keyword::Fptrunc,
929 "fpext" => Keyword::Fpext,
930 "fptoui" => Keyword::Fptoui,
931 "fptosi" => Keyword::Fptosi,
932 "uitofp" => Keyword::Uitofp,
933 "sitofp" => Keyword::Sitofp,
934 "ptrtoint" => Keyword::Ptrtoint,
935 "inttoptr" => Keyword::Inttoptr,
936 "bitcast" => Keyword::Bitcast,
937 "addrspacecast" => Keyword::Addrspacecast,
938 "freeze" => Keyword::Freeze,
939 "select" => Keyword::Select,
940 "phi" => Keyword::Phi,
941 "extractvalue" => Keyword::Extractvalue,
942 "insertvalue" => Keyword::Insertvalue,
943 "extractelement" => Keyword::Extractelement,
944 "insertelement" => Keyword::Insertelement,
945 "shufflevector" => Keyword::Shufflevector,
946 "call" => Keyword::Call,
947 "ret" => Keyword::Ret,
948 "br" => Keyword::Br,
949 "switch" => Keyword::Switch,
950 "unreachable" => Keyword::Unreachable,
951 "eq" => Keyword::Eq,
952 "ne" => Keyword::Ne,
953 "ugt" => Keyword::Ugt,
954 "uge" => Keyword::Uge,
955 "ult" => Keyword::Ult,
956 "ule" => Keyword::Ule,
957 "sgt" => Keyword::Sgt,
958 "sge" => Keyword::Sge,
959 "slt" => Keyword::Slt,
960 "sle" => Keyword::Sle,
961 "false" => Keyword::False,
962 "oeq" => Keyword::Oeq,
963 "ogt" => Keyword::Ogt,
964 "oge" => Keyword::Oge,
965 "olt" => Keyword::Olt,
966 "ole" => Keyword::Ole,
967 "one" => Keyword::One,
968 "ord" => Keyword::Ord,
969 "uno" => Keyword::Uno,
970 "ueq" => Keyword::Ueq,
971 "une" => Keyword::Une,
972 "true" => Keyword::True,
973 "zeroinitializer" => Keyword::Zeroinitializer,
974 "undef" => Keyword::Undef,
975 "poison" => Keyword::Poison,
976 "null" => Keyword::Null,
977 "align" => Keyword::Align,
978 "to" => Keyword::To,
979 "x" => Keyword::X,
980 "vscale" => Keyword::Vscale,
981 other => return Token::LocalIdent(other.to_string()),
983 };
984 Token::Kw(kw)
985 }
986}
987
988#[cfg(test)]
989mod tests {
990 use super::*;
991
992 fn lex_all(src: &str) -> Vec<Token> {
993 let mut lex = Lexer::new(src);
994 let mut toks = Vec::new();
995 loop {
996 let t = lex.next().unwrap();
997 if t == Token::Eof {
998 break;
999 }
1000 toks.push(t);
1001 }
1002 toks
1003 }
1004
1005 #[test]
1006 fn lex_basic_tokens() {
1007 let toks = lex_all("define i32 @foo(i32 %x) {");
1008 assert_eq!(toks[0], Token::Kw(Keyword::Define));
1009 assert_eq!(toks[1], Token::IntType(32));
1010 assert_eq!(toks[2], Token::GlobalIdent("foo".to_string()));
1011 assert_eq!(toks[3], Token::LParen);
1012 assert_eq!(toks[4], Token::IntType(32));
1013 assert_eq!(toks[5], Token::LocalIdent("x".to_string()));
1014 assert_eq!(toks[6], Token::RParen);
1015 assert_eq!(toks[7], Token::LBrace);
1016 }
1017
1018 #[test]
1019 fn lex_integer_literals() {
1020 let toks = lex_all("42 -7 0");
1021 assert_eq!(toks[0], Token::IntLit(42));
1022 assert_eq!(toks[1], Token::IntLit(-7));
1023 assert_eq!(toks[2], Token::IntLit(0));
1024 }
1025
1026 #[test]
1027 fn lex_hex_float() {
1028 let toks = lex_all("0x4000000000000000");
1029 assert_eq!(toks[0], Token::FloatLit(2.0));
1030 }
1031
1032 #[test]
1033 fn lex_comment_skipped() {
1034 let toks = lex_all("; this is a comment\ni32");
1035 assert_eq!(toks[0], Token::IntType(32));
1036 }
1037
1038 #[test]
1039 fn lex_string_literal() {
1040 let toks = lex_all("\"hello\"");
1041 assert_eq!(toks[0], Token::StringLit("hello".to_string()));
1042 }
1043
1044 #[test]
1045 fn lex_ellipsis() {
1046 let toks = lex_all("...");
1047 assert_eq!(toks[0], Token::Ellipsis);
1048 }
1049
1050 #[test]
1051 fn lex_keywords() {
1052 let toks = lex_all("ret void add nsw");
1053 assert_eq!(toks[0], Token::Kw(Keyword::Ret));
1054 assert_eq!(toks[1], Token::Kw(Keyword::Void));
1055 assert_eq!(toks[2], Token::Kw(Keyword::Add));
1056 assert_eq!(toks[3], Token::Kw(Keyword::Nsw));
1057 }
1058}