Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b4a28f342d | |||
| 0a0f1e9e95 |
@@ -5,6 +5,24 @@ All notable changes to WAFER are documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Search-order conveniences from common practice** (none are Forth 2012;
|
||||||
|
all three exist in gforth and friends, and the semantics were checked
|
||||||
|
against gforth 0.7.3):
|
||||||
|
- `>ORDER ( wid -- )` pushes a wordlist on top of the search order --
|
||||||
|
the word the standard forgot when ANS replaced named vocabularies
|
||||||
|
with anonymous wid handles and left `ALSO` with nothing to name.
|
||||||
|
- `-ORDER ( wid -- )` removes a wordlist from the search order wherever
|
||||||
|
it sits (VFX/MPE extension, the inverse of `>ORDER`).
|
||||||
|
- `VOCABULARY <name>` creates a named wordlist; executing the name
|
||||||
|
replaces the top of the search order, the same semantics the standard
|
||||||
|
gives `FORTH`. `ORDER` and `WORDS ALL` now print vocabulary names
|
||||||
|
instead of `wid#N`, and `MARKER` rollback forgets them along with
|
||||||
|
the words.
|
||||||
|
|
||||||
## [0.2.9] - 2026-08-10
|
## [0.2.9] - 2026-08-10
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
Generated
+3
-3
@@ -1589,7 +1589,7 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wafer"
|
name = "wafer"
|
||||||
version = "0.2.9"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -1600,7 +1600,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wafer-core"
|
name = "wafer-core"
|
||||||
version = "0.2.9"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"insta",
|
"insta",
|
||||||
@@ -1615,7 +1615,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wafer-web"
|
name = "wafer-web"
|
||||||
version = "0.2.9"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ members = ["crates/*"]
|
|||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.2.9"
|
version = "0.3.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://github.com/ok2/wafer"
|
repository = "https://github.com/ok2/wafer"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ license.workspace = true
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wafer-core = { path = "../core", version = "0.2.9" }
|
wafer-core = { path = "../core", version = "0.3.0" }
|
||||||
wasmtime = { workspace = true }
|
wasmtime = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
clap = { version = "4", features = ["derive"] }
|
clap = { version = "4", features = ["derive"] }
|
||||||
|
|||||||
@@ -955,7 +955,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
let out = expand_self_guard(body, SELF);
|
let out = expand_self_guard(body, SELF);
|
||||||
let IrOp::If { then_body, .. } = &out[7] else {
|
let IrOp::If { then_body, .. } = &out[7] else {
|
||||||
panic!("expected the expanded guard at index 7, got {:?}", out);
|
panic!("expected the expanded guard at index 7, got {out:?}");
|
||||||
};
|
};
|
||||||
assert_eq!(then_body, &vec![IrOp::Drop, IrOp::PushI32(0)]);
|
assert_eq!(then_body, &vec![IrOp::Drop, IrOp::PushI32(0)]);
|
||||||
}
|
}
|
||||||
|
|||||||
+155
-20
@@ -270,6 +270,7 @@ pub(crate) const INTERPRETER_TOKENS: &[&str] = &[
|
|||||||
"GILD",
|
"GILD",
|
||||||
"EMPTY",
|
"EMPTY",
|
||||||
"SYNONYM",
|
"SYNONYM",
|
||||||
|
"VOCABULARY",
|
||||||
"CONSOLIDATE",
|
"CONSOLIDATE",
|
||||||
// Parsing words
|
// Parsing words
|
||||||
"'",
|
"'",
|
||||||
@@ -348,6 +349,7 @@ struct MarkerState {
|
|||||||
// REPLACES table, ABORT" texts
|
// REPLACES table, ABORT" texts
|
||||||
search_order: Vec<u32>,
|
search_order: Vec<u32>,
|
||||||
next_wid: u32,
|
next_wid: u32,
|
||||||
|
wid_names: HashMap<u32, String>,
|
||||||
current_wid: u32,
|
current_wid: u32,
|
||||||
substitutions: HashMap<String, Vec<u8>>,
|
substitutions: HashMap<String, Vec<u8>>,
|
||||||
abort_messages_len: usize,
|
abort_messages_len: usize,
|
||||||
@@ -484,6 +486,8 @@ pub struct ForthVM<R: Runtime> {
|
|||||||
search_order: Arc<Mutex<Vec<u32>>>,
|
search_order: Arc<Mutex<Vec<u32>>>,
|
||||||
/// Next wordlist ID to allocate (shared).
|
/// Next wordlist ID to allocate (shared).
|
||||||
next_wid: Arc<Mutex<u32>>,
|
next_wid: Arc<Mutex<u32>>,
|
||||||
|
/// Names of wordlists created by VOCABULARY, for ORDER/WORDS display.
|
||||||
|
wid_names: HashMap<u32, String>,
|
||||||
/// xorshift64 PRNG state for RANDOM / RND-SEED.
|
/// xorshift64 PRNG state for RANDOM / RND-SEED.
|
||||||
rng_state: Arc<Mutex<u64>>,
|
rng_state: Arc<Mutex<u64>>,
|
||||||
/// Stacked compile state for nested definitions (quotations `[: ;]`).
|
/// Stacked compile state for nested definitions (quotations `[: ;]`).
|
||||||
@@ -712,6 +716,7 @@ impl<R: Runtime> ForthVM<R> {
|
|||||||
substitutions: Arc::new(Mutex::new(HashMap::new())),
|
substitutions: Arc::new(Mutex::new(HashMap::new())),
|
||||||
search_order: Arc::new(Mutex::new(vec![1])),
|
search_order: Arc::new(Mutex::new(vec![1])),
|
||||||
next_wid: Arc::new(Mutex::new(2)),
|
next_wid: Arc::new(Mutex::new(2)),
|
||||||
|
wid_names: HashMap::new(),
|
||||||
// SystemTime::now() PANICS on wasm32-unknown-unknown (no time
|
// SystemTime::now() PANICS on wasm32-unknown-unknown (no time
|
||||||
// source), which turned VM construction into an `unreachable`
|
// source), which turned VM construction into an `unreachable`
|
||||||
// trap in the browser. Seed from the wall clock only where one
|
// trap in the browser. Seed from the wall clock only where one
|
||||||
@@ -1236,21 +1241,14 @@ impl<R: Runtime> ForthVM<R> {
|
|||||||
"FVALUE" => return self.define_fvalue(),
|
"FVALUE" => return self.define_fvalue(),
|
||||||
"CONSOLIDATE" => return self.consolidate(),
|
"CONSOLIDATE" => return self.consolidate(),
|
||||||
"SYNONYM" => return self.define_synonym(),
|
"SYNONYM" => return self.define_synonym(),
|
||||||
|
"VOCABULARY" => return self.define_vocabulary(),
|
||||||
"ORDER" => {
|
"ORDER" => {
|
||||||
// wid 1 is FORTH-WORDLIST; other wids are anonymous.
|
let order = self.search_order.lock().unwrap().clone();
|
||||||
let wid_name = |wid: u32| {
|
let names: Vec<String> = order.iter().map(|&w| self.wid_name(w)).collect();
|
||||||
if wid == 1 {
|
|
||||||
"FORTH".to_string()
|
|
||||||
} else {
|
|
||||||
format!("wid#{wid}")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let so = self.search_order.lock().unwrap();
|
|
||||||
let names: Vec<String> = so.iter().map(|&w| wid_name(w)).collect();
|
|
||||||
let output = format!(
|
let output = format!(
|
||||||
"Search order: {} Compilation: {}\n",
|
"Search order: {} Compilation: {}\n",
|
||||||
names.join(" "),
|
names.join(" "),
|
||||||
wid_name(self.dictionary.current_wid())
|
self.wid_name(self.dictionary.current_wid())
|
||||||
);
|
);
|
||||||
self.output.lock().unwrap().push_str(&output);
|
self.output.lock().unwrap().push_str(&output);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -3742,6 +3740,47 @@ impl<R: Runtime> ForthVM<R> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// VOCABULARY <name> -- create a named wordlist (fig-Forth heritage;
|
||||||
|
/// gforth/SwiftForth extension, not Forth 2012). Executing the created
|
||||||
|
/// word replaces the top of the search order with its wordlist, the
|
||||||
|
/// same semantics the standard gives the word FORTH. The name is
|
||||||
|
/// remembered so ORDER and WORDS ALL display it instead of wid#N.
|
||||||
|
fn define_vocabulary(&mut self) -> anyhow::Result<()> {
|
||||||
|
let name = self
|
||||||
|
.next_token()
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("VOCABULARY: expected name"))?;
|
||||||
|
|
||||||
|
let set_context_id = self
|
||||||
|
.dictionary
|
||||||
|
.find("_SET_CONTEXT_")
|
||||||
|
.map(|(_, id, _)| id)
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("_SET_CONTEXT_ not found"))?;
|
||||||
|
|
||||||
|
let wid = {
|
||||||
|
let mut nw = self.next_wid.lock().unwrap();
|
||||||
|
let wid = *nw;
|
||||||
|
*nw += 1;
|
||||||
|
wid
|
||||||
|
};
|
||||||
|
self.wid_names.insert(wid, name.to_uppercase());
|
||||||
|
|
||||||
|
let word_id = self
|
||||||
|
.dictionary
|
||||||
|
.create(&name, false)
|
||||||
|
.map_err(|e| anyhow::anyhow!("{e}"))?;
|
||||||
|
let ir_body = vec![IrOp::PushI32(wid as i32), IrOp::Call(set_context_id)];
|
||||||
|
self.ir_bodies.insert(word_id, ir_body.clone());
|
||||||
|
self.word_sources
|
||||||
|
.insert(word_id, format!("VOCABULARY {name}"));
|
||||||
|
let config = self.codegen_config(word_id.0);
|
||||||
|
let compiled = compile_word(&name, &ir_body, &config)
|
||||||
|
.map_err(|e| anyhow::anyhow!("codegen error for VOCABULARY: {e}"))?;
|
||||||
|
self.instantiate_and_install(&compiled, word_id)?;
|
||||||
|
self.dictionary.reveal();
|
||||||
|
self.next_table_index = self.next_table_index.max(word_id.0 + 1);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// IMMEDIATE -- toggle the immediate flag on the most recently defined word.
|
/// IMMEDIATE -- toggle the immediate flag on the most recently defined word.
|
||||||
/// Called via `pending_define` when IMMEDIATE is executed from compiled code.
|
/// Called via `pending_define` when IMMEDIATE is executed from compiled code.
|
||||||
fn set_immediate(&mut self) -> anyhow::Result<()> {
|
fn set_immediate(&mut self) -> anyhow::Result<()> {
|
||||||
@@ -3811,6 +3850,7 @@ impl<R: Runtime> ForthVM<R> {
|
|||||||
fvalue_words: self.fvalue_words.clone(),
|
fvalue_words: self.fvalue_words.clone(),
|
||||||
search_order: self.search_order.lock().unwrap().clone(),
|
search_order: self.search_order.lock().unwrap().clone(),
|
||||||
next_wid: *self.next_wid.lock().unwrap(),
|
next_wid: *self.next_wid.lock().unwrap(),
|
||||||
|
wid_names: self.wid_names.clone(),
|
||||||
current_wid: self.dictionary.current_wid(),
|
current_wid: self.dictionary.current_wid(),
|
||||||
substitutions: self.substitutions.lock().unwrap().clone(),
|
substitutions: self.substitutions.lock().unwrap().clone(),
|
||||||
abort_messages_len: self.abort_messages.lock().unwrap().len(),
|
abort_messages_len: self.abort_messages.lock().unwrap().len(),
|
||||||
@@ -3834,6 +3874,7 @@ impl<R: Runtime> ForthVM<R> {
|
|||||||
self.fvalue_words = state.fvalue_words;
|
self.fvalue_words = state.fvalue_words;
|
||||||
*self.search_order.lock().unwrap() = state.search_order;
|
*self.search_order.lock().unwrap() = state.search_order;
|
||||||
*self.next_wid.lock().unwrap() = state.next_wid;
|
*self.next_wid.lock().unwrap() = state.next_wid;
|
||||||
|
self.wid_names = state.wid_names;
|
||||||
*self.substitutions.lock().unwrap() = state.substitutions;
|
*self.substitutions.lock().unwrap() = state.substitutions;
|
||||||
self.abort_messages
|
self.abort_messages
|
||||||
.lock()
|
.lock()
|
||||||
@@ -6522,6 +6563,17 @@ impl<R: Runtime> ForthVM<R> {
|
|||||||
|
|
||||||
/// `WORDS ALL` -- grouped full view: one section per wordlist (search
|
/// `WORDS ALL` -- grouped full view: one section per wordlist (search
|
||||||
/// order first, then any other populated wids), then internal words.
|
/// order first, then any other populated wids), then internal words.
|
||||||
|
/// Display name for a wordlist: FORTH, a VOCABULARY name, or wid#N.
|
||||||
|
fn wid_name(&self, wid: u32) -> String {
|
||||||
|
if wid == 1 {
|
||||||
|
return "FORTH".to_string();
|
||||||
|
}
|
||||||
|
self.wid_names
|
||||||
|
.get(&wid)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(|| format!("wid#{wid}"))
|
||||||
|
}
|
||||||
|
|
||||||
fn do_words_all(&mut self) {
|
fn do_words_all(&mut self) {
|
||||||
let entries = self.dictionary.visible_entries();
|
let entries = self.dictionary.visible_entries();
|
||||||
let mut wids: Vec<u32> = self.search_order.lock().unwrap().clone();
|
let mut wids: Vec<u32> = self.search_order.lock().unwrap().clone();
|
||||||
@@ -6530,15 +6582,9 @@ impl<R: Runtime> ForthVM<R> {
|
|||||||
wids.push(*wid);
|
wids.push(*wid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let wid_name = |wid: u32| {
|
let wid_names: Vec<String> = wids.iter().map(|&w| self.wid_name(w)).collect();
|
||||||
if wid == 1 {
|
|
||||||
"FORTH".to_string()
|
|
||||||
} else {
|
|
||||||
format!("wid#{wid}")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut out = self.output.lock().unwrap();
|
let mut out = self.output.lock().unwrap();
|
||||||
for wid in wids {
|
for (wid, wid_name) in wids.iter().copied().zip(wid_names) {
|
||||||
let names: Vec<&str> = entries
|
let names: Vec<&str> = entries
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, w, internal)| *w == wid && !internal)
|
.filter(|(_, w, internal)| *w == wid && !internal)
|
||||||
@@ -6547,7 +6593,7 @@ impl<R: Runtime> ForthVM<R> {
|
|||||||
if names.is_empty() {
|
if names.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out.push_str(&format!("-- {} ({} words)\n", wid_name(wid), names.len()));
|
out.push_str(&format!("-- {} ({} words)\n", wid_name, names.len()));
|
||||||
push_wrapped(&mut out, &names);
|
push_wrapped(&mut out, &names);
|
||||||
}
|
}
|
||||||
let internals: Vec<&str> = entries
|
let internals: Vec<&str> = entries
|
||||||
@@ -6853,6 +6899,56 @@ impl<R: Runtime> ForthVM<R> {
|
|||||||
self.register_host_primitive("ALSO", false, func)?;
|
self.register_host_primitive("ALSO", false, func)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// >ORDER ( wid -- ) — push wid on top of the search order.
|
||||||
|
// Not in Forth 2012; a widely used gforth extension.
|
||||||
|
{
|
||||||
|
let so = Arc::clone(&self.search_order);
|
||||||
|
let func: HostFn = Box::new(move |ctx: &mut dyn HostAccess| {
|
||||||
|
let sp = host_need(ctx, 1)?;
|
||||||
|
let wid = ctx.mem_read_i32(sp) as u32;
|
||||||
|
so.lock().unwrap().insert(0, wid);
|
||||||
|
ctx.set_dsp(sp + CELL_SIZE);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
self.register_host_primitive(">ORDER", false, func)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -ORDER ( wid -- ) — remove wid from the search order wherever it
|
||||||
|
// sits (no-op if absent). VFX/MPE extension, the inverse of >ORDER.
|
||||||
|
{
|
||||||
|
let so = Arc::clone(&self.search_order);
|
||||||
|
let func: HostFn = Box::new(move |ctx: &mut dyn HostAccess| {
|
||||||
|
let sp = host_need(ctx, 1)?;
|
||||||
|
let wid = ctx.mem_read_i32(sp) as u32;
|
||||||
|
so.lock().unwrap().retain(|&w| w != wid);
|
||||||
|
ctx.set_dsp(sp + CELL_SIZE);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
self.register_host_primitive("-ORDER", false, func)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// _SET_CONTEXT_ ( wid -- ) — replace the top of the search order.
|
||||||
|
// Internal carrier for words created by VOCABULARY (same pattern as
|
||||||
|
// _MARKER_RESTORE_): a vocabulary word compiles to
|
||||||
|
// `PushI32(wid) Call(_SET_CONTEXT_)`.
|
||||||
|
{
|
||||||
|
let so = Arc::clone(&self.search_order);
|
||||||
|
let func: HostFn = Box::new(move |ctx: &mut dyn HostAccess| {
|
||||||
|
let sp = host_need(ctx, 1)?;
|
||||||
|
let wid = ctx.mem_read_i32(sp) as u32;
|
||||||
|
let mut order = so.lock().unwrap();
|
||||||
|
if order.is_empty() {
|
||||||
|
order.push(wid);
|
||||||
|
} else {
|
||||||
|
order[0] = wid;
|
||||||
|
}
|
||||||
|
drop(order);
|
||||||
|
ctx.set_dsp(sp + CELL_SIZE);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
self.register_host_primitive("_SET_CONTEXT_", false, func)?;
|
||||||
|
}
|
||||||
|
|
||||||
// PREVIOUS ( -- ) remove top of search order
|
// PREVIOUS ( -- ) remove top of search order
|
||||||
{
|
{
|
||||||
let so = Arc::clone(&self.search_order);
|
let so = Arc::clone(&self.search_order);
|
||||||
@@ -10727,6 +10823,45 @@ mod tests {
|
|||||||
assert!(!output.contains('['));
|
assert!(!output.contains('['));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_to_order_pushes_on_top() {
|
||||||
|
let output = eval_output("WORDLIST >ORDER ORDER");
|
||||||
|
assert!(output.contains("Search order: wid#2 FORTH"), "{output}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_minus_order_removes_wid() {
|
||||||
|
let output = eval_output("WORDLIST DUP >ORDER -ORDER ORDER");
|
||||||
|
assert!(output.contains("Search order: FORTH "), "{output}");
|
||||||
|
assert!(!output.contains("wid#"), "{output}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vocabulary_replaces_top_and_names_order() {
|
||||||
|
// Vocabulary execution has FORTH-word semantics: replace the top
|
||||||
|
// of the search order. ALSO first, so FORTH stays underneath.
|
||||||
|
let output = eval_output("VOCABULARY EDITOR ALSO EDITOR ORDER");
|
||||||
|
assert!(output.contains("Search order: EDITOR FORTH"), "{output}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vocabulary_definitions_land_in_it_and_words_groups_by_name() {
|
||||||
|
let output = eval_output("VOCABULARY EDITOR ALSO EDITOR DEFINITIONS : E1 1 ; WORDS ALL");
|
||||||
|
assert!(output.contains("-- EDITOR (1 words)"), "{output}");
|
||||||
|
// and the word is findable through the search order
|
||||||
|
let output = eval_output("VOCABULARY EDITOR ALSO EDITOR DEFINITIONS : E1 42 ; E1 .");
|
||||||
|
assert!(output.contains("42"), "{output}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_marker_rolls_back_vocabulary_name() {
|
||||||
|
// After rollback the vocabulary is gone; a freshly allocated wid
|
||||||
|
// with the same number must not inherit its stale name.
|
||||||
|
let output = eval_output("MARKER M VOCABULARY V0 M WORDLIST >ORDER ORDER");
|
||||||
|
assert!(!output.contains("V0"), "{output}");
|
||||||
|
assert!(output.contains("wid#2"), "{output}");
|
||||||
|
}
|
||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
// Double DOES>: Forth 2012 WEIRD: W1 test
|
// Double DOES>: Forth 2012 WEIRD: W1 test
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|||||||
@@ -1004,6 +1004,21 @@ pub const WORD_DOCS: &[(&str, &str, &str)] = &[
|
|||||||
"New definitions go to the top wordlist.",
|
"New definitions go to the top wordlist.",
|
||||||
),
|
),
|
||||||
("ALSO", "( -- )", "Duplicate the top of the search order."),
|
("ALSO", "( -- )", "Duplicate the top of the search order."),
|
||||||
|
(
|
||||||
|
">ORDER",
|
||||||
|
"( wid -- )",
|
||||||
|
"Push wid on top of the search order (gforth extension).",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"-ORDER",
|
||||||
|
"( wid -- )",
|
||||||
|
"Remove wid from the search order (VFX extension).",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"VOCABULARY",
|
||||||
|
"( \"name\" -- )",
|
||||||
|
"Create a named wordlist; executing name replaces the top of the search order.",
|
||||||
|
),
|
||||||
("ONLY", "( -- )", "Reset the search order to the minimum."),
|
("ONLY", "( -- )", "Reset the search order to the minimum."),
|
||||||
("PREVIOUS", "( -- )", "Drop the top of the search order."),
|
("PREVIOUS", "( -- )", "Drop the top of the search order."),
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -901,7 +901,7 @@ fn best_of_processes(mut measure: impl FnMut() -> Option<u64>) -> Option<u64> {
|
|||||||
/// sf64 needs one statement per line (it truncates input at ~256 characters);
|
/// sf64 needs one statement per line (it truncates input at ~256 characters);
|
||||||
/// the others do not care.
|
/// the others do not care.
|
||||||
fn repeat_timed(sep: &str) -> String {
|
fn repeat_timed(sep: &str) -> String {
|
||||||
vec!["TIMED-BENCH"; REPS].join(sep)
|
["TIMED-BENCH"; REPS].join(sep)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the microsecond values printed by `TIMED-BENCH` and reduce them to
|
/// Parse the microsecond values printed by `TIMED-BENCH` and reduce them to
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ workspace = true
|
|||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wafer-core = { path = "../core", version = "0.2.9", default-features = false, features = ["crypto"] }
|
wafer-core = { path = "../core", version = "0.3.0", default-features = false, features = ["crypto"] }
|
||||||
wasm-bindgen = "0.2"
|
wasm-bindgen = "0.2"
|
||||||
js-sys = "0.3"
|
js-sys = "0.3"
|
||||||
send_wrapper = { workspace = true }
|
send_wrapper = { workspace = true }
|
||||||
|
|||||||
Reference in New Issue
Block a user