cordillera 0.1.4

IR generation library for Sierra
Documentation
//! # IR Module
//! - Made to store IR assets

use std::fmt;
#[allow(unused_imports)]
use super::entities::{Type, Value};

/// IR Code
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub enum IRNode {
    Export(Vec<Export>),
    ConstInt(i64),
    ConstFloat(f64),
    Variable(String),
    IAdd {
        left: Box<IRNode>,
        right: Box<IRNode>
    },
    ISub {
        left: Box<IRNode>,
        right: Box<IRNode>
    },
    IMul {
        left: Box<IRNode>,
        right: Box<IRNode>
    },
    IDiv {
        left: Box<IRNode>,
        right: Box<IRNode>
    },

    INeg {
        operand: Box<IRNode>
    },

    Label(String),

    Assign {
        name: String,
        value: Box<IRNode>,
        var_type: Type
    },
    Function {
        return_type: Type,
        name: String,
        body: Vec<IRNode>
    },
    Ret(Box<IRNode>),
    End
}

/// Types of Exports
#[derive(Debug, Clone)]
pub enum Export {
    Function(FunctionExport)
}

impl fmt::Display for Export {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Self::Function(func) => write!(
                f, "[function({}/{})]", 
                func.name, 
                func.arg_number
            )
        }
    }
}

/// Function Export
#[derive(Debug, Clone)]
pub struct FunctionExport {
    pub name: String,
    pub arg_number: u64
}

impl IRNode {
    /// Turn the IR Node into a String
    /// 
    /// 
    /// EXAMPLES:
    /// let tmp = IRNode::ConstInt(5);
    /// println!("{}", tmp.into_string());
    pub fn into_string(&self) -> String {
        match self {
            Self::Export(exports) => {
                let mut output: String = String::from("@export(");
                for (index, export) in exports.iter().enumerate() {
                    output.push_str(&export.to_string());
                    if index < exports.len() - 1 {
                        output.push_str(", ")
                    }
                }
                output.push_str(")");

                output
            },
            Self::ConstInt(number) => format!("int.{}", number),
            Self::ConstFloat(number) => format!("float.{}", number),
            Self::Variable(var) => format!("${}", var),
            Self::IAdd {
                left
                ,right
            } => format!("iadd {} {}", (*left).into_string(), (*right).into_string()),
            Self::ISub {
                left
                ,right
            } => format!("isub {} {}", (*left).into_string(), (*right).into_string()),
            Self::IMul {
                left
                ,right
            } => format!("imul {} {}", (*left).into_string(), (*right).into_string()),
            Self::IDiv {
                left
                ,right
            } => format!("idiv {} {}", (*left).into_string(), (*right).into_string()),
            Self::INeg {
                operand
            } => format!("ineg {}", (*operand).into_string()),
            Self::Label(label) => format!("{}:", label),
            Self::Assign {
                name,
                value,
                var_type
            } => format!("assign {} {} = {}", var_type, name, (*value).into_string()),
            Self::Function {
                return_type,
                name,
                body
            } => format!("function {} > {}:\n{}", 
                name,
                return_type.to_string(),
                &serialize(body)
            ),
            Self::Ret(return_value) => format!("ret {}", (*return_value).into_string()),
            Self::End => "end".to_string()
        }
    }
}


/// Serializing an entire module/program
pub fn serialize(program: &Vec<IRNode>) -> String {
    let mut output = String::new();
    for (index, instruction) in program.iter().enumerate() {
        output.push_str(&instruction.into_string());
        if index < program.len() - 1 {
            output.push_str("\n")
        }
    }

    output
}