1use std::fmt::Display;
4
5pub use logos::Span;
6
7pub type Lexer<'source> = logos::Lexer<'source, Token>;
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq, logos::Logos)]
12#[logos(error = Option<Span>)]
13#[logos(skip r"[ \t\n\r]+")]
14#[logos(skip r"//[^\n]*")]
15#[logos(subpattern label_word = r"[a-z][a-z0-9]*|[A-Z][A-Z0-9]*")]
16#[logos(subpattern char_escape = r#"\\['"tnr\\]|\\u\{[0-9a-fA-F]{1,6}\}"#)]
17pub enum Token {
18 #[token("{")]
20 BraceOpen,
21 #[token("}")]
23 BraceClose,
24
25 #[token("(")]
27 ParenOpen,
28 #[token(")")]
30 ParenClose,
31
32 #[token("[")]
34 BracketOpen,
35 #[token("]")]
37 BracketClose,
38
39 #[token(":")]
41 Colon,
42
43 #[token(",")]
45 Comma,
46
47 #[regex(r"-?(0|([1-9][0-9]*))(\.[0-9]+)?([eE][-+]?[0-9]+)?")]
49 #[token("-inf")]
50 Number,
51
52 #[regex(r"%?(?&label_word)(-(?&label_word))*")]
54 LabelOrKeyword,
55
56 #[regex(r#"'([^\\'\n]{1,4}|(?&char_escape))'"#, validate_char)]
58 Char,
59
60 #[regex(r#""([^\\"\n]|(?&char_escape))*""#)]
62 String,
63
64 #[token(r#"""""#, lex_multiline_string)]
66 MultilineString,
67}
68
69impl Display for Token {
70 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 write!(f, "{self:?}")
72 }
73}
74
75fn validate_char(lex: &mut Lexer) -> Result<(), Option<Span>> {
76 let s = &lex.slice()[1..lex.slice().len() - 1];
77 if s.starts_with('\\') || s.chars().count() == 1 {
78 Ok(())
79 } else {
80 Err(Some(lex.span()))
81 }
82}
83
84fn lex_multiline_string(lex: &mut Lexer) -> bool {
85 if let Some(end) = lex.remainder().find(r#"""""#) {
86 lex.bump(end + 3);
87 true
88 } else {
89 false
90 }
91}
92
93#[derive(Clone, Copy, Debug, PartialEq)]
95#[allow(missing_docs)]
96pub enum Keyword {
97 True,
98 False,
99 Some,
100 None,
101 Ok,
102 Err,
103 Inf,
104 Nan,
105}
106
107impl Keyword {
108 pub fn decode(raw_label: &str) -> Option<Self> {
110 Some(match raw_label {
111 "true" => Self::True,
112 "false" => Self::False,
113 "some" => Self::Some,
114 "none" => Self::None,
115 "ok" => Self::Ok,
116 "err" => Self::Err,
117 "inf" => Self::Inf,
118 "nan" => Self::Nan,
119 _ => return None,
120 })
121 }
122}
123
124impl Display for Keyword {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 f.write_str(match self {
127 Keyword::True => "true",
128 Keyword::False => "false",
129 Keyword::Some => "some",
130 Keyword::None => "none",
131 Keyword::Ok => "ok",
132 Keyword::Err => "err",
133 Keyword::Inf => "inf",
134 Keyword::Nan => "nan",
135 })
136 }
137}