Support Hex, Binary, and Octal number literals #20

Merged
mlokis merged 3 commits from :trunk into trunk 2024-09-01 14:19:14 -05:00
5 changed files with 70 additions and 8 deletions

View file

@ -543,3 +543,18 @@ sqrt := fn(x: int): int {
return g return g
} }
``` ```
#### hex_octal_binary_literals
```hb
main := fn(): int {
hex := 0xFF
decimal := 255
octal := 0o377
binary := 0b11111111
if hex == decimal & octal == decimal & binary == decimal {
return 0
}
return 1
}
```

View file

@ -3340,5 +3340,6 @@ mod tests {
struct_return_from_module_function => README; struct_return_from_module_function => README;
comptime_pointers => README; comptime_pointers => README;
sort_something_viredly => README; sort_something_viredly => README;
hex_octal_binary_literals => README;
} }
} }

View file

@ -292,6 +292,24 @@ impl<'a> Lexer<'a> {
let kind = match c { let kind = match c {
..=b' ' => continue, ..=b' ' => continue,
b'0' if self.advance_if(b'x') => {
while let Some(b'0'..=b'9' | b'A'..=b'F' | b'a'..=b'f') = self.peek() {
mlokis marked this conversation as resolved Outdated

this should account for hex digits

this should account for hex digits
self.advance();
}
T::Number
}
b'0' if self.advance_if(b'b') => {
while let Some(b'0' | b'1') = self.peek() {
mlokis marked this conversation as resolved Outdated

should only accept [01]

should only accept `[01]`
self.advance();
}
T::Number
}
b'0' if self.advance_if(b'o') => {
while let Some(b'0'..=b'7') = self.peek() {
mlokis marked this conversation as resolved Outdated

same here but octal

same here but octal
self.advance();
}
T::Number
}
b'0'..=b'9' => { b'0'..=b'9' => {
while let Some(b'0'..=b'9') = self.peek() { while let Some(b'0'..=b'9') = self.peek() {
self.advance(); self.advance();

View file

@ -389,13 +389,23 @@ impl<'a, 'b> Parser<'a, 'b> {
pos: token.start, pos: token.start,
stmts: self.collect_list(T::Semi, T::RBrace, Self::expr), stmts: self.collect_list(T::Semi, T::RBrace, Self::expr),
}, },
T::Number => E::Number { T::Number => {
pos: token.start, let slice = self.lexer.slice(token.range());
value: match self.lexer.slice(token.range()).parse() { let (slice, radix) = match &slice.get(0..2) {
Ok(value) => value, Some("0x") => (slice.trim_start_matches("0x"), Radix::Hex),
Err(e) => self.report(format_args!("invalid number: {e}")), Some("0b") => (slice.trim_start_matches("0b"), Radix::Binary),
}, Some("0o") => (slice.trim_start_matches("0o"), Radix::Octal),
mlokis marked this conversation as resolved Outdated

the radixes are wrong

the radixes are wrong
}, _ => (slice, Radix::Decimal),
};
E::Number {
pos: token.start,
value: match u64::from_str_radix(slice, radix as u32) {
Ok(value) => value,
Err(e) => self.report(format_args!("invalid number: {e}")),
},
radix,
}
}
T::LParen => { T::LParen => {
let expr = self.expr(); let expr = self.expr();
self.expect_advance(T::RParen); self.expect_advance(T::RParen);
@ -620,6 +630,15 @@ macro_rules! generate_expr {
(@last ($($last:tt)*),) => { $($last)* }; (@last ($($last:tt)*),) => { $($last)* };
} }
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Radix {
Hex = 16,
Octal = 8,
Binary = 2,
Decimal = 10,
}
// it would be real nice if we could use relative pointers and still pattern match easily // it would be real nice if we could use relative pointers and still pattern match easily
generate_expr! { generate_expr! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -671,6 +690,7 @@ generate_expr! {
Number { Number {
pos: Pos, pos: Pos,
value: u64, value: u64,
radix: Radix,
}, },
BinOp { BinOp {
left: &'a Self, left: &'a Self,
@ -992,7 +1012,12 @@ impl<'a> std::fmt::Display for Expr<'a> {
write!(f, "}}")?; write!(f, "}}")?;
res res
} }
Self::Number { value, .. } => write!(f, "{value}"), Self::Number { value, radix, .. } => match radix {
Radix::Decimal => write!(f, "{value}"),
Radix::Hex => write!(f, "{value:#X}"),
Radix::Octal => write!(f, "{value:#o}"),
Radix::Binary => write!(f, "{value:#b}"),
},
Self::Bool { value, .. } => write!(f, "{value}"), Self::Bool { value, .. } => write!(f, "{value}"),
Self::BinOp { Self::BinOp {
left, left,

View file

@ -0,0 +1,3 @@
code size: 210
ret: 0
status: Ok(())