nilang 0.4.1

A scripting language interpreter for Advent of Code
Documentation
use crate::operators::{BinaryOp, UnaryOp};
use crate::symbol_map::SymID;

pub type LabelID = usize;
pub type FuncID = u32;
pub type VReg = u32;
pub type UpValId = u16;

#[derive(Debug, PartialEq, Clone)]
pub enum TacConst {
    String(String),
    Int(i64),
    Float(f64),
    Bool(bool),
    Func(FuncID),
    Sym(SymID),
    Null,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Tac {
    Pop {
        dest: VReg,
        src: VReg,
    },
    Unaop {
        dest: VReg,
        op: UnaryOp,
        src: VReg,
    },
    Binop {
        dest: VReg,
        op: BinaryOp,
        lhs: VReg,
        rhs: VReg,
    },
    Push {
        store: VReg,
        src: VReg
    },
    NewList {
        dest: VReg,
    },
    NewMap {
        dest: VReg,
    },
    Print {
        src: VReg,
    },
    Read {
        dest: VReg,
    },
    Copy {
        dest: VReg,
        src: VReg,
    },
    MemStore {
        store: VReg,
        key: VReg,
        src: VReg,
    },
    MemLoad {
        dest: VReg,
        store: VReg,
        key: VReg,
    },
    LoadConst {
        dest: VReg,
        src: TacConst,
    },
    LoadGlobal {
        dest: VReg,
        sym: VReg,
    },
    StoreGlobal {
        src: VReg,
        sym: VReg,
    },
    LoadUpvalue {
        dest: VReg,
        id: UpValId,
    },
    StoreUpvalue {
        func: VReg,
        src: VReg,
    },
    StoreArg {
        src: VReg,
    },
    Call {
        dest: VReg,
        src: VReg,
    },
    Return {
        src: VReg,
    },
    Jump {
        label: LabelID,
    },
    Jnt {
        label: LabelID,
        src: VReg,
    },
    Jit {
        label: LabelID,
        src: VReg,
    },
    Label {
        label: LabelID,
    },
    Noop,
    Import {
        dest: VReg,
        path: VReg,
    },
    Delete {
        dest: VReg,
        store: VReg,
        key: VReg,
    },
    Bind {
        dest: VReg,
        func: VReg,
        arg: VReg,
    },
    Clone {
        dest: VReg,
        src: VReg,
    },
    Type {
        dest: VReg,
        src: VReg,
    },
}

impl Tac {
    pub fn used_regs(&self) -> [Option<&VReg>; 3] {
        match self {
            Tac::Binop { lhs, rhs, .. } => [Some(lhs), Some(rhs), None],

            Tac::LoadGlobal { sym, .. } => [Some(sym), None, None],
            Tac::StoreGlobal { src, sym, .. } => [Some(src), Some(sym), None],
            Tac::Copy { src, .. }
            | Tac::Print { src, .. }
            | Tac::StoreArg { src, .. }
            | Tac::Call { src, .. }
            | Tac::Return { src, .. }
            | Tac::Pop { src, .. }
            | Tac::Clone { src, .. }
            | Tac::Type { src, .. }
            | Tac::Jnt { src, .. }
            | Tac::Jit { src, .. } => [Some(src), None, None],
            Tac::Import { path, .. } => [Some(path), None, None],
            Tac::Unaop { src, .. } => [Some(src), None, None],
            Tac::MemLoad { store, key, .. } => [Some(store), Some(key), None],
            Tac::Delete { store, key, .. } => [Some(store), Some(key), None],
            Tac::Bind { func, arg, .. } => [Some(func), Some(arg), None],
            Tac::MemStore { store, key, src } => [Some(store), Some(key), Some(src)],
            Tac::StoreUpvalue { func, src } => [Some(func), Some(src), None],
            Tac::Push { store, src } => [Some(store), Some(src), None],
            _ => [None, None, None],
        }
    }
    pub fn used_regs_mut(&mut self) -> [Option<&mut VReg>; 3] {
        match self {
            Tac::Binop { lhs, rhs, .. } => [Some(lhs), Some(rhs), None],

            Tac::LoadGlobal { sym, .. } => [Some(sym), None, None],
            Tac::StoreGlobal { src, sym, .. } => [Some(src), Some(sym), None],
            Tac::Copy { src, .. }
            | Tac::Print { src, .. }
            | Tac::StoreArg { src, .. }
            | Tac::Call { src, .. }
            | Tac::Return { src, .. }
            | Tac::Pop { src, .. }
            | Tac::Clone { src, .. }
            | Tac::Type { src, .. }
            | Tac::Jnt { src, .. }
            | Tac::Jit { src, .. } => [Some(src), None, None],
            Tac::Import { path, .. } => [Some(path), None, None],
            Tac::Unaop { src, .. } => [Some(src), None, None],
            Tac::MemLoad { store, key, .. } => [Some(store), Some(key), None],
            Tac::Delete { store, key, .. } => [Some(store), Some(key), None],
            Tac::Bind { func, arg, .. } => [Some(func), Some(arg), None],
            Tac::MemStore { store, key, src } => [Some(store), Some(key), Some(src)],
            Tac::StoreUpvalue { func, src } => [Some(func), Some(src), None],
            Tac::Push { store, src } => [Some(store), Some(src), None],
            _ => [None, None, None],
        }
    }

    pub fn dest_reg(&self) -> Option<&VReg> {
        match self {
            Tac::LoadUpvalue { dest, .. }
            | Tac::LoadGlobal { dest, .. }
            | Tac::Call { dest, .. }
            | Tac::LoadConst { dest, .. }
            | Tac::MemLoad { dest, .. }
            | Tac::Copy { dest, .. }
            | Tac::Read { dest, .. }
            | Tac::NewMap { dest, .. }
            | Tac::NewList { dest, .. }
            | Tac::Pop { dest, .. }
            | Tac::Import { dest, .. }
            | Tac::Unaop { dest, .. }
            | Tac::Clone { dest, .. }
            | Tac::Type { dest, .. }
            | Tac::Bind { dest, .. }
            | Tac::Delete { dest, .. }
            | Tac::Binop { dest, .. } => Some(dest),
            _ => None,
        }
    }

    pub fn dest_reg_mut(&mut self) -> Option<&mut VReg> {
        match self {
            Tac::LoadUpvalue { dest, .. }
            | Tac::LoadGlobal { dest, .. }
            | Tac::Call { dest, .. }
            | Tac::LoadConst { dest, .. }
            | Tac::MemLoad { dest, .. }
            | Tac::Copy { dest, .. }
            | Tac::Read { dest, .. }
            | Tac::NewMap { dest, .. }
            | Tac::NewList { dest, .. }
            | Tac::Pop { dest, .. }
            | Tac::Unaop { dest, .. }
            | Tac::Clone { dest, .. }
            | Tac::Type { dest, .. }
            | Tac::Bind { dest, .. }
            | Tac::Delete { dest, .. }
            | Tac::Import { dest, .. }
            | Tac::Binop { dest, .. } => Some(dest),
            _ => None,
        }
    }

    pub fn has_side_effects(&self) -> bool {
        matches!(
            self,
            Tac::Read { .. }
                | Tac::Print { .. }
                | Tac::Call { .. }
                | Tac::Import { .. }
                | Tac::Pop { .. }
                | Tac::Delete { .. }
        )
    }
}