cordillera 0.1.2

IR generation library for Sierra
Documentation
//! # Builder Module
//! - Made to store the Builder and its implementations

use super::context::*;
use super::entities::*;
use super::ir::*;

pub struct Builder<'a> {
    pub program: Program,
    pub context: &'a mut Context<'a>
}

#[allow(dead_code)]
impl<'a> Builder<'a> {
    /// Constructs a new Builder
    /// 
    /// # Arguments
    /// * `context` - Context for the builder to use
    /// 
    /// # Examples
    /// ```rust
    /// let builder = Builder::new();
    /// ```
    pub fn new(context: &'a mut Context<'a>) -> Self {
        Builder {
            program: Program {
                program: vec![
                    IRNode::Export(Vec::new())
                ]
            },
            context
        }
    }
    /// Inserts a function
    /// 
    /// # Arguments:
    /// * `name` - The name of the function to create
    /// * `arg_number` - The amount of arguments in the function
    /// * `return_type` - The return type of the function
    /// 
    /// # Panics
    /// - When an export instruction isn't supplied
    /// 
    /// # Examples
    /// ```rust
    /// builder.create_function("main", 0);
    /// 
    /// builder.create_function("foo", 67);
    /// ```
    pub fn create_function(&mut self, name: &'a str, arg_number: u64, return_type: Type) -> &mut Self{
        let function = FunctionExport {
            name: name.to_string(),
            arg_number
        };
        if let Some(&mut IRNode::Export(ref mut exports)) = self.program.program.get_mut(0) {
            exports.push(Export::Function(function));
            self.context.func_dent.push(name.to_string());
            self.program.program.push(IRNode::Function { 
                return_type, 
                name: name.to_string(), 
                body: vec![
                    IRNode::Label("entry".to_string())
                ]
            });
            self.context.insert_symbol(Symbol {
                symbol_name: name,
                symbol_type: SymbolType::Function,
                symbol_value: Value::Function {
                    return_type,
                    labels: vec!["entry".to_string()]
                }
            });
            self
        } else {
            panic!("Expected beginning export, you may have deleted or moved the export somewhere...")
        }
    }
    /// Close the current function
    /// 
    /// # Arguments:
    /// * `name` - The name of the function to close
    /// 
    /// # Panics
    /// - If the function (provided with `name`) is either not defined, already closed, or has an unclosed function in it
    /// 
    /// # Examples
    /// ```rust
    /// builder.create_function("main", 0);
    /// // add stuff ...
    /// builder.close_function("main");
    /// ```
    pub fn close_function(&mut self, name: &str)  -> &mut Self {
        if self.context.func_dent.last() == Some(&name.to_string()) {
            self.context.func_dent.pop();
            self.program.program.push(IRNode::End);
            self
        } else {
            panic!("Function {} either not defined, already closed, or has an unclosed function in it", name)
        }
    }
    /// Insert a new label in the specified function
    /// 
    /// # Arguments
    /// * `name` - Name of the label to insert
    /// * `func_name` - Name of the function to insert the label into
    /// 
    /// # Panics
    /// - If the function (provided with `func_name`) doesn't exist or isn't found in the context
    /// - if the label already exists in the function
    /// - if the function's symbol value isn't a `Value::Labels(Vec<String)`
    /// 
    /// # Examples
    /// ```rust
    /// builder.insert_label("is_true")
    /// 
    /// builder.insert_label("is_false")
    /// ```
    pub fn insert_label_in_function(&mut self, name: &str, func_name: &str) -> &mut Self {
        let symbol = self.context.context
        .iter_mut()
        .find(|symbol| symbol.symbol_name == func_name);

        if let Some(symbol) = symbol {
            if let Value::Function {
                return_type: _,
                labels
            } = &mut symbol.symbol_value {
                if labels.contains(&name.to_string()) {
                    panic!("Label {} is taken", name)
                }
                labels.push(name.to_string());
                self
            } else {
                panic!("Expected labels value")
            }
        } else {
            panic!("Function {} is not defined", func_name)
        }
    }
    /// Creates a new `ret` instruction
    /// 
    /// # Arguments
    /// * `ret` - The value to return
    /// 
    /// # Examples
    /// ```rust
    /// builder.ret(IRNode::ConstInt(10));
    /// ```
    pub fn ret(&mut self, ret: IRNode) -> &mut Self {
        IRNode::Ret(Box::new(ret));
        self
    }
    /// Creates a new assignment instruction
    /// 
    /// # Arguments
    /// * `name` - The name of the variable to assign
    /// * `value` - The value of the variable to assign
    /// 
    /// # Examples
    /// ```rust
    /// builder.assign("v0", IRNode::ConstInt(5));
    /// ```
    pub fn assign(&mut self, name: &'a str, value: IRNode, var_type: Type) -> &mut Self {
        self.context.insert_symbol(
            Symbol {
                symbol_name: name,
                symbol_type: SymbolType::Variable,
                symbol_value: Value::Void
            }
        );
        let instruction= IRNode::Assign {
            name: name.to_string(),
            value: Box::new(value),
            var_type
        };
        self.append_instruction(instruction);
        self
    }
    /// Adds an instruction
    /// 
    /// # Arguments
    /// * `instruction` - The instruction to add
    /// 
    /// # Examples
    /// ```rust
    /// let iadd_instruction = builder.iadd(IRNode::ConstInt(1), IRNode::ConstInt(2));
    /// builder.append_instruction(iadd_instruction);
    /// ```
    pub fn append_instruction(&mut self, instruction: IRNode) {
        self.program.program.push(instruction)
    }
    /// Returns the program and finalizes the program
    /// 
    /// # Examples
    /// ```rust
    /// let program = builder.finalize_program()
    /// ```
    pub fn finalize_program(&self) -> Program {
        if self.context.func_dent.len() > 0 {
            panic!("Function(s) '{}' are not closed, please close all before finalizing", self.context.func_dent.join("', '"))
        }
        self.program.clone()
    }
}