summary refs log tree commit diff
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2025-05-04 00:59:43 -0700
committerIrene Knapp <ireneista@irenes.space>2025-05-04 00:59:43 -0700
commit44c3362bcb565aa81f6e3fe0ab7a106dc89f4ba9 (patch)
tree5eb26c109d988c8cf345ac747b8e37cc560b5cb2
parent381f71833ebfb99a7dde16b6f3ceeb4c0fd5a8bd (diff)
okay now swap and roll exist. some mnemonics changed, too
Force-Push: yes
Change-Id: Ie496dfdfda969a3b6c9b3f9daadc22bd779b1f14
-rw-r--r--src/main.rs83
1 files changed, 70 insertions, 13 deletions
diff --git a/src/main.rs b/src/main.rs
index a94feaa..5c183b4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -28,14 +28,16 @@ const HELP_TEXT: &str =
      v       take the square root of the top item on the stack\n\
      \n\
      STACK OPERATIONS\n\
-     d       duplicate the top item on the stack\n\
+     s       swap the top two items on the stack\n\
+     d       drop the top item from the stack\n\
+     r       roll the stack, rotating downwards by 1, top item as size\n\
+     p       duplicate the top item on the stack\n\
      c       clear the stack\n\
-     ,       drop the top item from the stack\n\
      !       assert the stack height, with the top item as desired height\n\
      \n\
      REGISTER OPERATIONS\n\
      l       load from register (register name as next character)\n\
-     s       store to register (register name as next character)\n\
+     v       save to register (register name as next character)\n\
      \n\
      CONTROL FLOW\n\
      x       evaluate string\n\
@@ -383,30 +385,85 @@ fn make_command_character_readtable() -> ReadTable {
   ////////////////////////////////////////////////////////////
   // Stack operation actions
   //
+  result.set_action('s', move |_, state| {
+    if state.stack.len() < 2 {
+      return Err(err_msg("Data underflow!".into()));
+    }
+
+    let a = state.stack.pop().ok_or_else(|| err_msg(
+        "Data underflow!".into()))?;
+    let b = state.stack.pop().ok_or_else(|| err_msg(
+        "Data underflow!".into()))?;
+
+    state.stack.push(a);
+    state.stack.push(b);
+
+    Ok(())
+  });
+
   result.set_action('d', move |_, state| {
     if state.stack.is_empty() {
       return Err(err_msg("Data underflow!".into()));
     }
 
-    let val = state.stack.pop().unwrap();
-    state.stack.push(val.clone());
-    state.stack.push(val.clone());
+    state.stack.pop();
 
     Ok(())
   });
 
-  result.set_action('c', move |_, state| {
-    state.stack.clear();
+  result.set_action('r', move |_, state| {
+    if state.stack.is_empty() {
+      return Err(err_msg("Data underflow!".into()));
+    }
 
-    Ok(())
+    if let Value::Num(size) = state.stack.pop().ok_or_else(|| err_msg(
+        "Data underflow!".into()))?
+    {
+      if !size.is_integer() {
+        return Err(err_msg("Size to roll must be an integer.".into()));
+      }
+      if !size.is_sign_positive() {
+        return Err(err_msg("Size to roll must be zero or more.".into()));
+      }
+
+      let mut top_item = state.stack.pop().ok_or_else(|| err_msg(
+        "Data underflow!".into()))?;
+
+      let mut other_items = Vec::new();
+      let mut i = Decimal::ONE;
+      while i < size {
+        i += Decimal::ONE;
+
+        other_items.push(state.stack.pop().ok_or_else(|| err_msg(
+            "Data underflow!".into()))?);
+      }
+
+      state.stack.push(top_item);
+
+      while !other_items.is_empty() {
+        state.stack.push(other_items.pop().unwrap());
+      }
+
+      Ok(())
+    } else {
+      Err(err_msg("Size must be a number.".into()))
+    }
   });
 
-  result.set_action(',', move |_, state| {
+  result.set_action('p', move |_, state| {
     if state.stack.is_empty() {
       return Err(err_msg("Data underflow!".into()));
     }
 
-    state.stack.pop();
+    let val = state.stack.pop().unwrap();
+    state.stack.push(val.clone());
+    state.stack.push(val.clone());
+
+    Ok(())
+  });
+
+  result.set_action('c', move |_, state| {
+    state.stack.clear();
 
     Ok(())
   });
@@ -439,7 +496,7 @@ fn make_command_character_readtable() -> ReadTable {
   };
 
   result.set_action('l', register_command_action.clone());
-  result.set_action('s', register_command_action.clone());
+  result.set_action('v', register_command_action.clone());
 
   ////////////////////////////////////////////////////////////
   // Control flow actions
@@ -608,7 +665,7 @@ fn dispatch_register_command(name: &str, state: &mut RPState)
 {
   match state.reg_command.as_str() {
     "l" => load_from_register(name, state),
-    "s" => store_to_register(name, state),
+    "v" => store_to_register(name, state),
 
     _ => {
       Err(err_msg(format!(