Skip to main content

microcad_lang/syntax/parameter/
mod.rs

1// Copyright © 2024-2026 The µcad authors <info@microcad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! µcad parameter syntax elements
5
6mod parameter_list;
7
8use crate::{eval::*, ord_map::*, syntax::*, ty::*, value::*};
9
10use microcad_lang_base::{PushDiag, Refer, SrcRef, SrcReferrer, TreeDisplay, TreeState};
11pub use parameter_list::*;
12
13/// A parameter of a parameter list.
14#[derive(Clone, Default)]
15pub struct Parameter {
16    /// Name of the parameter
17    pub(crate) id: Identifier,
18    /// Type of the parameter or `None`
19    pub specified_type: Option<TypeAnnotation>,
20    /// default value of the parameter or `None`
21    pub default_value: Option<Expression>,
22    /// Source code reference
23    pub src_ref: SrcRef,
24}
25
26impl Parameter {
27    /// Create new parameter
28    pub fn new(
29        id: Identifier,
30        specified_type: Option<TypeAnnotation>,
31        default_value: Option<Expression>,
32        src_ref: SrcRef,
33    ) -> Self {
34        assert!(!id.is_empty());
35        Self {
36            id,
37            specified_type,
38            default_value,
39            src_ref,
40        }
41    }
42
43    /// Create a new parameter without any SrcRef's
44    pub fn no_ref(id: &str, ty: Type) -> Self {
45        Self {
46            id: Identifier::no_ref(id),
47            specified_type: Some(TypeAnnotation(Refer::none(ty))),
48            default_value: None,
49            src_ref: SrcRef(None),
50        }
51    }
52
53    /// Evaluate default value considering specified type
54    ///
55    /// If there is no default value, returns `Value::None` without raising an error.
56    pub fn eval_default_value(&self, context: &mut EvalContext) -> crate::eval::EvalResult<Value> {
57        use crate::eval::Eval;
58
59        match (&self.specified_type, &self.default_value) {
60            (Some(specified_type), Some(default_value)) => {
61                let value: Value = default_value.eval(context)?;
62                if specified_type.ty() != value.ty() {
63                    context.error(
64                        &self.src_ref,
65                        EvalError::TypeMismatch {
66                            id: self.id(),
67                            expected: specified_type.ty(),
68                            found: value.ty(),
69                        },
70                    )?;
71                    Ok(Value::None)
72                } else {
73                    Ok(value)
74                }
75            }
76            (None, Some(default_value)) => Ok(default_value.eval(context)?),
77            _ => Ok(Value::None),
78        }
79    }
80}
81
82impl Identifiable for Parameter {
83    fn id_ref(&self) -> &Identifier {
84        &self.id
85    }
86}
87
88impl SrcReferrer for Parameter {
89    fn src_ref(&self) -> SrcRef {
90        self.src_ref.clone()
91    }
92}
93
94impl OrdMapValue<Identifier> for Parameter {
95    fn key(&self) -> Option<Identifier> {
96        Some(self.id())
97    }
98}
99
100impl std::fmt::Display for Parameter {
101    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
102        match (&self.specified_type, &self.default_value) {
103            (Some(t), Some(v)) => write!(f, "{}: {t} = {v}", self.id),
104            (Some(t), None) => write!(f, "{}: {t}", self.id),
105            (None, Some(v)) => write!(f, "{} = {v}", self.id),
106            _ => Ok(()),
107        }
108    }
109}
110
111impl std::fmt::Debug for Parameter {
112    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
113        match (&self.specified_type, &self.default_value) {
114            (Some(t), Some(v)) => write!(f, "{:?}: {t:?} = {v:?}", self.id),
115            (Some(t), None) => write!(f, "{:?}: {t:?}", self.id),
116            (None, Some(v)) => write!(f, "{:?} = {v:?}", self.id),
117            _ => Ok(()),
118        }
119    }
120}
121
122impl TreeDisplay for Parameter {
123    fn tree_print(&self, f: &mut std::fmt::Formatter, depth: TreeState) -> std::fmt::Result {
124        match (&self.specified_type, &self.default_value) {
125            (Some(specified_type), Some(default_value)) => writeln!(
126                f,
127                "{:depth$}Parameter: {}: {} = {}",
128                "", self.id, specified_type, default_value
129            ),
130            (Some(specified_type), None) => {
131                writeln!(f, "{:depth$}Parameter: {}: {}", "", self.id, specified_type)
132            }
133            (None, Some(default_value)) => {
134                writeln!(f, "{:depth$}Parameter: {} = {}", "", self.id, default_value)
135            }
136            _ => unreachable!("impossible parameter declaration"),
137        }
138    }
139}