microcad_lang/eval/mod.rs
1// Copyright © 2024-2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Evaluation of parsed content.
5//!
6//! To be able to evaluate (run) a source file, it must be loaded, parsed and resolved.
7//! To do so a [`EvalContext`] can be created with [`EvalContext::new()`] based on an already resolved symbol or
8//! by using [`EvalContext::from_source()`] or `ContextBuilder::from_source_captured()` which both automatically
9//! load and resolve the source file and build a context around it which then can be evaluated with [`EvalContext::eval()`]:
10//!
11//! ```ignore
12//! use microcad_lang::eval::EvalContext;
13//! use microcad_lang::diag::Diag;
14//! use std::io::stdout;
15//!
16//! // create a context for evaluation of the source file
17//! let mut context = EvalContext::from_source(
18//! "my.µcad", // root file name
19//! builtin_module(), // `__builtin` library
20//! &["./std/lib".into()] // list of std library path
21//! ).expect("successful load, parse and resolve");
22//!
23//! // evaluate the source file in it's context
24//! let node = context.eval().expect("successful evaluation");
25//!
26//! // print any error
27//! println!("{}", context.diagnosis());
28//! ```
29
30mod argument_match;
31mod attribute;
32mod body;
33mod call;
34mod eval_context;
35mod eval_error;
36mod expression;
37mod format_string;
38mod function;
39mod grant;
40mod init;
41mod literal;
42mod locals;
43mod module_definition;
44mod output;
45mod parameter;
46mod source_file;
47mod sources;
48mod statements;
49mod tuple;
50mod workbench;
51
52pub use argument_match::*;
53pub use attribute::*;
54pub use call::*;
55pub use eval_context::*;
56pub use eval_error::*;
57pub use output::*;
58
59use grant::*;
60use locals::*;
61use statements::*;
62
63use crate::{diag::*, resolve::*, src_ref::*, syntax::*, ty::*, value::*};
64
65/// Evaluation trait.
66///
67/// The return type `T` defines to which output type the type is evaluated.
68/// Usually, these output types are used in specific context:
69///
70/// | Return type `T` | Context / Scope | Return value on error | Description |
71/// | ------------------- | --------------------------------------------------- | ----------------------- | ----------------------------------------------------------------------- |
72/// | `()` | [`Assignment`]. | `()` | An assignment returns nothing but alters the symbol table. |
73/// | | | |
74/// | `Value` | Function calls, module statements, | `Value::None` | These trait implementations are
75/// | | parameter lists, argument lists. | | mostly used when evaluating functions.
76/// | | | |
77/// | `Option<Model>` | Workbenches, object bodies, source files, if. | `None` | Something is evaluated into a single model. |
78/// | | | |
79/// | `Models` | Statement, statement list, body, multiplicities. | `Models::default()` | A collection of models . |
80pub trait Eval<T = Value> {
81 /// Evaluate a syntax element into a type `T`.
82 fn eval(&self, context: &mut EvalContext) -> EvalResult<T>;
83}
84
85impl MethodCall {
86 /// Evaluate method call.
87 ///
88 /// Examples:
89 /// ```microcad
90 /// assert([2.0, 2.0].all_equal(), "All elements in this list must be equal.");
91 /// ```
92 fn eval(&self, context: &mut EvalContext, lhs: &Expression) -> EvalResult<Value> {
93 let value: Value = lhs.eval(context)?;
94 if let Value::Model(model) = &value {
95 if model.has_no_output() {
96 context.warning(&lhs, EvalError::EmptyModelExpression)?;
97 }
98 }
99 let args = self.argument_list.eval(context)?;
100 value.call_method(&self.name, &args, context)
101 }
102}
103
104/// Like `todo!()` but within a evaluation context
105///
106/// emits a diagnostic error instead of panicking.
107#[macro_export]
108macro_rules! eval_todo {
109 ($context: ident, $refer: ident, $($arg:tt)*) => {{
110 $context.error($refer, EvalError::Todo(format_args!($($arg)*).to_string()))?;
111 Ok(Value::None)
112 }}
113}
114
115pub use eval_todo;