Skip to main content

ironcalc_base/expressions/lexer/
mod.rs

1//! A tokenizer for spreadsheet formulas.
2//!
3//! This is meant to feed a formula parser.
4//!
5//! You will need to instantiate it with a language and a locale.
6//!
7//! It supports two working modes:
8//!
9//! 1. A1 or display mode
10//!    This is for user formulas. References are like `D4`, `D$4` or `F5:T10`
11//! 2. R1C1, internal or runtime mode
12//!    A reference like R1C1 refers to $A$1 and R3C4 to $D$4
13//!    `R[2]C[5]` refers to a cell two rows below and five columns to the right
14//!    It uses the 'en' locale and language.
15//!    This is used internally at runtime.
16//!
17//! Formulas look different in different locales:
18//!
19//! =IF(A1, B1, NA()) versus =IF(A1; B1; NA())
20//!
21//! Also numbers are different:
22//!
23//! 1,123.45 versus 1.123,45
24//!
25//! The names of the errors and functions are different in different languages,
26//! but they stay the same in different locales.
27//!
28//! Note that in IronCalc if you are using a locale different from 'en' or a language different from 'en'
29//! you will still need the 'en' locale and language because formulas are stored in that language and locale
30//!
31//! # Examples:
32//! ```
33//! use ironcalc_base::expressions::lexer::{Lexer, LexerMode};
34//! use ironcalc_base::expressions::token::{TokenType, OpCompare};
35//! use ironcalc_base::locale::get_locale;
36//! use ironcalc_base::language::get_language;
37//!
38//! let locale = get_locale("en").unwrap();
39//! let language = get_language("en").unwrap();
40//! let mut lexer = Lexer::new("=A1*SUM(Sheet2!C3:D5)", LexerMode::A1, &locale, &language);
41//! assert_eq!(lexer.next_token(), TokenType::Compare(OpCompare::Equal));
42//! assert!(matches!(lexer.next_token(), TokenType::Reference { .. }));
43//! ```
44
45use std::mem;
46
47use serde::{Deserialize, Serialize};
48
49use crate::expressions::token::{OpCompare, OpProduct, OpSum};
50
51use crate::language::Language;
52use crate::locale::Locale;
53
54use super::token::{Error, TokenType};
55use super::types::*;
56use super::utils;
57
58pub mod util;
59
60#[cfg(test)]
61mod test;
62
63mod ranges;
64mod structured_references;
65
66#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
67pub struct LexerError {
68    pub position: usize,
69    pub message: String,
70}
71
72pub(super) type Result<T> = std::result::Result<T, LexerError>;
73
74/// Decides whether `name` should be accepted as an identifier in R1C1 mode, once
75/// the reference-parsing paths have already failed.
76///
77/// This uses the A1 identifier rules (`is_valid_a1_identifier`) rather than
78/// `is_valid_identifier`, so the single-character names "R"/"C" are accepted: they
79/// are valid LAMBDA parameters and LET variables. This matters on reload, because
80/// formulas are stored internally in R1C1 format, so a formula like
81/// `=BYROW(A1:C1, LAMBDA(c, MAX(c)))` is re-parsed in R1C1 mode and must not reject
82/// the `c` parameter.
83///
84/// The one exception is a bare "R"/"C" immediately followed by '[': that is a
85/// malformed R1C1 reference (e.g. `R[`), not an identifier, so it is rejected.
86/// Genuine R1C1 references (`R[n]C[n]`, `RnCn`) are consumed before this fallback.
87fn is_valid_r1c1_identifier(name: &str, next_char: Option<char>) -> bool {
88    if !utils::is_valid_a1_identifier(name) {
89        return false;
90    }
91    // `is_valid_identifier` differs from `is_valid_a1_identifier` only for "R"/"C".
92    // For those, only reject when they start a (malformed) reference, i.e. `R[`.
93    utils::is_valid_identifier(name) || next_char != Some('[')
94}
95
96#[derive(Clone, PartialEq, Eq)]
97pub enum LexerMode {
98    A1,
99    R1C1,
100}
101
102/// Tokenize an input
103#[derive(Clone)]
104pub struct Lexer<'a> {
105    position: usize,
106    next_token_position: Option<usize>,
107    len: usize,
108    chars: Vec<char>,
109    mode: LexerMode,
110    locale: &'a Locale,
111    language: &'a Language,
112}
113
114impl<'a> Lexer<'a> {
115    /// Creates a new `Lexer` that returns the tokens of a formula.
116    pub fn new(
117        formula: &str,
118        mode: LexerMode,
119        locale: &'a Locale,
120        language: &'a Language,
121    ) -> Lexer<'a> {
122        let chars: Vec<char> = formula.chars().collect();
123        let len = chars.len();
124        Lexer {
125            chars,
126            position: 0,
127            next_token_position: None,
128            len,
129            mode,
130            locale,
131            language,
132        }
133    }
134
135    /// Changes the lexer mode
136    pub fn set_lexer_mode(&mut self, mode: LexerMode) {
137        self.mode = mode;
138    }
139
140    /// Sets the locale
141    pub fn set_locale(&mut self, locale: &'a Locale) {
142        self.locale = locale;
143    }
144
145    /// Sets the language
146    pub fn set_language(&mut self, language: &'a Language) {
147        self.language = language;
148    }
149
150    // FIXME: I don't think we should have `is_a1_mode` and   `get_formula`.
151    // The caller already knows those two
152
153    /// Returns true if mode is A1
154    pub fn is_a1_mode(&self) -> bool {
155        self.mode == LexerMode::A1
156    }
157
158    /// Returns the formula
159    pub fn get_formula(&self) -> String {
160        self.chars.iter().collect()
161    }
162
163    // FIXME: This is used to get the "marked tokens"
164    // I think a better API would be to return the marked tokens
165    /// Returns the position of the lexer
166    pub fn get_position(&self) -> i32 {
167        self.position as i32
168    }
169
170    /// Resets the formula
171    pub fn set_formula(&mut self, content: &str) {
172        self.chars = content.chars().collect();
173        self.len = self.chars.len();
174        self.position = 0;
175        self.next_token_position = None;
176    }
177
178    /// Returns an error if the token is not the expected one.
179    pub fn expect(&mut self, tk: TokenType) -> Result<()> {
180        let nt = self.next_token();
181        if mem::discriminant(&nt) != mem::discriminant(&tk) {
182            return Err(self.set_error(&format!("Error, expected {tk:?}"), self.position));
183        }
184        Ok(())
185    }
186
187    /// Checks the next token without advancing position
188    /// See also [advance_token](Self::advance_token)
189    pub fn peek_token(&mut self) -> TokenType {
190        let position = self.position;
191        let tk = self.next_token();
192        self.next_token_position = Some(self.position);
193        self.position = position;
194        tk
195    }
196
197    /// Advances position. This is used in conjunction with [`peek_token`](Self::peek_token)
198    /// It is a noop if the has not been a previous peek_token
199    pub fn advance_token(&mut self) {
200        if let Some(position) = self.next_token_position {
201            self.position = position;
202            self.next_token_position = None;
203        }
204    }
205
206    /// Returns the next token
207    pub fn next_token(&mut self) -> TokenType {
208        self.next_token_position = None;
209        self.consume_whitespace();
210
211        match self.read_next_char() {
212            Some(char) => {
213                match char {
214                    '+' => TokenType::Addition(OpSum::Add),
215                    '-' => TokenType::Addition(OpSum::Minus),
216                    '*' => TokenType::Product(OpProduct::Times),
217                    '/' => TokenType::Product(OpProduct::Divide),
218                    '(' => TokenType::LeftParenthesis,
219                    ')' => TokenType::RightParenthesis,
220                    '=' => TokenType::Compare(OpCompare::Equal),
221                    '{' => TokenType::LeftBrace,
222                    '}' => TokenType::RightBrace,
223                    '[' => TokenType::LeftBracket,
224                    ']' => TokenType::RightBracket,
225                    ':' => TokenType::Colon,
226                    ';' => TokenType::Semicolon,
227                    '@' => TokenType::At,
228                    '\\' => TokenType::Backslash,
229                    ',' => {
230                        if self.locale.numbers.symbols.decimal == "," {
231                            match self.consume_number(',') {
232                                Ok(number) => TokenType::Number(number),
233                                Err(error) => TokenType::Illegal(error),
234                            }
235                        } else {
236                            TokenType::Comma
237                        }
238                    }
239                    '.' => {
240                        if self.locale.numbers.symbols.decimal == "." {
241                            match self.consume_number('.') {
242                                Ok(number) => TokenType::Number(number),
243                                Err(error) => TokenType::Illegal(error),
244                            }
245                        } else {
246                            // There is no TokenType::PERIOD
247                            TokenType::Illegal(self.set_error("Expecting a number", self.position))
248                        }
249                    }
250                    '!' => TokenType::Bang,
251                    '^' => TokenType::Power,
252                    '%' => TokenType::Percent,
253                    '&' => TokenType::And,
254                    '$' => self.consume_absolute_reference(),
255                    '<' => {
256                        let next_token = self.peek_char();
257                        if next_token == Some('=') {
258                            self.position += 1;
259                            TokenType::Compare(OpCompare::LessOrEqualThan)
260                        } else if next_token == Some('>') {
261                            self.position += 1;
262                            TokenType::Compare(OpCompare::NonEqual)
263                        } else {
264                            TokenType::Compare(OpCompare::LessThan)
265                        }
266                    }
267                    '>' => {
268                        if self.peek_char() == Some('=') {
269                            self.position += 1;
270                            TokenType::Compare(OpCompare::GreaterOrEqualThan)
271                        } else {
272                            TokenType::Compare(OpCompare::GreaterThan)
273                        }
274                    }
275                    '#' => self.consume_error(),
276                    '"' => match self.consume_string() {
277                        Ok(s) => TokenType::String(s),
278                        Err(error) => TokenType::Illegal(error),
279                    },
280                    '\'' => self.consume_quoted_sheet_reference(),
281                    '0'..='9' => {
282                        let position = self.position - 1;
283                        match self.consume_number(char) {
284                            Ok(number) => {
285                                if self.peek_token() == TokenType::Colon
286                                    && self.mode == LexerMode::A1
287                                {
288                                    // Its a row range  3:5
289                                    // FIXME: There are faster ways of parsing this
290                                    // Like checking that 'number' is integer and that the next token is integer
291                                    self.position = position;
292                                    match self.consume_range_a1() {
293                                        Ok(ParsedRange { left, right }) => {
294                                            if let Some(right) = right {
295                                                TokenType::Range {
296                                                    sheet: None,
297                                                    left,
298                                                    right,
299                                                }
300                                            } else {
301                                                TokenType::Illegal(
302                                                    self.set_error("Expecting row range", position),
303                                                )
304                                            }
305                                        }
306                                        Err(error) => {
307                                            // Examples:
308                                            //   * 'Sheet 1'!3.4:5
309                                            //   * 'Sheet 1'!3:A2
310                                            //   * 'Sheet 1'!3:
311                                            TokenType::Illegal(error)
312                                        }
313                                    }
314                                } else {
315                                    TokenType::Number(number)
316                                }
317                            }
318                            Err(error) => {
319                                // tried to read a number but failed
320                                self.position = self.len;
321                                TokenType::Illegal(error)
322                            }
323                        }
324                    }
325                    _ => {
326                        if char.is_alphabetic() || char == '_' {
327                            // At this point is one of the following:
328                            //   1. A range with sheet: Sheet3!A3:D7
329                            //   2. A boolean: TRUE or FALSE (dependent on the language)
330                            //   3. A reference like WS34 or R3C5
331                            //   4. A range without sheet ER4:ER7
332                            //   5. A column range E:E
333                            //   6. An identifier like a function name or a defined name
334                            //   7. A range operator A1:OFFSET(...)
335                            //   8. An Invalid token
336                            let position = self.position;
337                            self.position -= 1;
338                            let name = self.consume_identifier();
339                            let position_indent = self.position;
340
341                            let peek_char = self.peek_char();
342                            let next_char_is_colon = self.peek_char() == Some(':');
343
344                            if peek_char == Some('!') {
345                                // reference
346                                self.position += 1;
347                                return self.consume_range(Some(name));
348                            } else if peek_char == Some('$') {
349                                self.position = position - 1;
350                                return self.consume_range(None);
351                            }
352                            let name_upper = name.to_uppercase();
353                            if name_upper == self.language.booleans.r#true {
354                                return TokenType::Boolean(true);
355                            } else if name_upper == self.language.booleans.r#false {
356                                return TokenType::Boolean(false);
357                            }
358                            if self.peek_char() == Some('(') {
359                                return TokenType::Ident(name);
360                            }
361                            if self.mode == LexerMode::A1 {
362                                let parsed_reference = utils::parse_reference_a1(&name_upper);
363                                if parsed_reference.is_some()
364                                    || (utils::is_valid_column(name_upper.trim_start_matches('$'))
365                                        && next_char_is_colon)
366                                {
367                                    self.position = position - 1;
368                                    match self.consume_range_a1() {
369                                        Ok(ParsedRange { left, right }) => {
370                                            if let Some(right) = right {
371                                                return TokenType::Range {
372                                                    sheet: None,
373                                                    left,
374                                                    right,
375                                                };
376                                            } else {
377                                                return TokenType::Reference {
378                                                    sheet: None,
379                                                    column: left.column,
380                                                    row: left.row,
381                                                    absolute_row: left.absolute_row,
382                                                    absolute_column: left.absolute_column,
383                                                };
384                                            }
385                                        }
386                                        Err(error) => {
387                                            // This could be the range operator: ":"
388                                            if let Some(r) = parsed_reference {
389                                                if next_char_is_colon {
390                                                    self.position = position_indent;
391                                                    return TokenType::Reference {
392                                                        sheet: None,
393                                                        row: r.row,
394                                                        column: r.column,
395                                                        absolute_column: r.absolute_column,
396                                                        absolute_row: r.absolute_row,
397                                                    };
398                                                }
399                                            }
400                                            self.position = self.len;
401                                            return TokenType::Illegal(error);
402                                        }
403                                    }
404                                } else if utils::is_valid_a1_identifier(&name) {
405                                    if peek_char == Some('[') {
406                                        if let Ok(r) = self.consume_structured_reference(&name) {
407                                            return r;
408                                        }
409                                        return TokenType::Illegal(self.set_error(
410                                            "Invalid structured reference",
411                                            self.position,
412                                        ));
413                                    }
414                                    return TokenType::Ident(name);
415                                } else {
416                                    return TokenType::Illegal(
417                                        self.set_error("Invalid identifier (A1)", self.position),
418                                    );
419                                }
420                            } else {
421                                let pos = self.position;
422                                self.position = position - 1;
423                                match self.consume_range_r1c1() {
424                                    // it's a valid R1C1 range
425                                    // We need to check it's not something like R1C1P
426                                    Ok(ParsedRange { left, right }) => {
427                                        if pos > self.position {
428                                            self.position = pos;
429                                            if is_valid_r1c1_identifier(&name, self.peek_char()) {
430                                                return TokenType::Ident(name);
431                                            } else {
432                                                self.position = self.len;
433                                                return TokenType::Illegal(
434                                                    self.set_error(
435                                                        "Invalid identifier (R1C1)",
436                                                        pos,
437                                                    ),
438                                                );
439                                            }
440                                        }
441                                        if let Some(right) = right {
442                                            return TokenType::Range {
443                                                sheet: None,
444                                                left,
445                                                right,
446                                            };
447                                        } else {
448                                            return TokenType::Reference {
449                                                sheet: None,
450                                                column: left.column,
451                                                row: left.row,
452                                                absolute_row: left.absolute_row,
453                                                absolute_column: left.absolute_column,
454                                            };
455                                        }
456                                    }
457                                    Err(error) => {
458                                        self.position = position - 1;
459                                        if let Ok(r) = self.consume_reference_r1c1() {
460                                            if self.peek_char() == Some(':') {
461                                                return TokenType::Reference {
462                                                    sheet: None,
463                                                    row: r.row,
464                                                    column: r.column,
465                                                    absolute_column: r.absolute_column,
466                                                    absolute_row: r.absolute_row,
467                                                };
468                                            }
469                                        }
470                                        self.position = pos;
471
472                                        if is_valid_r1c1_identifier(&name, self.peek_char()) {
473                                            return TokenType::Ident(name);
474                                        } else {
475                                            return TokenType::Illegal(self.set_error(
476                                                &format!("Invalid identifier (R1C1): {name}"),
477                                                error.position,
478                                            ));
479                                        }
480                                    }
481                                }
482                            }
483                        }
484                        TokenType::Illegal(self.set_error("Unknown error", self.position))
485                    }
486                }
487            }
488            None => TokenType::EOF,
489        }
490    }
491
492    // Private methods
493
494    fn set_error(&mut self, message: &str, position: usize) -> LexerError {
495        self.position = self.len;
496        LexerError {
497            position,
498            message: message.to_string(),
499        }
500    }
501
502    fn peek_char(&mut self) -> Option<char> {
503        let position = self.position;
504        if position < self.len {
505            Some(self.chars[position])
506        } else {
507            None
508        }
509    }
510
511    fn expect_char(&mut self, ch_expected: char) -> Result<()> {
512        let position = self.position;
513        if position >= self.len {
514            return Err(self.set_error(
515                &format!("Error, expected {} found EOF", ch_expected),
516                self.position,
517            ));
518        } else {
519            let ch = self.chars[position];
520            if ch_expected != ch {
521                return Err(self.set_error(
522                    &format!("Error, expected {} found {}", ch_expected, ch),
523                    self.position,
524                ));
525            }
526            self.position += 1;
527        }
528        Ok(())
529    }
530
531    fn read_next_char(&mut self) -> Option<char> {
532        let position = self.position;
533        if position < self.len {
534            self.position = position + 1;
535            Some(self.chars[position])
536        } else {
537            None
538        }
539    }
540
541    // Consumes an integer from the input stream
542    fn consume_integer(&mut self, first: char) -> Result<i32> {
543        let mut position = self.position;
544        let len = self.len;
545        let mut chars = first.to_string();
546        while position < len {
547            let next_char = self.chars[position];
548            if next_char.is_ascii_digit() {
549                chars.push(next_char);
550            } else {
551                break;
552            }
553            position += 1;
554        }
555        self.position = position;
556        chars.parse::<i32>().map_err(|_| LexerError {
557            position,
558            message: format!("Failed to parse to int: {chars}"),
559        })
560    }
561
562    // Consumes a number in the current locale.
563    // It only takes into account the decimal separator
564    // Note that we do not parse the thousands separator
565    // Let's say ',' is the thousands separator. Then 1,234 would be an error.
566    // This is ok for most cases:
567    // =IF(A1=1,234, TRUE, FALSE) will not work
568    // If a user introduces a single number in the cell 1,234 we should be able to parse
569    // and format the cell appropriately
570    fn consume_number(&mut self, first: char) -> Result<f64> {
571        let mut position = self.position;
572        let len = self.len;
573        let mut chars = first.to_string();
574        // numbers before the decimal point
575        while position < len {
576            let x = self.chars[position];
577            if x.is_ascii_digit() {
578                chars.push(x);
579            } else {
580                break;
581            }
582            position += 1;
583        }
584        if position < len && self.chars[position].to_string() == self.locale.numbers.symbols.decimal
585        {
586            // numbers after the decimal point
587            chars.push('.');
588            position += 1;
589            while position < len {
590                let x = self.chars[position];
591                if x.is_ascii_digit() {
592                    chars.push(x);
593                } else {
594                    break;
595                }
596                position += 1;
597            }
598        }
599        if position + 1 < len && (self.chars[position] == 'e' || self.chars[position] == 'E') {
600            // exponential side
601            let x = self.chars[position + 1];
602            if x == '-' || x == '+' || x.is_ascii_digit() {
603                chars.push('e');
604                chars.push(x);
605                position += 2;
606                while position < len {
607                    let x = self.chars[position];
608                    if x.is_ascii_digit() {
609                        chars.push(x);
610                    } else {
611                        break;
612                    }
613                    position += 1;
614                }
615            }
616        }
617        self.position = position;
618        match chars.parse::<f64>() {
619            Err(_) => Err(self.set_error(&format!("Failed to parse to double: {chars}"), position)),
620            Ok(v) => Ok(v),
621        }
622    }
623
624    // Consumes an identifier from the input stream
625    fn consume_identifier(&mut self) -> String {
626        let mut position = self.position;
627        while position < self.len {
628            let next_char = self.chars[position];
629            if next_char.is_alphanumeric() || next_char == '_' || next_char == '.' {
630                position += 1;
631            } else {
632                break;
633            }
634        }
635        let chars = self.chars[self.position..position].iter().collect();
636        self.position = position;
637        chars
638    }
639
640    fn consume_string(&mut self) -> Result<String> {
641        let mut position = self.position;
642        let len = self.len;
643        let mut chars = "".to_string();
644        let mut terminated = false;
645        while position < len {
646            let x = self.chars[position];
647            position += 1;
648            if x != '"' {
649                chars.push(x);
650            } else if position < len && self.chars[position] == '"' {
651                chars.push(x);
652                chars.push(self.chars[position]);
653                position += 1;
654            } else {
655                terminated = true;
656                break;
657            }
658        }
659        self.position = position;
660
661        if !terminated {
662            return Err(self.set_error("Expected closing '\"' but found end of input", position));
663        }
664        Ok(chars)
665    }
666
667    // Consumes a quoted string from input
668    // 'This is a quoted string'
669    // ' Also is a ''quoted'' string'
670    // Returns an error if it does not find a closing quote
671    fn consume_single_quote_string(&mut self) -> Result<String> {
672        let mut position = self.position;
673        let len = self.len;
674        let mut success = false;
675        let mut needs_escape = false;
676        while position < len {
677            let next_char = self.chars[position];
678            position += 1;
679            if next_char == '\'' {
680                if position == len {
681                    success = true;
682                    break;
683                }
684                if self.chars[position] != '\'' {
685                    success = true;
686                    break;
687                } else {
688                    // In Excel we escape "'" with "''"
689                    needs_escape = true;
690                    position += 1;
691                }
692            }
693        }
694        if !success {
695            // We reached the end without the closing quote
696            return Err(self.set_error("Expected closing \"'\" but found end of input", position));
697        }
698        let chars: String = self.chars[self.position..position - 1].iter().collect();
699        self.position = position;
700        if needs_escape {
701            // In most cases we will not needs escaping so this would be an overkill
702            return Ok(chars.replace("''", "'"));
703        }
704
705        Ok(chars)
706    }
707
708    // Reads an error from the input stream
709    fn consume_error(&mut self) -> TokenType {
710        let errors = &self.language.errors;
711        let rest_of_formula: String = self.chars[self.position - 1..self.len].iter().collect();
712        if rest_of_formula.starts_with(&errors.r#ref) {
713            self.position += errors.r#ref.chars().count() - 1;
714            return TokenType::Error(Error::REF);
715        } else if rest_of_formula.starts_with(&errors.name) {
716            self.position += errors.name.chars().count() - 1;
717            return TokenType::Error(Error::NAME);
718        } else if rest_of_formula.starts_with(&errors.value) {
719            self.position += errors.value.chars().count() - 1;
720            return TokenType::Error(Error::VALUE);
721        } else if rest_of_formula.starts_with(&errors.div) {
722            self.position += errors.div.chars().count() - 1;
723            return TokenType::Error(Error::DIV);
724        } else if rest_of_formula.starts_with(&errors.na) {
725            self.position += errors.na.chars().count() - 1;
726            return TokenType::Error(Error::NA);
727        } else if rest_of_formula.starts_with(&errors.num) {
728            self.position += errors.num.chars().count() - 1;
729            return TokenType::Error(Error::NUM);
730        } else if rest_of_formula.starts_with(&errors.error) {
731            self.position += errors.error.chars().count() - 1;
732            return TokenType::Error(Error::ERROR);
733        } else if rest_of_formula.starts_with(&errors.nimpl) {
734            self.position += errors.nimpl.chars().count() - 1;
735            return TokenType::Error(Error::NIMPL);
736        } else if rest_of_formula.starts_with(&errors.spill) {
737            self.position += errors.spill.chars().count() - 1;
738            return TokenType::Error(Error::SPILL);
739        } else if rest_of_formula.starts_with(&errors.calc) {
740            self.position += errors.calc.chars().count() - 1;
741            return TokenType::Error(Error::CALC);
742        } else if rest_of_formula.starts_with(&errors.null) {
743            self.position += errors.null.chars().count() - 1;
744            return TokenType::Error(Error::NULL);
745        } else if rest_of_formula.starts_with(&errors.circ) {
746            self.position += errors.circ.chars().count() - 1;
747            return TokenType::Error(Error::CIRC);
748        }
749        // If it is not an error it _might_ be a spill operator.
750        TokenType::Spill
751    }
752
753    fn consume_whitespace(&mut self) {
754        let mut position = self.position;
755        let len = self.len;
756        while position < len {
757            let x = self.chars[position];
758            if !x.is_whitespace() {
759                break;
760            }
761            position += 1;
762        }
763        self.position = position;
764    }
765
766    fn consume_absolute_reference(&mut self) -> TokenType {
767        // This is an absolute reference.
768        // $A$4
769        if self.mode == LexerMode::R1C1 {
770            return TokenType::Illegal(
771                self.set_error("Cannot parse A1 reference in R1C1 mode", self.position),
772            );
773        }
774        self.position -= 1;
775        self.consume_range(None)
776    }
777
778    fn consume_quoted_sheet_reference(&mut self) -> TokenType {
779        // This is a reference:
780        // 'First Sheet'!A34
781        let sheet_name = match self.consume_single_quote_string() {
782            Ok(v) => v,
783            Err(error) => {
784                return TokenType::Illegal(error);
785            }
786        };
787        if self.next_token() != TokenType::Bang {
788            return TokenType::Illegal(self.set_error("Expected '!'", self.position));
789        }
790        self.consume_range(Some(sheet_name))
791    }
792
793    fn consume_range(&mut self, sheet: Option<String>) -> TokenType {
794        let m = if self.mode == LexerMode::A1 {
795            self.consume_range_a1()
796        } else {
797            self.consume_range_r1c1()
798        };
799        match m {
800            Ok(ParsedRange { left, right }) => {
801                if let Some(right) = right {
802                    TokenType::Range { sheet, left, right }
803                } else {
804                    TokenType::Reference {
805                        sheet,
806                        column: left.column,
807                        row: left.row,
808                        absolute_row: left.absolute_row,
809                        absolute_column: left.absolute_column,
810                    }
811                }
812            }
813            Err(error) => TokenType::Illegal(error),
814        }
815    }
816}