use std::fmt;
use lexer::TokenType;
#[derive(PartialEq, Debug, Clone)]
pub enum SpecificNode {
List(Vec<Box<Node>>),
Text(String),
VariableBlock(Box<Node>),
Identifier(String),
Int(i32),
Float(f32),
Bool(bool),
Math {lhs: Box<Node>, rhs: Box<Node>, operator: TokenType},
Logic {lhs: Box<Node>, rhs: Box<Node>, operator: TokenType},
If {condition_nodes: Vec<Box<Node>>, else_node: Option<Box<Node>>},
Conditional {condition: Box<Node>, body: Box<Node>},
For {local: Box<Node>, array: Box<Node>, body: Box<Node>},
Block {name: String, body: Box<Node>}
}
#[derive(PartialEq, Debug, Clone)]
pub struct Node {
pub position: usize,
pub specific: SpecificNode,
}
impl Node {
pub fn new(position: usize, specific: SpecificNode) -> Node {
Node {
position: position,
specific: specific
}
}
pub fn push(&mut self, specific: Box<Node>) {
match self.specific {
SpecificNode::List(ref mut l) => l.push(specific),
SpecificNode::If {ref mut condition_nodes, ..} => condition_nodes.push(specific),
SpecificNode::Conditional {ref mut body, ..} | SpecificNode::For {ref mut body, ..}
| SpecificNode::Block {ref mut body, ..} => {
body.push(specific)
},
_ => panic!("tried to push on a non list node")
}
}
pub fn push_to_else(&mut self, node: Box<Node>) {
match self.specific {
SpecificNode::If {ref mut else_node, ..} => {
if let Some(e) = else_node.as_mut() { e.push(node); }
},
_ => panic!("tried to push_to_else on a non-if node")
}
}
pub fn pop(&mut self) -> Box<Node> {
match self.specific {
SpecificNode::List(ref mut l) => l.pop().unwrap(),
_ => panic!("tried to pop on a non list node")
}
}
pub fn get_children(&self) -> Vec<Box<Node>> {
match self.specific {
SpecificNode::List(ref l) => l.clone(),
SpecificNode::If {ref condition_nodes, ..} => condition_nodes.clone(),
_ => panic!("tried to get_children on a non-list/if node")
}
}
pub fn len(&self) -> usize {
match self.specific {
SpecificNode::List(ref l) => l.len(),
SpecificNode::If {ref condition_nodes, ..} => {
condition_nodes.last().unwrap().len()
},
SpecificNode::Conditional {ref body, ..} | SpecificNode::For {ref body, ..}
| SpecificNode::Block {ref body, ..} => {
match body.specific {
SpecificNode::List(ref l2) => l2.len(),
_ => unreachable!()
}
},
_ => panic!("tried to len() on a non list node: {:?}", self.specific)
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn append_to_last_conditional(&mut self, node: Box<Node>) {
match self.specific {
SpecificNode::If {ref mut condition_nodes, ..} => {
condition_nodes.last_mut().unwrap().push(node);
},
_ => panic!("tried to append_to_last_conditional on a non-if node")
}
}
}
impl fmt::Display for Node {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.specific {
SpecificNode::List(ref l) => {
let mut stringified = String::new();
for n in l {
stringified.push_str(&format!("{}\n", n));
}
write!(f, "{}", stringified)
},
SpecificNode::Text(ref s) => write!(f, "{}", s),
SpecificNode::VariableBlock(ref s) => write!(f, "{{ {} }}", s),
SpecificNode::Identifier(ref s) => write!(f, "[{}]", s),
SpecificNode::Int(ref s) => write!(f, "<{}>", s),
SpecificNode::Float(ref s) => write!(f, "<{}>", s),
SpecificNode::Bool(ref s) => write!(f, "<{}>", s),
SpecificNode::Math { ref lhs, ref rhs , ref operator} => {
write!(f, "<{} {} {}>", lhs, operator, rhs)
},
SpecificNode::Logic { ref lhs, ref rhs , ref operator} => {
write!(f, "<{} {} {}>", lhs, operator, rhs)
},
SpecificNode::If { ref condition_nodes, ref else_node } => {
let mut stringified = String::new();
for (i, n) in condition_nodes.iter().enumerate() {
if i == 0 {
stringified.push_str(&format!("if: {}\n", n));
} else {
stringified.push_str(&format!("elif: {}\n", n));
}
}
if else_node.is_some() {
stringified.push_str(&format!("else: {}\n", else_node.clone().unwrap()));
}
write!(f, "{}", stringified)
},
SpecificNode::Conditional {ref condition, ref body } => {
write!(f, "{} ? => {}", condition, body)
},
SpecificNode::For {ref local, ref array, ref body } => {
write!(f, "for {} in {} ? => {}", local, array, body)
},
SpecificNode::Block { ref name, ref body } => {
write!(f, "block {} => {}", name, body)
}
}
}
}