1use crate::block_string::{dedent_block_lines_mut, print_block_string, BlockStringToken};
2use logos::{Lexer, Logos};
3
4#[derive(Debug, PartialEq, Clone, Default)]
5pub enum LexingError {
7 #[default]
8 UnknownToken,
9 UnterminatedString(usize),
11}
12
13#[derive(Logos, Debug, PartialEq)]
14#[logos(skip r"([\s,]+|#[^\r\n]*)+")]
15#[logos(error = LexingError)]
16pub(crate) enum Token<'a> {
17 #[token("{")]
18 BraceOpen,
19
20 #[token("}")]
21 BraceClose,
22
23 #[token("(")]
24 ParenOpen,
25
26 #[token(")")]
27 ParenClose,
28
29 #[token("[")]
30 BracketOpen,
31
32 #[token("]")]
33 BracketClose,
34
35 #[token(":")]
36 Colon,
37
38 #[token("=")]
39 Equals,
40
41 #[token("!")]
42 Exclamation,
43
44 #[token("?")]
45 Question,
46
47 #[token("&")]
48 Ampersand,
49
50 #[token("|")]
51 Pipe,
52
53 #[token("...")]
54 Ellipsis,
55
56 #[regex(r#"""""#)]
57 BlockStringDelimiter,
58
59 #[regex(r#""([^"\\]*(\\.[^"\\]*)*)""#, |lexer| match lexer.slice() {
60 s if s.contains(['\n', '\r']) => Err(LexingError::UnterminatedString(lexer.span().start)),
61 s => Ok(s),
62 })]
63 String(&'a str),
64
65 #[regex("-?[0-9]+")]
66 Int(&'a str),
67
68 #[regex("-?[0-9]+\\.[0-9]+(e-?[0-9]+)?")]
69 Float(&'a str),
70
71 #[regex("true|false")]
72 Bool(&'a str),
73
74 #[regex("@[a-zA-Z_][a-zA-Z0-9_]*")]
75 Directive(&'a str),
76
77 #[regex("\\$[a-zA-Z_][a-zA-Z0-9_]*")]
78 Variable(&'a str),
79
80 #[regex(r"[a-zA-Z_][a-zA-Z0-9_]*")]
81 Identifier(&'a str),
82}
83
84impl<'a> Token<'a> {
85 pub(crate) fn parse_block_string(&self, lexer: &mut Lexer<'a, Token<'a>>) -> String {
86 let mut lines = vec![];
87 let mut current_line = String::new();
88
89 let remainder = lexer.remainder();
90 let mut block_lexer = BlockStringToken::lexer(remainder);
91
92 while let Some(Ok(token)) = block_lexer.next() {
93 match token {
94 BlockStringToken::NewLine => {
95 lines.push(current_line);
96 current_line = String::new();
97 }
98 BlockStringToken::Text | BlockStringToken::Quote | BlockStringToken::EscapeSeq => {
99 current_line.push_str(block_lexer.slice())
100 }
101 BlockStringToken::EscapedTripleQuote => current_line.push_str(r#"""""#),
102 BlockStringToken::TripleQuote => break,
103 }
104 }
105
106 if !current_line.is_empty() {
107 lines.push(current_line);
108 }
109
110 lexer.bump(remainder.len() - block_lexer.remainder().len());
111
112 dedent_block_lines_mut(&mut lines);
113 print_block_string(lines.join("\n"))
114 }
115}