retrobasic 0.1.0

A BASIC emulator with easy access to a libary of classic games
use lexer::Token;
use std::fmt;

#[derive(Debug, PartialEq, Clone)]
pub struct AST {
    pub line_num: Option<u32>,
    pub token: Token,
    pub children: Vec<AST>,
}

fn fmt_node(node: &AST) -> String {
    let mut s = String::new();
    s.push_str("(");
    let m = match node.token.val {
        Some(ref s) => format!("{:?}:{}", node.token.id, s),
        None => format!("{:?}", node.token.id),
    };
    s.push_str(&m);
    for i in 0..node.children.len() {
        s.push_str(&fmt_node(&node.children[i]));
    }
    s.push_str(")");
    s
}

impl fmt::Display for AST {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", fmt_node(&self))
    }
}

impl AST {
    pub fn new(token: Token) -> Self {
        AST {
            line_num: None,
            token: token,
            children: Vec::new(),
        }
    }

    pub fn set_linenum(&mut self, line_num: u32) {
        self.line_num = Some(line_num)
    }

    pub fn add_child(&mut self, child: AST) -> &mut Self {
        self.children.push(child);
        self
    }

    pub fn add_children(&mut self, children: Vec<AST>) -> &mut Self {
        for i in 0..children.len() {
            let c = &children[i];
            self.children.push(c.clone());
        }
        self
    }

    pub fn add_optional_child(&mut self, child: Option<AST>) -> &mut Self {
        match child {
            Some(c) => self.children.push(c.clone()),
            None => (),
        }
        self
    }

    pub fn nop(&mut self, _: AST) -> &mut Self {
        self
    }

    pub fn finalize(&self) -> Self {
        AST {
            line_num: self.line_num.clone(),
            token: self.token.clone(),
            children: self.children.clone(),
        }
    }
}

#[cfg(test)]
mod tests {
    use ast::*;
    use lexer::*;
    use tokenid::*;

    #[test]
    fn can_add_children() {
        let mut a = AST::new(Token::new(TID::NONE, None));
        let c1 = AST::new(Token::new(TID::INT, Some(String::from("10"))));
        let c2 = AST::new(Token::new(TID::ID, Some(String::from("foo"))));
        a.add_child(c1).add_child(c2);

        assert_eq!(2, a.children.len());
    }
}