1use unescape::unescape;
4use std::ops::Range;
5use super::{
6 name_range,
7 start_name_range
8};
9
10#[derive(Debug, Clone)]
13pub enum DefinitionType {
14 InlineProp,
15 InlineArg,
16 ChildProp,
17 ChildArg,
18 Object(String)
19}
20
21#[derive(Debug, Clone)]
22pub enum DirectiveType {
23 Include,
24 Header
25}
26#[derive(Debug, Clone)]
27pub enum TypeIdentifierType {
28 String,
29 Number,
30 Bool
31}
32
33#[derive(Debug, Clone)]
34pub enum IdentifierType {
35 Generic(String),
36 Type(TypeIdentifierType)
37}
38
39#[derive(Debug, Clone)]
40pub enum TokenValue {
41 String(String), Number(f32), Bool(i32), Definition(DefinitionType), Directive(DirectiveType), Setter(String), Identifier(IdentifierType), Comment, Inherits, StartBlock, EndBlock, StartArgList, EndArgList, ArgListDeliminator, }
56
57#[derive(Debug, Clone)]
58pub struct Token {
59 pub value: TokenValue,
60 pub range: Range<usize>
61}
62
63impl Token {
66 pub fn to_string(&self) -> &str {
67 match &self.value {
68 TokenValue::String(_) => "string",
69 TokenValue::Number(_) => "number",
70 TokenValue::Bool(_) => "boolean",
71 TokenValue::Definition(_) => "definition",
72 TokenValue::Directive(_) => "directive",
73 TokenValue::Setter(_) => "setter",
74 TokenValue::Identifier(_) => "identifier",
75 TokenValue::StartBlock => "{",
76 TokenValue::EndBlock => "}",
77 TokenValue::StartArgList => "(",
78 TokenValue::EndArgList => ")",
79 TokenValue::ArgListDeliminator => ",",
80 TokenValue::Inherits => "->",
81 TokenValue::Comment => "comment"
82 }
83 }
84
85 pub fn value_to_string(&self) -> String {
86 match &self.value {
87 TokenValue::String(string) => string.to_string(),
88 TokenValue::Number(number) => number.to_string(),
89 TokenValue::Bool(boolean) => boolean.to_string(),
90 _ => todo!("not implemented yet, but not needed yet!")
91 }
92 }
93}
94
95impl DefinitionType {
96 pub fn from(definition: &String) -> TokenValue {
97 TokenValue::Definition(
98 if definition == "InlineProp" {
99 DefinitionType::InlineProp
100 } else if definition == "InlineArg" {
101 DefinitionType::InlineArg
102 } else if definition == "ChildProp" {
103 DefinitionType::ChildProp
104 } else if definition == "ChildArg" {
105 DefinitionType::ChildArg
106 } else {
107 DefinitionType::Object(String::from(definition))
108 }
109 )
110 }
111}
112
113impl DefinitionType {
114 pub fn to_string(&self) -> &str {
115 match self {
116 DefinitionType::InlineArg => "InlineArg",
117 DefinitionType::InlineProp => "InlineProp",
118 DefinitionType::ChildArg => "ChildArg",
119 DefinitionType::ChildProp => "ChildProp",
120 DefinitionType::Object(_) => "Object"
121 }
122 }
123}
124
125impl DirectiveType {
126 pub fn from(directive: &String) -> TokenValue {
127 let directive_type: Option<DirectiveType>;
128
129 if directive == "include" {
130 directive_type = Some(DirectiveType::Include);
131 } else if directive == "header" {
132 directive_type = Some(DirectiveType::Header);
133 } else {
134 directive_type = None;
135 }
136
137 match directive_type {
138 Some(t) => TokenValue::Directive(t),
139 None => panic!("invalid directive")
140 }
141 }
142}
143
144pub struct Lexer {
147 pub tokens: Vec<Token>,
148 index: usize,
149 input: String,
150}
151
152impl Lexer {
153
154 #[inline]
157 fn move_foward(&mut self) {
158 self.index += 1;
159 }
160
161 #[inline]
162 fn move_forward_n(&mut self, n: usize) {
163 self.index += n;
164 }
165
166 fn definition(&mut self) -> Result<Token, (String, Range<usize>)> {
169 let mut definition = String::new();
170 let start_position = self.index.clone();
171 self.move_foward();
172 for c in self.input[self.index..].chars() {
173 match c {
174 name_range!() => {
175 definition.push(c);
176 },
177 _ => break
178 }
179 }
180
181 self.move_forward_n(definition.len());
182 Ok(Token {
183 value: DefinitionType::from(&definition),
184 range: (start_position..self.index)
185 })
186 }
187
188 fn directive(&mut self) -> Result<Token, (String, Range<usize>)> {
189 let mut directive = String::new();
190 let start_position = self.index.clone();
191 self.move_foward();
192 for c in self.input[self.index..].chars() {
193 match c {
194 name_range!() => {
195 directive.push(c);
196 },
197 _ => break
198 }
199 }
200
201 self.move_forward_n(directive.len());
202 Ok(Token {
203 value: DirectiveType::from(&directive),
204 range: (start_position..self.index)
205 })
206 }
207
208 fn string(&mut self) -> Result<Token, (String, Range<usize>)> {
209 let mut string = String::new();
210 let start_position = self.index.clone();
211 self.move_foward();
212 loop {
213 let c = self.input.chars().nth(self.index).unwrap();
214 match c {
215 '\\' => {
216 string.push(c);
217 string.push(self.input.chars().nth(self.index + 1).unwrap());
218 self.move_forward_n(2);
219 },
220 '"' => {
221 self.move_foward();
222 break
223 },
224 '\n' => {
225 return Err(( String::from("unexpected end of string input"), (self.index..self.index) ));
226 },
227 _ => {
228 self.move_foward();
229 string.push(c);
230 }
231 }
232 }
233
234 match unescape(string.as_str()) {
235 Some(string) =>
236 Ok(Token {
237 value: TokenValue::String(string),
238 range: (start_position..self.index)
239 }),
240 None => Err(( String::from("unable to escape string"), (start_position..self.index) ))
241 }
242 }
243
244 fn setter(&mut self) -> Result<Token, (String, Range<usize>)> {
245 let mut setter = String::new();
246 let start_position = self.index.clone();
247 self.move_foward();
248 for c in self.input[self.index..].chars() {
249 match c {
250 name_range!() => {
251 setter.push(c);
252 },
253 _ => break
254 }
255 }
256
257 self.move_forward_n(setter.len());
258 Ok(Token {
259 value: TokenValue::Setter(setter),
260 range: (start_position..self.index)
261 })
262 }
263
264 fn number(&mut self) -> Result<Token, (String, Range<usize>)> {
265 let mut number = String::new();
266 let start_position = self.index.clone();
267 for c in self.input[self.index..].chars() {
268 if ! c.is_digit(10) && c != '.' {
269 break
270 }
271 number.push(c);
272 }
273
274 self.move_forward_n(number.len());
275
276 match number.parse::<f32>() {
277 Ok(num) =>
278 Ok(Token {
279 value: TokenValue::Number(num),
280 range: (start_position..self.index)
281 }),
282 Err(e) => Err((e.to_string(), (start_position..self.index)))
283 }
284 }
285
286 fn identifier(&mut self) -> Result<Token, (String, Range<usize>)> {
288 let mut identifier = String::new();
289 let start_position = self.index.clone();
290 for c in self.input[self.index..].chars() {
291 match c {
292 name_range!() => {
293 identifier.push(c);
294 },
295 _ => break
296 }
297 }
298
299 self.move_forward_n(identifier.len());
300
301 let value = match identifier.as_str() {
302 "true" => TokenValue::Bool(1),
303 "false" => TokenValue::Bool(0),
304 "String" => TokenValue::Identifier(IdentifierType::Type(TypeIdentifierType::String)),
305 "Number" => TokenValue::Identifier(IdentifierType::Type(TypeIdentifierType::Number)),
306 "Bool" => TokenValue::Identifier(IdentifierType::Type(TypeIdentifierType::Bool)),
307 _ => TokenValue::Identifier(IdentifierType::Generic(identifier))
308 };
309
310 Ok(Token {
311 value,
312 range: (start_position..self.index)
313 })
314 }
315
316 fn add_and_move(&mut self, value: TokenValue) -> Result<Token, (String, Range<usize>)> {
317 self.move_foward();
318 Ok(Token {
319 value,
320 range: ((self.index - 1)..self.index)
321 })
322 }
323
324 fn comment(&mut self) -> Result<Token, (String, Range<usize>)> {
325 let start_position = self.index.clone();
326 loop {
327 let c = self.input.chars().nth(self.index);
328 if let Some(c) = c {
329 if c == '\n' {
330 break;
331 }
332 self.move_foward();
333 } else {
334 break;
335 }
336 }
337 return Ok(Token {
338 value: TokenValue::Comment,
339 range: (start_position..self.index)
340 })
341 }
342
343 fn inherits(&mut self) -> Result<Token, (String, Range<usize>)> {
344 self.move_foward();
345 if let Some(char) = self.input.chars().nth(self.index) {
346 if char == '>' {
347 self.move_foward();
348 Ok(Token {
349 value: TokenValue::Inherits,
350 range: ((self.index - 2)..self.index)
351 })
352 } else {
353 Err((format!("unrecognized character '{}'", char), (self.index..(self.index + 1))))
354 }
355 } else {
356 Err((format!("unexpected end of input"), (self.index..self.index)))
357 }
358 }
359
360 pub fn new(s: String) -> Self {
362 Self {
363 tokens: Vec::new(),
364 index: 0,
365 input: s,
366 }
367 }
368 pub fn lex(&mut self, lex_comments: bool) -> Result<(), (String, Range<usize>)> {
369 loop {
370 let input_char = self.input.chars().nth(self.index);
371 if let Some(c) = input_char {
372 let token = match c {
373 '@' => self.definition(),
374 '#' => self.directive(),
375 '"' => self.string(),
376 '.' => self.setter(),
377 '0'..='9' => self.number(),
378 '-' => self.inherits(),
379 start_name_range!() => self.identifier(),
380 '{' => self.add_and_move(TokenValue::StartBlock),
381 '}' => self.add_and_move(TokenValue::EndBlock),
382 ',' => self.add_and_move(TokenValue::ArgListDeliminator),
383 '(' => self.add_and_move(TokenValue::StartArgList),
384 ')' => self.add_and_move(TokenValue::EndArgList),
385 ' ' | '\t' | '\n' => {
386 self.move_foward();
387 continue
388 },
389 '/' => {
390 let comment = self.comment();
391 if lex_comments {
392 comment
393 } else {
394 continue
395 }
396 },
397 _ => Err((format!("unrecognized character '{}'", c), (self.index..self.index))),
398 };
399
400 match token {
401 Ok(token) => self.tokens.push(token),
402 Err(err) => return Err(err)
403 }
404 } else {
405 return Ok(());
406 }
407 }
408 }
409}