Feat: lots of improvements
Some checks failed
Deploy Website / deploy (push) Failing after 4m49s

This commit is contained in:
2026-02-08 13:52:40 +01:00
parent d6bbae173b
commit bc5d12e53a
34 changed files with 333 additions and 123 deletions

View File

@@ -8,8 +8,8 @@ use std::sync::Arc;
use super::compiler::compile_script;
use super::ops::Op;
use super::types::{
CmdRegister, Dictionary, ExecutionTrace, Rng, Stack, StepContext, Value, Variables,
VariablesMap,
CmdRegister, Dictionary, ExecutionTrace, ResolvedValue, Rng, SourceSpan, Stack, StepContext,
Value, Variables, VariablesMap,
};
pub struct Forth {
@@ -637,7 +637,7 @@ impl Forth {
stack.push(val);
}
Op::Rand => {
Op::Rand(word_span) => {
let b = stack.pop().ok_or("stack underflow")?;
let a = stack.pop().ok_or("stack underflow")?;
match (&a, &b) {
@@ -648,6 +648,7 @@ impl Forth {
(*b_i, *a_i)
};
let val = self.rng.lock().gen_range(lo..=hi);
record_resolved(&trace_cell, *word_span, ResolvedValue::Int(val));
stack.push(Value::Int(val, None));
}
_ => {
@@ -659,11 +660,12 @@ impl Forth {
} else {
self.rng.lock().gen_range(lo..hi)
};
record_resolved(&trace_cell, *word_span, ResolvedValue::Float(val));
stack.push(Value::Float(val, None));
}
}
}
Op::ExpRand => {
Op::ExpRand(word_span) => {
let hi = stack.pop().ok_or("stack underflow")?.as_float()?;
let lo = stack.pop().ok_or("stack underflow")?.as_float()?;
if lo <= 0.0 || hi <= 0.0 {
@@ -672,9 +674,10 @@ impl Forth {
let (lo, hi) = if lo <= hi { (lo, hi) } else { (hi, lo) };
let u: f64 = self.rng.lock().gen();
let val = lo * (hi / lo).powf(u);
record_resolved(&trace_cell, *word_span, ResolvedValue::Float(val));
stack.push(Value::Float(val, None));
}
Op::LogRand => {
Op::LogRand(word_span) => {
let hi = stack.pop().ok_or("stack underflow")?.as_float()?;
let lo = stack.pop().ok_or("stack underflow")?.as_float()?;
if lo <= 0.0 || hi <= 0.0 {
@@ -683,6 +686,7 @@ impl Forth {
let (lo, hi) = if lo <= hi { (lo, hi) } else { (hi, lo) };
let u: f64 = self.rng.lock().gen();
let val = hi * (lo / hi).powf(u);
record_resolved(&trace_cell, *word_span, ResolvedValue::Float(val));
stack.push(Value::Float(val, None));
}
Op::Seed => {
@@ -690,28 +694,42 @@ impl Forth {
*self.rng.lock() = StdRng::seed_from_u64(s as u64);
}
Op::Cycle | Op::PCycle => {
Op::Cycle(word_span) | Op::PCycle(word_span) => {
let count = stack.pop().ok_or("stack underflow")?.as_int()? as usize;
if count == 0 {
return Err("cycle count must be > 0".into());
}
let idx = match &ops[pc] {
Op::Cycle => ctx.runs,
Op::Cycle(_) => ctx.runs,
_ => ctx.iter,
} % count;
if let Some(span) = word_span {
if stack.len() >= count {
let start = stack.len() - count;
let selected = &stack[start + idx];
record_resolved_from_value(&trace_cell, Some(*span), selected);
}
}
drain_select_run(count, idx, stack, outputs, cmd)?;
}
Op::Choose => {
Op::Choose(word_span) => {
let count = stack.pop().ok_or("stack underflow")?.as_int()? as usize;
if count == 0 {
return Err("choose count must be > 0".into());
}
let idx = self.rng.lock().gen_range(0..count);
if let Some(span) = word_span {
if stack.len() >= count {
let start = stack.len() - count;
let selected = &stack[start + idx];
record_resolved_from_value(&trace_cell, Some(*span), selected);
}
}
drain_select_run(count, idx, stack, outputs, cmd)?;
}
Op::Bounce => {
Op::Bounce(word_span) => {
let count = stack.pop().ok_or("stack underflow")?.as_int()? as usize;
if count == 0 {
return Err("bounce count must be > 0".into());
@@ -723,10 +741,17 @@ impl Forth {
let raw = ctx.runs % period;
if raw < count { raw } else { period - raw }
};
if let Some(span) = word_span {
if stack.len() >= count {
let start = stack.len() - count;
let selected = &stack[start + idx];
record_resolved_from_value(&trace_cell, Some(*span), selected);
}
}
drain_select_run(count, idx, stack, outputs, cmd)?;
}
Op::WChoose => {
Op::WChoose(word_span) => {
let count = stack.pop().ok_or("stack underflow")?.as_int()? as usize;
if count == 0 {
return Err("wchoose count must be > 0".into());
@@ -763,25 +788,30 @@ impl Forth {
}
}
let selected = values.swap_remove(selected_idx);
record_resolved_from_value(&trace_cell, *word_span, &selected);
select_and_run(selected, stack, outputs, cmd)?;
}
Op::ChanceExec | Op::ProbExec => {
Op::ChanceExec(word_span) | Op::ProbExec(word_span) => {
let threshold = stack.pop().ok_or("stack underflow")?.as_float()?;
let quot = stack.pop().ok_or("stack underflow")?;
let val: f64 = self.rng.lock().gen();
let limit = match &ops[pc] {
Op::ChanceExec => threshold,
Op::ChanceExec(_) => threshold,
_ => threshold / 100.0,
};
if val < limit {
let fired = val < limit;
record_resolved(&trace_cell, *word_span, ResolvedValue::Bool(fired));
if fired {
run_quotation(quot, stack, outputs, cmd)?;
}
}
Op::Coin => {
Op::Coin(word_span) => {
let val: f64 = self.rng.lock().gen();
stack.push(Value::Int(if val < 0.5 { 1 } else { 0 }, None));
let result = val < 0.5;
record_resolved(&trace_cell, *word_span, ResolvedValue::Bool(result));
stack.push(Value::Int(if result { 1 } else { 0 }, None));
}
Op::Every => {
@@ -1241,6 +1271,36 @@ impl Forth {
}
}
fn record_resolved(
trace_cell: &std::cell::RefCell<Option<&mut ExecutionTrace>>,
span: Option<SourceSpan>,
value: ResolvedValue,
) {
if let Some(span) = span {
if let Some(trace) = trace_cell.borrow_mut().as_mut() {
trace.resolved.push((span, value));
}
}
}
fn record_resolved_from_value(
trace_cell: &std::cell::RefCell<Option<&mut ExecutionTrace>>,
span: Option<SourceSpan>,
value: &Value,
) {
if let Some(span) = span {
let resolved = match value {
Value::Int(i, _) => ResolvedValue::Int(*i),
Value::Float(f, _) => ResolvedValue::Float(*f),
Value::Str(s, _) => ResolvedValue::Str(s.clone()),
_ => return,
};
if let Some(trace) = trace_cell.borrow_mut().as_mut() {
trace.resolved.push((span, resolved));
}
}
}
fn extract_dev_param(params: &[(&str, Value)]) -> u8 {
params
.iter()
@@ -1323,7 +1383,7 @@ fn emit_output(
let _ = write!(&mut out, "delta/{nudge_secs}");
}
if sound.is_some() && !has_dur {
if !has_dur {
if !out.ends_with('/') {
out.push('/');
}