Skip to main content

microcad_lang/value/
argument_value_list.rs

1// Copyright © 2024-2026 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! *Argument value list* evaluation entity.
5
6use crate::{eval::*, src_ref::*, value::*};
7use derive_more::{Deref, DerefMut};
8
9/// Collection of *argument values* (e.g. `( x=1, y=2 )`).
10///
11/// Also provides methods to find a matching call
12/// between it and a given *parameter list*.
13#[derive(Clone, Default, Deref, DerefMut)]
14pub struct ArgumentValueList {
15    #[deref]
16    #[deref_mut]
17    map: Vec<(Identifier, ArgumentValue)>,
18    src_ref: SrcRef,
19}
20
21impl ArgumentValueList {
22    /// Return a single argument.
23    ///
24    /// Returns error if there is no or more than one argument available.
25    pub fn get_single(&self) -> EvalResult<(&Identifier, &ArgumentValue)> {
26        if self.map.len() == 1 {
27            if let Some(a) = self.map.first() {
28                return Ok((&a.0, &a.1));
29            }
30        }
31
32        Err(EvalError::ArgumentCountMismatch {
33            args: self.to_string(),
34            expected: 1,
35            found: self.map.len(),
36        })
37    }
38
39    /// Get value by type
40    pub fn get_by_type(&self, ty: &Type) -> Option<(&Identifier, &ArgumentValue)> {
41        let arg = self.map.iter().find(|(_, arg)| arg.value.ty() == *ty);
42        arg.map(|arg| (&arg.0, &arg.1))
43    }
44}
45
46impl ValueAccess for ArgumentValueList {
47    fn by_id(&self, id: &Identifier) -> Option<&Value> {
48        self.map
49            .iter()
50            .find(|(i, _)| i == id)
51            .map(|arg| &arg.1.value)
52    }
53
54    fn by_ty(&self, ty: &Type) -> Option<&Value> {
55        self.get_by_type(ty).map(|(_, arg)| &arg.value)
56    }
57}
58
59impl SrcReferrer for ArgumentValueList {
60    fn src_ref(&self) -> SrcRef {
61        self.src_ref.clone()
62    }
63}
64
65impl std::fmt::Display for ArgumentValueList {
66    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67        write!(f, "{}", {
68            let mut v = self
69                .map
70                .iter()
71                .map(|(id, val)| {
72                    if !id.is_empty() {
73                        format!("{id} = {}", val.value)
74                    } else if let Some(id) = &val.inline_id {
75                        format!("{id} = {}", val.value)
76                    } else {
77                        format!("{}", val.value)
78                    }
79                })
80                .collect::<Vec<_>>();
81            v.sort();
82            v.join(", ")
83        })
84    }
85}
86
87impl std::fmt::Debug for ArgumentValueList {
88    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89        write!(f, "{}", {
90            let mut v = self
91                .map
92                .iter()
93                .map(|(id, val)| {
94                    if !id.is_empty() {
95                        format!("{id:?} = {:?}", val.value)
96                    } else if let Some(id) = &val.inline_id {
97                        format!("{id:?} = {:?}", val.value)
98                    } else {
99                        format!("{:?}", val.value)
100                    }
101                })
102                .collect::<Vec<_>>();
103            v.sort();
104            v.join(", ")
105        })
106    }
107}
108
109impl FromIterator<(Identifier, ArgumentValue)> for ArgumentValueList {
110    fn from_iter<T: IntoIterator<Item = (Identifier, ArgumentValue)>>(iter: T) -> Self {
111        let map: Vec<_> = iter.into_iter().collect();
112        Self {
113            src_ref: SrcRef::merge_all(map.iter().map(|(_, v)| v.src_ref())),
114            map,
115        }
116    }
117}
118
119#[test]
120fn test_argument_value_debug() {
121    let arg1 = ArgumentValue::new(
122        Value::Target(Target::new("my::name1".into(), Some("my::target1".into()))),
123        Some("id1".into()),
124        SrcRef(None),
125    );
126
127    let arg2 = ArgumentValue::new(
128        Value::Target(Target::new("my::name2".into(), None)),
129        Some("id2".into()),
130        SrcRef(None),
131    );
132
133    let mut args = ArgumentValueList::default();
134
135    args.push(("id1".into(), arg1));
136    args.push(("id2".into(), arg2));
137
138    log::info!("{args}");
139    log::info!("{args:?}");
140}