memory_spec/
lib.rs

1use std::{
2    collections::HashMap,
3    fmt::{Display, Write as _},
4    str::FromStr,
5};
6mod expr;
7pub mod region;
8use kdl::{KdlDocument, KdlError, KdlNode, KdlValue};
9pub use region::Region;
10
11use crate::expr::{EvalError, Namespace, Value};
12
13#[derive(Clone, Debug)]
14pub struct Regions {
15    region: Region,
16    subregions: HashMap<String, Regions>,
17}
18
19impl Regions {
20    fn new(region: Region) -> Self {
21        Self {
22            region,
23            subregions: Default::default(),
24        }
25    }
26
27    pub fn region(&self) -> &Region {
28        &self.region
29    }
30
31    pub fn origin(&self) -> u64 {
32        self.region.origin()
33    }
34
35    pub fn length(&self) -> u64 {
36        self.region.length()
37    }
38
39    pub fn end(&self) -> u64 {
40        self.region.end()
41    }
42
43    pub fn get(&self, key: &str) -> Option<&Regions> {
44        self.subregions.get(key)
45    }
46}
47
48impl std::ops::Index<&str> for Regions {
49    type Output = Regions;
50
51    fn index(&self, index: &str) -> &Self::Output {
52        &self.subregions[index]
53    }
54}
55
56#[derive(Clone, Default, Debug)]
57pub struct MemorySpec {
58    regions: HashMap<String, Regions>,
59    symbols: HashMap<String, u64>,
60}
61
62impl FromStr for MemorySpec {
63    type Err = Error;
64
65    fn from_str(content: &str) -> Result<Self, Error> {
66        let doc: KdlDocument = content.parse()?;
67        let mut namespace = Namespace::default();
68        let mut spec = Self::default();
69        for node in doc.nodes() {
70            match node.name().value() {
71                "vars" => spec.handle_vars(node, &mut namespace)?,
72                "regions" => spec.handle_regions(node, &mut namespace)?,
73                "symbols" => spec.handle_symbols(node, &mut namespace)?,
74                _ => (),
75            }
76        }
77        Ok(spec)
78    }
79}
80
81impl MemorySpec {
82    pub fn regions(&self) -> &HashMap<String, Regions> {
83        &self.regions
84    }
85
86    pub fn render_symbols(&self) -> String {
87        let mut r = String::new();
88        for (name, value) in &self.symbols {
89            writeln!(&mut r, "{name} = 0x{value:08x};").unwrap();
90        }
91        r
92    }
93
94    fn handle_vars(&self, node: &KdlNode, namespace: &mut Namespace<'_>) -> Result<(), Error> {
95        // TODO warn/reject params
96        for child in node
97            .children()
98            .ok_or_else(|| Error::InvalidNode("vars".into()))?
99            .nodes()
100        {
101            let name = child.name().value();
102            let path = || format!("vars.{}", name);
103            let value = child.get(0).ok_or_else(|| Error::InvalidNode(path()))?;
104            let value = eval_kdl_value(value, namespace, path)?;
105            namespace.insert(name.into(), expr::Value::N(value));
106        }
107        Ok(())
108    }
109
110    // basically the same as handle_vars but add the entries to the symbols table too
111    fn handle_symbols(
112        &mut self,
113        node: &KdlNode,
114        namespace: &mut Namespace<'_>,
115    ) -> Result<(), Error> {
116        // TODO warn/reject params
117        for child in node
118            .children()
119            .ok_or_else(|| Error::InvalidNode("vars".into()))?
120            .nodes()
121        {
122            let name = child.name().value();
123            let path = || format!("symbols.{}", name);
124            let value = child.get(0).ok_or_else(|| Error::InvalidNode(path()))?;
125            let value = eval_kdl_value(value, namespace, path)?;
126            namespace.insert(name.into(), expr::Value::N(value));
127            let value = u64::try_from(value).map_err(|_| Error::InvalidNode(path()))?;
128            let prev = self.symbols.insert(name.into(), value);
129            if prev.is_some() {
130                return Err(Error::NameExists(path()));
131            }
132        }
133        Ok(())
134    }
135
136    fn handle_regions(
137        &mut self,
138        node: &KdlNode,
139        namespace: &mut Namespace<'_>,
140    ) -> Result<(), Error> {
141        let mut subregions = vec![];
142        for child in node
143            .children()
144            .ok_or_else(|| Error::InvalidNode("regions".into()))?
145            .nodes()
146        {
147            let r = self.handle_region(child, namespace, None, &mut vec![])?;
148            subregions.push((r, String::from(child.name().value())));
149        }
150        check_overlap(subregions, &[])?;
151        Ok(())
152    }
153
154    fn handle_region(
155        &mut self,
156        node: &KdlNode,
157        namespace: &mut Namespace<'_>,
158        parent_region: Option<&Region>,
159        path: &mut Vec<String>,
160    ) -> Result<Region, Error> {
161        let name = node.name().value();
162        let path_str = || format!("regions.{}.{}", path.join("."), name);
163        let origin = node
164            .get("origin")
165            .map(|v| eval_kdl_value(v, namespace, path_str))
166            .transpose()?;
167        let length = node
168            .get("length")
169            .map(|v| eval_kdl_value(v, namespace, path_str))
170            .transpose()?;
171        let end = node
172            .get("end")
173            .map(|v| eval_kdl_value(v, namespace, path_str))
174            .transpose()?;
175        let align = node
176            .get("align")
177            .map(|v| eval_kdl_value(v, namespace, path_str))
178            .transpose()?;
179        let origin = origin
180            .map(u64::try_from)
181            .transpose()
182            .map_err(|_| Error::InvalidNode(path_str()))?;
183        let length = length
184            .map(u64::try_from)
185            .transpose()
186            .map_err(|_| Error::InvalidNode(path_str()))?;
187        let end = end
188            .map(u64::try_from)
189            .transpose()
190            .map_err(|_| Error::InvalidNode(path_str()))?;
191        let align = align
192            .map(u64::try_from)
193            .transpose()
194            .map_err(|_| Error::InvalidNode(path_str()))?;
195
196        let region =
197            Region::new(origin, length, end).map_err(|_| Error::InvalidNode(path_str()))?;
198        if let Some(align) = align
199            && (region.origin() % align != 0 || region.end() % align != 0)
200        {
201            return Err(Error::AlignError(path_str()));
202        }
203        if let Some(parent_region) = parent_region
204            && !parent_region.contains(&region)
205        {
206            return Err(Error::SubregionError {
207                outer: format!("regions.{}", path.join(".")),
208                inner: name.into(),
209            });
210        }
211
212        path.push(name.into());
213        self.add_region(region, path);
214        add_value(namespace, path, Value::Namespace(Namespace::default()))?;
215        path.push("origin".into());
216        add_value(
217            namespace,
218            path,
219            Value::N(i64::try_from(region.origin()).unwrap()),
220        )?;
221        path.last_mut().unwrap().replace_range(.., "length");
222        add_value(
223            namespace,
224            path,
225            Value::N(i64::try_from(region.length()).unwrap()),
226        )?;
227        path.last_mut().unwrap().replace_range(.., "end");
228        add_value(
229            namespace,
230            path,
231            Value::N(i64::try_from(region.end()).unwrap()),
232        )?;
233        path.pop();
234
235        let children = node.children().map(|d| d.nodes());
236        if let Some(children) = children {
237            let mut subregions = vec![];
238            for child in children {
239                let subregion = self.handle_region(child, namespace, Some(&region), path)?;
240                let name = child.name().value();
241                subregions.push((subregion, String::from(name)));
242            }
243            check_overlap(subregions, path)?;
244        }
245        path.pop();
246
247        Ok(region)
248    }
249
250    fn add_region(&mut self, region: Region, path: &[String]) {
251        let mut map = &mut self.regions;
252        for name in &path[..path.len() - 1] {
253            map = &mut map.get_mut(name).unwrap().subregions;
254        }
255        map.insert(path.last().unwrap().clone(), Regions::new(region));
256    }
257}
258
259fn eval_kdl_value(
260    value: &KdlValue,
261    namespace: &Namespace<'_>,
262    path: impl Fn() -> String,
263) -> Result<i64, Error> {
264    match value {
265        KdlValue::Integer(n) => Ok(i64::try_from(*n).map_err(|_| Error::InvalidValue(path()))?),
266        KdlValue::String(ex) => Ok(expr::eval(ex, namespace)?),
267        _ => Err(Error::InvalidValue(path())),
268    }
269}
270
271fn check_overlap(mut regions: Vec<(Region, String)>, path: &[String]) -> Result<(), Error> {
272    let path_str = || {
273        if path.is_empty() {
274            "regions".into()
275        } else {
276            format!("regions.{}", path.join("."))
277        }
278    };
279    regions.sort_unstable();
280    for w in regions.windows(2) {
281        let ((l, lname), (r, rname)) = (&w[0], &w[1]);
282        if l.overlaps(r) {
283            return Err(Error::OverlapError {
284                parent_region: path_str(),
285                region1: lname.clone(),
286                region2: rname.clone(),
287            });
288        }
289    }
290    Ok(())
291}
292
293fn add_value<'a>(
294    namespace: &mut Namespace<'a>,
295    path: &[String],
296    value: expr::Value<'a>,
297) -> Result<(), Error> {
298    match path {
299        [k] => {
300            let r = namespace.insert(k.clone(), value);
301            if r.is_some() {
302                Err(Error::NameExists(k.clone()))
303            } else {
304                Ok(())
305            }
306        }
307        [k, tail @ ..] => add_value(
308            namespace.get_mut(k).unwrap().namespace_mut().unwrap(),
309            tail,
310            value,
311        ),
312        [] => unreachable!(),
313    }
314}
315
316#[derive(Debug, Clone, PartialEq, Eq)]
317pub enum Error {
318    KdlError(KdlError),
319    EvalError(EvalError),
320    AlignError(String),
321    InvalidNode(String),
322    InvalidValue(String),
323    NameExists(String),
324    OverlapError {
325        parent_region: String,
326        region1: String,
327        region2: String,
328    },
329    SubregionError {
330        outer: String,
331        inner: String,
332    },
333}
334
335impl Display for Error {
336    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
337        match self {
338            Self::KdlError(e) => e.fmt(f),
339            Self::EvalError(e) => e.fmt(f),
340            Self::AlignError(r) => write!(f, "{} is not aligned", r),
341            Self::InvalidNode(n) => write!(f, "invalid node name {}", n),
342            Self::InvalidValue(n) => write!(f, "invalid value in {}", n),
343            Self::NameExists(n) => write!(f, "{} already exists", n),
344            Self::OverlapError {
345                parent_region,
346                region1,
347                region2,
348            } => write!(f, "{parent_region}: {region1} overlaps with {region2}"),
349            Self::SubregionError { outer, inner } => {
350                write!(f, "{} is not contained by {}", inner, outer)
351            }
352        }
353    }
354}
355
356impl From<KdlError> for Error {
357    fn from(t: KdlError) -> Self {
358        Self::KdlError(t)
359    }
360}
361
362impl From<EvalError> for Error {
363    fn from(t: EvalError) -> Self {
364        Self::EvalError(t)
365    }
366}
367
368#[cfg(test)]
369mod tests {
370    use super::*;
371
372    #[test]
373    fn regions_test() {
374        let content = r#"regions {
375            region1 origin=0 end=2
376            region2 origin=2 end=3
377        }"#;
378
379        let r = MemorySpec::from_str(content).unwrap();
380    }
381
382    #[test]
383    fn overlap_test() {
384        let content = r#"regions {
385            region1 origin=0 end=2
386            region2 origin=1 end=3
387        }"#;
388
389        let _err = MemorySpec::from_str(content).unwrap_err();
390    }
391
392    #[test]
393    fn subregion_test() {
394        let content = r#"regions {
395            region1 origin=0 end=2 {
396                region2 origin=1 end=3
397            }
398        }"#;
399        let _err = MemorySpec::from_str(content).unwrap_err();
400    }
401}