]> rethought.computer Git - sorel-lang.git/commitdiff
support hex number literals
authorBryan English <bryan@rethought.computer>
Sat, 28 Mar 2026 03:24:28 +0000 (23:24 -0400)
committerBryan English <bryan@rethought.computer>
Fri, 3 Apr 2026 02:21:15 +0000 (22:21 -0400)
sorel-parser/src/lib.rs
sorel-tokenizer/src/lib.rs
stdlib/net.sorel [new file with mode: 0644]

index dd94d97b548472de809f4b54f944b6a7cc0ba0bf..120243ffb747f52a7a1654b10903df470062a598 100644 (file)
@@ -127,7 +127,7 @@ mod tests {
 
     #[test]
     fn try_some_parsing() {
-        let result = Module::parse(crate::tokenizer::tokenize("
+        let result = Module::parse(sorel_tokenizer::tokenize("
 : hello world 16 \"planet\" ;
 : soup chicken 4.5 hello ;
 
index 06dac68c972ef5d0ab3e1e445c5c16daf22294ae..86c2b42e9a43e707f3d5bf6460311334c5b826ac 100644 (file)
@@ -1,4 +1,5 @@
 use anyhow::{Result, anyhow};
+use std::str::FromStr;
 
 #[derive(Debug, Clone)]
 pub enum Token<'a> {
@@ -16,6 +17,41 @@ pub enum Token<'a> {
     NumF64(f64),
 }
 
+trait IntFromStrRadix {
+    fn from_radix(src: &str, radix: u32) -> Result<Self> where Self: Sized;
+}
+
+macro_rules! radix_impl {
+    ($type:ty) => {
+        impl IntFromStrRadix for $type {
+            fn from_radix(src: &str, radix: u32) -> Result<Self> {
+                <$type>::from_str_radix(src, radix)
+                    .map_err(|_| anyhow!("parse error for number: {}", src))
+            }
+        }
+    };
+    ($typ1:ty, $($typ2:ty),+) => {
+        radix_impl!($typ1);
+        radix_impl!($($typ2),+);
+    };
+}
+
+radix_impl!(u8, i8, u16, i16, u32, i32, u64, i64);
+
+fn parse_int<T: IntFromStrRadix + FromStr>(num: &str) -> Result<T> {
+    let mut radix = 10;
+    let mut num_cleaned = num;
+    if num.starts_with("0x") {
+        radix = 16;
+        num_cleaned = &num[2..];
+    }
+    T::from_radix(num_cleaned, radix)
+}
+
+fn parse_float<T: FromStr>(num: &str) -> Result<T> {
+    num.parse().map_err(|_| anyhow!("parse error for number: {}", num))
+}
+
 impl<'a> Token<'a>{
     fn parse_word_or_num(input: &'a str) -> Result<Token<'a>> {
         if input == "-" {
@@ -30,24 +66,24 @@ impl<'a> Token<'a>{
                 let num = splat.next().ok_or(anyhow!("no number found"))?;
                 let typ = splat.next().ok_or(anyhow!("no number type found"))?;
                 match typ {
-                    "u8" => Ok(Token::NumU8(num.parse()?)),
-                    "i8" => Ok(Token::NumI8(num.parse()?)),
-                    "u16" => Ok(Token::NumU16(num.parse()?)),
-                    "i16" => Ok(Token::NumI16(num.parse()?)),
-                    "u32" => Ok(Token::NumU32(num.parse()?)),
-                    "i32" => Ok(Token::NumI32(num.parse()?)),
-                    "u64" => Ok(Token::NumU64(num.parse()?)),
-                    "i64" => Ok(Token::NumI64(num.parse()?)),
-                    "f32" => Ok(Token::NumF32(num.parse()?)),
-                    "f64" => Ok(Token::NumF64(num.parse()?)),
+                    "u8" => Ok(Token::NumU8(parse_int(num)?)),
+                    "i8" => Ok(Token::NumI8(parse_int(num)?)),
+                    "u16" => Ok(Token::NumU16(parse_int(num)?)),
+                    "i16" => Ok(Token::NumI16(parse_int(num)?)),
+                    "u32" => Ok(Token::NumU32(parse_int(num)?)),
+                    "i32" => Ok(Token::NumI32(parse_int(num)?)),
+                    "u64" => Ok(Token::NumU64(parse_int(num)?)),
+                    "i64" => Ok(Token::NumI64(parse_int(num)?)),
+                    "f32" => Ok(Token::NumF32(parse_float(num)?)),
+                    "f64" => Ok(Token::NumF64(parse_float(num)?)),
                     _ => panic!("unknown number type")
                 }
             } else if input.contains('.') {
-                Ok(Token::NumF64(input.parse()?))
+                Ok(Token::NumF64(parse_float(input)?))
             } else if input.starts_with('-') {
-                Ok(Token::NumI64(input.parse()?))
+                Ok(Token::NumI64(parse_int(input)?))
             } else {
-                Ok(Token::NumU64(input.parse()?))
+                Ok(Token::NumU64(parse_int(input)?))
             }
         } else {
             Ok(Token::Word(input))
@@ -155,7 +191,7 @@ mod tests {
         let result = tokenize("
 
         \\ soup
-            2 3.4 - -88 bacon \"hello\" 43:f32 2345:u32 -57:i8 soup
+            2 0x10 3.4 - -88 bacon \"hello\" 43:f32 2345:u32 -57:i8 soup
 ");
         println!("result: {:?}", result);
     }
diff --git a/stdlib/net.sorel b/stdlib/net.sorel
new file mode 100644 (file)
index 0000000..403e4d3
--- /dev/null
@@ -0,0 +1,3 @@
+\ vim: filetype=forth
+
+