1use microcad_lang_base::{PushDiag, SrcReferrer};
5
6use crate::{
7 eval::*,
8 model::*,
9 symbol::{Symbol, SymbolDef},
10};
11
12impl Eval for RangeFirst {
13 fn eval(&self, context: &mut EvalContext) -> EvalResult<Value> {
14 let value: Value = self.0.eval(context)?;
15 Ok(match value {
16 Value::Integer(_) => value,
17 value => {
18 context.error(
19 self,
20 EvalError::ExpectedType {
21 expected: Type::Integer,
22 found: value.ty(),
23 },
24 )?;
25
26 Value::None
27 }
28 })
29 }
30}
31
32impl Eval for RangeLast {
33 fn eval(&self, context: &mut EvalContext) -> EvalResult<Value> {
34 let value: Value = self.0.eval(context)?;
35 Ok(match value {
36 Value::Integer(_) => value,
37 value => {
38 context.error(
39 self,
40 EvalError::ExpectedType {
41 expected: Type::Integer,
42 found: value.ty(),
43 },
44 )?;
45
46 Value::None
47 }
48 })
49 }
50}
51
52impl Eval for RangeExpression {
53 fn eval(&self, context: &mut EvalContext) -> EvalResult<Value> {
54 Ok(
55 match (self.first.eval(context)?, self.last.eval(context)?) {
56 (Value::Integer(first), Value::Integer(last)) => {
57 if first > last {
58 context.error(self, EvalError::BadRange(first, last))?;
59 }
60
61 Value::Array(Array::from_values(
62 (first..last + 1).map(Value::Integer).collect(),
63 Type::Integer,
64 ))
65 }
66 (_, _) => Value::None,
67 },
68 )
69 }
70}
71
72impl Eval for ArrayExpression {
73 fn eval(&self, context: &mut EvalContext) -> EvalResult<Value> {
74 match &self.inner {
75 ArrayExpressionInner::Range(range_expression) => range_expression.eval(context),
76 ArrayExpressionInner::List(expressions) => {
77 let value_list = ValueList::new(
78 expressions
79 .iter()
80 .map(|expr| expr.eval(context))
81 .collect::<Result<_, _>>()?,
82 );
83
84 match value_list.types().common_type() {
85 Some(common_type) => {
86 match Value::Array(Array::from_values(value_list, common_type)) * self.unit
87 {
88 Ok(value) => Ok(value),
89 Err(err) => {
90 context.error(self, err)?;
91 Ok(Value::None)
92 }
93 }
94 }
95 None => {
96 context.error(
97 self,
98 EvalError::ArrayElementsDifferentTypes(value_list.types()),
99 )?;
100 Ok(Value::None)
101 }
102 }
103 }
104 }
105 }
106}
107
108impl Eval<Option<Symbol>> for QualifiedName {
109 fn eval(&self, context: &mut EvalContext) -> EvalResult<Option<Symbol>> {
110 match context.lookup(self, LookupTarget::AnyButMethod) {
111 Ok(symbol) => Ok(Some(symbol.clone())),
112 Err(error) => {
113 context.error(self, error)?;
114 Ok(None)
115 }
116 }
117 }
118}
119
120impl Eval for QualifiedName {
121 fn eval(&self, context: &mut EvalContext) -> EvalResult<Value> {
122 context
123 .lookup(self, LookupTarget::AnyButMethod)?
124 .with_def(|def| match def {
125 SymbolDef::Root => unreachable!("<ROOT> cannot be looked up"),
126 SymbolDef::Value(.., value) => Ok(value.clone()),
127 SymbolDef::Assignment(a) => a.eval(context),
128 SymbolDef::SourceFile(_) => Ok(Value::None),
129 SymbolDef::Builtin(crate::builtin::Builtin::Constant(c)) => Ok(c.value.clone()),
130 SymbolDef::Module(ns) => {
131 context.error(self, EvalError::UnexpectedNested("mod", ns.id()))?;
132 Ok(Value::None)
133 }
134 SymbolDef::Workbench(w) => {
135 context.error(self, EvalError::UnexpectedNested(w.kind.as_str(), w.id()))?;
136 Ok(Value::None)
137 }
138 SymbolDef::Function(f) => {
139 context.error(self, EvalError::UnexpectedNested("function", f.id()))?;
140 Ok(Value::None)
141 }
142 SymbolDef::Builtin(bm) => {
143 context.error(self, EvalError::UnexpectedNested("builtin", bm.id()))?;
144 Ok(Value::None)
145 }
146 SymbolDef::Alias(_, id, _) => {
147 unreachable!(
149 "Unexpected alias {id} in value expression at {}",
150 self.src_ref()
151 )
152 }
153 SymbolDef::UseAll(_, name) => {
154 unreachable!("Unexpected use {name} in value expression")
155 }
156 #[cfg(test)]
157 SymbolDef::Tester(..) => {
158 unreachable!()
159 }
160 })
161 }
162}
163
164impl Expression {
165 pub fn eval_with_attribute_list(
170 &self,
171 attribute_list: &AttributeList,
172 context: &mut EvalContext,
173 ) -> EvalResult<Value> {
174 let value = self.eval(context)?;
175 match value {
176 Value::Model(model) => {
177 let attributes = attribute_list.eval(context)?;
178 model.borrow_mut().attributes = attributes.clone();
179 Ok(Value::Model(model))
180 }
181 Value::None => Ok(Value::None),
182 _ => {
183 if !attribute_list.is_empty() {
184 context.error(
185 attribute_list,
186 AttributeError::CannotAssignAttribute(self.to_string()),
187 )?;
188 }
189 Ok(value)
190 }
191 }
192 }
193}
194
195impl Eval for Expression {
196 fn eval(&self, context: &mut EvalContext) -> EvalResult<Value> {
197 log::trace!("Evaluating expression:\n{self}");
198 let result = match self {
199 Self::Literal(literal) => literal.eval(context),
200 Self::FormatString(format_string) => format_string.eval(context),
201 Self::ArrayExpression(array_expression) => array_expression.eval(context),
202 Self::TupleExpression(tuple_expression) => tuple_expression.eval(context),
203 Self::BinaryOp {
204 lhs,
205 op,
206 rhs,
207 src_ref: _,
208 } => {
209 let lhs: Value = lhs.eval(context)?;
210 let rhs: Value = rhs.eval(context)?;
211 if lhs.is_invalid() || rhs.is_invalid() {
212 return Ok(Value::None);
213 }
214
215 match Value::binary_op(lhs, rhs, op.as_str()) {
216 Err(err) => {
217 context.error(self, err)?;
218 Ok(Value::None)
219 }
220 Ok(value) => Ok(value),
221 }
222 }
223 Self::UnaryOp {
224 op,
225 rhs,
226 src_ref: _,
227 } => {
228 let value: Value = rhs.eval(context)?;
229 value.unary_op(op.as_str()).map_err(EvalError::ValueError)
230 }
231 Self::ArrayElementAccess(lhs, rhs, _) => {
232 let lhs = lhs.eval(context)?;
233 let rhs = rhs.eval(context)?;
234
235 match (lhs, rhs) {
236 (Value::Array(list), Value::Integer(index)) => {
237 let index = index as usize;
238 if index < list.len() {
239 match list.get(index) {
240 Some(value) => Ok(value.clone()),
241 None => Err(EvalError::ListIndexOutOfBounds {
242 index,
243 len: list.len(),
244 }),
245 }
246 } else {
247 context.error(
248 self,
249 EvalError::ListIndexOutOfBounds {
250 index,
251 len: list.len(),
252 },
253 )?;
254 Ok(Value::None)
255 }
256 }
257 _ => unimplemented!(),
258 }
259 }
260 Self::MethodCall(lhs, method_call, _) => method_call.eval(context, lhs),
261 Self::Call(call) => call.eval(context),
262 Self::Body(body) => {
263 if let Some(model) = body.eval(context)? {
264 Ok(model.into())
265 } else {
266 Ok(Value::None)
267 }
268 }
269 Self::If(if_) => {
270 if let Some(model) = if_.eval(context)? {
271 Ok(model.into())
272 } else {
273 Ok(Value::None)
274 }
275 }
276 Self::QualifiedName(qualified_name) => qualified_name.eval(context),
277 Self::Marker(marker) => {
278 let model: Option<Model> = marker.eval(context)?;
279 Ok(model.map(Value::Model).unwrap_or_default())
280 }
281 Self::PropertyAccess(lhs, id, src_ref) => {
283 let value: Value = lhs.eval(context)?;
284 match value {
285 Value::Tuple(tuple) => match tuple.by_id(id) {
286 Some(value) => return Ok(value.clone()),
287 None => context.error(src_ref, EvalError::PropertyNotFound(id.clone()))?,
288 },
289 Value::Model(model) => match model.borrow().get_property(id) {
290 Some(prop) => return Ok(prop.clone()),
291 None => context.error(src_ref, EvalError::PropertyNotFound(id.clone()))?,
292 },
293 _ => {}
294 }
295
296 Ok(Value::None)
297 }
298 Self::AttributeAccess(lhs, identifier, src_ref) => {
299 let value: Value = lhs.eval(context)?;
300 let value = value.get_attribute_value(identifier);
301 if value == Value::None {
302 context.error(src_ref, AttributeError::NotFound(identifier.clone()))?;
303 }
304 Ok(value)
305 }
306 expr => todo!("{expr:?}"),
307 };
308 match result {
309 Ok(value) => {
310 log::trace!("Evaluated expression:\n{self:?}\n--- into ---\n{value:?}");
311 Ok(value)
312 }
313 Err(err) => {
314 context.error(self, err)?;
315 Ok(Value::None)
316 }
317 }
318 }
319}
320
321impl Eval<Option<Model>> for Expression {
322 fn eval(&self, context: &mut EvalContext) -> EvalResult<Option<Model>> {
323 Ok(match self.eval(context)? {
324 Value::Model(model) => Some(model),
325 _ => None,
326 })
327 }
328}