Skip to main content

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