summaryrefslogtreecommitdiff
path: root/src/syntax
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-04-04 15:22:48 +0200
committerLaurenz <laurmaedje@gmail.com>2023-04-04 15:46:09 +0200
commit570c528b3e4e41af2bb8ec0cf091e52dd50db13a (patch)
tree02ed402ad10741ae70fb9dab03ce735d35eac2a8 /src/syntax
parentf738d89ff2de20f3293a8e413160b7ab48cf593a (diff)
Integers with different bases
Diffstat (limited to 'src/syntax')
-rw-r--r--src/syntax/ast.rs12
-rw-r--r--src/syntax/lexer.rs47
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!(