nodespeak 0.2.1

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)]
struct Label {
    occurs_in_static_body: bool,
}

#[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 {
    static_init: Vec<Instruction>,
    instructions: Vec<Instruction>,
    variables: Vec<Variable>,
    static_vars: Vec<VariableId>,
    inputs: Vec<VariableId>,
    outputs: Vec<VariableId>,
    errors: Vec<String>,
    labels: Vec<Label>,
}

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, "static vars:")?;
        for variable in self.static_vars.iter() {
            write!(formatter, " {:?}", variable)?;
        }
        writeln!(formatter)?;
        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.labels.len())?;
        writeln!(formatter, "error codes:")?;
        for (code, description) in self.errors.iter().enumerate() {
            writeln!(formatter, "  {}: {}", code, description)?;
        }
        writeln!(formatter, "static init:")?;
        for instruction in self.static_init.iter() {
            writeln!(formatter, "  {:?}", instruction)?;
        }
        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(),
            static_init: Vec::new(),
            variables: Vec::new(),
            static_vars: Vec::new(),
            inputs: Vec::new(),
            outputs: Vec::new(),
            errors: vec!["Success".to_owned()],
            labels: Vec::new(),
        }
    }

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

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

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

    pub fn borrow_static_init_instructions(&self) -> &Vec<Instruction> {
        &self.static_init
    }

    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 create_label(&mut self, occurs_in_static_body: bool) -> LabelId {
        let id = LabelId(self.labels.len());
        self.labels.push(Label {
            occurs_in_static_body,
        });
        id
    }

    pub fn is_label_in_static_body(&self, label: LabelId) -> bool {
        assert!(label.0 < self.labels.len());
        self.labels[label.0].occurs_in_static_body
    }

    pub fn iterate_all_labels(&self) -> impl Iterator<Item = LabelId> {
        (0..self.labels.len()).map(|i| LabelId(i))
    }

    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
    }
}