Feat: prelude and new words
This commit is contained in:
@@ -19,6 +19,12 @@ pub enum Op {
|
||||
Drop2,
|
||||
Swap2,
|
||||
Over2,
|
||||
Rev,
|
||||
Shuffle,
|
||||
Sort,
|
||||
RSort,
|
||||
Sum,
|
||||
Prod,
|
||||
Forget,
|
||||
Add,
|
||||
Sub,
|
||||
@@ -91,6 +97,7 @@ pub enum Op {
|
||||
SetSpeed,
|
||||
At,
|
||||
IntRange,
|
||||
StepRange,
|
||||
Generate,
|
||||
GeomRange,
|
||||
Times,
|
||||
|
||||
@@ -345,6 +345,77 @@ impl Forth {
|
||||
stack.push(a);
|
||||
stack.push(b);
|
||||
}
|
||||
Op::Rev => {
|
||||
let count = stack.pop().ok_or("stack underflow")?.as_int()? as usize;
|
||||
if count > stack.len() {
|
||||
return Err("stack underflow".into());
|
||||
}
|
||||
let start = stack.len() - count;
|
||||
stack[start..].reverse();
|
||||
}
|
||||
Op::Shuffle => {
|
||||
let count = stack.pop().ok_or("stack underflow")?.as_int()? as usize;
|
||||
if count > stack.len() {
|
||||
return Err("stack underflow".into());
|
||||
}
|
||||
let start = stack.len() - count;
|
||||
let slice = &mut stack[start..];
|
||||
let mut rng = self.rng.lock();
|
||||
for i in (1..slice.len()).rev() {
|
||||
let j = rng.gen_range(0..=i);
|
||||
slice.swap(i, j);
|
||||
}
|
||||
}
|
||||
Op::Sort => {
|
||||
let count = stack.pop().ok_or("stack underflow")?.as_int()? as usize;
|
||||
if count > stack.len() {
|
||||
return Err("stack underflow".into());
|
||||
}
|
||||
let start = stack.len() - count;
|
||||
stack[start..].sort_by(|a, b| {
|
||||
a.as_float()
|
||||
.unwrap_or(0.0)
|
||||
.partial_cmp(&b.as_float().unwrap_or(0.0))
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
});
|
||||
}
|
||||
Op::RSort => {
|
||||
let count = stack.pop().ok_or("stack underflow")?.as_int()? as usize;
|
||||
if count > stack.len() {
|
||||
return Err("stack underflow".into());
|
||||
}
|
||||
let start = stack.len() - count;
|
||||
stack[start..].sort_by(|a, b| {
|
||||
b.as_float()
|
||||
.unwrap_or(0.0)
|
||||
.partial_cmp(&a.as_float().unwrap_or(0.0))
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
});
|
||||
}
|
||||
Op::Sum => {
|
||||
let count = stack.pop().ok_or("stack underflow")?.as_int()? as usize;
|
||||
if count > stack.len() {
|
||||
return Err("stack underflow".into());
|
||||
}
|
||||
let start = stack.len() - count;
|
||||
let total: f64 = stack
|
||||
.drain(start..)
|
||||
.map(|v| v.as_float().unwrap_or(0.0))
|
||||
.sum();
|
||||
stack.push(float_to_value(total));
|
||||
}
|
||||
Op::Prod => {
|
||||
let count = stack.pop().ok_or("stack underflow")?.as_int()? as usize;
|
||||
if count > stack.len() {
|
||||
return Err("stack underflow".into());
|
||||
}
|
||||
let start = stack.len() - count;
|
||||
let product: f64 = stack
|
||||
.drain(start..)
|
||||
.map(|v| v.as_float().unwrap_or(1.0))
|
||||
.product();
|
||||
stack.push(float_to_value(product));
|
||||
}
|
||||
|
||||
Op::Add => binary_op(stack, |a, b| a + b)?,
|
||||
Op::Sub => binary_op(stack, |a, b| a - b)?,
|
||||
@@ -889,6 +960,25 @@ impl Forth {
|
||||
}
|
||||
}
|
||||
|
||||
Op::StepRange => {
|
||||
let step = stack.pop().ok_or("stack underflow")?.as_float()?;
|
||||
let end = stack.pop().ok_or("stack underflow")?.as_float()?;
|
||||
let start = stack.pop().ok_or("stack underflow")?.as_float()?;
|
||||
if step == 0.0 {
|
||||
return Err("step cannot be zero".into());
|
||||
}
|
||||
let ascending = step > 0.0;
|
||||
let mut val = start;
|
||||
loop {
|
||||
let done = if ascending { val > end } else { val < end };
|
||||
if done {
|
||||
break;
|
||||
}
|
||||
stack.push(float_to_value(val));
|
||||
val += step;
|
||||
}
|
||||
}
|
||||
|
||||
Op::Generate => {
|
||||
let count = stack.pop().ok_or("stack underflow")?.as_int()?;
|
||||
let quot = stack.pop().ok_or("stack underflow")?;
|
||||
|
||||
@@ -20,6 +20,12 @@ pub(super) fn simple_op(name: &str) -> Option<Op> {
|
||||
"2drop" => Op::Drop2,
|
||||
"2swap" => Op::Swap2,
|
||||
"2over" => Op::Over2,
|
||||
"rev" => Op::Rev,
|
||||
"shuffle" => Op::Shuffle,
|
||||
"sort" => Op::Sort,
|
||||
"rsort" => Op::RSort,
|
||||
"sum" => Op::Sum,
|
||||
"prod" => Op::Prod,
|
||||
"+" => Op::Add,
|
||||
"-" => Op::Sub,
|
||||
"*" => Op::Mul,
|
||||
@@ -83,6 +89,7 @@ pub(super) fn simple_op(name: &str) -> Option<Op> {
|
||||
"oct" => Op::Oct,
|
||||
"clear" => Op::ClearCmd,
|
||||
".." => Op::IntRange,
|
||||
".," => Op::StepRange,
|
||||
"gen" => Op::Generate,
|
||||
"geom.." => Op::GeomRange,
|
||||
"times" => Op::Times,
|
||||
|
||||
@@ -123,6 +123,66 @@ pub(super) const WORDS: &[Word] = &[
|
||||
compile: Simple,
|
||||
varargs: false,
|
||||
},
|
||||
Word {
|
||||
name: "rev",
|
||||
aliases: &[],
|
||||
category: "Stack",
|
||||
stack: "(..n n -- ..n)",
|
||||
desc: "Reverse top n items",
|
||||
example: "1 2 3 3 rev => 3 2 1",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "shuffle",
|
||||
aliases: &[],
|
||||
category: "Stack",
|
||||
stack: "(..n n -- ..n)",
|
||||
desc: "Randomly shuffle top n items",
|
||||
example: "1 2 3 3 shuffle",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "sort",
|
||||
aliases: &[],
|
||||
category: "Stack",
|
||||
stack: "(..n n -- ..n)",
|
||||
desc: "Sort top n items ascending",
|
||||
example: "3 1 2 3 sort => 1 2 3",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "rsort",
|
||||
aliases: &[],
|
||||
category: "Stack",
|
||||
stack: "(..n n -- ..n)",
|
||||
desc: "Sort top n items descending",
|
||||
example: "1 2 3 3 rsort => 3 2 1",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "sum",
|
||||
aliases: &[],
|
||||
category: "Stack",
|
||||
stack: "(..n n -- total)",
|
||||
desc: "Sum top n items",
|
||||
example: "1 2 3 3 sum => 6",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
Word {
|
||||
name: "prod",
|
||||
aliases: &[],
|
||||
category: "Stack",
|
||||
stack: "(..n n -- product)",
|
||||
desc: "Multiply top n items",
|
||||
example: "2 3 4 3 prod => 24",
|
||||
compile: Simple,
|
||||
varargs: true,
|
||||
},
|
||||
// Arithmetic
|
||||
Word {
|
||||
name: "+",
|
||||
|
||||
@@ -390,6 +390,16 @@ pub(super) const WORDS: &[Word] = &[
|
||||
compile: Simple,
|
||||
varargs: false,
|
||||
},
|
||||
Word {
|
||||
name: ".,",
|
||||
aliases: &[],
|
||||
category: "Generator",
|
||||
stack: "(start end step -- start start+step ...)",
|
||||
desc: "Push arithmetic sequence with custom step",
|
||||
example: "0 1 0.25 ., => 0 0.25 0.5 0.75 1",
|
||||
compile: Simple,
|
||||
varargs: false,
|
||||
},
|
||||
Word {
|
||||
name: "gen",
|
||||
aliases: &[],
|
||||
|
||||
Reference in New Issue
Block a user