summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/main.rs131
1 files changed, 79 insertions, 52 deletions
diff --git a/src/main.rs b/src/main.rs
index 41e5e3a..3866316 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -115,6 +115,8 @@ fn main() {
     mode: Mode::CommandChar,
     readtables: BTreeMap::from([
       (Mode::Integer, make_integer_readtable()),
+      (Mode::Decimal, make_decimal_readtable()),
+      (Mode::Str, make_string_readtable()),
     ]),
     wip_str: String::from(""),
     // TODO: I don't think we need a return stack
@@ -164,6 +166,35 @@ struct ReadTable {
   default_action: ReadAction,
 }
 
+impl ReadTable {
+  fn new(default_action: fn(char, &mut RPState) -> Result<(), Exit>)
+    -> ReadTable
+  {
+    ReadTable {
+      action_map: BTreeMap::new(),
+      default_action: Rc::new(default_action),
+    }
+  }
+
+  fn set_action(&mut self, c: char,
+         action: fn(char, &mut RPState) -> Result<(), Exit>)
+  {
+    let _ = self.action_map.insert(c, Rc::new(action));
+  }
+
+  fn set_digit_action(&mut self,
+                       action: fn(char, &mut RPState) -> Result<(), Exit>)
+  {
+    for range in ['0' ..= '9', 'a' ..= 'z', 'A' ..= 'Z'] {
+      for c in range {
+        if c.is_digit(RADIX) {
+          let _ = self.action_map.insert(c, Rc::new(action.clone()));
+        }
+      }
+    }
+  }
+}
+
 
 struct RPState {
   registers: HashMap<String, Value>,
@@ -402,72 +433,70 @@ fn finish_num(c: char, state: &mut RPState) -> Result<(), Exit> {
 
 
 fn make_integer_readtable() -> ReadTable {
-  let mut items: Vec<(char, ReadAction)> = vec![
-    ('.', Rc::new(move |_, state| {
-      state.decimal_offset = dec!(1);
-      state.mode = Mode::Decimal;
+  let mut result = ReadTable::new(finish_num);
 
-      Ok(())
-    })),
-    ('_', Rc::new(move |_, state| {
-      state.is_num_negative = true;
+  result.set_action('.', move |_, state| {
+    state.decimal_offset = dec!(1);
+    state.mode = Mode::Decimal;
 
-      Ok(())
-    })),
-  ];
+    Ok(())
+  });
+
+  result.set_action('_', move |_, state| {
+    state.is_num_negative = true;
+
+    Ok(())
+  });
 
-  let handle_digit = move |c: char, state: &mut RPState| {
+  result.set_digit_action(move |c: char, state: &mut RPState| {
     if c.is_digit(RADIX) {
       state.num *= INTEGER_RADIX;
       state.num += to_decimal(c.to_digit(10).unwrap());
     }
 
     Ok(())
-  };
-
-  for range in ['0' ..= '9', 'a' ..= 'z', 'A' ..= 'Z'] {
-    for c in range {
-      if c.is_digit(RADIX) {
-        items.push((c, Rc::new(handle_digit.clone())));
-      }
-    }
-  }
+  });
 
-  ReadTable {
-    action_map: BTreeMap::from_iter(items.into_iter()),
-    default_action: Rc::new(finish_num),
-  }
+  result
 }
 
 
-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(());
+fn make_decimal_readtable() -> ReadTable {
+  let mut result = ReadTable::new(finish_num);
+
+  result.set_digit_action(move |c: char, state: &mut RPState| {
+    if c.is_digit(RADIX) {
+      state.decimal_offset *= dec!(0.1);
+      state.num += to_decimal(c.to_digit(10).unwrap())
+                   * state.decimal_offset;
+    }
+
+    Ok(())
+  });
+
+  result
 }
 
 
-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(())
+fn make_string_readtable() -> ReadTable {
+  ReadTable::new(move |c, state| {
+    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(())
+  })
 }
 
 
@@ -558,8 +587,6 @@ fn eval(input: &str, state: &mut RPState) -> Result<(), Exit> {
       match state.mode {
         Mode::CommandChar => command_char(c, state),
         Mode::CommandNamed => command_str(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 Err(err_msg(