diff --git a/src/core/dictionary.rs b/src/core/dictionary.rs index 9ec5093..8ad6e58 100644 --- a/src/core/dictionary.rs +++ b/src/core/dictionary.rs @@ -165,6 +165,10 @@ impl Dictionary { } define_word_impl(&mut self.words, name.into(), word, allow_redefine) } + + pub fn undefine_word(&mut self, name: &str) -> bool { + self.words.remove(name).is_some() + } } type WordsMap = HashMap; diff --git a/src/core/mod.rs b/src/core/mod.rs index 16d0478..e1dd694 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -26,6 +26,8 @@ pub struct Context<'a> { pub dictionary: Dictionary, pub input: Lexer<'a>, + pub clock: &'a dyn Clock, + pub stdout: &'a mut dyn Write, } @@ -38,6 +40,7 @@ impl<'a> Context<'a> { next: None, dictionary: Default::default(), input: Lexer::new(input), + clock: &SystemClock, stdout, } } @@ -51,6 +54,15 @@ impl<'a> Context<'a> { module.init(&mut self.dictionary) } + pub fn with_clock(mut self, clock: &'a dyn Clock) -> Self { + self.set_clock(clock); + self + } + + pub fn set_clock(&mut self, clock: &'a dyn Clock) { + self.clock = clock; + } + pub fn run(&mut self) -> Result { let mut current = Some(Rc::new(InterpreterCont) as Cont); while let Some(cont) = current.take() { @@ -166,6 +178,21 @@ impl Module for &T { } } +pub trait Clock { + fn now_ms(&self) -> u64; +} + +struct SystemClock; + +impl Clock for SystemClock { + fn now_ms(&self) -> u64 { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_millis() as u64 + } +} + struct InterpreterCont; impl ContImpl for InterpreterCont { diff --git a/src/core/stack.rs b/src/core/stack.rs index b2db8f6..fe652d3 100644 --- a/src/core/stack.rs +++ b/src/core/stack.rs @@ -69,11 +69,11 @@ impl Stack { } pub fn push_bool(&mut self, value: bool) -> Result<()> { - self.push(BigInt::from(if value { + self.push(if value { -BigInt::one() } else { BigInt::zero() - })) + }) } pub fn push_int>(&mut self, value: T) -> Result<()> { diff --git a/src/modules/control.rs b/src/modules/control.rs index 73386a1..bf951d8 100644 --- a/src/modules/control.rs +++ b/src/modules/control.rs @@ -219,6 +219,27 @@ impl Control { ctx.stack.push_argcount(0, ctx.dictionary.make_nop()) } + #[cmd(name = "forget", args(word_from_stack = false))] + #[cmd(name = "(forget)", args(word_from_stack = true))] + fn interpret_forget(ctx: &mut Context, word_from_stack: bool) -> Result<()> { + let mut word = if word_from_stack { + *ctx.stack.pop_string()? + } else { + let word = ctx.input.scan_word()?.ok_or(Error::UnexpectedEof)?; + word.data.to_owned() + }; + + if ctx.dictionary.lookup(&word).is_none() { + word.push(' '); + if ctx.dictionary.lookup(&word).is_none() { + return Err(Error::UndefinedWord); + } + } + + ctx.dictionary.undefine_word(&word); + Ok(()) + } + // === Input parse === #[cmd(name = "word")] diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 363b033..2409bf1 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -123,4 +123,14 @@ impl FiftModule for BaseModule { Ok(()) } + + #[cmd(name = "now")] + fn interpret_now(ctx: &mut Context) -> Result<()> { + ctx.stack.push_int(ctx.clock.now_ms() / 1000) + } + + #[cmd(name = "now_ms")] + fn interpret_now_ms(ctx: &mut Context) -> Result<()> { + ctx.stack.push_int(ctx.clock.now_ms()) + } }