yulang-native 0.1.1

Native backend experiments for Yulang
Documentation
use crate::cps_env::{CpsEnvironmentSlot, layout_cps_environments};
use crate::cps_ir::{CpsContinuationId, CpsModule, CpsShotKind, CpsValueId};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CpsClosureModule {
    pub functions: Vec<CpsClosureFunction>,
    pub roots: Vec<CpsClosureFunction>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CpsClosureFunction {
    pub name: String,
    pub continuations: Vec<CpsClosureContinuation>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CpsClosureContinuation {
    pub code: CpsContinuationId,
    pub params: Vec<CpsValueId>,
    pub environment: Vec<CpsEnvironmentSlot>,
    pub shot_kind: CpsShotKind,
}

pub fn closure_convert_cps_module(module: &CpsModule) -> CpsClosureModule {
    let layout = layout_cps_environments(module);
    CpsClosureModule {
        functions: module
            .functions
            .iter()
            .zip(layout.functions)
            .map(|(function, layout)| closure_convert_function(function, layout.continuations))
            .collect(),
        roots: module
            .roots
            .iter()
            .zip(layout.roots)
            .map(|(function, layout)| closure_convert_function(function, layout.continuations))
            .collect(),
    }
}

fn closure_convert_function(
    function: &crate::cps_ir::CpsFunction,
    layouts: Vec<crate::cps_env::CpsContinuationEnvironmentLayout>,
) -> CpsClosureFunction {
    CpsClosureFunction {
        name: function.name.clone(),
        continuations: function
            .continuations
            .iter()
            .zip(layouts)
            .map(|(continuation, layout)| CpsClosureContinuation {
                code: continuation.id,
                params: continuation.params.clone(),
                environment: layout.slots,
                shot_kind: continuation.shot_kind,
            })
            .collect(),
    }
}

#[cfg(test)]
mod tests {
    use crate::cps_ir::{
        CpsContinuation, CpsContinuationId, CpsFunction, CpsModule, CpsShotKind, CpsTerminator,
        CpsValueId,
    };

    use super::*;

    #[test]
    fn closure_conversion_preserves_code_params_and_environment_slots() {
        let module = CpsModule {
            functions: Vec::new(),
            roots: vec![CpsFunction {
                name: "root".to_string(),
                params: Vec::new(),
                entry: CpsContinuationId(0),
                continuations: vec![CpsContinuation {
                    id: CpsContinuationId(7),
                    params: vec![CpsValueId(1)],
                    captures: vec![CpsValueId(4), CpsValueId(2)],
                    shot_kind: CpsShotKind::MultiShot,
                    stmts: Vec::new(),
                    terminator: CpsTerminator::Return(CpsValueId(1)),
                }],
                handlers: Vec::new(),
            }],
        };

        let converted = closure_convert_cps_module(&module);

        assert_eq!(
            converted.roots[0].continuations,
            vec![CpsClosureContinuation {
                code: CpsContinuationId(7),
                params: vec![CpsValueId(1)],
                environment: vec![
                    CpsEnvironmentSlot {
                        index: 0,
                        value: CpsValueId(4),
                    },
                    CpsEnvironmentSlot {
                        index: 1,
                        value: CpsValueId(2),
                    },
                ],
                shot_kind: CpsShotKind::MultiShot,
            }]
        );
    }
}