sack is fully implemented
[pspp] / rust / src / sack.rs
index 4dfcf335ef43cd35c1b729ddf8084760c28b80d8..ab35f8661e8c4963b1e07380082fae995d4031b0 100644 (file)
@@ -101,14 +101,18 @@ fn parse_data_item(
     let initial_len = output.len();
     match lexer.take()? {
         Token::Integer(integer) => {
-            let Ok(integer): Result<i32, _> = integer.try_into() else {
+            if let Ok(integer) = TryInto::<i32>::try_into(integer) {
+                output.extend_from_slice(&lexer.endian.to_bytes(integer));
+            } else if let Ok(integer) = TryInto::<u32>::try_into(integer) {
+                output.extend_from_slice(&lexer.endian.to_bytes(integer));
+            } else {
                 Err(lexer.error(format!(
                     "{integer} is not in the valid range [{},{}]",
-                    u32::min_value(),
+                    i32::min_value(),
                     u32::max_value()
-                )))?
+                )))?;
             };
-            output.extend_from_slice(&lexer.endian.to_bytes(integer))},
+        }
         Token::Float(float) => output.extend_from_slice(&lexer.endian.to_bytes(float.0)),
         Token::PcSysmis => {
             output.extend_from_slice(&[0xf5, 0x1e, 0x26, 0x02, 0x8a, 0x8c, 0xed, 0xff])
@@ -143,18 +147,28 @@ fn parse_data_item(
             let Some((Token::String(ref string), _)) = lexer.token else {
                 Err(lexer.error(String::from("string expected after 'hex'")))?
             };
-            let mut i = string.chars();
+            let mut string = &string[..];
             loop {
+                string = string.trim_start();
+                if string.is_empty() {
+                    break;
+                };
+
+                let mut i = string.chars();
                 let Some(c0) = i.next() else { return Ok(true) };
                 let Some(c1) = i.next() else {
                     Err(lexer.error(String::from("hex string has odd number of characters")))?
                 };
+
                 let (Some(digit0), Some(digit1)) = (c0.to_digit(16), c1.to_digit(16)) else {
                     Err(lexer.error(String::from("invalid digit in hex string")))?
                 };
                 let byte = digit0 * 16 + digit1;
                 output.push(byte as u8);
+
+                string = i.as_str();
             }
+            lexer.get()?;
         }
         Token::Label(name) => {
             println!("define {name}");
@@ -177,11 +191,7 @@ fn parse_data_item(
             return Ok(true);
         }
         Token::At(name) => {
-            let mut value = symbol_table
-                .entry(name.clone())
-                .or_insert(None)
-                .unwrap_or(0);
-            println!("{name} has value {value}");
+            let mut value = *symbol_table.entry(name.clone()).or_insert(None);
             loop {
                 let plus = match lexer.token {
                     Some((Token::Plus, _)) => true,
@@ -191,27 +201,33 @@ fn parse_data_item(
                 lexer.get()?;
 
                 let operand = match lexer.token {
-                    Some((Token::At(ref name), _)) => if let Some(value) = symbol_table.get(name) {
-                        *value
-                    } else {
-                        symbol_table.insert(name.clone(), None);
-                        None
+                    Some((Token::At(ref name), _)) => {
+                        *symbol_table.entry(name.clone()).or_insert(None)
                     }
-                    .unwrap_or(0),
-                    Some((Token::Integer(integer), _)) => integer
-                        .try_into()
-                        .map_err(|msg| lexer.error(format!("bad offset literal ({msg})")))?,
+                    Some((Token::Integer(integer), _)) => Some(
+                        integer
+                            .try_into()
+                            .map_err(|msg| lexer.error(format!("bad offset literal ({msg})")))?,
+                    ),
                     _ => Err(lexer.error(String::from("expecting @label or integer literal")))?,
                 };
                 lexer.get()?;
 
-                value = if plus {
-                    value.checked_add(operand)
-                } else {
-                    value.checked_sub(operand)
-                }
-                .ok_or_else(|| lexer.error(String::from("overflow in offset arithmetic")))?;
+                value = match (value, operand) {
+                    (Some(a), Some(b)) => Some(
+                        if plus {
+                            a.checked_add(b)
+                        } else {
+                            a.checked_sub(b)
+                        }
+                        .ok_or_else(|| {
+                            lexer.error(String::from("overflow in offset arithmetic"))
+                        })?,
+                    ),
+                    _ => None,
+                };
             }
+            let value = value.unwrap_or(0);
             output.extend_from_slice(&lexer.endian.to_bytes(value));
         }
         _ => (),