microcad_lang/eval/statements/
mod.rs

1// Copyright © 2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Workbench definition syntax element evaluation
5// Copyright © 2025 The µcad authors <info@ucad.xyz>
6// SPDX-License-Identifier: AGPL-3.0-or-later
7
8use crate::{eval::*, model::*};
9
10mod assignment_statement;
11mod expression_statement;
12mod if_statement;
13mod marker;
14mod return_statement;
15mod use_statement;
16
17pub use use_statement::*;
18
19impl Eval for Statement {
20    fn eval(&self, context: &mut EvalContext) -> EvalResult<Value> {
21        match self {
22            Self::Workbench(w) => {
23                w.grant(context)?;
24                Ok(Value::None)
25            }
26            Self::Module(m) => {
27                m.grant(context)?;
28                Ok(Value::None)
29            }
30            Self::Function(f) => {
31                f.grant(context)?;
32                Ok(Value::None)
33            }
34            Self::Use(u) => {
35                u.eval(context)?;
36                Ok(Value::None)
37            }
38            Self::Assignment(a) => {
39                a.eval(context)?;
40                Ok(Value::None)
41            }
42            Self::If(i) => i.eval(context),
43            Self::Expression(e) => e.eval(context),
44            Self::InnerAttribute(i) => {
45                i.grant(context)?;
46                Ok(Value::None)
47            }
48            Self::Init(i) => {
49                i.grant(context)?;
50                Ok(Value::None)
51            }
52            Self::Return(r) => r.eval(context),
53        }
54    }
55}
56
57impl Eval<Option<Model>> for Statement {
58    fn eval(&self, context: &mut EvalContext) -> EvalResult<Option<Model>> {
59        let model: Option<Model> = match self {
60            Self::Workbench(w) => {
61                w.grant(context)?;
62                None
63            }
64            Self::Module(m) => {
65                m.eval(context)?;
66                None
67            }
68            Self::Function(f) => {
69                f.grant(context)?;
70                None
71            }
72            Self::Init(i) => {
73                i.grant(context)?;
74                None
75            }
76            Self::Return(r) => {
77                r.grant(context)?;
78                None
79            }
80            Self::Use(u) => {
81                u.eval(context)?;
82                None
83            }
84            Self::Assignment(a) => {
85                a.eval(context)?;
86                None
87            }
88            Self::If(i) => i.eval(context)?,
89            Self::Expression(e) => e.eval(context)?,
90            Self::InnerAttribute(a) => {
91                a.grant(context)?;
92                None
93            }
94        };
95
96        if let Some(ref model) = model {
97            if model.deduce_output_type() == OutputType::InvalidMixed {
98                context.error(self, EvalError::CannotMixGeometry)?;
99            }
100        }
101
102        Ok(model)
103    }
104}
105
106impl Eval<Value> for StatementList {
107    fn eval(&self, context: &mut EvalContext) -> EvalResult<Value> {
108        let mut result = Value::None;
109        for statement in self.iter() {
110            log::trace!("Evaluating statement: {statement}");
111            match statement.eval(context)? {
112                Value::Return(result) => {
113                    return Ok(Value::Return(result));
114                }
115                value => result = value,
116            }
117        }
118        Ok(result)
119    }
120}
121
122/// Parse inner attributes of a statement list.
123impl Eval<Attributes> for StatementList {
124    fn eval(&self, context: &mut EvalContext) -> EvalResult<Attributes> {
125        let mut attributes = Vec::new();
126        for statement in self.iter() {
127            if let Statement::InnerAttribute(attribute) = statement {
128                attributes.append(&mut attribute.eval(context)?);
129            }
130        }
131
132        Ok(Attributes(attributes))
133    }
134}
135
136impl Eval<Models> for StatementList {
137    fn eval(&self, context: &mut EvalContext) -> EvalResult<Models> {
138        let mut models = Models::default();
139        let mut output_type = OutputType::NotDetermined;
140
141        for statement in self.iter() {
142            if let Some(model) = statement.eval(context)? {
143                output_type = output_type.merge(&model.deduce_output_type());
144                if output_type == OutputType::InvalidMixed {
145                    context.error(statement, EvalError::CannotMixGeometry)?;
146                }
147                models.push(model);
148            }
149        }
150        models.deduce_output_type();
151        Ok(models)
152    }
153}