Skip to main content

matugen_parser/engine/
resolve.rs

1use chumsky::span::SimpleSpan;
2
3use super::Engine;
4
5use crate::{
6    color::parse::parse_css_color,
7    {
8        Error, ParseErrorKind, Value,
9        engine::{FORMATS, format_color},
10    },
11};
12
13impl Engine {
14    pub fn resolve_generic_color<'a>(
15        &self,
16        color: &Value,
17        format: &'a str,
18        format_value: bool,
19        span: SimpleSpan,
20        name: &str,
21    ) -> Result<Value, Error> {
22        let color = match parse_css_color(&color.to_string()) {
23            Ok(v) => v,
24            Err(_) => {
25                return Err(Error::ResolveError {
26                    span,
27                    name: name.to_string(),
28                });
29            }
30        };
31        if format_value {
32            let res = match format_color(color, format) {
33                Some(v) => v,
34                None => {
35                    return Err(Error::ParseError {
36                        kind: ParseErrorKind::Keyword(crate::KeywordError::InvalidFormat {
37                            formats: FORMATS,
38                        }),
39                        span,
40                        name: name.to_string(),
41                    });
42                }
43            };
44
45            Ok(Value::Ident(res.to_string()))
46        } else {
47            Ok(Value::Color(color))
48        }
49    }
50
51    pub fn resolve_path<'a, I>(
52        &self,
53        path: I,
54        format_value: bool,
55        span: SimpleSpan,
56        name: &str,
57    ) -> Result<Value, Error>
58    where
59        I: IntoIterator<Item = &'a str> + Clone,
60    {
61        let mut iter = path.clone().into_iter().peekable();
62        let first = iter.next().ok_or(Error::ResolveError {
63            span,
64            name: name.to_string(),
65        })?;
66
67        let mut current = self
68            .runtime
69            .borrow()
70            .resolve_path(std::iter::once(first))
71            .or_else(|| self.context.data().get(first).cloned())
72            .ok_or(Error::ResolveError {
73                span,
74                name: name.to_string(),
75            })?;
76
77        while let Some(next_key) = iter.next() {
78            let next_key = if next_key.starts_with("_") {
79                next_key.strip_prefix("_").unwrap()
80            } else {
81                next_key
82            };
83
84            match current {
85                Value::Map(ref map) => {
86                    if map.contains_key("color") {
87                        let color = map.get("color").unwrap();
88                        current =
89                            self.resolve_generic_color(color, next_key, format_value, span, name)?;
90                    } else {
91                        current = map
92                            .get(next_key)
93                            .ok_or(Error::ResolveError {
94                                span,
95                                name: name.to_string(),
96                            })?
97                            .clone();
98                    }
99                }
100                Value::LazyColor { color, .. } => {
101                    current = if format_value {
102                        Value::Ident(
103                            format_color(color, next_key)
104                                .ok_or(Error::ResolveError {
105                                    span,
106                                    name: name.to_string(),
107                                })?
108                                .to_string(),
109                        )
110                    } else {
111                        Value::Color(color)
112                    }
113                }
114                Value::Color(color) => {
115                    current = if format_value {
116                        Value::Ident(
117                            format_color(color, next_key)
118                                .ok_or(Error::ResolveError {
119                                    span,
120                                    name: name.to_string(),
121                                })?
122                                .to_string(),
123                        )
124                    } else {
125                        Value::Color(color)
126                    }
127                }
128                _ => {
129                    return Err(Error::ResolveError {
130                        span,
131                        name: name.to_string(),
132                    });
133                }
134            }
135        }
136
137        Ok(current)
138    }
139
140    pub fn get_format<'a>(&self, keywords: &[&'a str]) -> &'a str {
141        keywords
142            .last()
143            .expect("Could not get format from {keywords}")
144    }
145}