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 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 fn handle_symbols(
112 &mut self,
113 node: &KdlNode,
114 namespace: &mut Namespace<'_>,
115 ) -> Result<(), Error> {
116 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(®ion)
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(®ion), 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}