Add double-stack words (2dup, 2drop, 2swap, 2over) and forget

This commit is contained in:
2026-02-02 07:46:39 +01:00
parent 3e8076e416
commit 2af0b67714
6 changed files with 186 additions and 0 deletions

View File

@@ -13,6 +13,11 @@ pub enum Op {
Rot,
Nip,
Tuck,
Dup2,
Drop2,
Swap2,
Over2,
Forget,
Add,
Sub,
Mul,

View File

@@ -262,6 +262,42 @@ impl Forth {
let v = stack[len - 1].clone();
stack.insert(len - 2, v);
}
Op::Dup2 => {
let len = stack.len();
if len < 2 {
return Err("stack underflow".into());
}
let a = stack[len - 2].clone();
let b = stack[len - 1].clone();
stack.push(a);
stack.push(b);
}
Op::Drop2 => {
let len = stack.len();
if len < 2 {
return Err("stack underflow".into());
}
stack.pop();
stack.pop();
}
Op::Swap2 => {
let len = stack.len();
if len < 4 {
return Err("stack underflow".into());
}
stack.swap(len - 4, len - 2);
stack.swap(len - 3, len - 1);
}
Op::Over2 => {
let len = stack.len();
if len < 4 {
return Err("stack underflow".into());
}
let a = stack[len - 4].clone();
let b = stack[len - 3].clone();
stack.push(a);
stack.push(b);
}
Op::Add => binary_op(stack, |a, b| a + b)?,
Op::Sub => binary_op(stack, |a, b| a - b)?,
@@ -915,6 +951,10 @@ impl Forth {
.unwrap_or(0);
stack.push(Value::Int(val as i64, None));
}
Op::Forget => {
let name = stack.pop().ok_or("stack underflow")?.as_str()?.to_string();
self.dict.lock().unwrap().remove(&name);
}
}
pc += 1;
}

View File

@@ -107,6 +107,46 @@ pub const WORDS: &[Word] = &[
compile: Simple,
varargs: false,
},
Word {
name: "2dup",
aliases: &[],
category: "Stack",
stack: "(a b -- a b a b)",
desc: "Duplicate top two values",
example: "1 2 2dup => 1 2 1 2",
compile: Simple,
varargs: false,
},
Word {
name: "2drop",
aliases: &[],
category: "Stack",
stack: "(a b --)",
desc: "Drop top two values",
example: "1 2 3 2drop => 1",
compile: Simple,
varargs: false,
},
Word {
name: "2swap",
aliases: &[],
category: "Stack",
stack: "(a b c d -- c d a b)",
desc: "Swap top two pairs",
example: "1 2 3 4 2swap => 3 4 1 2",
compile: Simple,
varargs: false,
},
Word {
name: "2over",
aliases: &[],
category: "Stack",
stack: "(a b c d -- a b c d a b)",
desc: "Copy second pair to top",
example: "1 2 3 4 2over => 1 2 3 4 1 2",
compile: Simple,
varargs: false,
},
// Arithmetic
Word {
name: "+",
@@ -2571,6 +2611,16 @@ pub const WORDS: &[Word] = &[
compile: Simple,
varargs: false,
},
Word {
name: "forget",
aliases: &[],
category: "Definitions",
stack: "(name --)",
desc: "Remove user-defined word from dictionary",
example: "\"double\" forget",
compile: Simple,
varargs: false,
},
// Generator
Word {
name: "..",
@@ -2770,6 +2820,10 @@ pub(super) fn simple_op(name: &str) -> Option<Op> {
"rot" => Op::Rot,
"nip" => Op::Nip,
"tuck" => Op::Tuck,
"2dup" => Op::Dup2,
"2drop" => Op::Drop2,
"2swap" => Op::Swap2,
"2over" => Op::Over2,
"+" => Op::Add,
"-" => Op::Sub,
"*" => Op::Mul,
@@ -2842,6 +2896,7 @@ pub(super) fn simple_op(name: &str) -> Option<Op> {
"mstart" => Op::MidiStart,
"mstop" => Op::MidiStop,
"mcont" => Op::MidiContinue,
"forget" => Op::Forget,
_ => return None,
})
}