diff --git a/rust/origen_metal/src/ast/node.rs b/rust/origen_metal/src/ast/node.rs index fe3c7446..4c27374c 100644 --- a/rust/origen_metal/src/ast/node.rs +++ b/rust/origen_metal/src/ast/node.rs @@ -3,12 +3,12 @@ use super::processors::ToString; //use crate::{Error, Operation, STATUS}; use crate::ast::processor::{Processor, Return}; use crate::Result; -use std::fmt::{self, Display}; +use std::fmt::{self, Debug, Display}; -pub trait Attrs: Clone + std::cmp::PartialEq + serde::Serialize + Display {} -impl Attrs for T {} +pub trait Attrs: Clone + std::cmp::PartialEq + serde::Serialize + Display + Debug {} +impl Attrs for T {} -#[derive(Clone, PartialEq, Serialize)] +#[derive(Clone, PartialEq, Serialize, Debug)] pub struct Node { pub attrs: T, pub inline: bool, @@ -29,18 +29,23 @@ impl fmt::Display for Node { } } -impl fmt::Debug for Node { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.to_string()) - } -} - impl PartialEq> for Node { fn eq(&self, ast: &AST) -> bool { *self == ast.to_node() } } +enum PostProcessAction { + None, + Unwrap, +} + +enum Handler { + OnNode, + OnEndOfBlock, + OnProcessedNode, +} + impl Node { pub fn new(attrs: T) -> Node { Node { @@ -94,8 +99,184 @@ impl Node { /// Returning None means that the processor has decided that the node should be removed /// from the next stage AST. pub fn process(&self, processor: &mut dyn Processor) -> Result>> { - let r = { processor.on_node(&self)? }; - self.process_return_code(r, processor) + self.process_(processor, Handler::OnNode) + } + + fn process_( + &self, + processor: &mut dyn Processor, + handler: Handler, + ) -> Result>> { + let mut node = self; + let mut open_nodes: Vec<(Node, PostProcessAction)> = vec![]; + let mut to_be_processed: Vec>> = vec![]; + + loop { + let r = { + match handler { + Handler::OnNode => processor.on_node(node)?, + Handler::OnEndOfBlock => processor.on_end_of_block(node)?, + Handler::OnProcessedNode => processor.on_processed_node(node)?, + } + }; + + match r { + // Terminal return codes + Return::None => { + if matches!(handler, Handler::OnProcessedNode) { + return Ok(None); + } + } + Return::Unmodified => { + if matches!(handler, Handler::OnProcessedNode) { + return Ok(Some(node.clone())); + } + open_nodes.push((node.clone(), PostProcessAction::None)); + to_be_processed.push(vec![]); + } + Return::Replace(node) => { + open_nodes.push((node, PostProcessAction::None)); + to_be_processed.push(vec![]); + } + // We can't return multiple nodes from this function, so we return them + // wrapped in a meta-node and the process_children method will identify + // this and remove the wrapper to inline the contained nodes. + Return::Unwrap => { + open_nodes.push(( + Node::inline(node.children.clone(), node.attrs.clone()), + PostProcessAction::None, + )); + to_be_processed.push(vec![]); + } + Return::Inline(nodes) => { + open_nodes.push(( + Node::inline( + nodes.into_iter().map(|n| Box::new(n)).collect(), + node.attrs.clone(), + ), + PostProcessAction::None, + )); + to_be_processed.push(vec![]); + } + Return::InlineBoxed(nodes) => { + open_nodes.push(( + Node::inline(nodes, node.attrs.clone()), + PostProcessAction::None, + )); + to_be_processed.push(vec![]); + } + Return::ReplaceChildren(nodes) => { + open_nodes.push(( + node.replace_unboxed_children(nodes), + PostProcessAction::None, + )); + to_be_processed.push(vec![]); + } + + // Child processing return codes + Return::ProcessChildren => { + open_nodes.push((node.without_children(), PostProcessAction::None)); + let mut children: Vec<&Node> = vec![]; + for child in &node.children { + children.push(child); + } + children.reverse(); + to_be_processed.push(children); + } + + Return::UnwrapWithProcessedChildren => { + open_nodes.push((node.without_children(), PostProcessAction::Unwrap)); + let mut children: Vec<&Node> = vec![]; + for child in &node.children { + children.push(child); + } + children.reverse(); + to_be_processed.push(children); + } + + Return::InlineWithProcessedChildren(nodes) => { + open_nodes.push(( + Node::inline( + nodes.into_iter().map(|n| Box::new(n)).collect(), + node.attrs.clone(), + ), + PostProcessAction::None, + )); + let mut children: Vec<&Node> = vec![]; + for child in &node.children { + children.push(child); + } + children.reverse(); + to_be_processed.push(children); + } + } + + loop { + if !to_be_processed.is_empty() { + let last_group = to_be_processed.last_mut().unwrap(); + if !last_group.is_empty() { + node = last_group.pop().unwrap(); + break; + } + to_be_processed.pop(); + // Just completed all the children of the last open node + let (mut node, action) = open_nodes.pop().unwrap(); + match action { + PostProcessAction::None => {} + PostProcessAction::Unwrap => { + node = Node::inline(node.children, node.attrs); + } + } + + // Call the end of block handler, giving the processor a chance to do any + // internal clean up or inject some more nodes at the end + //if let Some(n) = self.process_(processor, Handler::OnEndOfBlock)? { + // if n.inline { + // for c in n.children { + // node.add_child(*c); + // } + // } else { + // node.add_child(n); + // } + //} + + if matches!(handler, Handler::OnNode) { + if let Some(n) = node.process_(processor, Handler::OnProcessedNode)? { + node = n; + } else { + continue; + } + } + + if open_nodes.is_empty() { + if node.inline && node.children.len() == 1 { + return Ok(Some(*node.children[0].clone())); + } else { + return Ok(Some(node)); + } + } else { + let (parent, _) = open_nodes.last_mut().unwrap(); + if node.inline { + for c in node.children { + parent.add_child(*c); + } + } else { + parent.add_child(node); + } + } + } else { + if open_nodes.is_empty() { + return Ok(None); + } else if open_nodes.len() == 1 { + return Ok(Some(open_nodes.pop().unwrap().0)); + } else { + bail!( + "Internal error: open_nodes should be empty or have a single node left" + ) + } + } + } + } } fn inline(nodes: Vec>>, example_attrs: T) -> Node { @@ -222,49 +403,6 @@ impl Node { } } - pub fn process_return_code( - &self, - code: Return, - processor: &mut dyn Processor, - ) -> Result>> { - match code { - Return::None => Ok(None), - Return::ProcessChildren => Ok(Some(self.process_and_update_children(processor)?)), - Return::Unmodified => Ok(Some(self.clone())), - Return::Replace(node) => Ok(Some(node)), - // We can't return multiple nodes from this function, so we return them - // wrapped in a meta-node and the process_children method will identify - // this and remove the wrapper to inline the contained nodes. - Return::Unwrap => Ok(Some(Node::inline( - self.children.clone(), - self.attrs.clone(), - ))), - Return::Inline(nodes) => Ok(Some(Node::inline( - nodes.into_iter().map(|n| Box::new(n)).collect(), - self.attrs.clone(), - ))), - Return::InlineBoxed(nodes) => Ok(Some(Node::inline(nodes, self.attrs.clone()))), - Return::UnwrapWithProcessedChildren => { - let nodes = self.process_children(processor)?; - Ok(Some(Node::inline( - nodes.into_iter().map(|n| Box::new(n)).collect(), - self.attrs.clone(), - ))) - } - Return::InlineWithProcessedChildren(mut nodes) => { - nodes.append(&mut self.process_children(processor)?); - Ok(Some(Node::inline( - nodes.into_iter().map(|n| Box::new(n)).collect(), - self.attrs.clone(), - ))) - } - Return::ReplaceChildren(nodes) => { - let new_node = self.replace_unboxed_children(nodes); - Ok(Some(new_node)) - } - } - } - /// Returns a new node which is a copy of self with its children replaced /// by their processed counterparts. pub fn process_and_update_children(&self, processor: &mut dyn Processor) -> Result> { @@ -293,8 +431,7 @@ impl Node { } // Call the end of block handler, giving the processor a chance to do any // internal clean up or inject some more nodes at the end - let r = processor.on_end_of_block(&self)?; - if let Some(node) = self.process_return_code(r, processor)? { + if let Some(node) = self.process_(processor, Handler::OnEndOfBlock)? { if node.inline { for c in node.children { nodes.push(c); @@ -322,8 +459,7 @@ impl Node { } // Call the end of block handler, giving the processor a chance to do any // internal clean up or inject some more nodes at the end - let r = processor.on_end_of_block(&self)?; - if let Some(node) = self.process_return_code(r, processor)? { + if let Some(node) = self.process_(processor, Handler::OnEndOfBlock)? { if node.inline { for c in node.children { nodes.push(*c); diff --git a/rust/origen_metal/src/ast/processor.rs b/rust/origen_metal/src/ast/processor.rs index 7cca20b9..0230eb4d 100644 --- a/rust/origen_metal/src/ast/processor.rs +++ b/rust/origen_metal/src/ast/processor.rs @@ -49,4 +49,8 @@ pub trait Processor { fn on_end_of_block(&mut self, _node: &Node) -> Result> { Ok(Return::None) } + + fn on_processed_node(&mut self, _node: &Node) -> Result> { + Ok(Return::Unmodified) + } } diff --git a/rust/origen_metal/src/ast/processors/to_string.rs b/rust/origen_metal/src/ast/processors/to_string.rs index cc938723..6f64ae05 100644 --- a/rust/origen_metal/src/ast/processors/to_string.rs +++ b/rust/origen_metal/src/ast/processors/to_string.rs @@ -29,8 +29,11 @@ impl Processor for ToString { self.output += &" ".repeat(self.indent); self.output += &format!("{}\n", node.attrs); self.indent += 4; - node.process_children(self)?; + Ok(Return::ProcessChildren) + } + + fn on_processed_node(&mut self, _node: &Node) -> Result> { self.indent -= 4; - Ok(Return::Unmodified) + Ok(Return::None) } } diff --git a/rust/origen_metal/src/stil/nodes.rs b/rust/origen_metal/src/stil/nodes.rs index 8eb92f99..9449e29e 100644 --- a/rust/origen_metal/src/stil/nodes.rs +++ b/rust/origen_metal/src/stil/nodes.rs @@ -1,6 +1,6 @@ use crate::stil; -#[derive(Clone, Debug, PartialEq, Serialize)] +#[derive(Clone, PartialEq, Serialize, Debug)] pub enum STIL { Root, SourceFile(String), diff --git a/rust/origen_metal/src/stil/processors/time_expr.rs b/rust/origen_metal/src/stil/processors/time_expr.rs index 6da0a1bb..067f2570 100644 --- a/rust/origen_metal/src/stil/processors/time_expr.rs +++ b/rust/origen_metal/src/stil/processors/time_expr.rs @@ -7,7 +7,7 @@ use crate::Result; use std::collections::HashMap; pub struct TimeExpr { - process_children: bool, + time_expr_depth: usize, params: Option>>, } @@ -18,177 +18,175 @@ impl TimeExpr { params: Option>>, ) -> Result> { let mut p = TimeExpr { - process_children: false, + time_expr_depth: 0, params: params, }; Ok(node.process(&mut p)?.unwrap()) } + + fn processing_enabled(&self) -> bool { + self.time_expr_depth > 0 + } } impl Processor for TimeExpr { + fn on_processed_node(&mut self, node: &Node) -> Result> { + let result = match &node.attrs { + STIL::TimeExpr => Return::Unwrap, + STIL::Parens => Return::Unwrap, + STIL::Add => Return::Replace(match &node.children[0].attrs { + STIL::Integer(lhs) => match &node.children[1].attrs { + STIL::Integer(rhs) => node!(STIL::Integer, lhs + rhs), + STIL::Float(rhs) => node!(STIL::Float, *lhs as f64 + rhs), + STIL::String(rhs) => node!(STIL::String, format!("{}+{}", lhs, rhs)), + _ => unreachable!("{:?}", node.children[1]), + }, + STIL::Float(lhs) => match &node.children[1].attrs { + STIL::Integer(rhs) => node!(STIL::Float, lhs + *rhs as f64), + STIL::Float(rhs) => node!(STIL::Float, lhs + rhs), + STIL::String(rhs) => node!(STIL::String, format!("{}+{}", lhs, rhs)), + _ => unreachable!("{:?}", node.children[1]), + }, + STIL::String(lhs) => match &node.children[1].attrs { + STIL::Integer(rhs) => node!(STIL::String, format!("{}+{}", lhs, rhs)), + STIL::Float(rhs) => node!(STIL::String, format!("{}+{}", lhs, rhs)), + STIL::String(rhs) => node!(STIL::String, format!("{}+{}", lhs, rhs)), + _ => unreachable!("{:?}", node.children[1]), + }, + _ => unreachable!("{:?}", node.children[0]), + }), + STIL::Subtract => Return::Replace(match &node.children[0].attrs { + STIL::Integer(lhs) => match &node.children[1].attrs { + STIL::Integer(rhs) => node!(STIL::Integer, lhs - rhs), + STIL::Float(rhs) => node!(STIL::Float, *lhs as f64 - rhs), + STIL::String(rhs) => node!(STIL::String, format!("{}-{}", lhs, rhs)), + _ => unreachable!("{:?}", node.children[1]), + }, + STIL::Float(lhs) => match &node.children[1].attrs { + STIL::Integer(rhs) => node!(STIL::Float, lhs - *rhs as f64), + STIL::Float(rhs) => node!(STIL::Float, lhs - rhs), + STIL::String(rhs) => node!(STIL::String, format!("{}-{}", lhs, rhs)), + _ => unreachable!("{:?}", node.children[1]), + }, + STIL::String(lhs) => match &node.children[1].attrs { + STIL::Integer(rhs) => node!(STIL::String, format!("{}-{}", lhs, rhs)), + STIL::Float(rhs) => node!(STIL::String, format!("{}-{}", lhs, rhs)), + STIL::String(rhs) => node!(STIL::String, format!("{}-{}", lhs, rhs)), + _ => unreachable!("{:?}", node.children[1]), + }, + _ => unreachable!("{:?}", node.children[0]), + }), + STIL::Multiply => Return::Replace(match &node.children[0].attrs { + STIL::Integer(lhs) => match &node.children[1].attrs { + STIL::Integer(rhs) => node!(STIL::Integer, lhs * rhs), + STIL::Float(rhs) => node!(STIL::Float, *lhs as f64 * rhs), + STIL::String(rhs) => node!(STIL::String, format!("{}*{}", lhs, rhs)), + _ => unreachable!("{:?}", node.children[1]), + }, + STIL::Float(lhs) => match &node.children[1].attrs { + STIL::Integer(rhs) => node!(STIL::Float, lhs * *rhs as f64), + STIL::Float(rhs) => node!(STIL::Float, lhs * rhs), + STIL::String(rhs) => node!(STIL::String, format!("{}*{}", lhs, rhs)), + _ => unreachable!("{:?}", node.children[1]), + }, + STIL::String(lhs) => match &node.children[1].attrs { + STIL::Integer(rhs) => node!(STIL::String, format!("{}*{}", lhs, rhs)), + STIL::Float(rhs) => node!(STIL::String, format!("{}*{}", lhs, rhs)), + STIL::String(rhs) => node!(STIL::String, format!("{}*{}", lhs, rhs)), + _ => unreachable!("{:?}", node.children[1]), + }, + _ => unreachable!("{:?}", node.children[0]), + }), + STIL::Divide => Return::Replace(match &node.children[0].attrs { + STIL::Integer(lhs) => match &node.children[1].attrs { + STIL::Integer(rhs) => node!(STIL::Integer, lhs / rhs), + STIL::Float(rhs) => node!(STIL::Float, *lhs as f64 / rhs), + STIL::String(rhs) => node!(STIL::String, format!("{}/{}", lhs, rhs)), + _ => unreachable!("{:?}", node.children[1]), + }, + STIL::Float(lhs) => match &node.children[1].attrs { + STIL::Integer(rhs) => node!(STIL::Float, lhs / *rhs as f64), + STIL::Float(rhs) => node!(STIL::Float, lhs / rhs), + STIL::String(rhs) => node!(STIL::String, format!("{}/{}", lhs, rhs)), + _ => unreachable!("{:?}", node.children[1]), + }, + STIL::String(lhs) => match &node.children[1].attrs { + STIL::Integer(rhs) => node!(STIL::String, format!("{}/{}", lhs, rhs)), + STIL::Float(rhs) => node!(STIL::String, format!("{}/{}", lhs, rhs)), + STIL::String(rhs) => node!(STIL::String, format!("{}/{}", lhs, rhs)), + _ => unreachable!("{:?}", node.children[1]), + }, + _ => unreachable!("{:?}", node.children[0]), + }), + STIL::NumberWithUnit => Return::Replace(match &node.children[0].attrs { + STIL::Integer(val) => match &node.children[1].attrs { + STIL::EngPrefix(p) => match p.as_str() { + "E" => node!(STIL::Float, *val as f64 * 1_000_000_000_000_000_000_f64), + "P" => node!(STIL::Float, *val as f64 * 1_000_000_000_000_000_f64), + "T" => node!(STIL::Float, *val as f64 * 1_000_000_000_000_f64), + "G" => node!(STIL::Float, *val as f64 * 1_000_000_000_f64), + "M" => node!(STIL::Float, *val as f64 * 1_000_000_f64), + "k" => node!(STIL::Float, *val as f64 * 1_000_f64), + "m" => node!(STIL::Float, *val as f64 / 1_000_f64), + "u" => node!(STIL::Float, *val as f64 / 1_000_000_f64), + "n" => node!(STIL::Float, *val as f64 / 1_000_000_000_f64), + "p" => node!(STIL::Float, *val as f64 / 1_000_000_000_000_f64), + "f" => node!(STIL::Float, *val as f64 / 1_000_000_000_000_000_f64), + "a" => node!(STIL::Float, *val as f64 / 1_000_000_000_000_000_000_f64), + _ => unreachable!("Unknown eng prefix '{}'", p), + }, + _ => unreachable!("{:?}", node.children[1]), + }, + STIL::Float(val) => match &node.children[1].attrs { + STIL::EngPrefix(p) => match p.as_str() { + "E" => node!(STIL::Float, val * 1_000_000_000_000_000_000_f64), + "P" => node!(STIL::Float, val * 1_000_000_000_000_000_f64), + "T" => node!(STIL::Float, val * 1_000_000_000_000_f64), + "G" => node!(STIL::Float, val * 1_000_000_000_f64), + "M" => node!(STIL::Float, val * 1_000_000_f64), + "k" => node!(STIL::Float, val * 1_000_f64), + "m" => node!(STIL::Float, val / 1_000_f64), + "u" => node!(STIL::Float, val / 1_000_000_f64), + "n" => node!(STIL::Float, val / 1_000_000_000_f64), + "p" => node!(STIL::Float, val / 1_000_000_000_000_f64), + "f" => node!(STIL::Float, val / 1_000_000_000_000_000_f64), + "a" => node!(STIL::Float, val / 1_000_000_000_000_000_000_f64), + _ => unreachable!("Unknown eng prefix '{}'", p), + }, + _ => unreachable!("{:?}", node.children[1]), + }, + _ => unreachable!("{:?}", node.children[0]), + }), + _ => Return::Unmodified, + }; + Ok(result) + } + fn on_node(&mut self, node: &Node) -> Result> { let result = match &node.attrs { STIL::TimeExpr => { - self.process_children = true; - let mut nodes = node.process_children(self)?; - self.process_children = false; - Return::Replace(nodes.pop().unwrap()) + self.time_expr_depth += 1; + Return::ProcessChildren } - STIL::Parens => { - let mut nodes = node.process_children(self)?; - Return::Replace(nodes.pop().unwrap()) - } - STIL::String(val) => match &self.params { - None => Return::Unmodified, - Some(params) => { - if params.contains_key(val) { - Return::Replace(params[val].clone()) - } else { - Return::Unmodified + STIL::String(val) => { + if self.processing_enabled() { + match &self.params { + None => Return::Unmodified, + Some(params) => { + if params.contains_key(val) { + Return::Replace(params[val].clone()) + } else { + Return::Unmodified + } + } } + } else { + Return::Unmodified } - }, - STIL::Add => { - let nodes = node.process_children(self)?; - Return::Replace(match &nodes[0].attrs { - STIL::Integer(lhs) => match &nodes[1].attrs { - STIL::Integer(rhs) => node!(STIL::Integer, lhs + rhs), - STIL::Float(rhs) => node!(STIL::Float, *lhs as f64 + rhs), - STIL::String(rhs) => node!(STIL::String, format!("{}+{}", lhs, rhs)), - _ => unreachable!("{:?}", nodes[1]), - }, - STIL::Float(lhs) => match &nodes[1].attrs { - STIL::Integer(rhs) => node!(STIL::Float, lhs + *rhs as f64), - STIL::Float(rhs) => node!(STIL::Float, lhs + rhs), - STIL::String(rhs) => node!(STIL::String, format!("{}+{}", lhs, rhs)), - _ => unreachable!("{:?}", nodes[1]), - }, - STIL::String(lhs) => match &nodes[1].attrs { - STIL::Integer(rhs) => node!(STIL::String, format!("{}+{}", lhs, rhs)), - STIL::Float(rhs) => node!(STIL::String, format!("{}+{}", lhs, rhs)), - STIL::String(rhs) => node!(STIL::String, format!("{}+{}", lhs, rhs)), - _ => unreachable!("{:?}", nodes[1]), - }, - _ => unreachable!("{:?}", nodes[0]), - }) } - STIL::Subtract => { - let nodes = node.process_children(self)?; - Return::Replace(match &nodes[0].attrs { - STIL::Integer(lhs) => match &nodes[1].attrs { - STIL::Integer(rhs) => node!(STIL::Integer, lhs - rhs), - STIL::Float(rhs) => node!(STIL::Float, *lhs as f64 - rhs), - STIL::String(rhs) => node!(STIL::String, format!("{}-{}", lhs, rhs)), - _ => unreachable!("{:?}", nodes[1]), - }, - STIL::Float(lhs) => match &nodes[1].attrs { - STIL::Integer(rhs) => node!(STIL::Float, lhs - *rhs as f64), - STIL::Float(rhs) => node!(STIL::Float, lhs - rhs), - STIL::String(rhs) => node!(STIL::String, format!("{}-{}", lhs, rhs)), - _ => unreachable!("{:?}", nodes[1]), - }, - STIL::String(lhs) => match &nodes[1].attrs { - STIL::Integer(rhs) => node!(STIL::String, format!("{}-{}", lhs, rhs)), - STIL::Float(rhs) => node!(STIL::String, format!("{}-{}", lhs, rhs)), - STIL::String(rhs) => node!(STIL::String, format!("{}-{}", lhs, rhs)), - _ => unreachable!("{:?}", nodes[1]), - }, - _ => unreachable!("{:?}", nodes[0]), - }) - } - STIL::Multiply => { - let nodes = node.process_children(self)?; - Return::Replace(match &nodes[0].attrs { - STIL::Integer(lhs) => match &nodes[1].attrs { - STIL::Integer(rhs) => node!(STIL::Integer, lhs * rhs), - STIL::Float(rhs) => node!(STIL::Float, *lhs as f64 * rhs), - STIL::String(rhs) => node!(STIL::String, format!("{}*{}", lhs, rhs)), - _ => unreachable!("{:?}", nodes[1]), - }, - STIL::Float(lhs) => match &nodes[1].attrs { - STIL::Integer(rhs) => node!(STIL::Float, lhs * *rhs as f64), - STIL::Float(rhs) => node!(STIL::Float, lhs * rhs), - STIL::String(rhs) => node!(STIL::String, format!("{}*{}", lhs, rhs)), - _ => unreachable!("{:?}", nodes[1]), - }, - STIL::String(lhs) => match &nodes[1].attrs { - STIL::Integer(rhs) => node!(STIL::String, format!("{}*{}", lhs, rhs)), - STIL::Float(rhs) => node!(STIL::String, format!("{}*{}", lhs, rhs)), - STIL::String(rhs) => node!(STIL::String, format!("{}*{}", lhs, rhs)), - _ => unreachable!("{:?}", nodes[1]), - }, - _ => unreachable!("{:?}", nodes[0]), - }) - } - STIL::Divide => { - let nodes = node.process_children(self)?; - Return::Replace(match &nodes[0].attrs { - STIL::Integer(lhs) => match &nodes[1].attrs { - STIL::Integer(rhs) => node!(STIL::Integer, lhs / rhs), - STIL::Float(rhs) => node!(STIL::Float, *lhs as f64 / rhs), - STIL::String(rhs) => node!(STIL::String, format!("{}/{}", lhs, rhs)), - _ => unreachable!("{:?}", nodes[1]), - }, - STIL::Float(lhs) => match &nodes[1].attrs { - STIL::Integer(rhs) => node!(STIL::Float, lhs / *rhs as f64), - STIL::Float(rhs) => node!(STIL::Float, lhs / rhs), - STIL::String(rhs) => node!(STIL::String, format!("{}/{}", lhs, rhs)), - _ => unreachable!("{:?}", nodes[1]), - }, - STIL::String(lhs) => match &nodes[1].attrs { - STIL::Integer(rhs) => node!(STIL::String, format!("{}/{}", lhs, rhs)), - STIL::Float(rhs) => node!(STIL::String, format!("{}/{}", lhs, rhs)), - STIL::String(rhs) => node!(STIL::String, format!("{}/{}", lhs, rhs)), - _ => unreachable!("{:?}", nodes[1]), - }, - _ => unreachable!("{:?}", nodes[0]), - }) - } - STIL::NumberWithUnit => { - let nodes = node.process_children(self)?; - Return::Replace(match nodes[0].attrs { - STIL::Integer(val) => match &nodes[1].attrs { - STIL::EngPrefix(p) => match p.as_str() { - "E" => node!(STIL::Float, val as f64 * 1_000_000_000_000_000_000_f64), - "P" => node!(STIL::Float, val as f64 * 1_000_000_000_000_000_f64), - "T" => node!(STIL::Float, val as f64 * 1_000_000_000_000_f64), - "G" => node!(STIL::Float, val as f64 * 1_000_000_000_f64), - "M" => node!(STIL::Float, val as f64 * 1_000_000_f64), - "k" => node!(STIL::Float, val as f64 * 1_000_f64), - "m" => node!(STIL::Float, val as f64 / 1_000_f64), - "u" => node!(STIL::Float, val as f64 / 1_000_000_f64), - "n" => node!(STIL::Float, val as f64 / 1_000_000_000_f64), - "p" => node!(STIL::Float, val as f64 / 1_000_000_000_000_f64), - "f" => node!(STIL::Float, val as f64 / 1_000_000_000_000_000_f64), - "a" => node!(STIL::Float, val as f64 / 1_000_000_000_000_000_000_f64), - _ => unreachable!("Unknown eng prefix '{}'", p), - }, - _ => unreachable!("{:?}", nodes[1]), - }, - STIL::Float(val) => match &nodes[1].attrs { - STIL::EngPrefix(p) => match p.as_str() { - "E" => node!(STIL::Float, val * 1_000_000_000_000_000_000_f64), - "P" => node!(STIL::Float, val * 1_000_000_000_000_000_f64), - "T" => node!(STIL::Float, val * 1_000_000_000_000_f64), - "G" => node!(STIL::Float, val * 1_000_000_000_f64), - "M" => node!(STIL::Float, val * 1_000_000_f64), - "k" => node!(STIL::Float, val * 1_000_f64), - "m" => node!(STIL::Float, val / 1_000_f64), - "u" => node!(STIL::Float, val / 1_000_000_f64), - "n" => node!(STIL::Float, val / 1_000_000_000_f64), - "p" => node!(STIL::Float, val / 1_000_000_000_000_f64), - "f" => node!(STIL::Float, val / 1_000_000_000_000_000_f64), - "a" => node!(STIL::Float, val / 1_000_000_000_000_000_000_f64), - _ => unreachable!("Unknown eng prefix '{}'", p), - }, - _ => unreachable!("{:?}", nodes[1]), - }, - _ => unreachable!("{:?}", nodes[0]), - }) - } - // Only recurse inside time expression nodes _ => { - if self.process_children { + // Only process inside time expression nodes + if self.processing_enabled() { Return::ProcessChildren } else { Return::Unmodified @@ -215,12 +213,10 @@ mod tests { } #[test] - fn it_works() { + fn it_works() -> Result<()> { let expr = "1+2+3+4"; - assert_eq!( - TimeExpr::run(&parse(expr), None).unwrap(), - node!(STIL::Integer, 10) - ); + let p = TimeExpr::run(&parse(expr), None)?; + assert_eq!(p, node!(STIL::Integer, 10)); let expr = "1+2+3-3+4"; assert_eq!( TimeExpr::run(&parse(expr), None).unwrap(), @@ -275,5 +271,6 @@ mod tests { } else { assert_eq!(true, false); } + Ok(()) } }