From a09bccb255d11edaba663da00069e17adb668736 Mon Sep 17 00:00:00 2001 From: sofia Date: Thu, 24 Jul 2025 21:24:17 +0300 Subject: [PATCH] Add hexadecimal numerics --- examples/fibonacci.reid | 2 +- reid/src/ast/parse.rs | 13 ++++++++++- reid/src/lexer.rs | 51 ++++++++++++++++++++++++++++++++++++----- reid/src/lib.rs | 2 +- 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/examples/fibonacci.reid b/examples/fibonacci.reid index 546e636..1b6b1db 100644 --- a/examples/fibonacci.reid +++ b/examples/fibonacci.reid @@ -1,6 +1,6 @@ // Main fn main() -> bool { - return 5 == fibonacci(5); + return 144 == fibonacci(0xc); } // Fibonacci diff --git a/reid/src/ast/parse.rs b/reid/src/ast/parse.rs index 4bf5e82..f6c84d8 100644 --- a/reid/src/ast/parse.rs +++ b/reid/src/ast/parse.rs @@ -153,6 +153,16 @@ impl Parse for PrimaryExpression { Expression(Kind::VariableName(v.clone()), stream.get_range().unwrap()) } } + Token::HexadecimalValue(v) => { + stream.next(); // Consume hexadecimal + Expression( + Kind::Literal(Literal::Integer( + u128::from_str_radix(&v, 16) + .expect("Hexadecimal is not parseable as u128!"), + )), + stream.get_range().unwrap(), + ) + } Token::DecimalValue(v) => { stream.next(); // Consume decimal if let (Some(Token::Dot), Some(Token::DecimalValue(fractional))) = @@ -172,7 +182,8 @@ impl Parse for PrimaryExpression { } else { Expression( Kind::Literal(Literal::Integer( - v.parse().expect("Integer is not parseable as u128!"), + u128::from_str_radix(&v, 10) + .expect("Integer is not parseable as u128!"), )), stream.get_range().unwrap(), ) diff --git a/reid/src/lexer.rs b/reid/src/lexer.rs index 4a06b0a..3a1d477 100644 --- a/reid/src/lexer.rs +++ b/reid/src/lexer.rs @@ -1,13 +1,24 @@ -use std::{fmt::Debug, str::Chars}; +use std::{ + fmt::Debug, + ops::{Add, AddAssign}, + str::Chars, +}; +static BINARY_NUMERICS: &[char] = &['0', '1']; +static OCTAL_NUMERICS: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7']; static DECIMAL_NUMERICS: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; +static HEXADECIMAL_NUMERICS: &[char] = &[ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', +]; #[derive(Eq, PartialEq, Clone, PartialOrd, Ord)] pub enum Token { /// Values Identifier(String), - /// Number with at most one decimal point + /// Number in the decimal base DecimalValue(String), + /// Integer number in the hexadecimal base + HexadecimalValue(String), /// Some character literal that was surrounded by 'single-quotes'. CharLit(String), /// Some string literal that was surrounded by "double-quotes". @@ -130,6 +141,7 @@ impl ToString for Token { match &self { Token::Identifier(ident) => ident.clone(), Token::DecimalValue(val) => val.to_string(), + Token::HexadecimalValue(val) => val.to_string(), Token::CharLit(lit) => format!("\'{}\'", lit), Token::StringLit(lit) => format!("\"{}\"", lit), Token::LetKeyword => String::from("let"), @@ -348,15 +360,26 @@ pub fn tokenize>(to_tokenize: T) -> Result, Error } // Decimals c if DECIMAL_NUMERICS.contains(c) => { - let mut value = character.to_string(); + let mut value = NumberType::Decimal(character.to_string()); + let mut numerics = DECIMAL_NUMERICS; + if let Some(second) = cursor.second() { + if cursor.first() == Some('x') && HEXADECIMAL_NUMERICS.contains(&second) { + cursor.next(); + value = NumberType::Hexadecimal(String::new()); + numerics = HEXADECIMAL_NUMERICS; + } + } while let Some(c) = cursor.first() { - if !DECIMAL_NUMERICS.contains(&c) { + if !numerics.contains(&c) { break; } - value += &c.to_string(); + value += c; cursor.next(); } - Token::DecimalValue(value) + match value { + NumberType::Decimal(value) => Token::DecimalValue(value), + NumberType::Hexadecimal(hex) => Token::HexadecimalValue(hex), + } } '-' if cursor.first() == Some('>') => { cursor.next(); // Eat `>` @@ -411,6 +434,22 @@ fn escape_char(c: &char) -> char { } } +enum NumberType { + Decimal(String), + Hexadecimal(String), +} + +impl AddAssign for NumberType { + fn add_assign(&mut self, rhs: char) { + *self = match self { + NumberType::Decimal(val) => NumberType::Decimal(val.to_owned() + &rhs.to_string()), + NumberType::Hexadecimal(val) => { + NumberType::Hexadecimal(val.to_owned() + &rhs.to_string()) + } + }; + } +} + #[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum Error { #[error("Invalid token '{}' ", .0)] diff --git a/reid/src/lib.rs b/reid/src/lib.rs index 2b317dd..3fc9547 100644 --- a/reid/src/lib.rs +++ b/reid/src/lib.rs @@ -78,7 +78,7 @@ pub fn parse_module<'map, T: Into>( map.set_tokens(id, tokens.clone()); #[cfg(debug_assertions)] - dbg!(&tokens); + println!("{:#?}", &tokens); Ok((id, tokens)) }