summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/main.rs758
1 files changed, 384 insertions, 374 deletions
diff --git a/src/main.rs b/src/main.rs
index 420cdb3..987bce0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -47,124 +47,126 @@ const HELP_TEXT: &str =
      \n\
      Good luck!\n\n";
 
+
 #[derive(Debug,PartialEq,Eq,Clone)]
 enum Value {
-        Str(String),
-        Num(Decimal),
+  Str(String),
+  Num(Decimal),
 }
 
 impl fmt::Display for Value {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Value::Str(s) => write!(f, "[{}]", s),
-            Value::Num(d) => write!(f, "{}", d),
-        }
+  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    match self {
+      Value::Str(s) => write!(f, "[{}]", s),
+      Value::Num(d) => write!(f, "{}", d),
     }
+  }
 }
 
-
 fn print_value(v: &Value) {
-    match v {
-        Value::Str(s) => print!("{}", s),
-        Value::Num(d) => print!("{}", d),
-    }
+  match v {
+    Value::Str(s) => print!("{}", s),
+    Value::Num(d) => print!("{}", d),
+  }
 }
 
 
 #[derive(Debug)]
 enum Mode {
-    Integer,
-    Decimal,
-    Str,
-    CommandChar,
-    CommandNamed,
-    RegisterChar,
-    RegisterStr,
+  Integer,
+  Decimal,
+  Str,
+  CommandChar,
+  CommandNamed,
+  RegisterChar,
+  RegisterStr,
 }
 
 
 #[derive(Debug)]
 enum Exit {
-    WithMessage(String),
-    Quit,
+  WithMessage(String),
+  Quit,
 }
 
