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