nodespeak 0.0.6

A JIT-ish compiler for number-crunching applications.
Documentation
use super::Variable;
use crate::trivial::structure::Instruction;
use std::fmt::{self, Debug, Formatter};
use std::ops::{Index, IndexMut};

#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct VariableId(usize);

impl Debug for VariableId {
    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
        write!(formatter, "tv{}", self.0)
    }
}

#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct LabelId(usize);

impl LabelId {
    pub fn raw(&self) -> usize {
        self.0
    }
}

impl Debug for LabelId {
    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
        write!(formatter, "l{}", self.0)
    }
}

pub struct Program {
    instructions: Vec<Instruction>,
    variables: Vec<Variable>,
    inputs: Vec<VariableId>,
    outputs: Vec<VariableId>,
    errors: Vec<String>,
    num_labels: usize,
}

impl Debug for Program {
    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
        writeln!(formatter, "variables:")?;
        for (index, variable) in self.variables.iter().enumerate() {
            writeln!(formatter, "  tv{}: {:?}", index, variable)?;
        }
        write!(formatter, "inputs:")?;
        for variable in self.inputs.iter() {
            write!(formatter, " {:?}", variable)?;
        }
        writeln!(formatter)?;
        write!(formatter, "outputs:")?;
        for variable in self.outputs.iter() {
            write!(formatter, " {:?}", variable)?;
        }
        writeln!(formatter)?;
        writeln!(formatter, "{} labels", self.num_labels)?;
        writeln!(formatter, "error codes:")?;
        for (code, description) in self.errors.iter().enumerate() {
            writeln!(formatter, "  {}: {}", code, description)?;
        }
        writeln!(formatter, "instructions:")?;
        for instruction in self.instructions.iter() {
            writeln!(formatter, "  {:?}", instruction)?;
        }
        write!(formatter, "")
    }
}

impl Index<VariableId> for Program {
    type Output = Variable;

    fn index(&self, variable: VariableId) -> &Self::Output {
        &self.variables[variable.0]
    }
}

impl IndexMut<VariableId> for Program {
    fn index_mut(&mut self, variable: VariableId) -> &mut Self::Output {
        &mut self.variables[variable.0]
    }
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            variables: Vec::new(),
            inputs: Vec::new(),
            outputs: Vec::new(),
            errors: vec!["Success".to_owned()],
            num_labels: 0,
        }
    }

    pub fn add_instruction(&mut self, instruction: Instruction) {
        self.instructions.push(instruction);
    }

    pub fn borrow_instructions(&self) -> &Vec<Instruction> {
        &self.instructions
    }

    pub fn adopt_variable(&mut self, variable: Variable) -> VariableId {
        let id = VariableId(self.variables.len());
        self.variables.push(variable);
        id
    }

    pub fn borrow_variable(&self, id: VariableId) -> &Variable {
        &self.variables[id.0]
    }

    pub fn borrow_variable_mut(&mut self, id: VariableId) -> &mut Variable {
        &mut self.variables[id.0]
    }

    pub fn iterate_all_variables(&self) -> impl Iterator<Item = VariableId> {
        (0..self.variables.len()).map(|i| VariableId(i))
    }

    pub fn add_input(&mut self, input: VariableId) {
        self.inputs.push(input);
    }

    pub fn add_output(&mut self, output: VariableId) {
        self.outputs.push(output);
    }

    pub fn borrow_inputs(&self) -> &Vec<VariableId> {
        &self.inputs
    }

    pub fn borrow_outputs(&self) -> &Vec<VariableId> {
        &self.outputs
    }

    pub fn create_label(&mut self) -> LabelId {
        self.num_labels += 1;
        LabelId(self.num_labels - 1)
    }

    pub fn get_num_labels(&self) -> usize {
        self.num_labels
    }

    pub fn add_error(&mut self, description: String) -> u32 {
        let code = self.errors.len() as u32;
        self.errors.push(description);
        code
    }

    pub fn borrow_error_descriptions(&self) -> &Vec<String> {
        &self.errors
    }
}