From 781c40ede04ae9da9ca3029d712173ba816a74f0 Mon Sep 17 00:00:00 2001 From: koniifer Date: Sun, 1 Sep 2024 18:42:04 +0100 Subject: [PATCH 1/3] support hex, octal, binary literals --- hblang/src/lexer.rs | 12 ++++++++++++ hblang/src/parser.rs | 15 ++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/hblang/src/lexer.rs b/hblang/src/lexer.rs index b103860..8f36d69 100644 --- a/hblang/src/lexer.rs +++ b/hblang/src/lexer.rs @@ -292,6 +292,18 @@ impl<'a> Lexer<'a> { let kind = match c { ..=b' ' => continue, + b'0' if self.advance_if(b'x') => { + while let Some(b'0'..=b'9') = self.peek() { + self.advance(); + } + T::Number + } + b'0' if self.advance_if(b'b') => { + while let Some(b'0'..=b'9') = self.peek() { + self.advance(); + } + T::Number + } b'0'..=b'9' => { while let Some(b'0'..=b'9') = self.peek() { self.advance(); diff --git a/hblang/src/parser.rs b/hblang/src/parser.rs index 59fe5f8..6908f3b 100644 --- a/hblang/src/parser.rs +++ b/hblang/src/parser.rs @@ -391,9 +391,18 @@ impl<'a, 'b> Parser<'a, 'b> { }, T::Number => E::Number { pos: token.start, - value: match self.lexer.slice(token.range()).parse() { - Ok(value) => value, - Err(e) => self.report(format_args!("invalid number: {e}")), + value: { + let slice = self.lexer.slice(token.range()); + let (slice, radix) = match &slice.get(0..2) { + Some("0x") => (slice.trim_start_matches("0x"), 16), + Some("0b") => (slice.trim_start_matches("0b"), 16), + Some("0o") => (slice.trim_start_matches("0o"), 16), + _ => (slice, 10), + }; + match u64::from_str_radix(slice, radix) { + Ok(value) => value, + Err(e) => self.report(format_args!("invalid number: {e}")), + } }, }, T::LParen => { From 27462d9a335f91e5b9544ee03b01636737b3c9e8 Mon Sep 17 00:00:00 2001 From: koniifer Date: Sun, 1 Sep 2024 18:45:38 +0100 Subject: [PATCH 2/3] forgot octals exist --- hblang/src/lexer.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hblang/src/lexer.rs b/hblang/src/lexer.rs index 8f36d69..984451b 100644 --- a/hblang/src/lexer.rs +++ b/hblang/src/lexer.rs @@ -304,6 +304,12 @@ impl<'a> Lexer<'a> { } T::Number } + b'0' if self.advance_if(b'o') => { + while let Some(b'0'..=b'9') = self.peek() { + self.advance(); + } + T::Number + } b'0'..=b'9' => { while let Some(b'0'..=b'9') = self.peek() { self.advance(); From 581c4d531c83067d5d0aadf3a7c0129f2977f208 Mon Sep 17 00:00:00 2001 From: koniifer Date: Sun, 1 Sep 2024 20:07:19 +0100 Subject: [PATCH 3/3] fix obvious bugs, add unit test, hopefully preserve radix when formatting --- hblang/README.md | 15 ++++++ hblang/src/codegen.rs | 1 + hblang/src/lexer.rs | 6 +-- hblang/src/parser.rs | 46 +++++++++++++------ ...odegen_tests_hex_octal_binary_literals.txt | 3 ++ 5 files changed, 53 insertions(+), 18 deletions(-) create mode 100644 hblang/tests/codegen_tests_hex_octal_binary_literals.txt diff --git a/hblang/README.md b/hblang/README.md index ade4f69..f2ed519 100644 --- a/hblang/README.md +++ b/hblang/README.md @@ -543,3 +543,18 @@ sqrt := fn(x: int): int { 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 +} +``` \ No newline at end of file diff --git a/hblang/src/codegen.rs b/hblang/src/codegen.rs index ed556b9..acf9b5c 100644 --- a/hblang/src/codegen.rs +++ b/hblang/src/codegen.rs @@ -3340,5 +3340,6 @@ mod tests { struct_return_from_module_function => README; comptime_pointers => README; sort_something_viredly => README; + hex_octal_binary_literals => README; } } diff --git a/hblang/src/lexer.rs b/hblang/src/lexer.rs index 984451b..9b4a1ae 100644 --- a/hblang/src/lexer.rs +++ b/hblang/src/lexer.rs @@ -293,19 +293,19 @@ impl<'a> Lexer<'a> { let kind = match c { ..=b' ' => continue, b'0' if self.advance_if(b'x') => { - while let Some(b'0'..=b'9') = self.peek() { + while let Some(b'0'..=b'9' | b'A'..=b'F' | b'a'..=b'f') = self.peek() { self.advance(); } T::Number } b'0' if self.advance_if(b'b') => { - while let Some(b'0'..=b'9') = self.peek() { + while let Some(b'0' | b'1') = self.peek() { self.advance(); } T::Number } b'0' if self.advance_if(b'o') => { - while let Some(b'0'..=b'9') = self.peek() { + while let Some(b'0'..=b'7') = self.peek() { self.advance(); } T::Number diff --git a/hblang/src/parser.rs b/hblang/src/parser.rs index 6908f3b..541e66f 100644 --- a/hblang/src/parser.rs +++ b/hblang/src/parser.rs @@ -389,22 +389,23 @@ impl<'a, 'b> Parser<'a, 'b> { pos: token.start, stmts: self.collect_list(T::Semi, T::RBrace, Self::expr), }, - T::Number => E::Number { - pos: token.start, - value: { - let slice = self.lexer.slice(token.range()); - let (slice, radix) = match &slice.get(0..2) { - Some("0x") => (slice.trim_start_matches("0x"), 16), - Some("0b") => (slice.trim_start_matches("0b"), 16), - Some("0o") => (slice.trim_start_matches("0o"), 16), - _ => (slice, 10), - }; - match u64::from_str_radix(slice, radix) { + T::Number => { + let slice = self.lexer.slice(token.range()); + let (slice, radix) = match &slice.get(0..2) { + Some("0x") => (slice.trim_start_matches("0x"), Radix::Hex), + Some("0b") => (slice.trim_start_matches("0b"), Radix::Binary), + Some("0o") => (slice.trim_start_matches("0o"), Radix::Octal), + _ => (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 => { let expr = self.expr(); self.expect_advance(T::RParen); @@ -629,6 +630,15 @@ macro_rules! generate_expr { (@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 generate_expr! { #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -680,6 +690,7 @@ generate_expr! { Number { pos: Pos, value: u64, + radix: Radix, }, BinOp { left: &'a Self, @@ -1001,7 +1012,12 @@ impl<'a> std::fmt::Display for Expr<'a> { write!(f, "}}")?; 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::BinOp { left, diff --git a/hblang/tests/codegen_tests_hex_octal_binary_literals.txt b/hblang/tests/codegen_tests_hex_octal_binary_literals.txt new file mode 100644 index 0000000..e3aee3a --- /dev/null +++ b/hblang/tests/codegen_tests_hex_octal_binary_literals.txt @@ -0,0 +1,3 @@ +code size: 210 +ret: 0 +status: Ok(())