Again
This commit is contained in:
@@ -2,12 +2,14 @@ use parking_lot::Mutex;
|
||||
use rand::rngs::StdRng;
|
||||
use rand::{Rng as RngTrait, SeedableRng};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
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,
|
||||
};
|
||||
|
||||
pub struct Forth {
|
||||
@@ -38,7 +40,9 @@ impl Forth {
|
||||
}
|
||||
|
||||
pub fn evaluate(&self, script: &str, ctx: &StepContext) -> Result<Vec<String>, String> {
|
||||
self.evaluate_impl(script, ctx, None)
|
||||
let (outputs, var_writes) = self.evaluate_impl(script, ctx, None)?;
|
||||
self.apply_var_writes(var_writes);
|
||||
Ok(outputs)
|
||||
}
|
||||
|
||||
pub fn evaluate_with_trace(
|
||||
@@ -47,15 +51,37 @@ impl Forth {
|
||||
ctx: &StepContext,
|
||||
trace: &mut ExecutionTrace,
|
||||
) -> Result<Vec<String>, String> {
|
||||
let (outputs, var_writes) = self.evaluate_impl(script, ctx, Some(trace))?;
|
||||
self.apply_var_writes(var_writes);
|
||||
Ok(outputs)
|
||||
}
|
||||
|
||||
pub fn evaluate_raw(
|
||||
&self,
|
||||
script: &str,
|
||||
ctx: &StepContext,
|
||||
trace: &mut ExecutionTrace,
|
||||
) -> Result<(Vec<String>, HashMap<String, Value>), String> {
|
||||
self.evaluate_impl(script, ctx, Some(trace))
|
||||
}
|
||||
|
||||
fn apply_var_writes(&self, writes: HashMap<String, Value>) {
|
||||
if writes.is_empty() {
|
||||
return;
|
||||
}
|
||||
let mut new_vars = (**self.vars.load()).clone();
|
||||
for (k, v) in writes {
|
||||
new_vars.insert(k, v);
|
||||
}
|
||||
self.vars.store(Arc::new(new_vars));
|
||||
}
|
||||
|
||||
fn evaluate_impl(
|
||||
&self,
|
||||
script: &str,
|
||||
ctx: &StepContext,
|
||||
trace: Option<&mut ExecutionTrace>,
|
||||
) -> Result<Vec<String>, String> {
|
||||
) -> Result<(Vec<String>, HashMap<String, Value>), String> {
|
||||
if script.trim().is_empty() {
|
||||
return Err("empty script".into());
|
||||
}
|
||||
@@ -69,14 +95,25 @@ impl Forth {
|
||||
ops: &[Op],
|
||||
ctx: &StepContext,
|
||||
trace: Option<&mut ExecutionTrace>,
|
||||
) -> Result<Vec<String>, String> {
|
||||
) -> Result<(Vec<String>, HashMap<String, Value>), String> {
|
||||
let mut stack = self.stack.lock();
|
||||
let mut outputs: Vec<String> = Vec::with_capacity(8);
|
||||
let mut cmd = CmdRegister::new();
|
||||
let vars_snapshot = self.vars.load();
|
||||
let mut var_writes: HashMap<String, Value> = HashMap::new();
|
||||
|
||||
self.execute_ops(ops, ctx, &mut stack, &mut outputs, &mut cmd, trace)?;
|
||||
self.execute_ops(
|
||||
ops,
|
||||
ctx,
|
||||
&mut stack,
|
||||
&mut outputs,
|
||||
&mut cmd,
|
||||
trace,
|
||||
&vars_snapshot,
|
||||
&mut var_writes,
|
||||
)?;
|
||||
|
||||
Ok(outputs)
|
||||
Ok((outputs, var_writes))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
@@ -89,9 +126,12 @@ impl Forth {
|
||||
outputs: &mut Vec<String>,
|
||||
cmd: &mut CmdRegister,
|
||||
trace: Option<&mut ExecutionTrace>,
|
||||
vars_snapshot: &VariablesMap,
|
||||
var_writes: &mut HashMap<String, Value>,
|
||||
) -> Result<(), String> {
|
||||
let mut pc = 0;
|
||||
let trace_cell = std::cell::RefCell::new(trace);
|
||||
let var_writes_cell = std::cell::RefCell::new(Some(var_writes));
|
||||
|
||||
let run_quotation = |quot: Value,
|
||||
stack: &mut Vec<Value>,
|
||||
@@ -106,6 +146,8 @@ impl Forth {
|
||||
}
|
||||
}
|
||||
let mut trace_opt = trace_cell.borrow_mut().take();
|
||||
let mut var_writes_guard = var_writes_cell.borrow_mut();
|
||||
let vw = var_writes_guard.as_mut().expect("var_writes taken");
|
||||
self.execute_ops(
|
||||
"_ops,
|
||||
ctx,
|
||||
@@ -113,7 +155,10 @@ impl Forth {
|
||||
outputs,
|
||||
cmd,
|
||||
trace_opt.as_deref_mut(),
|
||||
vars_snapshot,
|
||||
vw,
|
||||
)?;
|
||||
drop(var_writes_guard);
|
||||
*trace_cell.borrow_mut() = trace_opt;
|
||||
Ok(())
|
||||
}
|
||||
@@ -475,15 +520,25 @@ impl Forth {
|
||||
Op::Get => {
|
||||
let name = stack.pop().ok_or("stack underflow")?;
|
||||
let name = name.as_str()?;
|
||||
let vars = self.vars.lock();
|
||||
let val = vars.get(name).cloned().unwrap_or(Value::Int(0, None));
|
||||
let vw = var_writes_cell.borrow();
|
||||
let vw_ref = vw.as_ref().expect("var_writes taken");
|
||||
let val = vw_ref
|
||||
.get(name)
|
||||
.or_else(|| vars_snapshot.get(name))
|
||||
.cloned()
|
||||
.unwrap_or(Value::Int(0, None));
|
||||
drop(vw);
|
||||
stack.push(val);
|
||||
}
|
||||
Op::Set => {
|
||||
let name = stack.pop().ok_or("stack underflow")?;
|
||||
let name = name.as_str()?.to_string();
|
||||
let val = stack.pop().ok_or("stack underflow")?;
|
||||
self.vars.lock().insert(name, val);
|
||||
var_writes_cell
|
||||
.borrow_mut()
|
||||
.as_mut()
|
||||
.expect("var_writes taken")
|
||||
.insert(name, val);
|
||||
}
|
||||
|
||||
Op::GetContext(name) => {
|
||||
@@ -710,16 +765,20 @@ impl Forth {
|
||||
Op::SetTempo => {
|
||||
let tempo = stack.pop().ok_or("stack underflow")?.as_float()?;
|
||||
let clamped = tempo.clamp(20.0, 300.0);
|
||||
self.vars
|
||||
.lock()
|
||||
var_writes_cell
|
||||
.borrow_mut()
|
||||
.as_mut()
|
||||
.expect("var_writes taken")
|
||||
.insert("__tempo__".to_string(), Value::Float(clamped, None));
|
||||
}
|
||||
|
||||
Op::SetSpeed => {
|
||||
let speed = stack.pop().ok_or("stack underflow")?.as_float()?;
|
||||
let clamped = speed.clamp(0.125, 8.0);
|
||||
self.vars
|
||||
.lock()
|
||||
var_writes_cell
|
||||
.borrow_mut()
|
||||
.as_mut()
|
||||
.expect("var_writes taken")
|
||||
.insert(ctx.speed_key.to_string(), Value::Float(clamped, None));
|
||||
}
|
||||
|
||||
@@ -735,7 +794,11 @@ impl Forth {
|
||||
use std::fmt::Write;
|
||||
let mut val = String::with_capacity(8);
|
||||
let _ = write!(&mut val, "{bank}:{pattern}");
|
||||
self.vars.lock().insert(ctx.chain_key.to_string(), Value::Str(Arc::from(val), None));
|
||||
var_writes_cell
|
||||
.borrow_mut()
|
||||
.as_mut()
|
||||
.expect("var_writes taken")
|
||||
.insert(ctx.chain_key.to_string(), Value::Str(Arc::from(val), None));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -849,8 +912,10 @@ impl Forth {
|
||||
return Err("times count must be >= 0".into());
|
||||
}
|
||||
for i in 0..count {
|
||||
self.vars
|
||||
.lock()
|
||||
var_writes_cell
|
||||
.borrow_mut()
|
||||
.as_mut()
|
||||
.expect("var_writes taken")
|
||||
.insert("i".to_string(), Value::Int(i, None));
|
||||
run_quotation(quot.clone(), stack, outputs, cmd)?;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user