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