Integers with different bases
This commit is contained in:
parent
f738d89ff2
commit
570c528b3e
@ -43,11 +43,18 @@ The number can be negative, zero, or positive. As Typst uses 64 bits to store
|
||||
integers, integers cannot be smaller than `{-9223372036854775808}` or larger than
|
||||
`{9223372036854775807}`.
|
||||
|
||||
The number can also be specified as hexadecimal, octal, or binary by starting it
|
||||
with a zero followed by either `x`, `o`, or `b`.
|
||||
|
||||
## Example
|
||||
```example
|
||||
#(1 + 2) \
|
||||
#(2 - 5) \
|
||||
#(3 + 4 < 8)
|
||||
|
||||
#0xff \
|
||||
#0o10 \
|
||||
#0b1001
|
||||
```
|
||||
|
||||
# Float
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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!(
|
||||
|
@ -109,6 +109,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
---
|
||||
// Test numbers with alternative bases.
|
||||
#test(0x10, 16)
|
||||
#test(0b1101, 13)
|
||||
#test(0xA + 0xa, 0x14)
|
||||
|
||||
---
|
||||
// Error: 2-7 invalid binary number
|
||||
#0b123
|
||||
|
||||
---
|
||||
// Error: 2-8 invalid hexadecimal number
|
||||
#0x123z
|
||||
|
||||
---
|
||||
// Test boolean operators.
|
||||
|
||||
|
@ -344,7 +344,7 @@
|
||||
},
|
||||
{
|
||||
"name": "constant.numeric.integer.typst",
|
||||
"match": "\\b\\d+\\b"
|
||||
"match": "\\b(0x[0-9a-zA-Z]+|(0b|0o)?\\d+)\\b"
|
||||
},
|
||||
{
|
||||
"name": "constant.numeric.float.typst",
|
||||
|
Loading…
x
Reference in New Issue
Block a user