Skip to main content

yulang_native/
cps_closure.rs

1use crate::cps_env::{CpsEnvironmentSlot, layout_cps_environments};
2use crate::cps_ir::{CpsContinuationId, CpsModule, CpsShotKind, CpsValueId};
3
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct CpsClosureModule {
6    pub functions: Vec<CpsClosureFunction>,
7    pub roots: Vec<CpsClosureFunction>,
8}
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct CpsClosureFunction {
12    pub name: String,
13    pub continuations: Vec<CpsClosureContinuation>,
14}
15
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct CpsClosureContinuation {
18    pub code: CpsContinuationId,
19    pub params: Vec<CpsValueId>,
20    pub environment: Vec<CpsEnvironmentSlot>,
21    pub shot_kind: CpsShotKind,
22}
23
24pub fn closure_convert_cps_module(module: &CpsModule) -> CpsClosureModule {
25    let layout = layout_cps_environments(module);
26    CpsClosureModule {
27        functions: module
28            .functions
29            .iter()
30            .zip(layout.functions)
31            .map(|(function, layout)| closure_convert_function(function, layout.continuations))
32            .collect(),
33        roots: module
34            .roots
35            .iter()
36            .zip(layout.roots)
37            .map(|(function, layout)| closure_convert_function(function, layout.continuations))
38            .collect(),
39    }
40}
41
42fn closure_convert_function(
43    function: &crate::cps_ir::CpsFunction,
44    layouts: Vec<crate::cps_env::CpsContinuationEnvironmentLayout>,
45) -> CpsClosureFunction {
46    CpsClosureFunction {
47        name: function.name.clone(),
48        continuations: function
49            .continuations
50            .iter()
51            .zip(layouts)
52            .map(|(continuation, layout)| CpsClosureContinuation {
53                code: continuation.id,
54                params: continuation.params.clone(),
55                environment: layout.slots,
56                shot_kind: continuation.shot_kind,
57            })
58            .collect(),
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use crate::cps_ir::{
65        CpsContinuation, CpsContinuationId, CpsFunction, CpsModule, CpsShotKind, CpsTerminator,
66        CpsValueId,
67    };
68
69    use super::*;
70
71    #[test]
72    fn closure_conversion_preserves_code_params_and_environment_slots() {
73        let module = CpsModule {
74            functions: Vec::new(),
75            roots: vec![CpsFunction {
76                name: "root".to_string(),
77                params: Vec::new(),
78                entry: CpsContinuationId(0),
79                continuations: vec![CpsContinuation {
80                    id: CpsContinuationId(7),
81                    params: vec![CpsValueId(1)],
82                    captures: vec![CpsValueId(4), CpsValueId(2)],
83                    shot_kind: CpsShotKind::MultiShot,
84                    stmts: Vec::new(),
85                    terminator: CpsTerminator::Return(CpsValueId(1)),
86                }],
87                handlers: Vec::new(),
88            }],
89        };
90
91        let converted = closure_convert_cps_module(&module);
92
93        assert_eq!(
94            converted.roots[0].continuations,
95            vec![CpsClosureContinuation {
96                code: CpsContinuationId(7),
97                params: vec![CpsValueId(1)],
98                environment: vec![
99                    CpsEnvironmentSlot {
100                        index: 0,
101                        value: CpsValueId(4),
102                    },
103                    CpsEnvironmentSlot {
104                        index: 1,
105                        value: CpsValueId(2),
106                    },
107                ],
108                shot_kind: CpsShotKind::MultiShot,
109            }]
110        );
111    }
112}