diff --git a/src/block_compiler.rs b/src/block_compiler.rs index e81d3ef..37cff2f 100644 --- a/src/block_compiler.rs +++ b/src/block_compiler.rs @@ -72,13 +72,10 @@ impl ASTNodeRef { } } -type BlkASTRef = Rc>; +type BlkASTRef = Rc; #[derive(Debug, Clone)] enum BlkASTNode { - Root { - child: BlkASTRef, - }, Area { childs: Vec, }, @@ -88,13 +85,11 @@ enum BlkASTNode { }, Get { id: usize, - use_count: usize, var: String, }, Node { id: usize, out: Option, - use_count: usize, typ: String, lbl: String, childs: Vec<(Option, BlkASTRef)>, @@ -115,60 +110,53 @@ impl BlkASTNode { } match self { - BlkASTNode::Root { child } => { - format!("{}Root\n", indent_str) + &child.borrow().dump(indent + 1, None) - } BlkASTNode::Area { childs } => { let mut s = format!("{}Area\n", indent_str); for c in childs.iter() { - s += &c.borrow().dump(indent + 1, None); + s += &c.dump(indent + 1, None); } s } BlkASTNode::Set { var, expr } => { - format!("{}set '{}'=\n", indent_str, var) + &expr.borrow().dump(indent + 1, None) + format!("{}set '{}'=\n", indent_str, var) + &expr.dump(indent + 1, None) } - BlkASTNode::Get { id, use_count, var } => { - format!("{}get '{}' (id={}, use={})\n", indent_str, var, id, use_count) + BlkASTNode::Get { id, var } => { + format!("{}get '{}' (id={})\n", indent_str, var, id) } BlkASTNode::Literal { value } => { format!("{}{}\n", indent_str, value) } - BlkASTNode::Node { id, out, use_count, typ, lbl, childs } => { + BlkASTNode::Node { id, out, typ, lbl, childs } => { let lbl = if *typ == *lbl { "".to_string() } else { format!("[{}]", lbl) }; let mut s = if let Some(out) = out { - format!("{}{}{} (id={}/{}, use={})\n", indent_str, typ, lbl, id, out, use_count) + format!("{}{}{} (id={}/{})\n", indent_str, typ, lbl, id, out) } else { - format!("{}{}{} (id={}, use={})\n", indent_str, typ, lbl, id, use_count) + format!("{}{}{} (id={})\n", indent_str, typ, lbl, id) }; for (inp, c) in childs.iter() { - s += &format!("{}", c.borrow().dump(indent + 1, inp.as_ref().map(|s| &s[..]))); + s += &format!("{}", c.dump(indent + 1, inp.as_ref().map(|s| &s[..]))); } s } } } - pub fn new_root(child: BlkASTRef) -> BlkASTRef { - Rc::new(RefCell::new(BlkASTNode::Root { child })) - } - pub fn new_area(childs: Vec) -> BlkASTRef { - Rc::new(RefCell::new(BlkASTNode::Area { childs })) + Rc::new(BlkASTNode::Area { childs }) } pub fn new_set(var: &str, expr: BlkASTRef) -> BlkASTRef { - Rc::new(RefCell::new(BlkASTNode::Set { var: var.to_string(), expr })) + Rc::new(BlkASTNode::Set { var: var.to_string(), expr }) } pub fn new_get(id: usize, var: &str) -> BlkASTRef { - Rc::new(RefCell::new(BlkASTNode::Get { id, var: var.to_string(), use_count: 1 })) + Rc::new(BlkASTNode::Get { id, var: var.to_string() }) } pub fn new_literal(val: &str) -> Result { if let Ok(value) = val.parse::() { - Ok(Rc::new(RefCell::new(BlkASTNode::Literal { value }))) + Ok(Rc::new(BlkASTNode::Literal { value })) } else { Err(BlkJITCompileError::BadLiteralNumber(val.to_string())) } @@ -181,14 +169,13 @@ impl BlkASTNode { lbl: &str, childs: Vec<(Option, BlkASTRef)>, ) -> BlkASTRef { - Rc::new(RefCell::new(BlkASTNode::Node { + Rc::new(BlkASTNode::Node { id, out, typ: typ.to_string(), lbl: lbl.to_string(), - use_count: 1, childs, - })) + }) } } @@ -236,26 +223,6 @@ impl Block2JITCompiler { node: &ASTNodeRef, my_out: Option, ) -> Result { - // TODO: Deal with multiple outputs. - // If we encounter a node with multiple outputs, assign each output - // to a temporary variable and save that. - // Store the name of the temporary in a id+output mapping. - // => XXX - // That means: If we have a single output, things are easy, just plug them into - // the JIT ast: - // outer(inner()) - // But if we have multiple outputs: - // assign(a = inner()) - // assign(b = %1) - // outer_x(a) - // outer_y(b) - - // TODO: Filter out -> nodes from the AST - // TODO: For ->2 and ->3, save the input in some variable - // and reserve a id+output variable for this. - - // XXX: SSA form of cranelift should take care of the rest! - let id = node.0.borrow().id; if let Some(out) = &my_out { @@ -394,13 +361,40 @@ impl Block2JITCompiler { } } - pub fn compile(&mut self, fun: &BlockFun) -> Result { + pub fn bjit2jit(&mut self, ast: &BlkASTRef) -> Result, BlkJITCompileError> { + use synfx_dsp_jit::build::*; + + match &**ast { + BlkASTNode::Area { childs } => { + let mut stmt = vec![]; + for c in childs.iter() { + stmt.push(self.bjit2jit(&c)?); + } + Ok(stmts(&stmt[..])) + }, + BlkASTNode::Set { var, expr } => { + let e = self.bjit2jit(&expr)?; + Ok(assign(var, e)) + } + BlkASTNode::Get { id, var: varname } => { + Ok(var(varname)) + }, + BlkASTNode::Node { id, out, typ, lbl, childs } => { + Err(BlkJITCompileError::UnknownError) + } + BlkASTNode::Literal { value } => { + Ok(literal(*value)) + } + } + } + + pub fn compile(&mut self, fun: &BlockFun) -> Result, BlkJITCompileError> { let tree = fun.generate_tree::("zero").unwrap(); println!("{}", tree.walk_dump("", "", 0)); - let blkast = self.trans2bjit(&tree, None); - println!("R: {}", blkast.unwrap().borrow().dump(0, None)); + let blkast = self.trans2bjit(&tree, None)?; + println!("R: {}", blkast.dump(0, None)); - Err(BlkJITCompileError::UnknownError) + self.bjit2jit(&blkast) } } diff --git a/src/dsp/node_code.rs b/src/dsp/node_code.rs index 44278c6..005d62a 100644 --- a/src/dsp/node_code.rs +++ b/src/dsp/node_code.rs @@ -110,6 +110,7 @@ impl DspNode for Code { for frame in 0..ctx.nframes() { let (s1, s2, ret) = backend.process(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + println!("OUT: {}", ret); out.write(frame, ret); } diff --git a/src/matrix.rs b/src/matrix.rs index 26a70b8..b592fca 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -11,6 +11,7 @@ use crate::nodes::{NodeConfigurator, NodeGraphOrdering, NodeProg, MAX_ALLOCATED_ pub use crate::CellDir; use crate::ScopeHandle; use crate::blocklang::BlockFun; +use crate::block_compiler::BlkJITCompileError; use std::collections::{HashMap, HashSet}; @@ -600,7 +601,7 @@ impl Matrix { /// Checks the block function for the id `id`. If the block function did change, /// updates are then sent to the audio thread. /// See also [get_block_function]. - pub fn check_block_function(&mut self, id: usize) { + pub fn check_block_function(&mut self, id: usize) -> Result<(), BlkJITCompileError> { self.config.check_block_function(id) } diff --git a/src/nodes/node_conf.rs b/src/nodes/node_conf.rs index 8f59084..55217b2 100644 --- a/src/nodes/node_conf.rs +++ b/src/nodes/node_conf.rs @@ -8,7 +8,7 @@ use super::{ }; use crate::blocklang::*; use crate::blocklang_def; -use crate::block_compiler::Block2JITCompiler; +use crate::block_compiler::{Block2JITCompiler, BlkJITCompileError}; use crate::dsp::tracker::{PatternData, Tracker}; use crate::dsp::{node_factory, Node, NodeId, NodeInfo, ParamId, SAtom}; use crate::monitor::{new_monitor_processor, MinMaxMonitorSamples, Monitor, MON_SIG_CNT}; @@ -695,33 +695,36 @@ impl NodeConfigurator { /// Checks the block function for the id `id`. If the block function did change, /// updates are then sent to the audio thread. /// See also [get_block_function]. - pub fn check_block_function(&mut self, id: usize) { + pub fn check_block_function(&mut self, id: usize) -> Result<(), BlkJITCompileError> { if let Some((generation, block_fun)) = self.block_functions.get_mut(id) { if let Ok(block_fun) = block_fun.lock() { if *generation != block_fun.generation() { *generation = block_fun.generation(); let mut compiler = Block2JITCompiler::new(block_fun.block_language()); - compiler.compile(&block_fun); + let ast = compiler.compile(&block_fun)?; // let ast = block_compiler::compile(block_fun); if let Some(cod) = self.code_engines.get_mut(id) { use synfx_dsp_jit::build::*; - cod.upload(stmts(&[ - assign( - "*phase", - op_add(var("*phase"), op_mul(literal(440.0), var("israte"))), - ), - _if( - op_gt(var("*phase"), literal(1.0)), - assign("*phase", op_sub(var("*phase"), literal(1.0))), - None, - ), - var("*phase"), - ])); + cod.upload(ast); +// stmts(&[ +// assign( +// "*phase", +// op_add(var("*phase"), op_mul(literal(440.0), var("israte"))), +// ), +// _if( +// op_gt(var("*phase"), literal(1.0)), +// assign("*phase", op_sub(var("*phase"), literal(1.0))), +// None, +// ), +// var("*phase"), +// ])); } } } } + + Ok(()) } /// Retrieve a handle to the block function `id`. In case you modify the block function, diff --git a/tests/blocklang.rs b/tests/blocklang.rs index d83ab96..278eb50 100644 --- a/tests/blocklang.rs +++ b/tests/blocklang.rs @@ -5,9 +5,8 @@ mod common; use common::*; -#[test] -fn check_blocklang_1() { - let (node_conf, mut node_exec) = new_node_engine(); +fn setup() -> (Matrix, NodeExecutor) { + let (node_conf, node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); let mut chain = MatrixCellChain::new(CellDir::B); @@ -20,7 +19,45 @@ fn check_blocklang_1() { .unwrap(); matrix.sync().unwrap(); - let code = NodeId::Code(0); + (matrix, node_exec) +} + +#[test] +fn check_blocklang_1() { + let (mut matrix, mut node_exec) = setup(); + + let block_fun = matrix.get_block_function(0).expect("block fun exists"); + { + let mut block_fun = block_fun.lock().expect("matrix lock"); + block_fun.instanciate_at(0, 0, 1, "value", Some("0.3".to_string())); +// block_fun.instanciate_at(0, 1, 1, "set", Some("&sig1".to_string())); + } + + matrix.check_block_function(0).expect("no compile error"); + + let res = run_for_ms(&mut node_exec, 25.0); + println!("RES: {:?}", res.1); + assert_decimated_feq!( + res.0, + 50, + vec![ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + ] + ); +} +#[test] +fn check_blocklang_2() { + let (mut matrix, mut node_exec) = setup(); let block_fun = matrix.get_block_function(0).expect("block fun exists"); { @@ -55,7 +92,7 @@ fn check_blocklang_1() { block_fun.instanciate_at(0, 4, 4, "set", Some("*ap".to_string())); } - matrix.check_block_function(0); + matrix.check_block_function(0).expect("no compile error"); let res = run_for_ms(&mut node_exec, 25.0); assert_decimated_feq!(