Skip to main content

litex/obj/
fn_set.rs

1use std::fmt;
2
3use crate::prelude::*;
4
5#[derive(Clone)]
6pub struct FnSetBody {
7    pub params_def_with_set: ParamDefWithSet,
8    pub dom_facts: Vec<OrAndChainAtomicFact>,
9    /// Return sets are intentionally non-dependent: they must not cite this function's parameters.
10    pub ret_set: Box<Obj>,
11}
12
13impl FnSetBody {
14    pub fn new(
15        params_def_with_set: impl Into<ParamDefWithSet>,
16        dom_facts: Vec<OrAndChainAtomicFact>,
17        ret_set: Obj,
18    ) -> Self {
19        Self {
20            params_def_with_set: params_def_with_set.into(),
21            dom_facts,
22            ret_set: Box::new(ret_set),
23        }
24    }
25
26    pub fn get_params(&self) -> Vec<String> {
27        let mut ret = Vec::with_capacity(ParamGroupWithSet::number_of_params(
28            &self.params_def_with_set,
29        ));
30        for param_def_with_set in &self.params_def_with_set {
31            ret.extend(param_def_with_set.params.iter().cloned());
32        }
33        ret
34    }
35}
36
37#[derive(Clone)]
38pub struct FnSet {
39    pub body: FnSetBody,
40}
41
42impl FnSet {
43    pub fn new(
44        params_and_their_sets: impl Into<ParamDefWithSet>,
45        dom_facts: Vec<OrAndChainAtomicFact>,
46        ret_set: Obj,
47    ) -> Result<Self, RuntimeError> {
48        let params_and_their_sets = params_and_their_sets.into();
49        params_and_their_sets.validate_obj_does_not_cite_params(&ret_set, "function return set")?;
50        let fn_set = FnSet {
51            body: FnSetBody::new(params_and_their_sets, dom_facts, ret_set),
52        };
53        check_fn_set_has_no_duplicate_fn_set_free_parameter(&fn_set)?;
54        Ok(fn_set)
55    }
56
57    pub fn from_body(body: FnSetBody) -> Result<Self, RuntimeError> {
58        body.params_def_with_set
59            .validate_obj_does_not_cite_params(&body.ret_set, "function return set")?;
60        let fn_set = FnSet { body };
61        check_fn_set_has_no_duplicate_fn_set_free_parameter(&fn_set)?;
62        Ok(fn_set)
63    }
64
65    pub fn get_params(&self) -> Vec<String> {
66        self.body.get_params()
67    }
68}
69
70// Anonymous function value: `FnSetBody` plus braced `equal_to` body.
71#[derive(Clone)]
72pub struct AnonymousFn {
73    pub body: FnSetBody,
74    pub equal_to: Box<Obj>,
75}
76
77impl AnonymousFn {
78    pub fn new(
79        params_and_their_sets: impl Into<ParamDefWithSet>,
80        dom_facts: Vec<OrAndChainAtomicFact>,
81        ret_set: Obj,
82        equal_to: Obj,
83    ) -> Result<Self, RuntimeError> {
84        let params_and_their_sets = params_and_their_sets.into();
85        params_and_their_sets
86            .validate_obj_does_not_cite_params(&ret_set, "anonymous function return set")?;
87        let anonymous_fn = AnonymousFn {
88            body: FnSetBody::new(params_and_their_sets, dom_facts, ret_set),
89            equal_to: Box::new(equal_to),
90        };
91        check_anonymous_fn_has_no_duplicate_fn_set_free_parameter(&anonymous_fn)?;
92        Ok(anonymous_fn)
93    }
94}
95
96// FnSet or AnonymousFn as the current callable space for curried FnObj application checks.
97#[derive(Clone)]
98pub enum FnSetSpace {
99    Set(FnSet),
100    Anon(AnonymousFn),
101}
102
103impl FnSetSpace {
104    pub fn params(&self) -> &ParamDefWithSet {
105        match self {
106            FnSetSpace::Set(f) => &f.body.params_def_with_set,
107            FnSetSpace::Anon(a) => &a.body.params_def_with_set,
108        }
109    }
110
111    pub fn dom(&self) -> &Vec<OrAndChainAtomicFact> {
112        match self {
113            FnSetSpace::Set(f) => &f.body.dom_facts,
114            FnSetSpace::Anon(a) => &a.body.dom_facts,
115        }
116    }
117
118    pub fn ret_set_obj(&self) -> Obj {
119        match self {
120            FnSetSpace::Set(f) => (*f.body.ret_set).clone(),
121            FnSetSpace::Anon(a) => (*a.body.ret_set).clone(),
122        }
123    }
124
125    pub fn binding(&self) -> ParamObjType {
126        match self {
127            FnSetSpace::Set(_) => ParamObjType::FnSet,
128            FnSetSpace::Anon(_) => ParamObjType::FnSet,
129        }
130    }
131
132    pub fn from_ret_obj(obj: Obj) -> Result<Self, RuntimeError> {
133        match obj {
134            Obj::FnSet(f) => Ok(FnSetSpace::Set(f)),
135            Obj::AnonymousFn(a) => Ok(FnSetSpace::Anon(a)),
136            _ => Err(RuntimeError::from(WellDefinedRuntimeError(
137                RuntimeErrorStruct::new_with_just_msg(format!(
138                    "expect return set of function space to be `fn` or anonymous fn, got {}",
139                    obj
140                )),
141            ))),
142        }
143    }
144}
145
146impl fmt::Display for FnSetBody {
147    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148        let params_with_sets_display: Vec<String> = self
149            .params_def_with_set
150            .iter()
151            .map(|g| g.to_string())
152            .collect();
153        write!(
154            f,
155            "{} {} {}",
156            FN_LOWER_CASE,
157            brace_vec_colon_vec_to_string(&params_with_sets_display, &self.dom_facts),
158            self.ret_set
159        )
160    }
161}
162
163impl fmt::Display for FnSet {
164    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165        write!(f, "{}", self.body)
166    }
167}
168
169impl fmt::Display for AnonymousFn {
170    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171        let params_with_sets_display: Vec<String> = self
172            .body
173            .params_def_with_set
174            .iter()
175            .map(|g| g.to_string())
176            .collect();
177        write!(
178            f,
179            "{}{} {} {}{}{}",
180            ANONYMOUS_FN_PREFIX,
181            brace_vec_colon_vec_to_string(&params_with_sets_display, &self.body.dom_facts),
182            self.body.ret_set,
183            LEFT_CURLY_BRACE,
184            self.equal_to,
185            RIGHT_CURLY_BRACE,
186        )
187    }
188}
189
190impl From<FnSet> for Obj {
191    fn from(fs: FnSet) -> Self {
192        Obj::FnSet(fs)
193    }
194}
195
196impl From<AnonymousFn> for Obj {
197    fn from(af: AnonymousFn) -> Self {
198        Obj::AnonymousFn(af)
199    }
200}