diff options
author | Irene Knapp <ireneista@irenes.space> | 2024-04-06 23:21:20 -0700 |
---|---|---|
committer | Irene Knapp <ireneista@irenes.space> | 2024-04-06 23:21:20 -0700 |
commit | 2ecd2af4745e165f0fa9c37e4a6a30f4a0a01496 (patch) | |
tree | 7fc53649a5cb68f4f48733b2cc92f08fa9dbe021 | |
parent | 871be040258e541b798650a77f21436d948ce2af (diff) |
readtables for decimals and strings
Change-Id: I610900748e5576c7a84ac39b040ce249a069408d
-rw-r--r-- | src/main.rs | 131 |
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( |