1pub mod preprocessor;
68
69use crate::{GlslVersion, Span, SpanEncoding, Spanned};
70
71pub type TokenStream = Vec<Spanned<Token>>;
73
74pub fn parse(source: &str) -> Result<(TokenStream, Metadata), ParseErr> {
94 let mut lexer: Lexer<Utf32> = Lexer::new(source, SpanEncoding::Utf32);
95 let tokens = parse_tokens(&mut lexer, false, false);
96 match lexer.metadata.version {
97 GlslVersion::Unsupported => {
98 Err(ParseErr::UnsupportedVersion(lexer.metadata.version))
99 }
100 _ => Ok((tokens, lexer.metadata)),
101 }
102}
103
104pub fn parse_with_version(
123 source: &str,
124 version: GlslVersion,
125) -> (TokenStream, Metadata) {
126 let mut lexer: Lexer<Utf32> = Lexer::new(source, SpanEncoding::Utf32);
127 lexer.metadata.version = version;
128 let tokens = parse_tokens(&mut lexer, false, true);
129 (tokens, lexer.metadata)
130}
131
132pub fn parse_with_utf_16_offsets(
138 source: &str,
139) -> Result<(TokenStream, Metadata), ParseErr> {
140 let mut lexer: Lexer<Utf16> = Lexer::new(source, SpanEncoding::Utf16);
141 let tokens = parse_tokens(&mut lexer, false, false);
142 match lexer.metadata.version {
143 GlslVersion::Unsupported => {
144 Err(ParseErr::UnsupportedVersion(lexer.metadata.version))
145 }
146 _ => Ok((tokens, lexer.metadata)),
147 }
148}
149
150pub fn parse_with_utf_16_offsets_and_version(
156 source: &str,
157 version: GlslVersion,
158) -> (TokenStream, Metadata) {
159 let mut lexer: Lexer<Utf16> = Lexer::new(source, SpanEncoding::Utf16);
160 lexer.metadata.version = version;
161 let tokens = parse_tokens(&mut lexer, false, true);
162 (tokens, lexer.metadata)
163}
164
165pub fn parse_with_utf_8_offsets(
170 source: &str,
171) -> Result<(TokenStream, Metadata), ParseErr> {
172 let mut lexer: Lexer<Utf8> = Lexer::new(source, SpanEncoding::Utf8);
173 let tokens = parse_tokens(&mut lexer, false, false);
174 match lexer.metadata.version {
175 GlslVersion::Unsupported => {
176 Err(ParseErr::UnsupportedVersion(lexer.metadata.version))
177 }
178 _ => Ok((tokens, lexer.metadata)),
179 }
180}
181
182pub fn parse_with_utf_8_offsets_and_version(
187 source: &str,
188 version: GlslVersion,
189) -> (TokenStream, Metadata) {
190 let mut lexer: Lexer<Utf8> = Lexer::new(source, SpanEncoding::Utf8);
191 lexer.metadata.version = version;
192 let tokens = parse_tokens(&mut lexer, false, true);
193 (tokens, lexer.metadata)
194}
195
196#[derive(Debug)]
198pub enum ParseErr {
199 UnsupportedVersion(GlslVersion),
201}
202
203#[derive(Debug, Clone, PartialEq)]
214#[non_exhaustive]
215pub struct Metadata {
216 pub span_encoding: SpanEncoding,
218 pub version: GlslVersion,
222 pub contains_conditional_directives: bool,
224}
225
226#[derive(Debug, Clone, PartialEq)]
228pub enum Token {
229 Num {
231 type_: NumType,
233 num: String,
235 suffix: Option<String>,
237 },
238 Bool(bool),
240 Ident(String),
242 Directive(preprocessor::TokenStream),
245 MacroConcat,
248 LineComment(String),
250 BlockComment {
252 str: String,
253 contains_eof: bool,
255 },
256 Invalid(char),
258 If,
261 Else,
263 For,
265 Do,
267 While,
269 Continue,
271 Switch,
273 Case,
275 Default,
277 Break,
279 Return,
281 Discard,
283 Struct,
285 Subroutine,
287 Reserved(String),
289 Const,
292 In,
294 Out,
296 InOut,
298 Attribute,
300 Uniform,
302 Varying,
304 Buffer,
306 Shared,
308 Centroid,
310 Sample,
312 Patch,
314 Layout,
316 Flat,
318 Smooth,
320 NoPerspective,
322 HighP,
324 MediumP,
326 LowP,
328 Invariant,
330 Precise,
332 Coherent,
334 Volatile,
336 Restrict,
338 Readonly,
340 Writeonly,
342 Op(OpTy),
345 Comma,
347 Dot,
349 Semi,
351 Colon,
353 Question,
355 LParen,
357 RParen,
359 LBracket,
361 RBracket,
363 LBrace,
365 RBrace,
367}
368
369#[derive(Debug, Clone, Copy, PartialEq, Eq)]
371pub enum NumType {
372 Dec,
375 Oct,
377 Hex,
379 Float,
381}
382
383#[derive(Debug, Clone, Copy, PartialEq, Eq)]
385pub enum OpTy {
386 Add,
389 Sub,
391 Mul,
393 Div,
395 Rem,
397 And,
399 Or,
401 Xor,
403 LShift,
405 RShift,
407 Flip,
409 Eq,
411 AddAdd,
413 SubSub,
415 AddEq,
417 SubEq,
419 MulEq,
421 DivEq,
423 RemEq,
425 AndEq,
427 OrEq,
429 XorEq,
431 LShiftEq,
433 RShiftEq,
435 EqEq,
438 NotEq,
440 Not,
442 Gt,
444 Lt,
446 Ge,
448 Le,
450 AndAnd,
452 OrOr,
454 XorXor,
456}
457
458impl Token {
459 pub fn non_semantic_colour(&self) -> crate::syntax::SyntaxType {
462 use crate::syntax::SyntaxType;
463 match self {
464 Token::Num { .. } => SyntaxType::Number,
465 Token::Bool(_) => SyntaxType::Boolean,
466 Token::Ident(_) => SyntaxType::Ident,
467 Token::Directive(_) => SyntaxType::Directive,
468 Token::MacroConcat => SyntaxType::DirectiveConcat,
469 Token::LineComment(_) | Token::BlockComment { .. } => {
470 SyntaxType::Comment
471 }
472 Token::Invalid(_) => SyntaxType::Invalid,
473 Token::If
474 | Token::Else
475 | Token::For
476 | Token::Do
477 | Token::While
478 | Token::Continue
479 | Token::Switch
480 | Token::Case
481 | Token::Default
482 | Token::Break
483 | Token::Return
484 | Token::Discard
485 | Token::Struct
486 | Token::Subroutine
487 | Token::Reserved(_)
488 | Token::Const
489 | Token::In
490 | Token::Out
491 | Token::InOut
492 | Token::Attribute
493 | Token::Uniform
494 | Token::Varying
495 | Token::Buffer
496 | Token::Shared
497 | Token::Centroid
498 | Token::Sample
499 | Token::Patch
500 | Token::Layout
501 | Token::Flat
502 | Token::Smooth
503 | Token::NoPerspective
504 | Token::HighP
505 | Token::MediumP
506 | Token::LowP
507 | Token::Invariant
508 | Token::Precise
509 | Token::Coherent
510 | Token::Volatile
511 | Token::Restrict
512 | Token::Readonly
513 | Token::Writeonly => SyntaxType::Keyword,
514 Token::Op(_) => SyntaxType::Operator,
515 Token::Comma
516 | Token::Dot
517 | Token::Semi
518 | Token::Colon
519 | Token::Question
520 | Token::LParen
521 | Token::RParen
522 | Token::LBracket
523 | Token::RBracket
524 | Token::LBrace
525 | Token::RBrace => SyntaxType::Punctuation,
526 }
527 }
528
529 pub fn can_start_statement(&self) -> bool {
531 match self {
532 Self::If
533 | Self::For
534 | Self::Do
535 | Self::While
536 | Self::Continue
537 | Self::Switch
538 | Self::Break
539 | Self::Return
540 | Self::Discard
541 | Self::Struct
542 | Self::Subroutine
543 | Self::Const
544 | Self::In
545 | Self::Out
546 | Self::InOut
547 | Self::Attribute
548 | Self::Uniform
549 | Self::Varying
550 | Self::Buffer
551 | Self::Shared
552 | Self::Centroid
553 | Self::Sample
554 | Self::Patch
555 | Self::Layout
556 | Self::Flat
557 | Self::Smooth
558 | Self::NoPerspective
559 | Self::HighP
560 | Self::MediumP
561 | Self::LowP
562 | Self::Invariant
563 | Self::Precise
564 | Self::Coherent
565 | Self::Volatile
566 | Self::Restrict
567 | Self::Readonly
568 | Self::Writeonly => true,
569 _ => false,
570 }
571 }
572}
573
574impl std::fmt::Display for Token {
575 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
576 match self {
577 Token::Num { type_, num, suffix } => {
578 match type_ {
579 NumType::Dec => {}
580 NumType::Oct => write!(f, "0")?,
581 NumType::Hex => write!(f, "0x")?,
582 NumType::Float => {}
583 }
584 write!(f, "{num}")?;
585 if let Some(suffix) = suffix {
586 write!(f, "{suffix}")
587 } else {
588 Ok(())
589 }
590 }
591 Token::Bool(b) => write!(f, "{b}"),
592 Token::Ident(s) => write!(f, "{s}"),
593 Token::Directive(_) => write!(f, "DIRECTIVE"),
594 Token::MacroConcat => write!(f, "##"),
595 Token::LineComment(s) => write!(f, "//{s}"),
596 Token::BlockComment { str, contains_eof } => {
597 write!(f, "/*{str}")?;
598 if *contains_eof {
599 write!(f, "*/")
600 } else {
601 Ok(())
602 }
603 }
604 Token::Invalid(c) => write!(f, "{c}"),
605 Token::If => write!(f, "if"),
606 Token::Else => write!(f, "else"),
607 Token::For => write!(f, "for"),
608 Token::Do => write!(f, "do"),
609 Token::While => write!(f, "while"),
610 Token::Continue => write!(f, "continue"),
611 Token::Switch => write!(f, "switch"),
612 Token::Case => write!(f, "case"),
613 Token::Default => write!(f, "default"),
614 Token::Break => write!(f, "break"),
615 Token::Return => write!(f, "return"),
616 Token::Discard => write!(f, "discard"),
617 Token::Struct => write!(f, "struct"),
618 Token::Subroutine => write!(f, "subroutine"),
619 Token::Reserved(s) => write!(f, "{s}"),
620 Token::Const => write!(f, "const"),
621 Token::In => write!(f, "in"),
622 Token::Out => write!(f, "out"),
623 Token::InOut => write!(f, "inout"),
624 Token::Attribute => write!(f, "attribute"),
625 Token::Uniform => write!(f, "uniform"),
626 Token::Varying => write!(f, "varying"),
627 Token::Buffer => write!(f, "buffer"),
628 Token::Shared => write!(f, "shared"),
629 Token::Centroid => write!(f, "centroid"),
630 Token::Sample => write!(f, "sample"),
631 Token::Patch => write!(f, "patch"),
632 Token::Layout => write!(f, "layout"),
633 Token::Flat => write!(f, "flat"),
634 Token::Smooth => write!(f, "smooth"),
635 Token::NoPerspective => write!(f, "noperspective"),
636 Token::HighP => write!(f, "highp"),
637 Token::MediumP => write!(f, "mediump"),
638 Token::LowP => write!(f, "lowp"),
639 Token::Invariant => write!(f, "invariant"),
640 Token::Precise => write!(f, "precise"),
641 Token::Coherent => write!(f, "coherent"),
642 Token::Volatile => write!(f, "volatile"),
643 Token::Restrict => write!(f, "restrict"),
644 Token::Readonly => write!(f, "readonly"),
645 Token::Writeonly => write!(f, "writeonly"),
646 Token::Op(op) => match op {
647 OpTy::Add => write!(f, "+"),
648 OpTy::Sub => write!(f, "-"),
649 OpTy::Mul => write!(f, "*"),
650 OpTy::Div => write!(f, "/"),
651 OpTy::Rem => write!(f, "%"),
652 OpTy::And => write!(f, "&"),
653 OpTy::Or => write!(f, "|"),
654 OpTy::Xor => write!(f, "^"),
655 OpTy::LShift => write!(f, "<<"),
656 OpTy::RShift => write!(f, ">>"),
657 OpTy::Flip => write!(f, "~"),
658 OpTy::Eq => write!(f, "="),
659 OpTy::AddAdd => write!(f, "++"),
660 OpTy::SubSub => write!(f, "--"),
661 OpTy::AddEq => write!(f, "+="),
662 OpTy::SubEq => write!(f, "-="),
663 OpTy::MulEq => write!(f, "*="),
664 OpTy::DivEq => write!(f, "/="),
665 OpTy::RemEq => write!(f, "%="),
666 OpTy::AndEq => write!(f, "&="),
667 OpTy::OrEq => write!(f, "|="),
668 OpTy::XorEq => write!(f, "^="),
669 OpTy::LShiftEq => write!(f, "<<="),
670 OpTy::RShiftEq => write!(f, ">>="),
671 OpTy::EqEq => write!(f, "=="),
672 OpTy::NotEq => write!(f, "!="),
673 OpTy::Not => write!(f, "!"),
674 OpTy::Gt => write!(f, ">"),
675 OpTy::Lt => write!(f, "<"),
676 OpTy::Ge => write!(f, ">="),
677 OpTy::Le => write!(f, "<="),
678 OpTy::AndAnd => write!(f, "&&"),
679 OpTy::OrOr => write!(f, "||"),
680 OpTy::XorXor => write!(f, "^^"),
681 },
682 Token::Comma => write!(f, ","),
683 Token::Dot => write!(f, "."),
684 Token::Semi => write!(f, ";"),
685 Token::Colon => write!(f, ":"),
686 Token::Question => write!(f, "?"),
687 Token::LParen => write!(f, "("),
688 Token::RParen => write!(f, ")"),
689 Token::LBracket => write!(f, "["),
690 Token::RBracket => write!(f, "]"),
691 Token::LBrace => write!(f, "{{"),
692 Token::RBrace => write!(f, "}}"),
693 }
694 }
695}
696
697fn parse_tokens<C: Char>(
706 lexer: &mut Lexer<C>,
707 parsing_define_body: bool,
708 hardcoded_version: bool,
709) -> TokenStream {
710 let mut tokens = Vec::new();
711
712 let mut can_start_directive = true;
717
718 let mut buffer = String::new();
727
728 let mut parsed_directive_yet = false;
732 'outer: while !lexer.is_done() {
733 let buffer_start = lexer.position();
734 let mut current = match lexer.peek() {
736 Some(c) => c,
737 None => {
738 break;
739 }
740 };
741
742 if parsing_define_body && (current == '\r' || current == '\n') {
743 return tokens;
746 }
747
748 if is_word_start(¤t) {
749 can_start_directive = false;
750 buffer.push(current);
751 lexer.advance();
752
753 'word: loop {
754 current = match lexer.peek() {
756 Some(c) => c,
757 None => {
758 tokens.push((
760 match_word(std::mem::take(&mut buffer)),
761 Span {
762 start: buffer_start,
763 end: lexer.position(),
764 },
765 ));
766 break 'word;
767 }
768 };
769
770 if is_word(¤t) {
772 buffer.push(current);
774 lexer.advance();
775 } else {
776 tokens.push((
779 match_word(std::mem::take(&mut buffer)),
780 Span {
781 start: buffer_start,
782 end: lexer.position(),
783 },
784 ));
785 break 'word;
786 }
787 }
788 } else if is_number_start(¤t) {
789 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
791 enum NumState {
792 Zero,
794 Hex,
796 Dec,
798 Float,
800 }
801
802 can_start_directive = false;
803
804 let mut num_buffer = String::new();
809 let mut suffix_buffer = None;
810
811 let mut state = if lexer.take_pat("0x") {
822 NumState::Hex
823 } else if lexer.take_pat("0X") {
824 NumState::Hex
825 } else if current == '0' {
826 num_buffer.push(current);
828 lexer.advance();
829 NumState::Zero
830 } else if current == '.' {
831 if let Some(lookahead) = lexer.lookahead_1() {
832 if lookahead.is_ascii_digit() {
833 num_buffer.push(current);
835 lexer.advance();
836 NumState::Float
837 } else {
838 lexer.advance();
841 tokens.push((
842 Token::Dot,
843 Span {
844 start: buffer_start,
845 end: lexer.position(),
846 },
847 ));
848 continue;
849 }
850 } else {
851 lexer.advance();
854 tokens.push((
855 Token::Dot,
856 Span {
857 start: buffer_start,
858 end: lexer.position(),
859 },
860 ));
861 continue;
862 }
863 } else {
864 num_buffer.push(current);
866 lexer.advance();
867 NumState::Dec
868 };
869
870 'number: loop {
871 current = match lexer.peek() {
873 Some(c) => c,
874 None => {
875 let type_ = match state {
877 NumState::Hex => NumType::Hex,
878 NumState::Zero => {
879 if num_buffer.as_str() == "0" {
880 NumType::Dec
881 } else {
882 num_buffer.remove(0);
883 NumType::Oct
884 }
885 }
886 NumState::Dec => NumType::Dec,
887 NumState::Float => NumType::Float,
888 };
889 tokens.push((
890 Token::Num {
891 num: num_buffer,
892 suffix: suffix_buffer,
893 type_,
894 },
895 Span {
896 start: buffer_start,
897 end: lexer.position(),
898 },
899 ));
900 break 'number;
901 }
902 };
903
904 if current == '.' && state == NumState::Hex {
905 tokens.push((
909 Token::Num {
910 num: num_buffer,
911 suffix: suffix_buffer,
912 type_: NumType::Hex,
913 },
914 Span {
915 start: buffer_start,
916 end: lexer.position(),
917 },
918 ));
919 tokens.push((
920 Token::Dot,
921 Span {
922 start: lexer.position(),
923 end: lexer.position() + 1,
924 },
925 ));
926 lexer.advance();
927 break 'number;
928 }
929 if current == '.' && suffix_buffer.is_some() {
930 let type_ = match state {
934 NumState::Hex => NumType::Hex,
935 NumState::Zero => {
936 if num_buffer.as_str() == "0" {
937 NumType::Dec
938 } else {
939 num_buffer.remove(0);
940 NumType::Oct
941 }
942 }
943 NumState::Dec => NumType::Dec,
944 NumState::Float => NumType::Float,
945 };
946 tokens.push((
947 Token::Num {
948 num: num_buffer,
949 suffix: suffix_buffer,
950 type_,
951 },
952 Span {
953 start: buffer_start,
954 end: lexer.position(),
955 },
956 ));
957 tokens.push((
958 Token::Dot,
959 Span {
960 start: lexer.position(),
961 end: lexer.position() + 1,
962 },
963 ));
964 lexer.advance();
965 break 'number;
966 }
967 if current == '.'
968 && (state == NumState::Dec || state == NumState::Zero)
969 {
970 state = NumState::Float;
974 num_buffer.push(current);
975 lexer.advance();
976 continue 'number;
977 }
978 if current == '.' && state == NumState::Float {
979 let type_ = match state {
984 NumState::Hex => NumType::Hex,
985 NumState::Zero => {
986 if num_buffer.as_str() == "0" {
987 NumType::Dec
988 } else {
989 num_buffer.remove(0);
990 NumType::Oct
991 }
992 }
993 NumState::Dec => NumType::Dec,
994 NumState::Float => NumType::Float,
995 };
996 tokens.push((
997 Token::Num {
998 num: num_buffer,
999 suffix: suffix_buffer,
1000 type_,
1001 },
1002 Span {
1003 start: buffer_start,
1004 end: lexer.position(),
1005 },
1006 ));
1007 tokens.push((
1008 Token::Dot,
1009 Span {
1010 start: lexer.position(),
1011 end: lexer.position() + 1,
1012 },
1013 ));
1014 lexer.advance();
1015 break 'number;
1016 }
1017
1018 if current == 'e' {
1019 if let Some(lookahead) = lexer.lookahead_1() {
1022 if lookahead.is_ascii_digit() {
1023 num_buffer.push(current);
1026 lexer.advance();
1027 state = NumState::Float;
1029 continue 'number;
1030 } else if lookahead == '+' || lookahead == '-' {
1031 if let Some(lookahead_2) = lexer.lookahead_2() {
1034 if lookahead_2.is_ascii_digit() {
1035 num_buffer.push(current);
1038 num_buffer.push(lookahead);
1039 lexer.advance();
1040 lexer.advance();
1041 state = NumState::Float;
1043 continue 'number;
1044 } else {
1045 lexer.advance();
1048 suffix_buffer = Some(String::from(current));
1049 let type_ = match state {
1050 NumState::Hex => NumType::Hex,
1051 NumState::Zero => {
1052 if num_buffer.as_str() == "0" {
1053 NumType::Dec
1054 } else {
1055 num_buffer.remove(0);
1056 NumType::Oct
1057 }
1058 }
1059 NumState::Dec => NumType::Dec,
1060 NumState::Float => NumType::Float,
1061 };
1062 tokens.push((
1063 Token::Num {
1064 num: num_buffer,
1065 suffix: suffix_buffer,
1066 type_,
1067 },
1068 Span {
1069 start: buffer_start,
1070 end: lexer.position(),
1071 },
1072 ));
1073 break 'number;
1074 }
1075 } else {
1076 suffix_buffer = Some(String::from(current));
1078 lexer.advance();
1079 let type_ = match state {
1080 NumState::Hex => NumType::Hex,
1081 NumState::Zero => {
1082 if num_buffer.as_str() == "0" {
1083 NumType::Dec
1084 } else {
1085 num_buffer.remove(0);
1086 NumType::Oct
1087 }
1088 }
1089 NumState::Dec => NumType::Dec,
1090 NumState::Float => NumType::Float,
1091 };
1092 tokens.push((
1093 Token::Num {
1094 num: num_buffer,
1095 suffix: suffix_buffer,
1096 type_,
1097 },
1098 Span {
1099 start: buffer_start,
1100 end: lexer.position(),
1101 },
1102 ));
1103 break 'number;
1104 }
1105 }
1106 }
1107 }
1108
1109 if current.is_ascii_hexdigit() || is_word(¤t) {
1114 match state {
1115 NumState::Zero | NumState::Dec | NumState::Float => {
1116 if !current.is_ascii_digit()
1117 && suffix_buffer.is_none()
1118 {
1119 suffix_buffer = Some(String::new());
1122 }
1123 }
1124 NumState::Hex => {
1125 if !current.is_ascii_hexdigit()
1126 && suffix_buffer.is_none()
1127 {
1128 suffix_buffer = Some(String::new());
1131 }
1132 }
1133 }
1134
1135 if let Some(suffix) = &mut suffix_buffer {
1137 suffix.push(current);
1138 } else {
1139 num_buffer.push(current);
1140 }
1141
1142 lexer.advance();
1143 } else {
1144 let type_ = match state {
1147 NumState::Hex => NumType::Hex,
1148 NumState::Zero => {
1149 if num_buffer.as_str() == "0" {
1150 NumType::Dec
1151 } else {
1152 num_buffer.remove(0);
1153 NumType::Oct
1154 }
1155 }
1156 NumState::Dec => NumType::Dec,
1157 NumState::Float => NumType::Float,
1158 };
1159 tokens.push((
1160 Token::Num {
1161 num: num_buffer,
1162 suffix: suffix_buffer,
1163 type_,
1164 },
1165 Span {
1166 start: buffer_start,
1167 end: lexer.position(),
1168 },
1169 ));
1170 break 'number;
1171 }
1172 }
1173 } else if is_punctuation_start(¤t) {
1174 can_start_directive = false;
1175
1176 if lexer.take_pat("//") {
1177 'line_comment: loop {
1179 current = match lexer.peek() {
1181 Some(c) => c,
1182 None => {
1183 tokens.push((
1185 Token::LineComment(std::mem::take(&mut buffer)),
1186 Span {
1187 start: buffer_start,
1188 end: lexer.position(),
1189 },
1190 ));
1191 break 'line_comment;
1192 }
1193 };
1194
1195 if current == '\r' || current == '\n' {
1196 tokens.push((
1198 Token::LineComment(std::mem::take(&mut buffer)),
1199 Span {
1200 start: buffer_start,
1201 end: lexer.position(),
1202 },
1203 ));
1204 break 'line_comment;
1205 } else {
1206 buffer.push(current);
1208 lexer.advance();
1209 }
1210 }
1211 } else if lexer.take_pat("/*") {
1212 'comment: loop {
1214 if lexer.take_pat("*/") {
1216 tokens.push((
1217 Token::BlockComment {
1218 str: std::mem::take(&mut buffer),
1219 contains_eof: false,
1220 },
1221 Span {
1222 start: buffer_start,
1223 end: lexer.position(),
1224 },
1225 ));
1226 can_start_directive = true;
1227 break 'comment;
1228 }
1229
1230 if let Some(char) = lexer.next() {
1232 buffer.push(char);
1233 } else {
1234 tokens.push((
1237 Token::BlockComment {
1238 str: std::mem::take(&mut buffer),
1239 contains_eof: true,
1240 },
1241 Span {
1242 start: buffer_start,
1243 end: lexer.position(),
1244 },
1245 ));
1246 break 'comment;
1247 }
1248 }
1249 } else {
1250 tokens.push((
1251 match_punctuation(lexer),
1252 Span {
1253 start: buffer_start,
1254 end: lexer.position(),
1255 },
1256 ));
1257 }
1258 } else if current.is_whitespace() {
1259 if current == '\r' || current == '\n' {
1261 can_start_directive = true;
1262 }
1263 lexer.advance();
1265 } else if can_start_directive && current == '#' && !parsing_define_body
1266 {
1267 let mut first_directive = false;
1271 if !parsed_directive_yet {
1272 first_directive = true;
1273 for (token, _) in &tokens {
1274 match token {
1275 Token::LineComment(_) | Token::BlockComment { .. } => {}
1276 _ => {
1277 first_directive = false;
1278 break;
1279 }
1280 }
1281 }
1282 parsed_directive_yet = true;
1283 };
1284
1285 let directive_start = lexer.position();
1289 lexer.advance();
1290
1291 loop {
1293 current = match lexer.peek() {
1294 Some(c) => c,
1295 None => {
1296 tokens.push((
1298 Token::Directive(preprocessor::TokenStream::Empty),
1299 Span {
1300 start: directive_start,
1301 end: lexer.position(),
1302 },
1303 ));
1304 break 'outer;
1305 }
1306 };
1307
1308 if current == '\r' || current == '\n' {
1309 tokens.push((
1311 Token::Directive(preprocessor::TokenStream::Empty),
1312 Span {
1313 start: directive_start,
1314 end: lexer.position(),
1315 },
1316 ));
1317 continue 'outer;
1318 }
1319
1320 if current.is_ascii_whitespace() {
1321 lexer.advance();
1322 continue;
1323 } else {
1324 break;
1325 }
1326 }
1327
1328 if !is_word_start(¤t) {
1329 let content_start = lexer.position();
1331 'content: loop {
1332 current = match lexer.peek() {
1334 Some(c) => c,
1335 None => {
1336 tokens.push((
1337 Token::Directive(
1338 preprocessor::TokenStream::Invalid {
1339 content: (
1340 std::mem::take(&mut buffer),
1341 Span {
1342 start: content_start,
1343 end: lexer.position(),
1344 },
1345 ),
1346 },
1347 ),
1348 Span {
1349 start: directive_start,
1350 end: lexer.position(),
1351 },
1352 ));
1353 break 'outer;
1354 }
1355 };
1356
1357 if current == '\r' || current == '\n' {
1358 break 'content;
1360 } else {
1361 buffer.push(current);
1363 lexer.advance();
1364 }
1365 }
1366
1367 tokens.push((
1368 Token::Directive(preprocessor::TokenStream::Invalid {
1369 content: (
1370 std::mem::take(&mut buffer),
1371 Span {
1372 start: content_start,
1373 end: lexer.position(),
1374 },
1375 ),
1376 }),
1377 Span {
1378 start: directive_start,
1379 end: lexer.position(),
1380 },
1381 ));
1382 continue 'outer;
1383 }
1384
1385 let directive_kw_start = lexer.position();
1387 buffer.push(current);
1388 lexer.advance();
1389 'directive_name: loop {
1390 current = match lexer.peek() {
1392 Some(c) => c,
1393 None => {
1394 tokens.push((
1396 Token::Directive(preprocessor::construct_empty(
1397 lexer,
1398 buffer,
1399 Span {
1400 start: directive_kw_start,
1401 end: lexer.position(),
1402 },
1403 )),
1404 Span {
1405 start: directive_start,
1406 end: lexer.position(),
1407 },
1408 ));
1409 break 'outer;
1410 }
1411 };
1412
1413 if is_word(¤t) {
1415 buffer.push(current);
1417 lexer.advance();
1418 } else {
1419 break 'directive_name;
1420 }
1421 }
1422
1423 let directive_kw_span = Span {
1424 start: directive_kw_start,
1425 end: lexer.position(),
1426 };
1427
1428 match buffer.as_ref() {
1430 "version" => {
1431 let (stream, version) = preprocessor::parse_version(
1432 lexer,
1433 directive_kw_span,
1434 first_directive,
1435 );
1436 tokens.push((
1437 Token::Directive(stream),
1438 Span {
1439 start: directive_start,
1440 end: lexer.position(),
1441 },
1442 ));
1443 if first_directive && !hardcoded_version {
1444 if let Some(version) = version {
1445 if version == GlslVersion::Unsupported {
1446 break 'outer;
1447 } else {
1448 lexer.metadata.version = version;
1449 }
1450 }
1451 }
1452 }
1453 "extension" => tokens.push((
1454 Token::Directive(preprocessor::parse_extension(
1455 lexer,
1456 directive_kw_span,
1457 )),
1458 Span {
1459 start: directive_start,
1460 end: lexer.position(),
1461 },
1462 )),
1463 "line" => tokens.push((
1464 Token::Directive(preprocessor::parse_line(
1465 lexer,
1466 directive_kw_span,
1467 )),
1468 Span {
1469 start: directive_start,
1470 end: lexer.position(),
1471 },
1472 )),
1473 "define" => {
1474 tokens.push((
1475 Token::Directive(preprocessor::TokenStream::Define {
1476 kw: directive_kw_span,
1477 ident_tokens: preprocessor::parse_define(lexer),
1478 body_tokens: parse_tokens(
1479 lexer,
1480 true,
1481 hardcoded_version,
1482 ),
1483 }),
1484 Span {
1485 start: directive_start,
1486 end: lexer.position(),
1487 },
1488 ));
1489 }
1490 "undef" => tokens.push((
1491 Token::Directive(preprocessor::parse_undef(
1492 lexer,
1493 directive_kw_span,
1494 )),
1495 Span {
1496 start: directive_start,
1497 end: lexer.position(),
1498 },
1499 )),
1500 "ifdef" | "ifndef" | "if" | "elif" | "else" | "endif" => {
1501 lexer.metadata.contains_conditional_directives = true;
1502 tokens.push((
1503 Token::Directive(preprocessor::parse_condition(
1504 lexer,
1505 &buffer,
1506 directive_kw_span,
1507 )),
1508 Span {
1509 start: directive_start,
1510 end: lexer.position(),
1511 },
1512 ));
1513 }
1514 "error" => {
1515 buffer.clear();
1516 let content_start = lexer.position();
1517
1518 'content: loop {
1519 current = match lexer.peek() {
1521 Some(c) => c,
1522 None => {
1523 break 'content;
1526 }
1527 };
1528
1529 if current == '\r' || current == '\n' {
1530 break 'content;
1532 } else {
1533 buffer.push(current);
1535 lexer.advance();
1536 }
1537 }
1538
1539 tokens.push((
1540 Token::Directive(preprocessor::TokenStream::Error {
1541 kw: directive_kw_span,
1542 message: Some((
1543 std::mem::take(&mut buffer),
1544 Span {
1545 start: content_start,
1546 end: lexer.position(),
1547 },
1548 )),
1549 }),
1550 Span {
1551 start: directive_start,
1552 end: lexer.position(),
1553 },
1554 ));
1555 }
1556 "pragma" => {
1557 buffer.clear();
1558 let content_start = lexer.position();
1559
1560 'content: loop {
1561 current = match lexer.peek() {
1563 Some(c) => c,
1564 None => {
1565 break 'content;
1568 }
1569 };
1570
1571 if current == '\r' || current == '\n' {
1572 break 'content;
1574 } else {
1575 buffer.push(current);
1577 lexer.advance();
1578 }
1579 }
1580
1581 tokens.push((
1582 Token::Directive(preprocessor::TokenStream::Pragma {
1583 kw: directive_kw_span,
1584 options: Some((
1585 std::mem::take(&mut buffer),
1586 Span {
1587 start: content_start,
1588 end: lexer.position(),
1589 },
1590 )),
1591 }),
1592 Span {
1593 start: directive_start,
1594 end: lexer.position(),
1595 },
1596 ));
1597 }
1598 _ => {
1599 let kw = (std::mem::take(&mut buffer), directive_kw_span);
1600 let content_start = lexer.position();
1601
1602 'content: loop {
1603 current = match lexer.peek() {
1605 Some(c) => c,
1606 None => {
1607 break 'content;
1610 }
1611 };
1612
1613 if current == '\r' || current == '\n' {
1614 break 'content;
1616 } else {
1617 buffer.push(current);
1619 lexer.advance();
1620 }
1621 }
1622
1623 tokens.push((
1624 Token::Directive(preprocessor::TokenStream::Custom {
1625 kw,
1626 content: Some((
1627 std::mem::take(&mut buffer),
1628 Span {
1629 start: content_start,
1630 end: lexer.position(),
1631 },
1632 )),
1633 }),
1634 Span {
1635 start: directive_start,
1636 end: lexer.position(),
1637 },
1638 ));
1639 }
1640 }
1641 buffer.clear();
1642 } else if current == '#' && parsing_define_body {
1643 if lexer.take_pat("##") {
1645 tokens.push((
1646 Token::MacroConcat,
1647 Span {
1648 start: buffer_start,
1649 end: lexer.position(),
1650 },
1651 ));
1652 } else {
1653 lexer.advance();
1654 tokens.push((
1655 Token::Invalid(current),
1656 Span {
1657 start: buffer_start,
1658 end: lexer.position(),
1659 },
1660 ));
1661 }
1662 } else {
1663 lexer.advance();
1665 tokens.push((
1666 Token::Invalid(current),
1667 Span {
1668 start: buffer_start,
1669 end: lexer.position(),
1670 },
1671 ));
1672 }
1673 }
1674
1675 tokens
1676}
1677
1678pub(crate) trait Char {
1680 fn offset(c: char) -> usize;
1681}
1682
1683pub(crate) struct Utf8;
1684impl Char for Utf8 {
1685 #[inline]
1686 fn offset(c: char) -> usize {
1687 c.len_utf8()
1688 }
1689}
1690
1691pub(crate) struct Utf16;
1692impl Char for Utf16 {
1693 #[inline]
1694 fn offset(c: char) -> usize {
1695 c.len_utf16()
1696 }
1697}
1698
1699pub(crate) struct Utf32;
1700impl Char for Utf32 {
1701 #[inline]
1702 fn offset(_: char) -> usize {
1703 1
1705 }
1706}
1707
1708pub(crate) struct Lexer<C> {
1713 chars: Vec<char>,
1715 cursor: usize,
1717 offset: usize,
1719 metadata: Metadata,
1721 _marker: std::marker::PhantomData<C>,
1722}
1723
1724impl<C: Char> Lexer<C> {
1725 pub(crate) fn new(source: &str, span_encoding: SpanEncoding) -> Self {
1727 let mut lexer = Lexer {
1728 chars: source.chars().collect(),
1731 cursor: 0,
1732 offset: 0,
1733 metadata: Metadata {
1734 span_encoding,
1735 version: Default::default(),
1736 contains_conditional_directives: false,
1737 },
1738 _marker: Default::default(),
1739 };
1740
1741 let i = lexer.take_line_continuator(0);
1745 lexer.cursor = i;
1746 lexer.offset = i;
1747
1748 lexer
1749 }
1750
1751 fn peek(&self) -> Option<char> {
1753 self.chars.get(self.cursor).map(|c| *c)
1754 }
1755
1756 fn lookahead_1(&self) -> Option<char> {
1759 let pos = self.cursor + 1 + self.take_line_continuator(self.cursor + 1);
1760 self.chars.get(pos).map(|c| *c)
1761 }
1762
1763 fn lookahead_2(&self) -> Option<char> {
1766 let pos = self.cursor + 1 + self.take_line_continuator(self.cursor + 1);
1767 let pos = pos + 1 + self.take_line_continuator(pos + 1);
1768 self.chars.get(pos).map(|c| *c)
1769 }
1770
1771 fn advance(&mut self) {
1773 match self.peek() {
1774 Some(c) => {
1775 self.offset += C::offset(c);
1776 }
1777 None => {}
1778 }
1779 self.cursor += 1;
1780
1781 let i = self.take_line_continuator(self.cursor);
1782 self.offset += i;
1783 self.cursor += i;
1784 }
1785
1786 fn next(&mut self) -> Option<char> {
1790 let c = self.peek();
1791 if c.is_some() {
1793 self.advance();
1794 }
1795 c
1796 }
1797
1798 fn take_pat(&mut self, pat: &str) -> bool {
1804 let pat = pat.chars().collect::<Vec<_>>();
1805 let pat_len = pat.len();
1806 let mut pat_count = 0;
1807
1808 let starting_position = self.cursor;
1811 let starting_offset = self.offset;
1812
1813 if self.chars.len() >= self.cursor + pat_len {
1815 while self.peek().is_some() {
1816 if pat_count == pat_len {
1819 break;
1820 }
1821
1822 if self.peek().unwrap() != pat[pat_count] {
1824 self.cursor = starting_position;
1825 self.offset = starting_offset;
1826 return false;
1827 }
1828
1829 self.advance();
1830 pat_count += 1;
1831 }
1832
1833 return true;
1834 }
1835
1836 false
1837 }
1838
1839 fn position(&self) -> usize {
1841 self.offset
1842 }
1843
1844 fn is_done(&self) -> bool {
1846 self.cursor == self.chars.len()
1849 }
1850
1851 fn take_line_continuator(&self, idx: usize) -> usize {
1856 let current = match self.chars.get(idx) {
1857 Some(c) => *c,
1858 None => return 0,
1859 };
1860
1861 if current != '\\' {
1863 return 0;
1864 }
1865
1866 if let Some(lookahead) = self.chars.get(idx + 1) {
1867 if *lookahead == '\n' {
1868 2
1870 } else if *lookahead == '\r' {
1871 if let Some(lookahead_2) = self.chars.get(idx + 2) {
1872 if *lookahead_2 == '\n' {
1873 3
1875 } else {
1876 2
1878 }
1879 } else {
1880 2
1882 }
1883 } else if *lookahead == '\\' {
1884 0
1887 } else {
1888 0
1891 }
1892 } else {
1893 1
1895 }
1896 }
1897}
1898
1899fn is_word_start(c: &char) -> bool {
1901 c.is_ascii_alphabetic() || *c == '_'
1902}
1903
1904fn is_word(c: &char) -> bool {
1906 c.is_ascii_alphanumeric() || *c == '_'
1907}
1908
1909fn is_number_start(c: &char) -> bool {
1911 c.is_ascii_digit() || *c == '.'
1912}
1913
1914fn is_punctuation_start(c: &char) -> bool {
1919 match c {
1920 '=' | ',' | '.' | ';' | '(' | ')' | '[' | ']' | '{' | '}' | ':'
1921 | '+' | '-' | '*' | '/' | '%' | '>' | '<' | '!' | '~' | '?' | '&'
1922 | '|' | '^' => true,
1923 _ => false,
1924 }
1925}
1926
1927macro_rules! match_op {
1928 ($lexer:ident, $str:expr, $token:expr) => {
1929 if $lexer.take_pat($str) {
1930 return $token;
1931 }
1932 };
1933}
1934
1935fn match_punctuation<C: Char>(lexer: &mut Lexer<C>) -> Token {
1937 match_op!(lexer, "<<=", Token::Op(OpTy::LShiftEq));
1938 match_op!(lexer, ">>=", Token::Op(OpTy::RShiftEq));
1939 match_op!(lexer, "==", Token::Op(OpTy::EqEq));
1940 match_op!(lexer, "!=", Token::Op(OpTy::NotEq));
1941 match_op!(lexer, ">=", Token::Op(OpTy::Ge));
1942 match_op!(lexer, "<=", Token::Op(OpTy::Le));
1943 match_op!(lexer, "&&", Token::Op(OpTy::AndAnd));
1944 match_op!(lexer, "||", Token::Op(OpTy::OrOr));
1945 match_op!(lexer, "++", Token::Op(OpTy::AddAdd));
1946 match_op!(lexer, "--", Token::Op(OpTy::SubSub));
1947 match_op!(lexer, "<<", Token::Op(OpTy::LShift));
1948 match_op!(lexer, ">>", Token::Op(OpTy::RShift));
1949 match_op!(lexer, "+=", Token::Op(OpTy::AddEq));
1950 match_op!(lexer, "-=", Token::Op(OpTy::SubEq));
1951 match_op!(lexer, "*=", Token::Op(OpTy::MulEq));
1952 match_op!(lexer, "/=", Token::Op(OpTy::DivEq));
1953 match_op!(lexer, "%=", Token::Op(OpTy::RemEq));
1954 match_op!(lexer, "&=", Token::Op(OpTy::AndEq));
1955 match_op!(lexer, "|=", Token::Op(OpTy::OrEq));
1956 match_op!(lexer, "^^", Token::Op(OpTy::XorXor));
1957 match_op!(lexer, "^=", Token::Op(OpTy::XorEq));
1958 match_op!(lexer, "=", Token::Op(OpTy::Eq));
1959 match_op!(lexer, ";", Token::Semi);
1960 match_op!(lexer, ".", Token::Dot);
1961 match_op!(lexer, ",", Token::Comma);
1962 match_op!(lexer, "(", Token::LParen);
1963 match_op!(lexer, ")", Token::RParen);
1964 match_op!(lexer, "[", Token::LBracket);
1965 match_op!(lexer, "]", Token::RBracket);
1966 match_op!(lexer, "{", Token::LBrace);
1967 match_op!(lexer, "}", Token::RBrace);
1968 match_op!(lexer, "+", Token::Op(OpTy::Add));
1969 match_op!(lexer, "-", Token::Op(OpTy::Sub));
1970 match_op!(lexer, "*", Token::Op(OpTy::Mul));
1971 match_op!(lexer, "/", Token::Op(OpTy::Div));
1972 match_op!(lexer, ">", Token::Op(OpTy::Gt));
1973 match_op!(lexer, "<", Token::Op(OpTy::Lt));
1974 match_op!(lexer, "!", Token::Op(OpTy::Not));
1975 match_op!(lexer, "~", Token::Op(OpTy::Flip));
1976 match_op!(lexer, "?", Token::Question);
1977 match_op!(lexer, ":", Token::Colon);
1978 match_op!(lexer, "%", Token::Op(OpTy::Rem));
1979 match_op!(lexer, "&", Token::Op(OpTy::And));
1980 match_op!(lexer, "|", Token::Op(OpTy::Or));
1981 match_op!(lexer, "^", Token::Op(OpTy::Xor));
1982 unreachable!("[token::match_punctuation] Exhausted all of the patterns without matching anything!");
1983}
1984
1985fn match_word(str: String) -> Token {
1987 match str.as_ref() {
1988 "true" => Token::Bool(true),
1990 "false" => Token::Bool(false),
1991 "if" => Token::If,
1993 "else" => Token::Else,
1994 "for" => Token::For,
1995 "do" => Token::Do,
1996 "while" => Token::While,
1997 "continue" => Token::Continue,
1998 "switch" => Token::Switch,
1999 "case" => Token::Case,
2000 "default" => Token::Default,
2001 "break" => Token::Break,
2002 "return" => Token::Return,
2003 "discard" => Token::Discard,
2004 "struct" => Token::Struct,
2005 "subroutine" => Token::Subroutine,
2006 "const" => Token::Const,
2007 "in" => Token::In,
2008 "out" => Token::Out,
2009 "inout" => Token::InOut,
2010 "attribute" => Token::Attribute,
2011 "uniform" => Token::Uniform,
2012 "varying" => Token::Varying,
2013 "buffer" => Token::Buffer,
2014 "shared" => Token::Shared,
2015 "centroid" => Token::Centroid,
2016 "sample" => Token::Sample,
2017 "patch" => Token::Patch,
2018 "layout" => Token::Layout,
2019 "flat" => Token::Flat,
2020 "smooth" => Token::Smooth,
2021 "noperspective" => Token::NoPerspective,
2022 "highp" => Token::HighP,
2023 "mediump" => Token::MediumP,
2024 "lowp" => Token::LowP,
2025 "invariant" => Token::Invariant,
2026 "precise" => Token::Precise,
2027 "coherent" => Token::Coherent,
2028 "volatile" => Token::Volatile,
2029 "restrict" => Token::Restrict,
2030 "readonly" => Token::Readonly,
2031 "writeonly" => Token::Writeonly,
2032 "common" | "partition" | "active" | "asm" | "class" | "union"
2034 | "enum" | "typedef" | "template" | "this" | "resource" | "goto"
2035 | "inline" | "noinline" | "public" | "static" | "extern"
2036 | "external" | "interface" | "long" | "short" | "half" | "fixed"
2037 | "unsigned" | "superp" | "input" | "output" | "hvec2" | "hvec3"
2038 | "hvec4" | "fvec2" | "fvec3" | "fvec4" | "sampler3DRect"
2039 | "filter" | "sizeof" | "cast" | "namespace" | "using" => {
2040 Token::Reserved(str)
2041 }
2042 _ => Token::Ident(str),
2044 }
2045}
2046
2047#[cfg(test)]
2048mod tests {
2049 use super::{NumType, OpTy, Token};
2050 use crate::span;
2051
2052 macro_rules! assert_tokens2 {
2053 ($src:expr, $($token:expr),*) => {
2054 let (tokens, _metadata) = crate::lexer::parse_with_version($src, crate::GlslVersion::_450);
2055 assert_eq!(tokens, vec![
2056 $(
2057 $token,
2058 )*
2059 ])
2060 };
2061 }
2062
2063 #[test]
2064 fn span_comparisons() {
2065 let src = "a 𐐀 c";
2066 let (tokens, _metadata) =
2067 super::parse_with_version(src, crate::GlslVersion::_450);
2068 assert_eq!(
2069 tokens,
2070 vec![
2071 (Token::Ident("a".into()), span(0, 1)),
2072 (Token::Invalid('𐐀'), span(2, 3)),
2073 (Token::Ident("c".into()), span(4, 5))
2074 ]
2075 );
2076
2077 let (tokens, _metadata) = super::parse_with_utf_16_offsets_and_version(
2078 src,
2079 crate::GlslVersion::_450,
2080 );
2081 assert_eq!(
2082 tokens,
2083 vec![
2084 (Token::Ident("a".into()), span(0, 1)),
2085 (Token::Invalid('𐐀'), span(2, 4)),
2086 (Token::Ident("c".into()), span(5, 6))
2087 ]
2088 );
2089
2090 let (tokens, _metadata) = super::parse_with_utf_8_offsets_and_version(
2091 src,
2092 crate::GlslVersion::_450,
2093 );
2094 assert_eq!(
2095 tokens,
2096 vec![
2097 (Token::Ident("a".into()), span(0, 1)),
2098 (Token::Invalid('𐐀'), span(2, 6)),
2099 (Token::Ident("c".into()), span(7, 8))
2100 ]
2101 );
2102 }
2103
2104 #[test]
2105 fn spans() {
2106 assert_tokens2!("return", (Token::Return, span(0, 6)));
2108 assert_tokens2!("break ", (Token::Break, span(0, 5)));
2109 assert_tokens2!(
2110 "return break",
2111 (Token::Return, span(0, 6)),
2112 (Token::Break, span(7, 12))
2113 );
2114 assert_tokens2!(";", (Token::Semi, span(0, 1)));
2116 assert_tokens2!(": ", (Token::Colon, span(0, 1)));
2117 assert_tokens2!(
2118 "; :",
2119 (Token::Semi, span(0, 1)),
2120 (Token::Colon, span(2, 3))
2121 );
2122 assert_tokens2!(
2124 "// comment",
2125 (Token::LineComment(" comment".into()), span(0, 10))
2126 );
2127 assert_tokens2!(
2128 "/* a */",
2129 (
2130 Token::BlockComment {
2131 str: " a ".into(),
2132 contains_eof: false
2133 },
2134 span(0, 7)
2135 )
2136 );
2137 assert_tokens2!(
2138 "/* a",
2139 (
2140 Token::BlockComment {
2141 str: " a".into(),
2142 contains_eof: true
2143 },
2144 span(0, 4)
2145 )
2146 );
2147 assert_tokens2!("@", (Token::Invalid('@'), span(0, 1)));
2152 assert_tokens2!("¬", (Token::Invalid('¬'), span(0, 1)));
2153 assert_tokens2!(
2154 "@ ¬",
2155 (Token::Invalid('@'), span(0, 1)),
2156 (Token::Invalid('¬'), span(3, 4))
2157 );
2158 assert_tokens2!(".", (Token::Dot, span(0, 1)));
2160 assert_tokens2!(". ", (Token::Dot, span(0, 1)));
2161 assert_tokens2!(
2162 "0xF.",
2163 (
2164 Token::Num {
2165 num: "F".into(),
2166 suffix: None,
2167 type_: NumType::Hex
2168 },
2169 span(0, 3)
2170 ),
2171 (Token::Dot, span(3, 4))
2172 );
2173 assert_tokens2!(
2174 "123u.",
2175 (
2176 Token::Num {
2177 num: "123".into(),
2178 suffix: Some("u".into()),
2179 type_: NumType::Dec
2180 },
2181 span(0, 4)
2182 ),
2183 (Token::Dot, span(4, 5))
2184 );
2185 assert_tokens2!(
2186 "1.2.",
2187 (
2188 Token::Num {
2189 num: "1.2".into(),
2190 suffix: None,
2191 type_: NumType::Float
2192 },
2193 span(0, 3)
2194 ),
2195 (Token::Dot, span(3, 4))
2196 );
2197 assert_tokens2!(
2198 "1e",
2199 (
2200 Token::Num {
2201 num: "1".into(),
2202 suffix: Some("e".into()),
2203 type_: NumType::Dec
2204 },
2205 span(0, 2)
2206 )
2207 );
2208 assert_tokens2!(
2209 "123 ",
2210 (
2211 Token::Num {
2212 num: "123".into(),
2213 suffix: None,
2214 type_: NumType::Dec
2215 },
2216 span(0, 3)
2217 )
2218 );
2219 assert_tokens2!(
2220 "1e+=",
2221 (
2222 Token::Num {
2223 num: "1".into(),
2224 suffix: Some("e".into()),
2225 type_: NumType::Dec
2226 },
2227 span(0, 2)
2228 ),
2229 (Token::Op(OpTy::AddEq), span(2, 4))
2230 );
2231 assert_tokens2!(
2232 "1e+",
2233 (
2234 Token::Num {
2235 num: "1".into(),
2236 suffix: Some("e".into()),
2237 type_: NumType::Dec
2238 },
2239 span(0, 2)
2240 ),
2241 (Token::Op(OpTy::Add), span(2, 3))
2242 );
2243 }
2244
2245 macro_rules! assert_tokens {
2248 ($src:expr, $($token:expr),*) => {
2249 let output = crate::lexer::parse_with_version($src, crate::GlslVersion::_450).0.into_iter().map(|(t, _)| t).collect::<Vec<_>>();
2250 assert_eq!(output, vec![
2251 $(
2252 $token,
2253 )*
2254 ])
2255 };
2256 }
2257
2258 #[test]
2259 fn identifiers() {
2260 assert_tokens!("ident", Token::Ident("ident".into()));
2261 assert_tokens!("gl_something", Token::Ident("gl_something".into()));
2262 assert_tokens!("id_145", Token::Ident("id_145".into()));
2263 assert_tokens!("_9ga", Token::Ident("_9ga".into()));
2264
2265 assert_tokens!("my_\\\r\nident", Token::Ident("my_ident".into()));
2267 assert_tokens!("_\\\n9ga", Token::Ident("_9ga".into()));
2268 }
2269
2270 #[test]
2271 fn keywords() {
2272 assert_tokens!("true", Token::Bool(true));
2273 assert_tokens!("false", Token::Bool(false));
2274 assert_tokens!("if", Token::If);
2275 assert_tokens!("else", Token::Else);
2276 assert_tokens!("for", Token::For);
2277 assert_tokens!("do", Token::Do);
2278 assert_tokens!("while", Token::While);
2279 assert_tokens!("continue", Token::Continue);
2280 assert_tokens!("switch", Token::Switch);
2281 assert_tokens!("case", Token::Case);
2282 assert_tokens!("default", Token::Default);
2283 assert_tokens!("break", Token::Break);
2284 assert_tokens!("return", Token::Return);
2285 assert_tokens!("discard", Token::Discard);
2286 assert_tokens!("struct", Token::Struct);
2287 assert_tokens!("subroutine", Token::Subroutine);
2288 assert_tokens!("const", Token::Const);
2289 assert_tokens!("in", Token::In);
2290 assert_tokens!("out", Token::Out);
2291 assert_tokens!("inout", Token::InOut);
2292 assert_tokens!("attribute", Token::Attribute);
2293 assert_tokens!("uniform", Token::Uniform);
2294 assert_tokens!("varying", Token::Varying);
2295 assert_tokens!("buffer", Token::Buffer);
2296 assert_tokens!("shared", Token::Shared);
2297 assert_tokens!("centroid", Token::Centroid);
2298 assert_tokens!("sample", Token::Sample);
2299 assert_tokens!("patch", Token::Patch);
2300 assert_tokens!("layout", Token::Layout);
2301 assert_tokens!("flat", Token::Flat);
2302 assert_tokens!("smooth", Token::Smooth);
2303 assert_tokens!("noperspective", Token::NoPerspective);
2304 assert_tokens!("highp", Token::HighP);
2305 assert_tokens!("mediump", Token::MediumP);
2306 assert_tokens!("lowp", Token::LowP);
2307 assert_tokens!("invariant", Token::Invariant);
2308 assert_tokens!("precise", Token::Precise);
2309 assert_tokens!("coherent", Token::Coherent);
2310 assert_tokens!("volatile", Token::Volatile);
2311 assert_tokens!("restrict", Token::Restrict);
2312 assert_tokens!("readonly", Token::Readonly);
2313 assert_tokens!("writeonly", Token::Writeonly);
2314 assert_tokens!("common", Token::Reserved("common".into()));
2316 assert_tokens!("partition", Token::Reserved("partition".into()));
2317 assert_tokens!("active", Token::Reserved("active".into()));
2318 assert_tokens!("asm", Token::Reserved("asm".into()));
2319 assert_tokens!("class", Token::Reserved("class".into()));
2320 assert_tokens!("union", Token::Reserved("union".into()));
2321 assert_tokens!("enum", Token::Reserved("enum".into()));
2322 assert_tokens!("typedef", Token::Reserved("typedef".into()));
2323 assert_tokens!("template", Token::Reserved("template".into()));
2324 assert_tokens!("this", Token::Reserved("this".into()));
2325 assert_tokens!("resource", Token::Reserved("resource".into()));
2326 assert_tokens!("goto", Token::Reserved("goto".into()));
2327 assert_tokens!("inline", Token::Reserved("inline".into()));
2328 assert_tokens!("noinline", Token::Reserved("noinline".into()));
2329 assert_tokens!("public", Token::Reserved("public".into()));
2330 assert_tokens!("static", Token::Reserved("static".into()));
2331 assert_tokens!("extern", Token::Reserved("extern".into()));
2332 assert_tokens!("external", Token::Reserved("external".into()));
2333 assert_tokens!("interface", Token::Reserved("interface".into()));
2334 assert_tokens!("long", Token::Reserved("long".into()));
2335 assert_tokens!("short", Token::Reserved("short".into()));
2336 assert_tokens!("half", Token::Reserved("half".into()));
2337 assert_tokens!("fixed", Token::Reserved("fixed".into()));
2338 assert_tokens!("unsigned", Token::Reserved("unsigned".into()));
2339 assert_tokens!("superp", Token::Reserved("superp".into()));
2340 assert_tokens!("input", Token::Reserved("input".into()));
2341 assert_tokens!("output", Token::Reserved("output".into()));
2342 assert_tokens!("hvec2", Token::Reserved("hvec2".into()));
2343 assert_tokens!("hvec3", Token::Reserved("hvec3".into()));
2344 assert_tokens!("hvec4", Token::Reserved("hvec4".into()));
2345 assert_tokens!("fvec2", Token::Reserved("fvec2".into()));
2346 assert_tokens!("fvec3", Token::Reserved("fvec3".into()));
2347 assert_tokens!("fvec4", Token::Reserved("fvec4".into()));
2348 assert_tokens!(
2349 "sampler3DRect",
2350 Token::Reserved("sampler3DRect".into())
2351 );
2352 assert_tokens!("filter", Token::Reserved("filter".into()));
2353 assert_tokens!("sizeof", Token::Reserved("sizeof".into()));
2354 assert_tokens!("cast", Token::Reserved("cast".into()));
2355 assert_tokens!("namespace", Token::Reserved("namespace".into()));
2356 assert_tokens!("using", Token::Reserved("using".into()));
2357
2358 assert_tokens!("tr\\\rue", Token::Bool(true));
2360 assert_tokens!("dis\\\ncard", Token::Discard);
2361 assert_tokens!("sub\\\r\nroutine", Token::Subroutine);
2362 }
2363
2364 #[test]
2365 fn punctuation() {
2366 assert_tokens!(";", Token::Semi);
2367 assert_tokens!(".", Token::Dot);
2368 assert_tokens!(",", Token::Comma);
2369 assert_tokens!("(", Token::LParen);
2370 assert_tokens!(")", Token::RParen);
2371 assert_tokens!("[", Token::LBracket);
2372 assert_tokens!("]", Token::RBracket);
2373 assert_tokens!("{", Token::LBrace);
2374 assert_tokens!("}", Token::RBrace);
2375 assert_tokens!(":", Token::Colon);
2376 assert_tokens!("=", Token::Op(OpTy::Eq));
2377 assert_tokens!("+", Token::Op(OpTy::Add));
2378 assert_tokens!("-", Token::Op(OpTy::Sub));
2379 assert_tokens!("*", Token::Op(OpTy::Mul));
2380 assert_tokens!("/", Token::Op(OpTy::Div));
2381 assert_tokens!(">", Token::Op(OpTy::Gt));
2382 assert_tokens!("<", Token::Op(OpTy::Lt));
2383 assert_tokens!("!", Token::Op(OpTy::Not));
2384 assert_tokens!("~", Token::Op(OpTy::Flip));
2385 assert_tokens!("?", Token::Question);
2386 assert_tokens!("%", Token::Op(OpTy::Rem));
2387 assert_tokens!("&", Token::Op(OpTy::And));
2388 assert_tokens!("|", Token::Op(OpTy::Or));
2389 assert_tokens!("^", Token::Op(OpTy::Xor));
2390 assert_tokens!("==", Token::Op(OpTy::EqEq));
2391 assert_tokens!("!=", Token::Op(OpTy::NotEq));
2392 assert_tokens!(">=", Token::Op(OpTy::Ge));
2393 assert_tokens!("<=", Token::Op(OpTy::Le));
2394 assert_tokens!("&&", Token::Op(OpTy::AndAnd));
2395 assert_tokens!("||", Token::Op(OpTy::OrOr));
2396 assert_tokens!("^^", Token::Op(OpTy::XorXor));
2397 assert_tokens!("++", Token::Op(OpTy::AddAdd));
2398 assert_tokens!("--", Token::Op(OpTy::SubSub));
2399 assert_tokens!("<<", Token::Op(OpTy::LShift));
2400 assert_tokens!(">>", Token::Op(OpTy::RShift));
2401 assert_tokens!("+=", Token::Op(OpTy::AddEq));
2402 assert_tokens!("-=", Token::Op(OpTy::SubEq));
2403 assert_tokens!("*=", Token::Op(OpTy::MulEq));
2404 assert_tokens!("/=", Token::Op(OpTy::DivEq));
2405 assert_tokens!("%=", Token::Op(OpTy::RemEq));
2406 assert_tokens!("&=", Token::Op(OpTy::AndEq));
2407 assert_tokens!("|=", Token::Op(OpTy::OrEq));
2408 assert_tokens!("^=", Token::Op(OpTy::XorEq));
2409 assert_tokens!("<<=", Token::Op(OpTy::LShiftEq));
2410 assert_tokens!(">>=", Token::Op(OpTy::RShiftEq));
2411
2412 assert_tokens!("!\\\n=", Token::Op(OpTy::NotEq));
2414 assert_tokens!("+\\\r=", Token::Op(OpTy::AddEq));
2415 assert_tokens!("=\\\n=", Token::Op(OpTy::EqEq));
2416 assert_tokens!(">>\\\r\n=", Token::Op(OpTy::RShiftEq));
2417 }
2418
2419 #[test]
2420 #[rustfmt::skip]
2421 fn comments() {
2422 assert_tokens!("// a comment", Token::LineComment(" a comment".into()));
2424 assert_tokens!("//a comment", Token::LineComment("a comment".into()));
2425
2426 assert_tokens!("// a comment \\\rcontinuation", Token::LineComment(" a comment continuation".into()));
2428 assert_tokens!("//a comment\\\ncontinuation", Token::LineComment("a commentcontinuation".into()));
2429 assert_tokens!("//a comment \\\r\ncontinuation", Token::LineComment("a comment continuation".into()));
2430 assert_tokens!("/\\\r/ a comment", Token::LineComment(" a comment".into()));
2431 assert_tokens!("/\\\r\n/ a comment", Token::LineComment(" a comment".into()));
2432 assert_tokens!("//\\\n a comment", Token::LineComment(" a comment".into()));
2433
2434 assert_tokens!("/* a comment */", Token::BlockComment{ str: " a comment ".into(), contains_eof: false});
2436 assert_tokens!("/*a comment*/", Token::BlockComment{ str: "a comment".into(), contains_eof: false});
2437 assert_tokens!("/* <Ll#,;#l,_!\"^$!6 */", Token::BlockComment{ str: " <Ll#,;#l,_!\"^$!6 ".into(), contains_eof: false});
2438 assert_tokens!("/* open-ended comment", Token::BlockComment{ str: " open-ended comment".into(), contains_eof: true});
2439
2440 assert_tokens!("/\\\r* a comment */", Token::BlockComment{ str: " a comment ".into(), contains_eof: false});
2442 assert_tokens!("/\\\n*a comment*\\\r\n/", Token::BlockComment{ str: "a comment".into(), contains_eof: false});
2443 }
2444
2445 #[test]
2446 #[rustfmt::skip]
2447 fn integers(){
2448 assert_tokens!("0", Token::Num{num: "0".into(), suffix: None, type_: NumType::Dec});
2450 assert_tokens!("0u", Token::Num{num: "0".into(), suffix: Some("u".into()), type_: NumType::Dec});
2452 assert_tokens!("1", Token::Num{num: "1".into(), suffix: None, type_: NumType::Dec});
2454 assert_tokens!("123456", Token::Num{num: "123456".into(), suffix: None, type_: NumType::Dec});
2455 assert_tokens!("100008", Token::Num{num: "100008".into(), suffix: None, type_: NumType::Dec});
2456 assert_tokens!("1u", Token::Num{num: "1".into(), suffix: Some("u".into()), type_: NumType::Dec});
2458 assert_tokens!("123456u", Token::Num{num: "123456".into(), suffix: Some("u".into()), type_: NumType::Dec});
2459 assert_tokens!("100008u", Token::Num{num: "100008".into(), suffix: Some("u".into()), type_: NumType::Dec});
2460 assert_tokens!("00", Token::Num{num: "0".into(), suffix: None, type_: NumType::Oct});
2462 assert_tokens!("01715", Token::Num{num: "1715".into(), suffix: None, type_: NumType::Oct});
2463 assert_tokens!("09183", Token::Num{num: "9183".into(), suffix: None, type_: NumType::Oct});
2464 assert_tokens!("00u", Token::Num{num: "0".into(), suffix: Some("u".into()), type_: NumType::Oct});
2466 assert_tokens!("01715u", Token::Num{num: "1715".into(), suffix: Some("u".into()), type_: NumType::Oct});
2467 assert_tokens!("09183u", Token::Num{num: "9183".into(), suffix: Some("u".into()), type_: NumType::Oct});
2468 assert_tokens!("0x", Token::Num{num: "".into(), suffix: None, type_: NumType::Hex});
2470 assert_tokens!("0x91fa", Token::Num{num: "91fa".into(), suffix: None, type_: NumType::Hex});
2471 assert_tokens!("0x00F", Token::Num{num: "00F".into(), suffix: None, type_: NumType::Hex});
2472 assert_tokens!("0xu", Token::Num{num: "".into(), suffix: Some("u".into()), type_: NumType::Hex});
2474 assert_tokens!("0x91fau", Token::Num{num: "91fa".into(), suffix: Some("u".into()), type_: NumType::Hex});
2475 assert_tokens!("0x00Fu", Token::Num{num: "00F".into(), suffix: Some("u".into()), type_: NumType::Hex});
2476
2477 assert_tokens!("123\\\r456", Token::Num{num: "123456".into(), suffix: None, type_: NumType::Dec});
2479 assert_tokens!("12\\\n3456u", Token::Num{num: "123456".into(), suffix: Some("u".into()), type_: NumType::Dec});
2480 assert_tokens!("0171\\\n5", Token::Num{num: "1715".into(), suffix: None, type_: NumType::Oct});
2481 assert_tokens!("0x91\\\r\nfa", Token::Num{num: "91fa".into(), suffix: None, type_: NumType::Hex});
2482 assert_tokens!("0x\\\r91fau", Token::Num{num: "91fa".into(), suffix: Some("u".into()), type_: NumType::Hex});
2483 assert_tokens!("0x\\\nu", Token::Num{num: "".into(), suffix: Some("u".into()), type_: NumType::Hex});
2484 }
2485
2486 #[test]
2487 #[rustfmt::skip]
2488 fn floats() {
2489 assert_tokens!("0.0", Token::Num{num: "0.0".into(), suffix: None, type_: NumType::Float});
2491 assert_tokens!("0.", Token::Num{num: "0.".into(), suffix: None, type_: NumType::Float});
2492 assert_tokens!(".0", Token::Num{num: ".0".into(), suffix: None, type_: NumType::Float});
2493 assert_tokens!("0.0lf", Token::Num{num: "0.0".into(), suffix: Some("lf".into()), type_: NumType::Float});
2495 assert_tokens!("0.lf", Token::Num{num: "0.".into(), suffix: Some("lf".into()), type_: NumType::Float});
2496 assert_tokens!(".0lf", Token::Num{num: ".0".into(), suffix: Some("lf".into()), type_: NumType::Float});
2497 assert_tokens!("0e7", Token::Num{num: "0e7".into(), suffix: None, type_: NumType::Float});
2499 assert_tokens!("0e+7", Token::Num{num: "0e+7".into(), suffix: None, type_: NumType::Float});
2500 assert_tokens!("0e-7", Token::Num{num: "0e-7".into(), suffix: None, type_: NumType::Float});
2501 assert_tokens!("0.0e7", Token::Num{num: "0.0e7".into(), suffix: None, type_: NumType::Float});
2502 assert_tokens!("0.0e+7", Token::Num{num: "0.0e+7".into(), suffix: None, type_: NumType::Float});
2503 assert_tokens!("0.0e-7", Token::Num{num: "0.0e-7".into(), suffix: None, type_: NumType::Float});
2504 assert_tokens!("0.e7", Token::Num{num: "0.e7".into(), suffix: None, type_: NumType::Float});
2505 assert_tokens!("0.e+7", Token::Num{num: "0.e+7".into(), suffix: None, type_: NumType::Float});
2506 assert_tokens!("0.e-7", Token::Num{num: "0.e-7".into(), suffix: None, type_: NumType::Float});
2507 assert_tokens!(".0e7", Token::Num{num: ".0e7".into(), suffix: None, type_: NumType::Float});
2508 assert_tokens!(".0e+7", Token::Num{num: ".0e+7".into(), suffix: None, type_: NumType::Float});
2509 assert_tokens!(".0e-7", Token::Num{num: ".0e-7".into(), suffix: None, type_: NumType::Float});
2510 assert_tokens!("0e7lf", Token::Num{num: "0e7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2512 assert_tokens!("0e+7lf", Token::Num{num: "0e+7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2513 assert_tokens!("0e-7lf", Token::Num{num: "0e-7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2514 assert_tokens!("0.0e7lf", Token::Num{num: "0.0e7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2515 assert_tokens!("0.0e+7lf", Token::Num{num: "0.0e+7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2516 assert_tokens!("0.0e-7lf", Token::Num{num: "0.0e-7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2517 assert_tokens!("0.e7lf", Token::Num{num: "0.e7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2518 assert_tokens!("0.e+7lf", Token::Num{num: "0.e+7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2519 assert_tokens!("0.e-7lf", Token::Num{num: "0.e-7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2520 assert_tokens!(".0e7lf", Token::Num{num: ".0e7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2521 assert_tokens!(".0e+7lf", Token::Num{num: ".0e+7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2522 assert_tokens!(".0e-7lf", Token::Num{num: ".0e-7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2523 assert_tokens!("1.0", Token::Num{num: "1.0".into(), suffix: None, type_: NumType::Float});
2525 assert_tokens!("1.1", Token::Num{num: "1.1".into(), suffix: None, type_: NumType::Float});
2526 assert_tokens!("1.", Token::Num{num: "1.".into(), suffix: None, type_: NumType::Float});
2527 assert_tokens!(".1", Token::Num{num: ".1".into(), suffix: None, type_: NumType::Float});
2528 assert_tokens!("1.0lf", Token::Num{num: "1.0".into(), suffix: Some("lf".into()), type_: NumType::Float});
2530 assert_tokens!("1.1lf", Token::Num{num: "1.1".into(), suffix: Some("lf".into()), type_: NumType::Float});
2531 assert_tokens!("1.lf", Token::Num{num: "1.".into(), suffix: Some("lf".into()), type_: NumType::Float});
2532 assert_tokens!(".1lf", Token::Num{num: ".1".into(), suffix: Some("lf".into()), type_: NumType::Float});
2533 assert_tokens!("1e7", Token::Num{num: "1e7".into(), suffix: None, type_: NumType::Float});
2535 assert_tokens!("1e+7", Token::Num{num: "1e+7".into(), suffix: None, type_: NumType::Float});
2536 assert_tokens!("1e-7", Token::Num{num: "1e-7".into(), suffix: None, type_: NumType::Float});
2537 assert_tokens!("1.0e7", Token::Num{num: "1.0e7".into(), suffix: None, type_: NumType::Float});
2538 assert_tokens!("1.0e+7", Token::Num{num: "1.0e+7".into(), suffix: None, type_: NumType::Float});
2539 assert_tokens!("1.0e-7", Token::Num{num: "1.0e-7".into(), suffix: None, type_: NumType::Float});
2540 assert_tokens!("1.1e7", Token::Num{num: "1.1e7".into(), suffix: None, type_: NumType::Float});
2541 assert_tokens!("1.1e+7", Token::Num{num: "1.1e+7".into(), suffix: None, type_: NumType::Float});
2542 assert_tokens!("1.1e-7", Token::Num{num: "1.1e-7".into(), suffix: None, type_: NumType::Float});
2543 assert_tokens!("1.e7", Token::Num{num: "1.e7".into(), suffix: None, type_: NumType::Float});
2544 assert_tokens!("1.e+7", Token::Num{num: "1.e+7".into(), suffix: None, type_: NumType::Float});
2545 assert_tokens!("1.e-7", Token::Num{num: "1.e-7".into(), suffix: None, type_: NumType::Float});
2546 assert_tokens!(".1e7", Token::Num{num: ".1e7".into(), suffix: None, type_: NumType::Float});
2547 assert_tokens!(".1e+7", Token::Num{num: ".1e+7".into(), suffix: None, type_: NumType::Float});
2548 assert_tokens!(".1e-7", Token::Num{num: ".1e-7".into(), suffix: None, type_: NumType::Float});
2549 assert_tokens!("1e7lf", Token::Num{num: "1e7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2551 assert_tokens!("1e+7lf", Token::Num{num: "1e+7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2552 assert_tokens!("1e-7lf", Token::Num{num: "1e-7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2553 assert_tokens!("1.0e7lf", Token::Num{num: "1.0e7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2554 assert_tokens!("1.0e+7lf", Token::Num{num: "1.0e+7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2555 assert_tokens!("1.0e-7lf", Token::Num{num: "1.0e-7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2556 assert_tokens!("1.1e7lf", Token::Num{num: "1.1e7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2557 assert_tokens!("1.1e+7lf", Token::Num{num: "1.1e+7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2558 assert_tokens!("1.1e-7lf", Token::Num{num: "1.1e-7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2559 assert_tokens!("1.e7lf", Token::Num{num: "1.e7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2560 assert_tokens!("1.e+7lf", Token::Num{num: "1.e+7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2561 assert_tokens!("1.e-7lf", Token::Num{num: "1.e-7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2562 assert_tokens!(".1e7lf", Token::Num{num: ".1e7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2563 assert_tokens!(".1e+7lf", Token::Num{num: ".1e+7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2564 assert_tokens!(".1e-7lf", Token::Num{num: ".1e-7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2565
2566 assert_tokens!("0.\\\r0", Token::Num{num: "0.0".into(), suffix: None, type_: NumType::Float});
2568 assert_tokens!(".\\\n0", Token::Num{num: ".0".into(), suffix: None, type_: NumType::Float});
2569 assert_tokens!(".0\\\nlf", Token::Num{num: ".0".into(), suffix: Some("lf".into()), type_: NumType::Float});
2570 assert_tokens!("0.\\\r\nlf", Token::Num{num: "0.".into(), suffix: Some("lf".into()), type_: NumType::Float});
2571 assert_tokens!("0e\\\r7", Token::Num{num: "0e7".into(), suffix: None, type_: NumType::Float});
2572 assert_tokens!("0e\\\r\n-7", Token::Num{num: "0e-7".into(), suffix: None, type_: NumType::Float});
2573 assert_tokens!(".0\\\r\ne+7", Token::Num{num: ".0e+7".into(), suffix: None, type_: NumType::Float});
2574 assert_tokens!("1.0e-\\\n7lf", Token::Num{num: "1.0e-7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2575 assert_tokens!(".1\\\re-7lf", Token::Num{num: ".1e-7".into(), suffix: Some("lf".into()), type_: NumType::Float});
2576 }
2577
2578 #[test]
2579 #[rustfmt::skip]
2580 fn illegal(){
2581 assert_tokens!("@", Token::Invalid('@'));
2584 assert_tokens!("¬", Token::Invalid('¬'));
2585 assert_tokens!("`", Token::Invalid('`'));
2586 assert_tokens!("¦", Token::Invalid('¦'));
2587 assert_tokens!("'", Token::Invalid('\''));
2588 assert_tokens!("\"", Token::Invalid('"'));
2589 assert_tokens!("£", Token::Invalid('£'));
2590 assert_tokens!("$", Token::Invalid('$'));
2591 assert_tokens!("€", Token::Invalid('€'));
2592 }
2593
2594 #[cfg(test)]
2595 mod preproc {
2596 use super::super::{
2597 preprocessor::{
2598 ConditionToken, DefineToken, ExtensionToken, LineToken,
2599 TokenStream, UndefToken, VersionToken,
2600 },
2601 Token,
2602 };
2603 use crate::span;
2604
2605 #[test]
2606 fn empty() {
2607 assert_tokens2!(
2608 "#",
2609 (Token::Directive(TokenStream::Empty), span(0, 1))
2610 );
2611
2612 assert_tokens2!(
2613 "# ",
2614 (Token::Directive(TokenStream::Empty), span(0, 5))
2615 );
2616 }
2617
2618 #[test]
2619 fn custom() {
2620 assert_tokens2!(
2621 "#custom",
2622 (
2623 Token::Directive(TokenStream::Custom {
2624 kw: ("custom".into(), span(1, 7)),
2625 content: None
2626 }),
2627 span(0, 7)
2628 )
2629 );
2630
2631 assert_tokens2!(
2632 "# custom ",
2633 (
2634 Token::Directive(TokenStream::Custom {
2635 kw: ("custom".into(), span(2, 8)),
2636 content: Some((" ".into(), span(8, 14)))
2637 }),
2638 span(0, 14)
2639 )
2640 );
2641
2642 assert_tokens2!(
2643 "#custom foobar 5 @;#",
2644 (
2645 Token::Directive(TokenStream::Custom {
2646 kw: ("custom".into(), span(1, 7)),
2647 content: Some((" foobar 5 @;#".into(), span(7, 20)))
2648 }),
2649 span(0, 20)
2650 )
2651 );
2652
2653 assert_tokens2!(
2654 "# custom-5 bar",
2655 (
2656 Token::Directive(TokenStream::Custom {
2657 kw: ("custom".into(), span(2, 8)),
2658 content: Some(("-5 bar".into(), span(8, 14))),
2659 }),
2660 span(0, 14)
2661 )
2662 );
2663 }
2664
2665 #[test]
2666 fn invalid() {
2667 assert_tokens2!(
2668 "# # 55 @ `!",
2669 (
2670 Token::Directive(TokenStream::Invalid {
2671 content: ("# 55 @ `!".into(), span(2, 11))
2672 }),
2673 span(0, 11)
2674 )
2675 );
2676 }
2677
2678 #[test]
2679 fn version() {
2680 assert_tokens2!(
2681 "#version",
2682 (
2683 Token::Directive(TokenStream::Version {
2684 kw: span(1, 8),
2685 tokens: vec![]
2686 }),
2687 span(0, 8)
2688 )
2689 );
2690
2691 assert_tokens2!(
2692 "#version 450 core",
2693 (
2694 Token::Directive(TokenStream::Version {
2695 kw: span(1, 8),
2696 tokens: vec![
2697 (VersionToken::Num(450), span(9, 12)),
2698 (VersionToken::Word("core".into()), span(13, 17)),
2699 ]
2700 }),
2701 span(0, 17)
2702 )
2703 );
2704
2705 assert_tokens2!(
2706 "# version 330 es",
2707 (
2708 Token::Directive(TokenStream::Version {
2709 kw: span(4, 11),
2710 tokens: vec![
2711 (VersionToken::Num(330), span(12, 15)),
2712 (VersionToken::Word("es".into()), span(16, 18)),
2713 ]
2714 }),
2715 span(0, 18)
2716 )
2717 );
2718
2719 assert_tokens2!(
2720 "#version foobar ",
2721 (
2722 Token::Directive(TokenStream::Version {
2723 kw: span(1, 8),
2724 tokens: vec![(
2725 VersionToken::Word("foobar".into()),
2726 span(9, 15)
2727 )]
2728 }),
2729 span(0, 20)
2730 )
2731 );
2732
2733 assert_tokens2!(
2734 "# version 100compatability ##@;",
2735 (
2736 Token::Directive(TokenStream::Version {
2737 kw: span(2, 9),
2738 tokens: vec![
2739 (
2740 VersionToken::InvalidNum(
2741 "100compatability".into()
2742 ),
2743 span(10, 26)
2744 ),
2745 (VersionToken::Invalid('#'), span(27, 28)),
2746 (VersionToken::Invalid('#'), span(28, 29)),
2747 (VersionToken::Invalid('@'), span(29, 30)),
2748 (VersionToken::Invalid(';'), span(30, 31))
2749 ]
2750 }),
2751 span(0, 31)
2752 )
2753 );
2754 }
2755
2756 #[test]
2757 fn extension() {
2758 assert_tokens2!(
2759 "#extension",
2760 (
2761 Token::Directive(TokenStream::Extension {
2762 kw: span(1, 10),
2763 tokens: vec![]
2764 }),
2765 span(0, 10)
2766 )
2767 );
2768 assert_tokens2!(
2769 "# extension foobar : enable",
2770 (
2771 Token::Directive(TokenStream::Extension {
2772 kw: span(3, 12),
2773 tokens: vec![
2774 (
2775 ExtensionToken::Word("foobar".into()),
2776 span(13, 19)
2777 ),
2778 (ExtensionToken::Colon, span(20, 21)),
2779 (
2780 ExtensionToken::Word("enable".into()),
2781 span(22, 28)
2782 )
2783 ]
2784 }),
2785 span(0, 28)
2786 )
2787 );
2788 assert_tokens2!(
2789 "#extension: 600 ",
2790 (
2791 Token::Directive(TokenStream::Extension {
2792 kw: span(1, 10),
2793 tokens: vec![
2794 (ExtensionToken::Colon, span(10, 11)),
2795 (ExtensionToken::Invalid('6'), span(12, 13)),
2796 (ExtensionToken::Invalid('0'), span(13, 14)),
2797 (ExtensionToken::Invalid('0'), span(14, 15))
2798 ]
2799 }),
2800 span(0, 18)
2801 )
2802 );
2803 }
2804
2805 #[test]
2806 fn line() {
2807 assert_tokens2!(
2808 "#line",
2809 (
2810 Token::Directive(TokenStream::Line {
2811 kw: span(1, 5),
2812 tokens: vec![]
2813 }),
2814 span(0, 5)
2815 )
2816 );
2817
2818 assert_tokens2!(
2819 "# line 5 1007",
2820 (
2821 Token::Directive(TokenStream::Line {
2822 kw: span(2, 6),
2823 tokens: vec![
2824 (LineToken::Num(5), span(7, 8)),
2825 (LineToken::Num(1007), span(9, 13))
2826 ]
2827 }),
2828 span(0, 13)
2829 )
2830 );
2831
2832 assert_tokens2!(
2833 "#line FOO",
2834 (
2835 Token::Directive(TokenStream::Line {
2836 kw: span(1, 5),
2837 tokens: vec![(
2838 LineToken::Ident("FOO".into()),
2839 span(6, 9)
2840 )]
2841 }),
2842 span(0, 9)
2843 )
2844 );
2845
2846 assert_tokens2!(
2847 "# line 734abc ",
2848 (
2849 Token::Directive(TokenStream::Line {
2850 kw: span(3, 7),
2851 tokens: vec![(
2852 LineToken::InvalidNum("734abc".into()),
2853 span(9, 15)
2854 )]
2855 }),
2856 span(0, 20)
2857 )
2858 );
2859 }
2860
2861 #[test]
2862 fn define() {
2863 use super::{NumType, OpTy};
2864
2865 assert_tokens2!(
2867 "#define",
2868 (
2869 Token::Directive(TokenStream::Define {
2870 kw: span(1, 7),
2871 ident_tokens: vec![],
2872 body_tokens: vec![],
2873 }),
2874 span(0, 7)
2875 )
2876 );
2877
2878 assert_tokens2!(
2879 "#define foobar",
2880 (
2881 Token::Directive(TokenStream::Define {
2882 kw: span(1, 7),
2883 ident_tokens: vec![(
2884 DefineToken::Ident("foobar".into()),
2885 span(8, 14)
2886 )],
2887 body_tokens: vec![],
2888 }),
2889 span(0, 14)
2890 )
2891 );
2892
2893 assert_tokens2!(
2894 "# define FOO 5 ",
2895 (
2896 Token::Directive(TokenStream::Define {
2897 kw: span(3, 9),
2898 ident_tokens: vec![(
2899 DefineToken::Ident("FOO".into()),
2900 span(10, 13)
2901 )],
2902 body_tokens: vec![(
2903 Token::Num {
2904 type_: NumType::Dec,
2905 num: "5".into(),
2906 suffix: None
2907 },
2908 span(14, 15)
2909 )]
2910 }),
2911 span(0, 18)
2912 )
2913 );
2914
2915 assert_tokens2!(
2916 "#define FOO_5 if [bar##0x6}",
2917 (
2918 Token::Directive(TokenStream::Define {
2919 kw: span(1, 7),
2920 ident_tokens: vec![(
2921 DefineToken::Ident("FOO_5".into()),
2922 span(8, 13)
2923 )],
2924 body_tokens: vec![
2925 (Token::If, span(15, 17)),
2926 (Token::LBracket, span(18, 19)),
2927 (Token::Ident("bar".into()), span(19, 22)),
2928 (Token::MacroConcat, span(22, 24)),
2929 (
2930 Token::Num {
2931 type_: NumType::Hex,
2932 num: "6".into(),
2933 suffix: None
2934 },
2935 span(24, 27)
2936 ),
2937 (Token::RBrace, span(27, 28))
2938 ]
2939 }),
2940 span(0, 28)
2941 )
2942 );
2943
2944 assert_tokens2!(
2945 "#define baz ( )",
2946 (
2947 Token::Directive(TokenStream::Define {
2948 kw: span(1, 7),
2949 ident_tokens: vec![(
2950 DefineToken::Ident("baz".into()),
2951 span(8, 11)
2952 ),],
2953 body_tokens: vec![
2954 (Token::LParen, span(12, 13)),
2955 (Token::RParen, span(14, 15))
2956 ]
2957 }),
2958 span(0, 15)
2959 )
2960 );
2961
2962 assert_tokens2!(
2963 "#define 5 @@ ` ",
2964 (
2965 Token::Directive(TokenStream::Define {
2966 kw: span(1, 7),
2967 ident_tokens: vec![],
2968 body_tokens: vec![
2969 (
2970 Token::Num {
2971 type_: NumType::Dec,
2972 num: "5".into(),
2973 suffix: None
2974 },
2975 span(8, 9)
2976 ),
2977 (Token::Invalid('@'), span(10, 11)),
2978 (Token::Invalid('@'), span(11, 12)),
2979 (Token::Invalid('`'), span(13, 14)),
2980 ]
2981 }),
2982 span(0, 15)
2983 )
2984 );
2985
2986 assert_tokens2!(
2988 "#define FOOBAR()",
2989 (
2990 Token::Directive(TokenStream::Define {
2991 kw: span(1, 7),
2992 ident_tokens: vec![
2993 (DefineToken::Ident("FOOBAR".into()), span(8, 14)),
2994 (DefineToken::LParen, span(14, 15)),
2995 (DefineToken::RParen, span(15, 16)),
2996 ],
2997 body_tokens: vec![]
2998 }),
2999 span(0, 16)
3000 )
3001 );
3002
3003 assert_tokens2!(
3004 "#define baz( )",
3005 (
3006 Token::Directive(TokenStream::Define {
3007 kw: span(1, 7),
3008 ident_tokens: vec![
3009 (DefineToken::Ident("baz".into()), span(8, 11)),
3010 (DefineToken::LParen, span(11, 12)),
3011 (DefineToken::RParen, span(13, 14))
3012 ],
3013 body_tokens: vec![]
3014 }),
3015 span(0, 14)
3016 )
3017 );
3018
3019 assert_tokens2!(
3020 "#define FOOBAR( a, b)",
3021 (
3022 Token::Directive(TokenStream::Define {
3023 kw: span(1, 7),
3024 ident_tokens: vec![
3025 (DefineToken::Ident("FOOBAR".into()), span(8, 14)),
3026 (DefineToken::LParen, span(14, 15)),
3027 (DefineToken::Ident("a".into()), span(16, 17)),
3028 (DefineToken::Comma, span(17, 18)),
3029 (DefineToken::Ident("b".into()), span(19, 20)),
3030 (DefineToken::RParen, span(20, 21)),
3031 ],
3032 body_tokens: vec![]
3033 }),
3034 span(0, 21)
3035 )
3036 );
3037
3038 assert_tokens2!(
3039 "#define FOOBAR( a # @@",
3040 (
3041 Token::Directive(TokenStream::Define {
3042 kw: span(1, 7),
3043 ident_tokens: vec![
3044 (DefineToken::Ident("FOOBAR".into()), span(8, 14)),
3045 (DefineToken::LParen, span(14, 15)),
3046 (DefineToken::Ident("a".into()), span(16, 17)),
3047 (DefineToken::Invalid('#'), span(18, 19)),
3048 (DefineToken::Invalid('@'), span(20, 21)),
3049 (DefineToken::Invalid('@'), span(21, 22)),
3050 ],
3051 body_tokens: vec![]
3052 }),
3053 span(0, 22)
3054 )
3055 );
3056
3057 assert_tokens2!(
3058 "#define FOOBAR( a) if [0x7u## %!",
3059 (
3060 Token::Directive(TokenStream::Define {
3061 kw: span(1, 7),
3062 ident_tokens: vec![
3063 (DefineToken::Ident("FOOBAR".into()), span(8, 14)),
3064 (DefineToken::LParen, span(14, 15)),
3065 (DefineToken::Ident("a".into()), span(16, 17)),
3066 (DefineToken::RParen, span(17, 18)),
3067 ],
3068 body_tokens: vec![
3069 (Token::If, span(20, 22)),
3070 (Token::LBracket, span(23, 24)),
3071 (
3072 Token::Num {
3073 type_: NumType::Hex,
3074 num: "7".into(),
3075 suffix: Some("u".into())
3076 },
3077 span(24, 28)
3078 ),
3079 (Token::MacroConcat, span(28, 30)),
3080 (Token::Op(OpTy::Rem), span(31, 32)),
3081 (Token::Op(OpTy::Not), span(32, 33)),
3082 ]
3083 }),
3084 span(0, 33)
3085 )
3086 );
3087 }
3088
3089 #[test]
3090 fn undef() {
3091 assert_tokens2!(
3092 "#undef",
3093 (
3094 Token::Directive(TokenStream::Undef {
3095 kw: span(1, 6),
3096 tokens: vec![]
3097 }),
3098 span(0, 6)
3099 )
3100 );
3101
3102 assert_tokens2!(
3103 "# undef foo ",
3104 (
3105 Token::Directive(TokenStream::Undef {
3106 kw: span(2, 7),
3107 tokens: vec![(
3108 UndefToken::Ident("foo".into()),
3109 span(8, 11)
3110 )]
3111 }),
3112 span(0, 12)
3113 )
3114 );
3115
3116 assert_tokens2!(
3117 "# undef foobar @ `` 4 ",
3118 (
3119 Token::Directive(TokenStream::Undef {
3120 kw: span(5, 10),
3121 tokens: vec![
3122 (UndefToken::Ident("foobar".into()), span(11, 17)),
3123 (UndefToken::Invalid('@'), span(18, 19)),
3124 (UndefToken::Invalid('`'), span(20, 21)),
3125 (UndefToken::Invalid('`'), span(21, 22)),
3126 (UndefToken::Invalid('4'), span(23, 24)),
3127 ]
3128 }),
3129 span(0, 28)
3130 )
3131 );
3132 }
3133
3134 #[test]
3135 fn conditional() {
3136 assert_tokens2!(
3137 "#if",
3138 (
3139 Token::Directive(TokenStream::If {
3140 kw: span(1, 3),
3141 tokens: vec![]
3142 }),
3143 span(0, 3)
3144 )
3145 );
3146
3147 assert_tokens2!(
3148 "# if FOO > 5",
3149 (
3150 Token::Directive(TokenStream::If {
3151 kw: span(2, 4),
3152 tokens: vec![
3153 (ConditionToken::Ident("FOO".into()), span(5, 8)),
3154 (ConditionToken::Gt, span(9, 10)),
3155 (ConditionToken::Num(5), span(11, 12))
3156 ]
3157 }),
3158 span(0, 12)
3159 )
3160 );
3161
3162 assert_tokens2!(
3163 "#if 5001bar",
3164 (
3165 Token::Directive(TokenStream::If {
3166 kw: span(1, 3),
3167 tokens: vec![(
3168 ConditionToken::InvalidNum("5001bar".into()),
3169 span(4, 11)
3170 )]
3171 }),
3172 span(0, 11)
3173 )
3174 );
3175
3176 assert_tokens2!(
3177 "#if (defined foobar) && 5 <8",
3178 (
3179 Token::Directive(TokenStream::If {
3180 kw: span(1, 3),
3181 tokens: vec![
3182 (ConditionToken::LParen, span(4, 5)),
3183 (ConditionToken::Defined, span(5, 12)),
3184 (
3185 ConditionToken::Ident("foobar".into()),
3186 span(13, 19)
3187 ),
3188 (ConditionToken::RParen, span(19, 20)),
3189 (ConditionToken::AndAnd, span(21, 23)),
3190 (ConditionToken::Num(5), span(24, 25)),
3191 (ConditionToken::Lt, span(26, 27)),
3192 (ConditionToken::Num(8), span(27, 28))
3193 ]
3194 }),
3195 span(0, 28)
3196 )
3197 );
3198 assert_tokens2!(
3199 "#if baz @ ## : ",
3200 (
3201 Token::Directive(TokenStream::If {
3202 kw: span(1, 3),
3203 tokens: vec![
3204 (ConditionToken::Ident("baz".into()), span(4, 7)),
3205 (ConditionToken::Invalid('@'), span(8, 9)),
3206 (ConditionToken::Invalid('#'), span(10, 11)),
3207 (ConditionToken::Invalid('#'), span(11, 12)),
3208 (ConditionToken::Invalid(':'), span(13, 14)),
3209 ]
3210 }),
3211 span(0, 17)
3212 )
3213 );
3214 }
3215
3216 #[test]
3217 fn error() {
3218 assert_tokens2!(
3219 "#error",
3220 (
3221 Token::Directive(TokenStream::Error {
3222 kw: span(1, 6),
3223 message: None
3224 }),
3225 span(0, 6)
3226 )
3227 );
3228
3229 assert_tokens2!(
3230 "# error foo bar ## @ ; ",
3231 (
3232 Token::Directive(TokenStream::Error {
3233 kw: span(2, 7),
3234 message: Some((
3235 " foo bar ## @ ; ".into(),
3236 span(7, 28)
3237 ))
3238 }),
3239 span(0, 28)
3240 )
3241 );
3242 }
3243
3244 #[test]
3245 fn pragma() {
3246 assert_tokens2!(
3247 "#pragma",
3248 (
3249 Token::Directive(TokenStream::Pragma {
3250 kw: span(1, 7),
3251 options: None
3252 }),
3253 span(0, 7)
3254 )
3255 );
3256
3257 assert_tokens2!(
3258 "# pragma foo bar ## @ ; ",
3259 (
3260 Token::Directive(TokenStream::Pragma {
3261 kw: span(2, 8),
3262 options: Some((
3263 " foo bar ## @ ; ".into(),
3264 span(8, 29)
3265 ))
3266 }),
3267 span(0, 29)
3268 )
3269 );
3270 }
3271 }
3272}