diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/syntax/ast.rs | 12 | ||||
| -rw-r--r-- | src/syntax/lexer.rs | 47 |
2 files changed, 48 insertions, 11 deletions
diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs index 4abf51d9..d718ccf0 100644 --- a/src/syntax/ast.rs +++ b/src/syntax/ast.rs @@ -912,7 +912,17 @@ node! { impl Int { /// Get the integer value. pub fn get(&self) -> i64 { - self.0.text().parse().unwrap_or_default() + let text = self.0.text(); + if let Some(rest) = text.strip_prefix("0x") { + i64::from_str_radix(rest, 16) + } else if let Some(rest) = text.strip_prefix("0o") { + i64::from_str_radix(rest, 8) + } else if let Some(rest) = text.strip_prefix("0b") { + i64::from_str_radix(rest, 2) + } else { + text.parse() + } + .unwrap_or_default() } } diff --git a/src/syntax/lexer.rs b/src/syntax/lexer.rs index 748cb076..b67a009c 100644 --- a/src/syntax/lexer.rs +++ b/src/syntax/lexer.rs @@ -524,9 +524,28 @@ impl Lexer<'_> { SyntaxKind::Ident } - fn number(&mut self, start: usize, c: char) -> SyntaxKind { + fn number(&mut self, mut start: usize, c: char) -> SyntaxKind { + // Handle alternative integer bases. + let mut base = 10; + if c == '0' { + if self.s.eat_if('b') { + base = 2; + } else if self.s.eat_if('o') { + base = 8; + } else if self.s.eat_if('x') { + base = 16; + } + if base != 10 { + start = self.s.cursor(); + } + } + // Read the first part (integer or fractional depending on `first`). - self.s.eat_while(char::is_ascii_digit); + self.s.eat_while(if base == 16 { + char::is_ascii_alphanumeric + } else { + char::is_ascii_digit + }); // Read the fractional part if not already done. // Make sure not to confuse a range for the decimal separator. @@ -534,12 +553,13 @@ impl Lexer<'_> { && !self.s.at("..") && !self.s.scout(1).map_or(false, is_id_start) && self.s.eat_if('.') + && base == 10 { self.s.eat_while(char::is_ascii_digit); } // Read the exponent. - if !self.s.at("em") && self.s.eat_if(['e', 'E']) { + if !self.s.at("em") && self.s.eat_if(['e', 'E']) && base == 10 { self.s.eat_if(['+', '-']); self.s.eat_while(char::is_ascii_digit); } @@ -553,14 +573,21 @@ impl Lexer<'_> { let number = self.s.get(start..suffix_start); let suffix = self.s.from(suffix_start); + let kind = if i64::from_str_radix(number, base).is_ok() { + SyntaxKind::Int + } else if base == 10 && number.parse::<f64>().is_ok() { + SyntaxKind::Float + } else { + return self.error(match base { + 2 => "invalid binary number", + 8 => "invalid octal number", + 16 => "invalid hexadecimal number", + _ => "invalid number", + }); + }; + if suffix.is_empty() { - return if number.parse::<i64>().is_ok() { - SyntaxKind::Int - } else if number.parse::<f64>().is_ok() { - SyntaxKind::Float - } else { - self.error("invalid number") - }; + return kind; } if !matches!( |