-
 fn err_msg(msg: String) -> Exit {
-    Exit::WithMessage(msg)
+  Exit::WithMessage(msg)
 }
 
 
 fn baseline_registers() -> HashMap<String, Value> {
-    let kvs = [
-        ("F->C", "1! 32- 5 9/*"),
-        ("C->F", "1! 9 5/* 32+"),
-        ("C->K", "1! 273+"),
-        ("K->C", "1! 273-"),
-        ("Km->mi", "1! 1.609344/"),
-        ("mi->Km", "1! 1.609344*"),
-    ].map(|kv: (&str, &str)| (String::from(kv.0), Value::Str(kv.1.into())));
-    HashMap::from(kvs)
+  let kvs = [
+    ("F->C", "1! 32- 5 9/*"),
+    ("C->F", "1! 9 5/* 32+"),
+    ("C->K", "1! 273+"),
+    ("K->C", "1! 273-"),
+    ("Km->mi", "1! 1.609344/"),
+    ("mi->Km", "1! 1.609344*"),
+  ].map(|kv: (&str, &str)| (String::from(kv.0), Value::Str(kv.1.into())));
+
+  HashMap::from(kvs)
 }
 
 
 fn main() {
-    let mut state = RPState {
-        registers: baseline_registers(),
-        stack: Vec::new(),
-        mode: Mode::CommandChar,
-        wip_str: String::from(""),
-        // TODO: I don't think we need a return stack
-        // But this the closest thing we have right now
-        reg_command: String::from(""),
-        eat_count: 0,
-        num: dec!(0.0),
-        is_num_negative: false,
-        decimal_offset: dec!(1),
-    };
-    let stdin = io::stdin();
-    for line in stdin.lock().lines() {
-        match eval(&line.unwrap(), &mut state) {
-            Ok(()) => {
-                let mut first = true;
-                print!("{}", "stack: {");
-                for elem in state.stack.iter() {
-                    if !first { print!("{}", ", "); }
-                    print!("{}", elem);
-                    first = false;
-                }
-                println!("{}", "}");
-            },
-            Err(Exit::WithMessage(msg)) => println!("Error: {}", msg),
-            Err(Exit::Quit) => break,
+  let mut state = RPState {
+    registers: baseline_registers(),
+    stack: Vec::new(),
+    mode: Mode::CommandChar,
+    wip_str: String::from(""),
+    // TODO: I don't think we need a return stack
+    // But this the closest thing we have right now
+    reg_command: String::from(""),
+    eat_count: 0,
+    num: dec!(0.0),
+    is_num_negative: false,
+    decimal_offset: dec!(1),
+  };
+  let stdin = io::stdin();
+  for line in stdin.lock().lines() {
+    match eval(&line.unwrap(), &mut state) {
+      Ok(()) => {
+        let mut first = true;
+        print!("{}", "stack: {");
+        for elem in state.stack.iter() {
+          if !first { print!("{}", ", "); }
+          print!("{}", elem);
+          first = false;
         }
+        println!("{}", "}");
+      },
+      Err(Exit::WithMessage(msg)) => println!("Error: {}", msg),
+      Err(Exit::Quit) => break,
     }
+  }
 }
 
+
 const RADIX: u32 = 10;
 const INTEGER_RADIX: Decimal = dec!(10);
 
 fn to_decimal(input: u32) -> Decimal {
-    <u32 as Into<Decimal>>::into(input)
+  <u32 as Into<Decimal>>::into(input)
 }
 
 fn usize_to_decimal(input: usize) -> Decimal {
-    <usize as Into<Decimal>>::into(input)
+  <usize as Into<Decimal>>::into(input)
 }
 
 
 struct RPState {
-    registers: HashMap<String, Value>,
-    stack: Vec<Value>,
-    mode: Mode,
-    reg_command: String,
-    wip_str: String,
-    eat_count: u32,
-    is_num_negative: bool,
-    num: Decimal,
-    decimal_offset: Decimal
+  registers: HashMap<String, Value>,
+  stack: Vec<Value>,
+  mode: Mode,
+  reg_command: String,
+  wip_str: String,
+  eat_count: u32,
+  is_num_negative: bool,
+  num: Decimal,
+  decimal_offset: Decimal
 }
 
+
 // TODO: Generalized shuffles
 // [[a-aa\](shuf)]s[dup]
 // [[ab-ba\](shuf)]s[swap]
@@ -175,344 +177,352 @@ struct RPState {
 // }
 
 fn command_str(c: char, state: &mut RPState) -> Result<(), Exit> {
-    if c != ')' {
-        state.wip_str.push(c);
-    } else if c == ')' {
-        match state.wip_str.as_str() {
-            // TODO:
-            // (times)
-            // (while)
-            // (?) -- (cond ifTrue ifFalse)
-            // [(?)x]s[if-else]
-            // [[\](?)x]s[if]
-            // (r?) -- show contents of registers
-            // Scope out
-            word => {
-                if state.registers.contains_key(word) {
-                    match &state.registers[word].clone() {
-                        Value::Str(eval_body) => {
-                            state.wip_str.clear();
-                            state.mode = Mode::CommandChar;
-                            return eval(&eval_body, state);
-                        }
-                        _ => {
-                            return Err(err_msg(format!(
-                                "Unable to execute ({}) as a named word",
-                                word)))
-                        }
-                    }
-                } else {
-                    return Err(err_msg(format!(
-                        "Unable to execute ({}) as a named word", word)))
-                }
+  if c != ')' {
+    state.wip_str.push(c);
+  } else if c == ')' {
+    match state.wip_str.as_str() {
+      // TODO:
+      // (times)
+      // (while)
+      // (?) -- (cond ifTrue ifFalse)
+      // [(?)x]s[if-else]
+      // [[\](?)x]s[if]
+      // (r?) -- show contents of registers
+      // Scope out
+      word => {
+        if state.registers.contains_key(word) {
+          match &state.registers[word].clone() {
+            Value::Str(eval_body) => {
+              state.wip_str.clear();
+              state.mode = Mode::CommandChar;
+              return eval(&eval_body, state);
             }
-
+            _ => {
+              return Err(err_msg(format!(
+                  "Unable to execute ({}) as a named word", word)))
+            }
+          }
+        } else {
+          return Err(err_msg(format!(
+              "Unable to execute ({}) as a named word", word)))
         }
+      }
     }
+  }
 
-    Ok(())
+  Ok(())
 }
 
+
 fn command_char(c: char, state: &mut RPState) -> Result<(), Exit> {
-    if c.is_digit(RADIX) {
-        state.mode = Mode::Integer;
-        state.num = dec!(0);
-        state.num += to_decimal(c.to_digit(10)
-            .ok_or_else(|| err_msg(format!("{} isn't a digit", c)))?);
-        Ok(())
-    }  else if c == '_' {
-        state.mode = Mode::Integer;
-        state.num = dec!(0);
-        state.is_num_negative = true;
-        Ok(())
-    } else if c == ' ' {
-        // do nothing
-        Ok(())
-    } else if c == '(' {
-        state.mode = Mode::CommandNamed;
-        state.wip_str.clear();
-        state.eat_count = 0;
-        Ok(())
-    } else if c == '[' {
-        state.mode = Mode::Str;
-        state.wip_str.clear();
-        state.eat_count = 0;
-        Ok(())
-    } else if let 'p' | 'n' | 'q' | 'l' | 's' | 'v' | 'x' | 'd' | ',' | 'c'
-                | '!' | '?' = c
-    {
-        match c {
-            '?' => {
-                print!("{}", HELP_TEXT);
-            },
-            '!' => {
-                if state.stack.is_empty() {
-                    return Err(err_msg("Data underflow!".into()));
-                }
-                match state.stack.pop() {
-                    Some(Value::Num(d)) => {
-                        if usize_to_decimal(state.stack.len()) < d {
-                            return Err(err_msg(format!(
-                                "Stack depth should be at least: {}", d)));
-                        }
-                    }
-                    Some(Value::Str(_)) => return Err(err_msg(
-                        "Cannot assert a string as a stack depth".into())),
-                    None => return Err(err_msg("Data underflow!".into()))
-                }
-            },
-            'q' => return Err(Exit::Quit),
-            'c' => state.stack.clear(),
-            'l' => {
-                state.reg_command = "l".into();
-                state.mode = Mode::RegisterChar;
-            }
-            'x' => {
-                if state.stack.is_empty() {
-                    return Err(err_msg("Data underflow!".into()));
-                }
-                match state.stack.pop() {
-                    Some(Value::Str(s)) => {
-                        return eval(&s, state)
-                    }
-                    Some(v) => {
-                        return Err(err_msg(format!("Cannot eval {}", v)));
-                    }
-                    None => {
-                        return Err(err_msg("Data underflow!".into()));
-                    }
-                }
-            }
-            's' => {
-                state.reg_command = "s".into();
-                state.mode = Mode::RegisterChar;
-            }
-            'd' => {
-                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());
-            }
-            ',' => {
-                if state.stack.is_empty() {
-                    return Err(err_msg("Data underflow!".into()));
-                }
-                state.stack.pop();
-            }
-            'v' => {
-                if state.stack.is_empty() {
-                    return Err(err_msg("Data underflow!".into()));
-                }
-                match state.stack.pop() {
-                    Some(Value::Num(d)) => {
-                        match d.sqrt() {
-                            Some(n) => state.stack.push(Value::Num(n)),
-                            None => return Err(err_msg(
-                                "Error attempting square root!".into())),
-                        }
-                    }
-                    Some(v) => {
-                        return Err(err_msg(format!(
-                            "Invalid attempt to sqrt {}", v)));
-                    }
-                    None => {
-                        return Err(err_msg(
-                            "Impossible data underflow!".into()));
-                    }
-                }
+  if c.is_digit(RADIX) {
+    state.mode = Mode::Integer;
+    state.num = dec!(0);
+    state.num += to_decimal(c.to_digit(10)
+        .ok_or_else(|| err_msg(format!("{} isn't a digit", c)))?);
+    Ok(())
+  } else if c == '_' {
+    state.mode = Mode::Integer;
+    state.num = dec!(0);
+    state.is_num_negative = true;
+    Ok(())
+  } else if c == ' ' {
+    // do nothing
+    Ok(())
+  } else if c == '(' {
+    state.mode = Mode::CommandNamed;
+    state.wip_str.clear();
+    state.eat_count = 0;
+    Ok(())
+  } else if c == '[' {
+    state.mode = Mode::Str;
+    state.wip_str.clear();
+    state.eat_count = 0;
+    Ok(())
+  } else if let 'p' | 'n' | 'q' | 'l' | 's' | 'v' | 'x' | 'd' | ',' | 'c'
+              | '!' | '?' = c
+  {
+    match c {
+      '?' => {
+        print!("{}", HELP_TEXT);
+      },
+      '!' => {
+        if state.stack.is_empty() {
+          return Err(err_msg("Data underflow!".into()));
+        }
+        match state.stack.pop() {
+          Some(Value::Num(d)) => {
+            if usize_to_decimal(state.stack.len()) < d {
+              return Err(err_msg(format!(
+                  "Stack depth should be at least: {}", d)));
             }
-            'p' =>  {
-                if state.stack.is_empty() {
-                    return Err(err_msg("Data underflow!".into()));
-                }
-                print_value(state.stack.last().unwrap());
-            },
-            'n' => {
-                if state.stack.is_empty() {
-                    return Err(err_msg("Data underflow!".into()));
-                }
-                print_value(&state.stack.pop().unwrap());
-            },
-            _ => return Err(err_msg(format!(
-                  "{} is unimplemented, this shouldn't be reachable!", c))),
+          }
+          Some(Value::Str(_)) => return Err(err_msg(
+              "Cannot assert a string as a stack depth".into())),
+          None => return Err(err_msg("Data underflow!".into()))
         }
-        Ok(())
-
-    } else if let '+' | '-' | '/' | '*' | '%' | '^' = c {
-        if state.stack.len() < 2 {
+      },
+      'q' => return Err(Exit::Quit),
+      'c' => state.stack.clear(),
+      'l' => {
+        state.reg_command = "l".into();
+        state.mode = Mode::RegisterChar;
+      }
+      'x' => {
+        if state.stack.is_empty() {
+          return Err(err_msg("Data underflow!".into()));
+        }
+        match state.stack.pop() {
+          Some(Value::Str(s)) => {
+            return eval(&s, state)
+          }
+          Some(v) => {
+            return Err(err_msg(format!("Cannot eval {}", v)));
+          }
+          None => {
             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()))?;
-
-        match (&a, &b) {
-            (Value::Num(ia), Value::Num(ib)) => {
-                let value = match c {
-                    '+' => Some(*ib + *ia),
-                    '-' => Some(*ib - *ia),
-                    '/' => Some(*ib / *ia),
-                    '*' => Some(*ib * *ia),
-                    '%' => Some(*ib % *ia),
-                    '^' => Some(Decimal::pow(*ib, *ia)),
-                    _ => None
-                }.ok_or_else(|| err_msg("This should never happen".into()))?;
-                state.stack.push(Value::Num(value));
-            }
-            _ =>  {
-                state.stack.push(b);
-                state.stack.push(a);
-                return Err(err_msg(format!(
-                    "Invalid operation {} on non-numbers!", c)))
-            }
+      }
+      's' => {
+        state.reg_command = "s".into();
+        state.mode = Mode::RegisterChar;
+      }
+      'd' => {
+        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());
+      }
+      ',' => {
+        if state.stack.is_empty() {
+          return Err(err_msg("Data underflow!".into()));
+        }
+        state.stack.pop();
+      }
+      'v' => {
+        if state.stack.is_empty() {
+          return Err(err_msg("Data underflow!".into()));
         }
-        Ok(())
-    } else {
-        panic!("{} isn't implemented yet!", c)
+        match state.stack.pop() {
+          Some(Value::Num(d)) => {
+            match d.sqrt() {
+              Some(n) => state.stack.push(Value::Num(n)),
+              None => return Err(err_msg(
+                  "Error attempting square root!".into())),
+              }
+          }
+          Some(v) => {
+            return Err(err_msg(format!("Invalid attempt to sqrt {}", v)));
+          }
+          None => {
+            return Err(err_msg("Impossible data underflow!".into()));
+          }
+        }
+      }
+      'p' =>  {
+        if state.stack.is_empty() {
+          return Err(err_msg("Data underflow!".into()));
+        }
+        print_value(state.stack.last().unwrap());
+      },
+      'n' => {
+        if state.stack.is_empty() {
+          return Err(err_msg("Data underflow!".into()));
+        }
+        print_value(&state.stack.pop().unwrap());
+      },
+      _ => return Err(err_msg(format!(
+          "{} is unimplemented, this shouldn't be reachable!", c))),
     }
+
+    Ok(())
+  } else if let '+' | '-' | '/' | '*' | '%' | '^' = c {
+    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()))?;
+
+    match (&a, &b) {
+      (Value::Num(ia), Value::Num(ib)) => {
+        let value = match c {
+          '+' => Some(*ib + *ia),
+          '-' => Some(*ib - *ia),
+          '/' => Some(*ib / *ia),
+          '*' => Some(*ib * *ia),
+          '%' => Some(*ib % *ia),
+          '^' => Some(Decimal::pow(*ib, *ia)),
+          _ => None
+        }.ok_or_else(|| err_msg("This should never happen".into()))?;
+
+        state.stack.push(Value::Num(value));
+      }
+      _ =>  {
+        state.stack.push(b);
+        state.stack.push(a);
+        return Err(err_msg(format!(
+            "Invalid operation {} on non-numbers!", c)))
+      }
+    }
+    Ok(())
+  } else {
+    panic!("{} isn't implemented yet!", c)
+  }
 }
 
+
 fn finish_num(c: char, state: &mut RPState) -> Result<(), Exit> {
-    // print!("finishing number, negative? {}", state.is_num_negative);
-    if state.is_num_negative {
-        state.num *= dec!(-1);
-    }
-    state.stack.push(Value::Num(state.num));
-    state.mode = Mode::CommandChar;
-    state.is_num_negative = false;
-    command_char(c, state)
+  // print!("finishing number, negative? {}", state.is_num_negative);
+  if state.is_num_negative {
+    state.num *= dec!(-1);
+  }
+  state.stack.push(Value::Num(state.num));
+  state.mode = Mode::CommandChar;
+  state.is_num_negative = false;
+  command_char(c, state)
 }
 
+
 fn integer(c: char, state: &mut RPState) -> Result<(), Exit> {
-    if c.is_digit(RADIX) {
-        state.num *= INTEGER_RADIX;
-        state.num += to_decimal(c.to_digit(10).unwrap());
-    } else if c == '.' {
-        state.decimal_offset = dec!(1);
-        state.mode = Mode::Decimal;
-    } else if c == '_' {
-        state.is_num_negative = true;
-    } else {
-        return finish_num(c, state);
-    }
-    return Ok(());
+  if c.is_digit(RADIX) {
+    state.num *= INTEGER_RADIX;
+    state.num += to_decimal(c.to_digit(10).unwrap());
+  } else if c == '.' {
+    state.decimal_offset = dec!(1);
+    state.mode = Mode::Decimal;
+  } else if c == '_' {
+    state.is_num_negative = true;
+  } else {
+    return finish_num(c, state);
+  }
+  return Ok(());
 }
 
+
 fn decimal(c: char, state: &mut RPState) -> Result<(), Exit> {
-    if c.is_digit(RADIX) {
-        state.decimal_offset *= dec!(0.1);
-        state.num += to_decimal(c.to_digit(10).unwrap())
-                     * state.decimal_offset;
-    } else {
-        return finish_num(c, state)
-    }
-    return Ok(());
+  if c.is_digit(RADIX) {
+    state.decimal_offset *= dec!(0.1);
+    state.num += to_decimal(c.to_digit(10).unwrap())
+                 * state.decimal_offset;
+  } else {
+    return finish_num(c, state)
+  }
+  return Ok(());
 }
 
+
 fn string(c: char, state: &mut RPState) -> Result<(), Exit> {
-    if state.eat_count > 0 {
-        state.eat_count-=1;
-        state.wip_str.push(c);
-    } else if c == '\\' {
-        state.eat_count = 1;
-    } else if c != ']' {
-        state.wip_str.push(c);
-    } else if c == ']' {
-        state.mode = Mode::CommandChar;
-        state.stack.push(Value::Str(state.wip_str.clone()));
-        state.wip_str.clear();
-    } else {
-        return Err(err_msg("Should Not Get Here!".into()))
-    }
-    Ok(())
+  if state.eat_count > 0 {
+    state.eat_count-=1;
+    state.wip_str.push(c);
+  } else if c == '\\' {
+    state.eat_count = 1;
+  } else if c != ']' {
+    state.wip_str.push(c);
+  } else if c == ']' {
+    state.mode = Mode::CommandChar;
+    state.stack.push(Value::Str(state.wip_str.clone()));
+    state.wip_str.clear();
+  } else {
+    return Err(err_msg("Should Not Get Here!".into()))
+  }
+  Ok(())
 }
 
+
 fn register_str(c: char, state: &mut RPState) -> Result<(), Exit> {
-    match (c, state.reg_command.as_str())  {
-        (']', "l")  => {
-            if state.registers.contains_key(&state.wip_str) {
-                state.stack.push(state.registers[&state.wip_str].clone());
-            }
-            state.wip_str.clear();
-            state.mode = Mode::CommandChar;
-        }
-        (']', "s")  => {
-            if state.stack.is_empty() {
-                return Err(err_msg(format!(
-                    "Data underflow attempting to store to register {}", c)));
-            }
-            state.registers.insert(state.wip_str.clone(),
-                                   state.stack.pop().unwrap());
-            state.wip_str.clear();
-            state.mode = Mode::CommandChar;
-        }
-        (_, "l"|"s") => {
-            state.wip_str.push(c)
-        }
-        _ => {
-            state.mode = Mode::CommandChar;
-            return Err(err_msg(format!(
-                "Unsupported register command {}", state.reg_command)));
-        }
+  match (c, state.reg_command.as_str()) {
+    (']', "l")  => {
+      if state.registers.contains_key(&state.wip_str) {
+        state.stack.push(state.registers[&state.wip_str].clone());
+      }
+      state.wip_str.clear();
+      state.mode = Mode::CommandChar;
     }
-    Ok(())
+    (']', "s")  => {
+      if state.stack.is_empty() {
+        return Err(err_msg(format!(
+            "Data underflow attempting to store to register {}", c)));
+      }
+      state.registers.insert(state.wip_str.clone(),
+                             state.stack.pop().unwrap());
+      state.wip_str.clear();
+      state.mode = Mode::CommandChar;
+    }
+    (_, "l"|"s") => {
+      state.wip_str.push(c)
+    }
+    _ => {
+      state.mode = Mode::CommandChar;
+      return Err(err_msg(format!(
+          "Unsupported register command {}", state.reg_command)));
+    }
+  }
+
+  Ok(())
 }
 
+
 fn register_char(c: char, state: &mut RPState) -> Result<(), Exit> {
-    match (state.reg_command.as_str(), c) {
-        (_, '[') => {
-            state.mode = Mode::RegisterStr;
-            Ok(())
-        }
-        ("s", c) => {
-            if state.stack.is_empty() {
-                return Err(err_msg(format!(
-                    "Data underflow attempting to store to register {}", c)));
-            }
-            state.registers.insert(String::from(c),
-                                   state.stack.pop().unwrap());
-            state.mode = Mode::CommandChar;
-            Ok(())
-        }
-        ("l", c) => {
-            if state.registers.contains_key(&String::from(c)) {
-                state.stack.push(state.registers[&String::from(c)].clone());
-            }
-            state.mode = Mode::CommandChar;
-            Ok(())
-        }
-        _ => {
-            state.mode = Mode::CommandChar;
-            return Err(err_msg(format!(
-                "Unsupported register command {}", state.reg_command)));
-        }
+  match (state.reg_command.as_str(), c) {
+    (_, '[') => {
+      state.mode = Mode::RegisterStr;
+      Ok(())
+    }
+    ("s", c) => {
+      if state.stack.is_empty() {
+          return Err(err_msg(format!(
+              "Data underflow attempting to store to register {}", c)));
+      }
+      state.registers.insert(String::from(c),
+                             state.stack.pop().unwrap());
+      state.mode = Mode::CommandChar;
+      Ok(())
+    }
+    ("l", c) => {
+      if state.registers.contains_key(&String::from(c)) {
+          state.stack.push(state.registers[&String::from(c)].clone());
+      }
+      state.mode = Mode::CommandChar;
+      Ok(())
     }
+    _ => {
+      state.mode = Mode::CommandChar;
+      return Err(err_msg(format!(
+          "Unsupported register command {}", state.reg_command)));
+    }
+  }
 }
 
+
 fn eval(input: &str, state: &mut RPState) -> Result<(), Exit> {
-    for (_cpos, c) in input.char_indices() {
-        let res = match state.mode {
-            Mode::CommandChar => command_char(c, state),
-            Mode::CommandNamed => command_str(c, state),
-            Mode::Integer => integer(c, state),
-            Mode::Decimal => decimal(c, state),
-            Mode::Str => string(c, state),
-            Mode::RegisterChar => register_char(c, state),
-            Mode::RegisterStr => register_str(c, state),
-        };
-        if res.is_err() {
-            return res
-        }
-    }
-    match state.mode {
-        Mode::Integer | Mode::Decimal => {
-            return finish_num(' ', state)
-        },
-        _ => {}
+  for (_cpos, c) in input.char_indices() {
+    let res = match state.mode {
+      Mode::CommandChar => command_char(c, state),
+      Mode::CommandNamed => command_str(c, state),
+      Mode::Integer => integer(c, state),
+      Mode::Decimal => decimal(c, state),
+      Mode::Str => string(c, state),
+      Mode::RegisterChar => register_char(c, state),
+      Mode::RegisterStr => register_str(c, state),
     };
-    return Ok(());
+    if res.is_err() {
+      return res
+    }
+  }
+  match state.mode {
+    Mode::Integer | Mode::Decimal => {
+      return finish_num(' ', state)
+    },
+    _ => {}
+  };
+
+  return Ok(());
 }
+