This commit is contained in:
2026-01-22 10:08:05 +01:00
parent 409e815414
commit 88b6f64a72
10 changed files with 43268 additions and 388 deletions

View File

@@ -17,7 +17,6 @@ pub struct ExecutionTrace {
pub struct StepContext {
pub step: usize,
pub beat: f64,
pub bank: usize,
pub pattern: usize,
pub tempo: f64,
pub phase: f64,
@@ -1751,7 +1750,7 @@ fn parse_interval(name: &str) -> Option<i64> {
Some(simple)
}
fn compile_word(name: &str, ops: &mut Vec<Op>) -> bool {
fn compile_word(name: &str, span: Option<SourceSpan>, ops: &mut Vec<Op>) -> bool {
for word in WORDS {
if word.name == name {
match &word.compile {
@@ -1762,7 +1761,7 @@ fn compile_word(name: &str, ops: &mut Vec<Op>) -> bool {
}
Context(ctx) => ops.push(Op::GetContext((*ctx).into())),
Param => ops.push(Op::SetParam(name.into())),
Alias(target) => return compile_word(target, ops),
Alias(target) => return compile_word(target, span, ops),
Probability(p) => {
ops.push(Op::PushFloat(*p, None));
ops.push(Op::ChanceExec);
@@ -1775,7 +1774,7 @@ fn compile_word(name: &str, ops: &mut Vec<Op>) -> bool {
// @varname - fetch variable
if let Some(var_name) = name.strip_prefix('@') {
if !var_name.is_empty() {
ops.push(Op::PushStr(var_name.to_string(), None));
ops.push(Op::PushStr(var_name.to_string(), span));
ops.push(Op::Get);
return true;
}
@@ -1784,7 +1783,7 @@ fn compile_word(name: &str, ops: &mut Vec<Op>) -> bool {
// !varname - store into variable
if let Some(var_name) = name.strip_prefix('!') {
if !var_name.is_empty() {
ops.push(Op::PushStr(var_name.to_string(), None));
ops.push(Op::PushStr(var_name.to_string(), span));
ops.push(Op::Set);
return true;
}
@@ -1792,14 +1791,14 @@ fn compile_word(name: &str, ops: &mut Vec<Op>) -> bool {
// Note names: c4, c#4, cs4, eb4, etc. -> MIDI number
if let Some(midi) = parse_note_name(name) {
ops.push(Op::PushInt(midi, None));
ops.push(Op::PushInt(midi, span));
return true;
}
// Intervals: m3, M3, P5, etc. -> dup top, add semitones (for chord building)
if let Some(semitones) = parse_interval(name) {
ops.push(Op::Dup);
ops.push(Op::PushInt(semitones, None));
ops.push(Op::PushInt(semitones, span));
ops.push(Op::Add);
return true;
}
@@ -1827,8 +1826,8 @@ enum Token {
Float(f64, SourceSpan),
Str(String, SourceSpan),
Word(String, SourceSpan),
QuoteStart(SourceSpan),
QuoteEnd(SourceSpan),
QuoteStart,
QuoteEnd,
}
fn tokenize(input: &str) -> Vec<Token> {
@@ -1869,22 +1868,14 @@ fn tokenize(input: &str) -> Vec<Token> {
}
if c == '{' {
let start = pos;
chars.next();
tokens.push(Token::QuoteStart(SourceSpan {
start,
end: start + 1,
}));
tokens.push(Token::QuoteStart);
continue;
}
if c == '}' {
let start = pos;
chars.next();
tokens.push(Token::QuoteEnd(SourceSpan {
start,
end: start + 1,
}));
tokens.push(Token::QuoteEnd);
continue;
}
@@ -1923,15 +1914,15 @@ fn compile(tokens: &[Token]) -> Result<Vec<Op>, String> {
Token::Int(n, span) => ops.push(Op::PushInt(*n, Some(*span))),
Token::Float(f, span) => ops.push(Op::PushFloat(*f, Some(*span))),
Token::Str(s, span) => ops.push(Op::PushStr(s.clone(), Some(*span))),
Token::QuoteStart(_) => {
Token::QuoteStart => {
let (quote_ops, consumed) = compile_quotation(&tokens[i + 1..])?;
i += consumed;
ops.push(Op::Quotation(quote_ops));
}
Token::QuoteEnd(_) => {
Token::QuoteEnd => {
return Err("unexpected }".into());
}
Token::Word(w, _) => {
Token::Word(w, span) => {
let word = w.as_str();
if word == "|" {
if pipe_parity {
@@ -1952,7 +1943,7 @@ fn compile(tokens: &[Token]) -> Result<Vec<Op>, String> {
ops.push(Op::Branch(else_ops.len()));
ops.extend(else_ops);
}
} else if !compile_word(word, &mut ops) {
} else if !compile_word(word, Some(*span), &mut ops) {
return Err(format!("unknown word: {word}"));
}
}
@@ -1969,8 +1960,8 @@ fn compile_quotation(tokens: &[Token]) -> Result<(Vec<Op>, usize), String> {
for (i, tok) in tokens.iter().enumerate() {
match tok {
Token::QuoteStart(_) => depth += 1,
Token::QuoteEnd(_) => {
Token::QuoteStart => depth += 1,
Token::QuoteEnd => {
depth -= 1;
if depth == 0 {
end_pos = Some(i);
@@ -2039,10 +2030,12 @@ impl Forth {
}
}
#[allow(dead_code)]
pub fn stack(&self) -> Vec<Value> {
self.stack.lock().unwrap().clone()
}
#[allow(dead_code)]
pub fn clear_stack(&self) {
self.stack.lock().unwrap().clear();
}
@@ -2104,6 +2097,7 @@ impl Forth {
Ok(outputs)
}
#[allow(clippy::too_many_arguments)]
fn execute_ops(
&self,
ops: &[Op],