harborc 0.1.1

A language that ports: targeting your thermostat, UFO, and kitchen sink.
Documentation

use core::fmt;

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Op {
    Comment(char),

    Plus(u32),
    Minus(u32),
    Left(u32),
    Right(u32),
    Loop,
    End,

    Put,
    Get,
    Putnum,
    Getnum,

    Refer,
    Deref,

    Alloc,
    Free
}

impl fmt::Display for Op {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Op::Comment(c) => write!(f, "{}", c),

            Op::Plus(n) if n > 1 => write!(f, "+({})", n),
            Op::Plus(n) if n == 1 => write!(f, "+"),
            Op::Plus(_) => {Ok(())},

            Op::Minus(n) if n > 1 => write!(f, "-({})", n),
            Op::Minus(n) if n == 1 => write!(f, "-"),
            Op::Minus(_) => {Ok(())},

            Op::Left(n) if n > 1 => write!(f, "<({})", n),
            Op::Left(_) => write!(f, "<"),

            Op::Right(n) if n > 1 => write!(f, ">({})", n),
            Op::Right(_) => write!(f, ">"),

            Op::Loop => write!(f, "["),
            Op::End => write!(f, "]"),
            
            Op::Get => write!(f, ","),
            Op::Put => write!(f, "."),
            Op::Getnum => write!(f, "#"),
            Op::Putnum => write!(f, "$"),
            
            Op::Refer => write!(f, "&"),
            Op::Deref => write!(f, "*"),
            
            Op::Alloc => write!(f, "?"),
            Op::Free => write!(f, "!"),
        }
    }
}

#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Program(pub Vec<Op>);

impl Program {

    pub fn comment(&mut self, c: &str) {
        self.0.push(Op::Comment('\n'));
        for ch in c.chars() {
            self.0.push(Op::Comment(ch));
        }
        self.0.push(Op::Comment('\n'));
    }

    pub fn zero(&mut self) {
        self.0.push(Op::Loop);
        self.0.push(Op::Minus(1));
        self.0.push(Op::End);
    }

    pub fn plus(&mut self, n: u32) {
        self.0.push(Op::Plus(n));
    }

    pub fn minus(&mut self, n: u32) {
        self.0.push(Op::Minus(n));
    }

    pub fn shift(&mut self, n: i32) {
        if n > 0 {
            self.0.push(Op::Right(n as u32));
        } else if n < 0 {
            self.0.push(Op::Left(-n as u32));
        }
    }

    pub fn left(&mut self, n: u32) {
        self.0.push(Op::Left(n));
    }

    pub fn right(&mut self, n: u32) {
        self.0.push(Op::Right(n));
    }

    pub fn begin_loop(&mut self) {
        self.0.push(Op::Loop);
    }

    pub fn end_loop(&mut self) {
        self.0.push(Op::End);
    }

    pub fn refer(&mut self) {
        self.0.push(Op::Refer);
    }

    pub fn deref(&mut self) {
        self.0.push(Op::Deref);
    }

    pub fn alloc(&mut self) {
        self.0.push(Op::Alloc);
    }

    pub fn free(&mut self) {
        self.0.push(Op::Free);
    }

    pub fn put(&mut self) {
        self.0.push(Op::Put);
    }

    pub fn putnum(&mut self) {
        self.0.push(Op::Putnum);
    }

    pub fn get(&mut self) {
        self.0.push(Op::Get);
    }

    pub fn getnum(&mut self) {
        self.0.push(Op::Getnum);
    }

    pub fn assemble(self) -> String {
        let mut result = String::new();
        for op in self.optimize() {
            match op {
                Op::Comment(c) => result.push(c),
                Op::Plus(n) => result += &"+".repeat(n as usize),
                Op::Minus(n) => result += &"-".repeat(n as usize),
                Op::Left(n) => result += &"<".repeat(n as usize),
                Op::Right(n) => result += &">".repeat(n as usize),
                Op::Loop => result += "[",
                Op::End => result += "]",

                Op::Get => result += ",",
                Op::Put => result += ".",
                Op::Getnum => result += "#",
                Op::Putnum => result += "$",

                Op::Refer => result += "&",
                Op::Deref => result += "*",

                Op::Alloc => result += "?",
                Op::Free => result += "!",
            }
        }
        result
    }

    pub fn optimize(self) -> Self {
        Self(self.0.into_iter().fold(vec![], 
            |mut result, this| {
                if result.is_empty() {
                    result.push(this);
                    return result;
                }
                let last_i = result.len()-1;
                let last = &mut result[last_i];
                match (&last.clone(), &this) {
                    (Op::Plus(n), Op::Plus(m)) => *last = Op::Plus(*n + *m),
                    (Op::Minus(n), Op::Minus(m)) => *last = Op::Minus(*n + *m),

                    (Op::Plus(n), Op::Minus(m))
                    | (Op::Minus(m), Op::Plus(n)) if *n >= *m => *last = Op::Plus(*n - *m),

                    (Op::Plus(n), Op::Minus(m))
                    | (Op::Minus(m), Op::Plus(n)) if *n < *m => *last = Op::Minus(*m - *n),
                    
                    (Op::Right(n), Op::Right(m)) => *last = Op::Right(*n + *m),
                    (Op::Left(n), Op::Left(m)) => *last = Op::Left(*n + *m),

                    (Op::Right(n), Op::Left(m))
                    | (Op::Left(m), Op::Right(n)) if *n >= *m => *last = Op::Right(*n - *m),

                    (Op::Right(n), Op::Left(m))
                    | (Op::Left(m), Op::Right(n)) if *n < *m => *last = Op::Left(*m - *n),
                    
                    _ => result.push(this)
                }
                result
            }
        ))
    }
}

impl From<&str> for Program {
    fn from(s: &str) -> Self {
        let mut result = vec![];
        for ch in s.chars() {
            match ch {
                '+' => result.push(Op::Plus(1)),
                '-' => result.push(Op::Minus(1)),
                '<' => result.push(Op::Left(1)),
                '>' => result.push(Op::Right(1)),
                '[' => result.push(Op::Loop),
                ']' => result.push(Op::End),
                ',' => result.push(Op::Get),
                '.' => result.push(Op::Put),
                '#' => result.push(Op::Getnum),
                '$' => result.push(Op::Putnum),
                '*' => result.push(Op::Deref),
                '&' => result.push(Op::Refer),
                '?' => result.push(Op::Alloc),
                '!' => result.push(Op::Free),
                _ => {}
            }
        }

        Self(result)
    }
}

impl IntoIterator for Program {
    type Item = Op;
    type IntoIter = std::vec::IntoIter<Op>;
    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl fmt::Display for Program {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.clone().assemble())
    }
}