truegrf 2.1.0

TrueGRF YAML to GRF compiler
Documentation
use std::collections::{BTreeMap, HashMap};

use super::stack::{
    Chain,
    Register,
    Stack,
};
use super::token::Type;

const STACK_REGISTER_START: u8 = 0xff;

pub struct FunctionResult {
    pub industry_inputs: HashMap<String, Register>,
    pub industry_outputs: HashMap<String, Register>,
    pub value: Option<Register>,
}

pub struct Function {
    pub chain: Chain,
    pub result: FunctionResult,
}

pub struct Engine<'a> {
    pub functions: HashMap<String, Function>,

    pub stack: Vec<Stack>,
    pub result: FunctionResult,

    pub constants: HashMap<String, BTreeMap<i32, i32>>,
    pub iterators: HashMap<String, Option<Stack>>,
    pub variable_is_list: HashMap<String, Type>,
    register_assignment: HashMap<String, Register>,
    next_free_register: u8,
    pub stack_register: u8,

    pub ctt: &'a HashMap<String, u8>,
}

impl FunctionResult {
    pub fn new() -> Self {
        FunctionResult {
            industry_inputs: HashMap::new(),
            industry_outputs: HashMap::new(),
            value: None,
        }
    }

    pub fn merge(&mut self, other: &Self) {
        if other.value.is_some() {
            self.value = other.value
        }
        for input in &other.industry_inputs {
            self.industry_inputs.insert(input.0.to_string(), *input.1);
        }
        for output in &other.industry_outputs {
            self.industry_outputs.insert(output.0.to_string(), *output.1);
        }
    }
}

impl<'a> Engine<'a> {
    pub fn new(ctt: &'a HashMap<String, u8>) -> Self {
        Engine {
            functions: HashMap::new(),

            stack: Vec::new(),
            result: FunctionResult::new(),

            constants: HashMap::new(),
            iterators: HashMap::new(),
            variable_is_list: HashMap::new(),
            register_assignment: HashMap::new(),
            next_free_register: 0,
            stack_register: STACK_REGISTER_START,

            ctt,
        }
    }

    pub fn reset_stack_register(&mut self) {
        self.stack_register = STACK_REGISTER_START;
    }

    pub fn get_register(&mut self, name: &str, allow_reservation: bool) -> Result<Register, String> {
        if let Some(register) = self.register_assignment.get(name) {
            return Ok(*register);
        }

        if allow_reservation {
            return self.reserve_register(name, false);
        }

        Err(format!("Undefined variable '{}'.", name))
    }

    pub fn reserve_register(&mut self, name: &str, temporary_or_persistent: bool) -> Result<Register, String> {
        if self.register_assignment.contains_key(name) {
            return Err(format!("Variable '{}' is already defined.", name));
        }
        if self.constants.contains_key(name) {
            return Err(format!("Variable '{}' is already defined.", name));
        }
        if self.iterators.contains_key(name) {
            return Err(format!("Variable '{}' is already defined.", name));
        }

        let register = if temporary_or_persistent {
            Register::Persistent(self.next_free_register)
        } else {
            Register::Temporary(self.next_free_register)
        };

        self.next_free_register += 1;
        self.register_assignment.insert(name.to_string(), register);

        Ok(register)
    }

    pub fn initialize_iterator(&mut self, name: &str) -> Result<(), String> {
        if self.register_assignment.contains_key(name) {
            return Err(format!("Variable '{}' is already defined.", name));
        }
        if self.constants.contains_key(name) {
            return Err(format!("Variable '{}' is already defined.", name));
        }
        if self.iterators.contains_key(name) {
            return Err(format!("Variable '{}' is already defined.", name));
        }

        self.iterators.insert(name.to_string(), None);

        Ok(())
    }

    pub fn initialize_const(&mut self, name: &str) -> Result<(), String> {
        if self.register_assignment.contains_key(name) {
            return Err(format!("Variable '{}' is already defined.", name));
        }
        if self.constants.contains_key(name) {
            return Err(format!("Variable '{}' is already defined.", name));
        }
        if self.iterators.contains_key(name) {
            return Err(format!("Variable '{}' is already defined.", name));
        }

        self.constants.insert(name.to_string(), BTreeMap::new());

        Ok(())
    }

    pub fn mark_variable_as_list(&mut self, name: &str, r#type: Type) {
        self.variable_is_list.insert(name.to_string(), r#type);
    }
}