microcad_lang/value/
argument_value_list.rs

1// Copyright © 2024-2025 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    /// Create new [`ArgumentValueList`]
23    pub fn new(map: Vec<(Identifier, ArgumentValue)>, src_ref: SrcRef) -> Self {
24        Self { map, src_ref }
25    }
26
27    /// Return a single argument.
28    ///
29    /// Returns error if there is no or more than one argument available.
30    pub fn get_single(&self) -> EvalResult<(&Identifier, &ArgumentValue)> {
31        if self.map.len() == 1 {
32            if let Some(a) = self.map.first() {
33                return Ok((&a.0, &a.1));
34            }
35        }
36
37        Err(EvalError::ArgumentCountMismatch {
38            args: self.to_string(),
39            expected: 1,
40            found: self.map.len(),
41        })
42    }
43
44    /// Get value by type
45    pub fn get_by_type(&self, ty: &Type) -> Option<(&Identifier, &ArgumentValue)> {
46        let arg = self.map.iter().find(|(_, arg)| arg.value.ty() == *ty);
47        arg.map(|arg| (&arg.0, &arg.1))
48    }
49}
50
51impl ValueAccess for ArgumentValueList {
52    fn by_id(&self, id: &Identifier) -> Option<&Value> {
53        self.map
54            .iter()
55            .find(|(i, _)| i == id)
56            .map(|arg| &arg.1.value)
57    }
58
59    fn by_ty(&self, ty: &Type) -> Option<&Value> {
60        self.get_by_type(ty).map(|(_, arg)| &arg.value)
61    }
62}
63
64impl SrcReferrer for ArgumentValueList {
65    fn src_ref(&self) -> SrcRef {
66        self.src_ref.clone()
67    }
68}
69
70impl std::fmt::Display for ArgumentValueList {
71    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72        write!(f, "{}", {
73            let mut v = self
74                .map
75                .iter()
76                .map(|(id, p)| format!("{id}{p}"))
77                .collect::<Vec<_>>();
78            v.sort();
79            v.join(", ")
80        })
81    }
82}
83
84impl std::fmt::Debug for ArgumentValueList {
85    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86        write!(f, "{}", {
87            let mut v = self
88                .map
89                .iter()
90                .map(|(id, av)| format!("{id:?}{av:?}"))
91                .collect::<Vec<_>>();
92            v.sort();
93            v.join(", ")
94        })
95    }
96}
97
98impl FromIterator<(Identifier, ArgumentValue)> for ArgumentValueList {
99    fn from_iter<T: IntoIterator<Item = (Identifier, ArgumentValue)>>(iter: T) -> Self {
100        let map: Vec<_> = iter.into_iter().collect();
101        Self {
102            src_ref: SrcRef::merge_all(map.iter().map(|(_, v)| v.src_ref())),
103            map,
104        }
105    }
106}
107
108#[test]
109fn test_argument_value_debug() {
110    let arg1 = ArgumentValue::new(
111        Value::Target(Target::new("my::name1".into(), Some("my::target1".into()))),
112        Some("id1".into()),
113        SrcRef(None),
114    );
115
116    let arg2 = ArgumentValue::new(
117        Value::Target(Target::new("my::name2".into(), None)),
118        Some("id2".into()),
119        SrcRef(None),
120    );
121
122    let mut args = ArgumentValueList::default();
123
124    args.push(("id1".into(), arg1));
125    args.push(("id2".into(), arg2));
126
127    log::info!("{args}");
128    log::info!("{args:?}");
129}