Add WORDS for Programming-Tools word set
Walk dictionary linked list, print all visible word names. Uses pending_define mechanism for dictionary access.
This commit is contained in:
@@ -409,6 +409,28 @@ impl Dictionary {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return names of all visible (non-hidden) words, newest first.
|
||||||
|
pub fn visible_words(&self) -> Vec<String> {
|
||||||
|
let mut names = Vec::new();
|
||||||
|
let mut addr = self.latest;
|
||||||
|
while addr != 0 {
|
||||||
|
let flags_byte = self.memory[(addr + 4) as usize];
|
||||||
|
if flags_byte & flags::HIDDEN == 0 {
|
||||||
|
let name_len = (flags_byte & flags::LENGTH_MASK) as usize;
|
||||||
|
let name_start = (addr + 5) as usize;
|
||||||
|
let name = String::from_utf8_lossy(&self.memory[name_start..name_start + name_len])
|
||||||
|
.to_string();
|
||||||
|
names.push(name);
|
||||||
|
}
|
||||||
|
let link = self.read_u32_unchecked(addr);
|
||||||
|
if link == addr {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
addr = link;
|
||||||
|
}
|
||||||
|
names
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a reference to the raw memory buffer.
|
/// Get a reference to the raw memory buffer.
|
||||||
pub fn memory(&self) -> &[u8] {
|
pub fn memory(&self) -> &[u8] {
|
||||||
&self.memory
|
&self.memory
|
||||||
|
|||||||
@@ -2584,6 +2584,7 @@ impl<R: Runtime> ForthVM<R> {
|
|||||||
|
|
||||||
// -- Programming-Tools word set --
|
// -- Programming-Tools word set --
|
||||||
self.register_n_to_r()?;
|
self.register_n_to_r()?;
|
||||||
|
self.register_words()?;
|
||||||
|
|
||||||
// -- Search-Order word set --
|
// -- Search-Order word set --
|
||||||
self.register_search_order()?;
|
self.register_search_order()?;
|
||||||
@@ -4704,6 +4705,7 @@ impl<R: Runtime> ForthVM<R> {
|
|||||||
self.dictionary.set_current_wid(top);
|
self.dictionary.set_current_wid(top);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
40 => self.do_words(),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5328,6 +5330,16 @@ impl<R: Runtime> ForthVM<R> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// WORDS ( -- ) Print all visible dictionary words.
|
||||||
|
fn do_words(&mut self) {
|
||||||
|
let names = self.dictionary.visible_words();
|
||||||
|
let mut out = self.output.lock().unwrap();
|
||||||
|
for name in &names {
|
||||||
|
out.push_str(name);
|
||||||
|
out.push(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Register Search-Order word set words.
|
/// Register Search-Order word set words.
|
||||||
fn register_search_order(&mut self) -> anyhow::Result<()> {
|
fn register_search_order(&mut self) -> anyhow::Result<()> {
|
||||||
// FORTH-WORDLIST ( -- wid )
|
// FORTH-WORDLIST ( -- wid )
|
||||||
@@ -5553,6 +5565,17 @@ impl<R: Runtime> ForthVM<R> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register WORDS for the Programming-Tools word set.
|
||||||
|
fn register_words(&mut self) -> anyhow::Result<()> {
|
||||||
|
let pending = Arc::clone(&self.pending_define);
|
||||||
|
let func: HostFn = Box::new(move |_ctx: &mut dyn HostAccess| {
|
||||||
|
pending.lock().unwrap().push(40); // WORDS action
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
self.register_host_primitive("WORDS", false, func)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Register UNESCAPE, SUBSTITUTE, REPLACES for the String word set.
|
/// Register UNESCAPE, SUBSTITUTE, REPLACES for the String word set.
|
||||||
fn register_string_substitution(&mut self) -> anyhow::Result<()> {
|
fn register_string_substitution(&mut self) -> anyhow::Result<()> {
|
||||||
// UNESCAPE ( c-addr1 u1 c-addr2 -- c-addr2 u2 )
|
// UNESCAPE ( c-addr1 u1 c-addr2 -- c-addr2 u2 )
|
||||||
@@ -7942,6 +7965,27 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
// WORDS (Programming-Tools)
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_words_lists_defined_words() {
|
||||||
|
let output = eval_output("WORDS");
|
||||||
|
// Should contain standard primitives
|
||||||
|
assert!(output.contains("DUP"));
|
||||||
|
assert!(output.contains("DROP"));
|
||||||
|
assert!(output.contains("SWAP"));
|
||||||
|
assert!(output.contains("+"));
|
||||||
|
assert!(output.contains("WORDS"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_words_includes_user_defined() {
|
||||||
|
let output = eval_output(": MYTEST 42 ; WORDS");
|
||||||
|
assert!(output.contains("MYTEST"));
|
||||||
|
}
|
||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
// Double DOES>: Forth 2012 WEIRD: W1 test
|
// Double DOES>: Forth 2012 WEIRD: W1 test
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user