Skip to main content

microcad_lang/value/
argument_value_list.rs

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