idl/
scanner.rs

1use regex::Regex;
2use std::fmt;
3
4use super::range::{Position, Range};
5
6static BOOLEAN_VALUES: &'static [&str] = &["false", "true"];
7
8static NATIVE_TYPES: &'static [&str] = &[
9    "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float32", "float64",
10    "bool", "string", "none", "int", "float", "byte",
11];
12
13#[derive(Debug, Copy, Clone, Eq, PartialEq)]
14pub enum NativeTypes {
15    Int,
16    Int8,
17    Int16,
18    Int32,
19    Int64,
20    Uint8,
21    Uint16,
22    Uint32,
23    Uint64,
24    Float32,
25    Float64,
26    Float,
27    String,
28    Byte,
29    Bool,
30    None,
31}
32
33impl From<&str> for NativeTypes {
34    fn from(value: &str) -> Self {
35        match value {
36            "int" => NativeTypes::Int,
37            "int8" => NativeTypes::Int8,
38            "int16" => NativeTypes::Int16,
39            "int32" => NativeTypes::Int32,
40            "int64" => NativeTypes::Int64,
41            "uint8" => NativeTypes::Uint8,
42            "uint16" => NativeTypes::Uint16,
43            "uint32" => NativeTypes::Uint32,
44            "uint64" => NativeTypes::Uint64,
45            "float" => NativeTypes::Float,
46            "float32" => NativeTypes::Float32,
47            "float64" => NativeTypes::Float64,
48            "string" => NativeTypes::String,
49            "byte" => NativeTypes::Byte,
50            "bool" => NativeTypes::Bool,
51            "none" => NativeTypes::None,
52            _ => panic!(),
53        }
54    }
55}
56
57impl fmt::Display for NativeTypes {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        let name = match self {
60            NativeTypes::Int => "int",
61            NativeTypes::Int8 => "int8",
62            NativeTypes::Int16 => "int16",
63            NativeTypes::Int32 => "int32",
64            NativeTypes::Int64 => "int64",
65            NativeTypes::Uint8 => "uint8",
66            NativeTypes::Uint16 => "uint16",
67            NativeTypes::Uint32 => "uint32",
68            NativeTypes::Uint64 => "uint64",
69            NativeTypes::Float => "float",
70            NativeTypes::Float32 => "float32",
71            NativeTypes::Float64 => "float64",
72            NativeTypes::String => "string",
73            NativeTypes::Byte => "byte",
74            NativeTypes::Bool => "bool",
75            NativeTypes::None => "none",
76        };
77
78        write!(f, "{}", name)
79    }
80}
81
82#[derive(Debug)]
83pub(super) struct WordRange<T> {
84    pub(super) range: Range,
85    word: T,
86}
87
88impl Range {
89    fn new_with_length(line: usize, index: usize, length: usize) -> Self {
90        Self {
91            start: Position {
92                line,
93                column: index,
94            },
95            end: Position {
96                line,
97                column: index + length,
98            },
99        }
100    }
101}
102
103impl<T> WordRange<T> {
104    pub(super) fn get_word(&self) -> &T {
105        &self.word
106    }
107}
108
109#[derive(Debug)]
110pub(super) enum WordStream {
111    LeftSquareBracket(WordRange<char>),
112    RightSquareBracket(WordRange<char>),
113    SquareBracketBody(Vec<WordStream>),
114    LeftCurlyBracket(WordRange<char>),
115    RightCurlyBracket(WordRange<char>),
116    CurlyBracketBody(Vec<WordStream>),
117    LeftParenthesis(WordRange<char>),
118    RightParenthesis(WordRange<char>),
119    ParenthesisBody(Vec<WordStream>),
120    Comma(WordRange<char>),
121    Dot(WordRange<char>),
122    Assignment(WordRange<char>),
123    Colon(WordRange<char>),
124    Hyphen(WordRange<char>),
125    Solidus(WordRange<char>),
126    QuestionMark(WordRange<char>),
127    ExclamationMark(WordRange<char>),
128    GreaterThan(WordRange<char>),
129    NewLine(WordRange<char>),
130    SemiColon(WordRange<char>),
131    Identifier(WordRange<String>),
132    NativeType(WordRange<NativeTypes>),
133    TypeName(WordRange<String>),
134    Comment(WordRange<String>),
135    Literal(WordRange<String>),
136    FloatValue(WordRange<String>),
137    IntegerValue(WordRange<String>),
138    UUIDValue(WordRange<String>),
139    BooleanValue(WordRange<String>),
140}
141
142impl WordStream {
143    pub(super) fn get_range(&self) -> Range {
144        match self {
145            WordStream::LeftCurlyBracket(value)
146            | WordStream::RightSquareBracket(value)
147            | WordStream::LeftSquareBracket(value)
148            | WordStream::RightCurlyBracket(value)
149            | WordStream::LeftParenthesis(value)
150            | WordStream::RightParenthesis(value)
151            | WordStream::Comma(value)
152            | WordStream::Dot(value)
153            | WordStream::Assignment(value)
154            | WordStream::Colon(value)
155            | WordStream::NewLine(value)
156            | WordStream::Hyphen(value)
157            | WordStream::Solidus(value)
158            | WordStream::GreaterThan(value)
159            | WordStream::QuestionMark(value)
160            | WordStream::ExclamationMark(value)
161            | WordStream::SemiColon(value) => value.range,
162            WordStream::Identifier(value)
163            | WordStream::TypeName(value)
164            | WordStream::Comment(value)
165            | WordStream::Literal(value)
166            | WordStream::FloatValue(value)
167            | WordStream::BooleanValue(value)
168            | WordStream::IntegerValue(value)
169            | WordStream::UUIDValue(value) => value.range,
170            WordStream::NativeType(value) => value.range,
171            WordStream::CurlyBracketBody(w_streams)
172            | WordStream::ParenthesisBody(w_streams)
173            | WordStream::SquareBracketBody(w_streams) => match w_streams.first() {
174                Some(value) => value.get_range(),
175                None => Range::default(),
176            },
177        }
178    }
179}
180
181impl fmt::Display for WordStream {
182    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183        let strname = match self {
184            WordStream::LeftCurlyBracket(name)
185            | WordStream::RightSquareBracket(name)
186            | WordStream::LeftSquareBracket(name)
187            | WordStream::RightCurlyBracket(name)
188            | WordStream::LeftParenthesis(name)
189            | WordStream::RightParenthesis(name)
190            | WordStream::Comma(name)
191            | WordStream::Dot(name)
192            | WordStream::Assignment(name)
193            | WordStream::Colon(name)
194            | WordStream::Hyphen(name)
195            | WordStream::Solidus(name)
196            | WordStream::GreaterThan(name)
197            | WordStream::QuestionMark(name)
198            | WordStream::ExclamationMark(name)
199            | WordStream::SemiColon(name) => name.get_word().to_string(),
200            WordStream::Identifier(name)
201            | WordStream::TypeName(name)
202            | WordStream::Comment(name)
203            | WordStream::Literal(name)
204            | WordStream::FloatValue(name)
205            | WordStream::BooleanValue(name)
206            | WordStream::IntegerValue(name)
207            | WordStream::UUIDValue(name) => name.get_word().to_owned(),
208            WordStream::NativeType(name) => name.get_word().to_string(),
209            WordStream::NewLine(_) => "".to_owned(),
210            WordStream::CurlyBracketBody(_)
211            | WordStream::ParenthesisBody(_)
212            | WordStream::SquareBracketBody(_) => "".to_owned(),
213        };
214
215        write!(f, "{}", strname)
216    }
217}
218
219#[derive(Debug)]
220pub(super) enum ScError {
221    SymbolMissing(WordStream),
222    Name(WordStream),
223    InvalidCharacter(WordRange<char>),
224    InvalidComment(WordRange<String>),
225    InvalidString(WordRange<String>),
226}
227
228#[derive(Default)]
229pub(super) struct ContextStream {
230    cur_line: usize,
231    cur_char: usize,
232}
233
234#[derive(Debug)]
235pub(super) struct SourceStream {
236    pub(super) word_streams: Vec<WordStream>,
237}
238
239lazy_static! {
240    static ref RE_UUID: Regex =
241        Regex::new(r"^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")
242            .unwrap();
243}
244
245impl ContextStream {
246    fn new() -> Self {
247        Self::default()
248    }
249
250    pub(super) fn scan_text(lines: &[&str]) -> Result<SourceStream, ScError> {
251        let mut context = Self::new();
252        let mut brackets_word_stream = vec![];
253
254        while let Some(line_text) = lines.get(context.cur_line) {
255            match line_text.chars().nth(context.cur_char) {
256                Some(ch) => {
257                    let line_str = line_text;
258
259                    // At this point, the character can only be a whitespace, start of a comment,
260                    // which means the entire line, an identifier, or a body.
261                    match ch {
262                        c if c.is_whitespace() => context.cur_char += 1,
263                        c if c.is_ascii_alphabetic() => {
264                            context.push_identifier(line_str, &mut brackets_word_stream)?
265                        }
266                        c if c.is_ascii_digit() => {
267                            context.push_numeric_string(line_str, &mut brackets_word_stream)?
268                        }
269                        '/' => {
270                            if context
271                                .consume_comment(line_str, &mut brackets_word_stream)
272                                .is_err()
273                            {
274                                context.push_solidus(&mut brackets_word_stream);
275                            }
276                        }
277                        '-' => {
278                            if context
279                                .push_numeric_string(line_str, &mut brackets_word_stream)
280                                .is_err()
281                            {
282                                context.push_hyphen(&mut brackets_word_stream);
283                            }
284                        }
285                        ';' => context.push_semi_colon(&mut brackets_word_stream),
286                        ',' => context.push_comma(&mut brackets_word_stream),
287                        '.' => context.push_dot(&mut brackets_word_stream),
288                        ':' => context.push_colon(&mut brackets_word_stream),
289                        '=' => context.push_assignment(&mut brackets_word_stream),
290                        '"' => context.consume_string(line_str, &mut brackets_word_stream)?,
291                        '{' => context.consume_body(lines, &mut brackets_word_stream)?,
292                        sw => {
293                            return Err(ScError::InvalidCharacter(WordRange {
294                                range: Range::new_with_length(
295                                    context.cur_line,
296                                    context.cur_char,
297                                    1,
298                                ),
299                                word: sw,
300                            }))
301                        }
302                    }
303                }
304                None => context.next_line(&mut brackets_word_stream),
305            }
306        }
307
308        Ok(SourceStream {
309            word_streams: brackets_word_stream,
310        })
311    }
312
313    fn consume_comment(
314        &mut self,
315        line_text: &str,
316        word_stream: &mut Vec<WordStream>,
317    ) -> Result<(), ScError> {
318        lazy_static! {
319            static ref RE: Regex = Regex::new(r"\A(?://)(.*)").unwrap();
320        }
321
322        let text = line_text[self.cur_char..].to_string();
323        match RE.captures(&text) {
324            Some(caps) => match caps.get(1) {
325                Some(m) => {
326                    let comment = m.as_str().to_owned();
327                    word_stream.push(WordStream::Comment(WordRange {
328                        range: Range::new_with_length(self.cur_line, self.cur_char, comment.len()),
329                        word: comment,
330                    }));
331                    self.next_line(word_stream);
332                    return Ok(());
333                }
334                None => {
335                    return Err(ScError::InvalidComment(WordRange {
336                        range: Range::new_with_length(self.cur_line, self.cur_char, text.len()),
337                        word: text,
338                    }));
339                }
340            },
341            None => {
342                return Err(ScError::InvalidComment(WordRange {
343                    range: Range::new_with_length(self.cur_line, self.cur_char, text.len()),
344                    word: text,
345                }));
346            }
347        }
348    }
349
350    fn consume_string(
351        &mut self,
352        line_text: &str,
353        word_stream: &mut Vec<WordStream>,
354    ) -> Result<(), ScError> {
355        lazy_static! {
356            static ref RE: Regex = Regex::new(r#"\A"(.*?)""#).unwrap();
357        }
358
359        let text = line_text[self.cur_char..].to_string();
360
361        match RE.captures(&text) {
362            Some(caps) => {
363                let match_len = caps.get(0).unwrap().as_str().chars().count();
364
365                match caps.get(1) {
366                    Some(m) => word_stream.push(WordStream::Literal(WordRange {
367                        range: Range::new_with_length(self.cur_line, self.cur_char, match_len),
368                        word: m.as_str().to_owned(),
369                    })),
370                    None => {
371                        return Err(ScError::InvalidString(WordRange {
372                            range: Range::new_with_length(self.cur_line, self.cur_char, text.len()),
373                            word: text,
374                        }));
375                    }
376                }
377
378                self.cur_char += match_len;
379            }
380            None => {
381                return Err(ScError::InvalidString(WordRange {
382                    range: Range::new_with_length(self.cur_line, self.cur_char, text.len()),
383                    word: text,
384                }));
385            }
386        }
387
388        Ok(())
389    }
390
391    fn consume_brackets(
392        &mut self,
393        lines: &[&str],
394        word_stream: &mut Vec<WordStream>,
395    ) -> Result<(), ScError> {
396        let mut brackets_word_stream = vec![];
397        self.push_left_square_bracket(word_stream);
398
399        while let Some(line_text) = lines.get(self.cur_line) {
400            match line_text.chars().nth(self.cur_char) {
401                Some(ch) => {
402                    let line_str = line_text;
403
404                    match ch {
405                        c if c.is_ascii_alphabetic() => {
406                            self.push_identifier(line_str, &mut brackets_word_stream)?
407                        }
408                        c if c.is_whitespace() => self.cur_char += 1,
409                        '[' => self.consume_brackets(lines, &mut brackets_word_stream)?,
410                        ']' => {
411                            word_stream.push(WordStream::SquareBracketBody(brackets_word_stream));
412                            self.push_right_square_bracket(word_stream);
413                            return Ok(());
414                        }
415                        '(' => self.consume_parenthesis(lines, &mut brackets_word_stream)?,
416                        ';' => self.push_semi_colon(&mut brackets_word_stream),
417                        '"' => self.consume_string(line_str, &mut brackets_word_stream)?,
418                        '-' => {
419                            if self
420                                .push_numeric_string(line_str, &mut brackets_word_stream)
421                                .is_err()
422                            {
423                                self.push_hyphen(&mut brackets_word_stream);
424                            }
425                        }
426                        '/' => {
427                            if self
428                                .consume_comment(line_str, &mut brackets_word_stream)
429                                .is_err()
430                            {
431                                self.push_solidus(&mut brackets_word_stream);
432                            }
433                        }
434                        '?' => self.push_question_mark(&mut brackets_word_stream),
435                        '!' => self.push_exclamation_mark(&mut brackets_word_stream),
436                        '>' => {
437                            self.push_greater_than(&mut brackets_word_stream);
438                        }
439                        ',' => self.push_comma(&mut brackets_word_stream),
440                        '.' => self.push_dot(&mut brackets_word_stream),
441                        sw => {
442                            return Err(ScError::InvalidCharacter(WordRange {
443                                range: Range::new_with_length(self.cur_line, self.cur_char, 1),
444                                word: sw,
445                            }));
446                        }
447                    }
448                }
449                None => self.next_line(&mut brackets_word_stream),
450            }
451        }
452
453        Err(ScError::SymbolMissing(WordStream::RightSquareBracket(
454            WordRange {
455                range: Range::new_with_length(self.cur_line, self.cur_char, 1),
456                word: ']',
457            },
458        )))
459    }
460
461    fn consume_parenthesis(
462        &mut self,
463        lines: &[&str],
464        word_stream: &mut Vec<WordStream>,
465    ) -> Result<(), ScError> {
466        let mut parens_word_stream = vec![];
467        self.push_left_paren(word_stream);
468
469        while let Some(line_text) = lines.get(self.cur_line) {
470            match line_text.chars().nth(self.cur_char) {
471                Some(ch) => {
472                    let line_str = line_text;
473
474                    match ch {
475                        c if c.is_ascii_alphabetic() => {
476                            self.push_identifier(line_str, &mut parens_word_stream)?
477                        }
478                        c if c.is_whitespace() => self.cur_char += 1,
479                        '(' => self.consume_parenthesis(lines, &mut parens_word_stream)?,
480                        ')' => {
481                            word_stream.push(WordStream::ParenthesisBody(parens_word_stream));
482                            self.push_right_paren(word_stream);
483                            return Ok(());
484                        }
485                        '[' => self.consume_brackets(lines, &mut parens_word_stream)?,
486                        '"' => self.consume_string(line_str, &mut parens_word_stream)?,
487                        ';' => self.push_semi_colon(&mut parens_word_stream),
488                        ':' => self.push_colon(&mut parens_word_stream),
489                        '-' => {
490                            if self
491                                .push_numeric_string(line_str, &mut parens_word_stream)
492                                .is_err()
493                            {
494                                self.push_hyphen(&mut parens_word_stream);
495                            }
496                        }
497                        '/' => {
498                            if self
499                                .consume_comment(line_str, &mut parens_word_stream)
500                                .is_err()
501                            {
502                                self.push_solidus(&mut parens_word_stream);
503                            }
504                        }
505                        '?' => self.push_question_mark(&mut parens_word_stream),
506                        '!' => self.push_exclamation_mark(&mut parens_word_stream),
507                        '>' => {
508                            self.push_greater_than(&mut parens_word_stream);
509                        }
510                        ',' => self.push_comma(&mut parens_word_stream),
511                        '.' => self.push_dot(&mut parens_word_stream),
512                        sw => {
513                            return Err(ScError::InvalidCharacter(WordRange {
514                                range: Range::new_with_length(self.cur_line, self.cur_char, 1),
515                                word: sw,
516                            }));
517                        }
518                    }
519                }
520                None => self.next_line(&mut parens_word_stream),
521            }
522        }
523
524        Err(ScError::SymbolMissing(WordStream::RightParenthesis(
525            WordRange {
526                range: Range::new_with_length(self.cur_line, self.cur_char, 1),
527                word: ')',
528            },
529        )))
530    }
531
532    fn consume_body(
533        &mut self,
534        lines: &[&str],
535        word_stream: &mut Vec<WordStream>,
536    ) -> Result<(), ScError> {
537        let mut brackets_word_stream = vec![];
538        self.push_left_curly_bracket(word_stream);
539
540        while let Some(line_text) = lines.get(self.cur_line) {
541            match line_text.chars().nth(self.cur_char) {
542                Some(ch) => {
543                    let line_str = line_text;
544
545                    match ch {
546                        c if c.is_ascii_alphabetic() => {
547                            self.push_identifier(line_str, &mut brackets_word_stream)?
548                        }
549                        c if c.is_ascii_digit() => {
550                            self.push_numeric_string(line_str, &mut brackets_word_stream)?
551                        }
552                        c if c.is_whitespace() => self.cur_char += 1,
553                        '{' => self.consume_body(lines, &mut brackets_word_stream)?,
554                        '}' => {
555                            word_stream.push(WordStream::CurlyBracketBody(brackets_word_stream));
556                            self.push_right_curly_bracket(word_stream);
557                            return Ok(());
558                        }
559                        '[' => self.consume_brackets(lines, &mut brackets_word_stream)?,
560                        '(' => self.consume_parenthesis(lines, &mut brackets_word_stream)?,
561                        ',' => self.push_comma(&mut brackets_word_stream),
562                        '.' => self.push_dot(&mut brackets_word_stream),
563                        ':' => self.push_colon(&mut brackets_word_stream),
564                        ';' => self.push_semi_colon(&mut brackets_word_stream),
565                        '=' => self.push_assignment(&mut brackets_word_stream),
566                        '?' => self.push_question_mark(&mut brackets_word_stream),
567                        '!' => self.push_exclamation_mark(&mut brackets_word_stream),
568                        '"' => self.consume_string(line_str, &mut brackets_word_stream)?,
569                        '-' => {
570                            if self
571                                .push_numeric_string(line_str, &mut brackets_word_stream)
572                                .is_err()
573                            {
574                                self.push_hyphen(&mut brackets_word_stream);
575                            }
576                        }
577                        '/' => {
578                            if self
579                                .consume_comment(line_str, &mut brackets_word_stream)
580                                .is_err()
581                            {
582                                self.push_solidus(&mut brackets_word_stream);
583                            }
584                        }
585                        '>' => {
586                            self.push_greater_than(&mut brackets_word_stream);
587                        }
588                        sw => {
589                            return Err(ScError::InvalidCharacter(WordRange {
590                                range: Range::new_with_length(self.cur_line, self.cur_char, 1),
591                                word: sw,
592                            }));
593                        }
594                    }
595                }
596                None => self.next_line(&mut brackets_word_stream),
597            }
598        }
599
600        Err(ScError::SymbolMissing(WordStream::RightCurlyBracket(
601            WordRange {
602                range: Range::new_with_length(self.cur_line, self.cur_char, 1),
603                word: '}',
604            },
605        )))
606    }
607
608    fn push_identifier(
609        &mut self,
610        line_text: &str,
611        word_stream: &mut Vec<WordStream>,
612    ) -> Result<(), ScError> {
613        let mut ident = String::new();
614        let index = self.cur_char;
615
616        while let Some(ch) = line_text.chars().nth(self.cur_char) {
617            // Looks for a correct word, until it finds a whitespace.
618            if ch.is_ascii_alphanumeric() || ch == '_' || ch == '-' {
619                ident.push(ch);
620                self.cur_char += 1;
621            } else {
622                break;
623            }
624        }
625
626        if NATIVE_TYPES.contains(&ident.as_str()) {
627            let native_type = NativeTypes::from(ident.as_str());
628            let word_range = WordRange {
629                range: Range::new_with_length(self.cur_line, index, ident.len()),
630                word: native_type,
631            };
632
633            word_stream.push(WordStream::NativeType(word_range));
634        } else if BOOLEAN_VALUES.contains(&ident.as_str()) {
635            let word_range = WordRange {
636                range: Range::new_with_length(self.cur_line, index, ident.len()),
637                word: ident.to_owned(),
638            };
639
640            word_stream.push(WordStream::BooleanValue(word_range));
641        } else {
642            let word_range = WordRange {
643                range: Range::new_with_length(self.cur_line, index, ident.len()),
644                word: ident.to_owned(),
645            };
646
647            if let Some(_) = RE_UUID.captures(ident.as_str()) {
648                word_stream.push(WordStream::UUIDValue(word_range));
649                return Ok(());
650            }
651
652            lazy_static! {
653                static ref RE: Regex =
654                    Regex::new(r"^(?:([A-Z]+[A-Za-z0-9]*)|([a-z]+[A-Za-z0-9]*))$").unwrap();
655            }
656
657            match RE.captures(ident.as_str()) {
658                Some(caps) => {
659                    if caps.get(1).is_some() {
660                        // Type name.
661                        word_stream.push(WordStream::TypeName(word_range));
662                    } else if caps.get(2).is_some() {
663                        // Identifier.
664                        word_stream.push(WordStream::Identifier(word_range));
665                    } else {
666                        return Err(ScError::Name(WordStream::Identifier(word_range)));
667                    }
668                }
669                None => {
670                    return Err(ScError::Name(WordStream::Identifier(word_range)));
671                }
672            }
673        }
674        Ok(())
675    }
676
677    fn push_numeric_string(
678        &mut self,
679        line_text: &str,
680        word_stream: &mut Vec<WordStream>,
681    ) -> Result<(), ScError> {
682        let mut ident = String::new();
683        let mut cur_char = self.cur_char;
684
685        while let Some(ch) = line_text.chars().nth(cur_char) {
686            match ch {
687                c if c.is_ascii_hexdigit() => {
688                    cur_char += 1;
689                    ident.push(c);
690                }
691                'x' | '.' | '-' => {
692                    cur_char += 1;
693                    ident.push(ch);
694                }
695                _ => break,
696            }
697        }
698
699        // TODO Use basic floating point notation.
700        lazy_static! {
701            static ref RE: Regex =
702                Regex::new(r"^(?:(-?(?:0x[0-9A-F]+|0x[0-9a-f]+|[0-9]+))|(-?(?:[0-9]+\.)+[0-9]+))$")
703                    .unwrap();
704        }
705
706        let word_range = WordRange {
707            range: Range::new_with_length(self.cur_line, self.cur_char, ident.len()), // TODO
708            word: ident.to_owned(),
709        };
710
711        if let Some(caps) = RE.captures(ident.as_str()) {
712            if caps.get(1).is_some() {
713                word_stream.push(WordStream::IntegerValue(word_range));
714                self.cur_char = cur_char;
715                return Ok(());
716            } else if caps.get(2).is_some() {
717                word_stream.push(WordStream::FloatValue(word_range));
718                self.cur_char = cur_char;
719                return Ok(());
720            }
721        } else if let Some(_) = RE_UUID.captures(ident.as_str()) {
722            word_stream.push(WordStream::UUIDValue(word_range));
723            self.cur_char = cur_char;
724            return Ok(());
725        }
726
727        return Err(ScError::InvalidString(WordRange {
728            range: Range::new_with_length(self.cur_line, self.cur_char, ident.len()),
729            word: ident,
730        }));
731    }
732
733    fn push_comma(&mut self, word_stream: &mut Vec<WordStream>) {
734        word_stream.push(WordStream::Comma(WordRange {
735            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
736            word: ',',
737        }));
738        self.cur_char += 1;
739    }
740
741    fn push_dot(&mut self, word_stream: &mut Vec<WordStream>) {
742        word_stream.push(WordStream::Dot(WordRange {
743            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
744            word: '.',
745        }));
746        self.cur_char += 1;
747    }
748
749    fn push_hyphen(&mut self, word_stream: &mut Vec<WordStream>) {
750        word_stream.push(WordStream::Hyphen(WordRange {
751            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
752            word: '-',
753        }));
754        self.cur_char += 1;
755    }
756
757    fn push_solidus(&mut self, word_stream: &mut Vec<WordStream>) {
758        word_stream.push(WordStream::Solidus(WordRange {
759            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
760            word: '/',
761        }));
762        self.cur_char += 1;
763    }
764
765    fn push_greater_than(&mut self, word_stream: &mut Vec<WordStream>) {
766        word_stream.push(WordStream::GreaterThan(WordRange {
767            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
768            word: '>',
769        }));
770        self.cur_char += 1;
771    }
772
773    fn push_left_square_bracket(&mut self, word_stream: &mut Vec<WordStream>) {
774        word_stream.push(WordStream::LeftSquareBracket(WordRange {
775            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
776            word: '[',
777        }));
778        self.cur_char += 1;
779    }
780
781    fn push_right_square_bracket(&mut self, word_stream: &mut Vec<WordStream>) {
782        word_stream.push(WordStream::RightSquareBracket(WordRange {
783            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
784            word: ']',
785        }));
786        self.cur_char += 1;
787    }
788
789    fn push_left_curly_bracket(&mut self, word_stream: &mut Vec<WordStream>) {
790        word_stream.push(WordStream::LeftCurlyBracket(WordRange {
791            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
792            word: '{',
793        }));
794        self.cur_char += 1;
795    }
796
797    fn push_right_curly_bracket(&mut self, word_stream: &mut Vec<WordStream>) {
798        word_stream.push(WordStream::RightCurlyBracket(WordRange {
799            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
800            word: '}',
801        }));
802        self.cur_char += 1;
803    }
804
805    fn push_left_paren(&mut self, word_stream: &mut Vec<WordStream>) {
806        word_stream.push(WordStream::LeftParenthesis(WordRange {
807            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
808            word: '(',
809        }));
810        self.cur_char += 1;
811    }
812
813    fn push_right_paren(&mut self, word_stream: &mut Vec<WordStream>) {
814        word_stream.push(WordStream::RightParenthesis(WordRange {
815            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
816            word: ')',
817        }));
818        self.cur_char += 1;
819    }
820
821    fn push_colon(&mut self, word_stream: &mut Vec<WordStream>) {
822        word_stream.push(WordStream::Colon(WordRange {
823            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
824            word: ':',
825        }));
826        self.cur_char += 1;
827    }
828
829    fn push_assignment(&mut self, word_stream: &mut Vec<WordStream>) {
830        word_stream.push(WordStream::Assignment(WordRange {
831            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
832            word: '=',
833        }));
834        self.cur_char += 1;
835    }
836
837    fn push_semi_colon(&mut self, word_stream: &mut Vec<WordStream>) {
838        word_stream.push(WordStream::SemiColon(WordRange {
839            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
840            word: ';',
841        }));
842        self.cur_char += 1;
843    }
844
845    fn push_question_mark(&mut self, word_stream: &mut Vec<WordStream>) {
846        word_stream.push(WordStream::QuestionMark(WordRange {
847            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
848            word: '?',
849        }));
850        self.cur_char += 1;
851    }
852
853    fn push_exclamation_mark(&mut self, word_stream: &mut Vec<WordStream>) {
854        word_stream.push(WordStream::ExclamationMark(WordRange {
855            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
856            word: '!',
857        }));
858        self.cur_char += 1;
859    }
860
861    fn next_line(&mut self, word_stream: &mut Vec<WordStream>) {
862        word_stream.push(WordStream::NewLine(WordRange {
863            range: Range::new_with_length(self.cur_line, self.cur_char, 1),
864            word: '\n',
865        }));
866        self.cur_line += 1;
867        self.cur_char = 0;
868    }
869}