1mod array;
10mod matrix;
11mod quantity;
12mod tuple;
13mod value_access;
14mod value_error;
15mod value_list;
16
17pub use array::*;
18use derive_more::From;
19pub use matrix::*;
20pub use quantity::*;
21pub use tuple::*;
22pub use value_access::*;
23pub use value_error::*;
24pub use value_list::*;
25
26use crate::{lower::ir, model, ty::*};
27use microcad_core::*;
28use microcad_lang_base::SrcRef;
29use std::hash::Hasher;
30
31pub(crate) type ValueResult<Type = Value> = std::result::Result<Type, ValueError>;
32
33#[derive(Clone, Debug, Default, PartialEq, From)]
35pub enum Value {
36 #[default]
38 None,
39 Quantity(Quantity),
41 Bool(bool),
43 Integer(Integer),
45 String(String),
47 Array(Array),
49 Tuple(Box<Tuple>),
51 Matrix(Box<Matrix>),
53 Model(model::Model),
55 Return(Box<Value>),
57}
58
59impl Value {
60 pub fn is_invalid(&self) -> bool {
62 matches!(self, Value::None)
63 }
64
65 pub fn pow(&self, rhs: &Value) -> ValueResult {
67 match (&self, rhs) {
68 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity(lhs.pow(rhs))),
69 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity(lhs.pow_int(rhs))),
70 (Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs.pow(*rhs as u32))),
71 _ => Err(ValueError::InvalidOperator("^".to_string())),
72 }
73 }
74
75 pub fn binary_op(lhs: Value, rhs: Value, op: &str) -> ValueResult {
77 match op {
78 "+" => lhs + rhs,
79 "-" => lhs - rhs,
80 "*" => lhs * rhs,
81 "/" => lhs / rhs,
82 "^" => lhs.pow(&rhs),
83 "&" | "and" => lhs & rhs,
84 "|" | "or" => lhs | rhs,
85 ">" => Ok(Value::Bool(lhs > rhs)),
86 "<" => Ok(Value::Bool(lhs < rhs)),
87 "≤" | "<=" => Ok(Value::Bool(lhs <= rhs)),
88 "≥" | ">=" => Ok(Value::Bool(lhs >= rhs)),
89 "~" => todo!("implement near ~="),
90 "==" => Ok(Value::Bool(lhs == rhs)),
91 "!=" => Ok(Value::Bool(lhs != rhs)),
92 _ => unimplemented!("{op:?}"),
93 }
94 }
95
96 pub fn unary_op(self, op: &str) -> ValueResult {
98 match op {
99 "-" => -self,
100 "!" => !self,
101 _ => Err(ValueError::InvalidOperator(op.to_string())),
102 }
103 }
104
105 pub fn try_string(&self) -> Result<String, ValueError> {
107 match self {
108 Value::String(s) => return Ok(s.clone()),
109 Value::Integer(i) => return Ok(i.to_string()),
110 _ => {}
111 }
112
113 Err(ValueError::CannotConvert(self.to_string(), "String".into()))
114 }
115
116 pub fn try_scalar(&self) -> Result<Scalar, ValueError> {
118 match self {
119 Value::Quantity(q) => return Ok(q.value),
120 Value::Integer(i) => return Ok((*i) as f64),
121 _ => {}
122 }
123
124 Err(ValueError::CannotConvert(self.to_string(), "Scalar".into()))
125 }
126
127 pub fn un_return(&self) -> Value {
129 match self {
130 Value::Return(value) => value.as_ref().clone(),
131 value => value.clone(),
132 }
133 }
134}
135
136impl PartialOrd for Value {
137 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
138 match (self, other) {
139 (Value::Integer(lhs), Value::Integer(rhs)) => lhs.partial_cmp(rhs),
141 (Value::Quantity(lhs), Value::Quantity(rhs)) => lhs.partial_cmp(rhs),
142 (
143 Value::Quantity(Quantity {
144 value,
145 quantity_type: QuantityType::Scalar,
146 ..
147 }),
148 Value::Integer(rhs),
149 ) => value.partial_cmp(&(*rhs as Scalar)),
150 _ => {
151 log::warn!("unhandled type mismatch between {self} and {other}");
152 None
153 }
154 }
155 }
156}
157
158impl crate::ty::Ty for Value {
159 fn ty(&self) -> Type {
160 match self {
161 Value::None => Type::Invalid,
162 Value::Integer(_) => Type::Integer,
163 Value::Quantity(q) => q.ty(),
164 Value::Bool(_) => Type::Bool,
165 Value::String(_) => Type::String,
166 Value::Array(list) => list.ty(),
167 Value::Tuple(tuple) => tuple.ty(),
168 Value::Matrix(matrix) => matrix.ty(),
169 Value::Model(_) => Type::Model,
170 Value::Return(r) => r.ty(),
171 }
172 }
173}
174
175impl std::ops::Neg for Value {
176 type Output = ValueResult;
177
178 fn neg(self) -> Self::Output {
179 match self {
180 Value::Integer(n) => Ok(Value::Integer(-n)),
181 Value::Quantity(q) => Ok(Value::Quantity(q.neg())),
182 Value::Array(a) => -a,
183 Value::Tuple(t) => -t.as_ref().clone(),
184 _ => Err(ValueError::InvalidOperator("-".into())),
185 }
186 }
187}
188
189impl std::ops::Not for Value {
190 type Output = ValueResult;
191
192 fn not(self) -> Self::Output {
193 match self {
194 Value::Bool(b) => Ok(Value::Bool(!b)),
195 Value::Array(a) => !a,
196 Value::Tuple(t) => !t.as_ref().clone(),
197 _ => Err(ValueError::InvalidOperator("!".into())),
198 }
199 }
200}
201
202impl std::ops::Add for Value {
204 type Output = ValueResult;
205
206 fn add(self, rhs: Self) -> Self::Output {
207 match (self, rhs) {
208 (Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs + rhs)),
210 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs + rhs)?)),
212 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs + rhs)?)),
214 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs + rhs)?)),
216 (Value::String(lhs), Value::String(rhs)) => Ok(Value::String(lhs + &rhs)),
218 (Value::Array(lhs), Value::Array(rhs)) => {
220 if lhs.ty() != rhs.ty() {
221 return Err(ValueError::CannotCombineVecOfDifferentType(
222 lhs.ty(),
223 rhs.ty(),
224 ));
225 }
226
227 Ok(Value::Array(Array::from_values(
228 lhs.iter().chain(rhs.iter()).cloned().collect(),
229 lhs.ty(),
230 )))
231 }
232 (Value::Array(lhs), rhs) => Ok((lhs + rhs)?),
234 (Value::Tuple(lhs), Value::Tuple(rhs)) => Ok((*lhs + *rhs)?.into()),
236 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} + {rhs}"))),
237 }
238 }
239}
240
241fn map_model_result(result: crate::model::ops::ModelResult) -> ValueResult {
245 result
246 .map_err(|err| match *err {
247 crate::eval::EvalError::ValueError(value_error) => value_error,
248 _ => unreachable!(),
249 })
250 .map(Value::from)
251}
252
253impl std::ops::Sub for Value {
255 type Output = ValueResult;
256
257 fn sub(self, rhs: Self) -> Self::Output {
258 match (self, rhs) {
259 (Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs - rhs)),
261 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs - rhs)?)),
263 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs - rhs)?)),
265 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs - rhs)?)),
267 (Value::Array(lhs), rhs) => Ok((lhs - rhs)?),
269 (Value::Tuple(lhs), Value::Tuple(rhs)) => Ok((*lhs - *rhs)?.into()),
271
272 (Value::Model(lhs), Value::Model(rhs)) => map_model_result(lhs - rhs),
274 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} - {rhs}"))),
275 }
276 }
277}
278
279impl std::ops::Mul for Value {
281 type Output = ValueResult;
282
283 fn mul(self, rhs: Self) -> Self::Output {
284 match (self, rhs) {
285 (Value::Integer(lhs), Value::Model(rhs)) => map_model_result(lhs * rhs),
286 (Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs * rhs)),
288 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs * rhs)?)),
290 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs * rhs)?)),
292 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs * rhs)?)),
294 (Value::Array(array), value) | (value, Value::Array(array)) => Ok((array * value)?),
295
296 (Value::Tuple(tuple), value) | (value, Value::Tuple(tuple)) => {
297 Ok((tuple.as_ref().clone() * value)?.into())
298 }
299 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} * {rhs}"))),
300 }
301 }
302}
303
304impl std::ops::Mul<Unit> for Value {
308 type Output = ValueResult;
309
310 fn mul(self, unit: Unit) -> Self::Output {
311 match (self, unit.ty()) {
312 (value, Type::Quantity(QuantityType::Scalar)) | (value, Type::Integer) => Ok(value),
313 (Value::Integer(i), Type::Quantity(quantity_type)) => Ok(Value::Quantity(
314 Quantity::new(unit.normalize(i as Scalar), quantity_type),
315 )),
316 (Value::Quantity(quantity), Type::Quantity(quantity_type)) => Ok(Value::Quantity(
317 (quantity * Quantity::new(unit.normalize(1.0), quantity_type))?,
318 )),
319 (Value::Array(array), Type::Quantity(quantity_type)) => {
320 Ok((array * Value::Quantity(Quantity::new(unit.normalize(1.0), quantity_type)))?)
321 }
322 (value, _) => Err(ValueError::CannotAddUnitToValueWithUnit(value.to_string())),
323 }
324 }
325}
326
327impl std::ops::Div for Value {
329 type Output = ValueResult;
330
331 fn div(self, rhs: Self) -> Self::Output {
332 match (self, rhs) {
333 (Value::Integer(lhs), Value::Integer(rhs)) => {
335 Ok(Value::Quantity((lhs as Scalar / rhs as Scalar).into()))
336 }
337 (Value::Quantity(lhs), Value::Integer(rhs)) => Ok(Value::Quantity((lhs / rhs)?)),
338 (Value::Integer(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs / rhs)?)),
339 (Value::Quantity(lhs), Value::Quantity(rhs)) => Ok(Value::Quantity((lhs / rhs)?)),
340 (Value::Array(array), value) => Ok((array / value)?),
341 (Value::Tuple(tuple), value) => Ok((tuple.as_ref().clone() / value)?.into()),
342 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} / {rhs}"))),
343 }
344 }
345}
346
347impl std::ops::BitOr for Value {
349 type Output = ValueResult;
350
351 fn bitor(self, rhs: Self) -> Self::Output {
352 match (self, rhs) {
353 (Value::Model(lhs), Value::Model(rhs)) => map_model_result(lhs | rhs),
354 (Value::Bool(lhs), Value::Bool(rhs)) => Ok(Value::Bool(lhs | rhs)),
355 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} | {rhs}"))),
356 }
357 }
358}
359
360impl std::ops::BitAnd for Value {
362 type Output = ValueResult;
363
364 fn bitand(self, rhs: Self) -> Self::Output {
365 match (self, rhs) {
366 (Value::Model(lhs), Value::Model(rhs)) => map_model_result(lhs & rhs),
367 (Value::Bool(lhs), Value::Bool(rhs)) => Ok(Value::Bool(lhs & rhs)),
368 (lhs, rhs) => Err(ValueError::InvalidOperator(format!("{lhs} & {rhs}"))),
369 }
370 }
371}
372
373impl std::fmt::Display for Value {
374 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
375 match self {
376 Value::None => write!(f, "<NO VALUE>"),
377 Value::Integer(n) => write!(f, "{n}"),
378 Value::Quantity(q) => write!(f, "{q}"),
379 Value::Bool(b) => write!(f, "{b}"),
380 Value::String(s) => write!(f, "{s}"),
381 Value::Array(l) => write!(f, "{l}"),
382 Value::Tuple(t) => write!(f, "{t}"),
383 Value::Matrix(m) => write!(f, "{m}"),
384 Value::Model(n) => write!(f, "{n}"),
385 Value::Return(r) => write!(f, "{r}"),
386 }
387 }
388}
389
390impl std::hash::Hash for Value {
391 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
392 match self {
393 Value::None => std::mem::discriminant(&Value::None).hash(state),
394 Value::Quantity(quantity) => quantity.hash(state),
395 Value::Bool(b) => b.hash(state),
396 Value::Integer(i) => i.hash(state),
397 Value::String(s) => s.hash(state),
398 Value::Array(array) => array.hash(state),
399 Value::Tuple(tuple) => tuple.hash(state),
400 Value::Matrix(matrix) => matrix.hash(state),
401 Value::Model(model) => model.hash(state),
402 Value::Return(value) => value.hash(state),
403 }
404 }
405}
406
407impl microcad_lang_base::ComputedHash for Value {
408 fn computed_hash(&self) -> hash::HashId {
409 use std::hash::Hash;
410 let mut hasher = microcad_lang_base::Hasher::default();
411 self.hash(&mut hasher);
412 hasher.finish()
413 }
414}
415
416macro_rules! impl_try_from {
417 ($($variant:ident),+ => $ty:ty ) => {
418 impl TryFrom<Value> for $ty {
419 type Error = ValueError;
420
421 fn try_from(value: Value) -> std::result::Result<Self, Self::Error> {
422 match value {
423 $(Value::$variant(v) => Ok(v),)*
424 value => Err(ValueError::CannotConvert(value.to_string(), stringify!($ty).into())),
425 }
426 }
427 }
428
429 impl TryFrom<&Value> for $ty {
430 type Error = ValueError;
431
432 fn try_from(value: &Value) -> std::result::Result<Self, Self::Error> {
433 match value {
434 $(Value::$variant(v) => Ok(v.clone().into()),)*
435 value => Err(ValueError::CannotConvert(value.to_string(), stringify!($ty).into())),
436 }
437 }
438 }
439 };
440}
441
442impl_try_from!(Integer => i64);
443impl_try_from!(Bool => bool);
444impl_try_from!(String => String);
445
446impl TryFrom<&Value> for Scalar {
447 type Error = ValueError;
448
449 fn try_from(value: &Value) -> Result<Self, Self::Error> {
450 match value {
451 Value::Integer(i) => Ok(*i as Scalar),
452 Value::Quantity(Quantity {
453 value,
454 quantity_type: QuantityType::Scalar,
455 ..
456 }) => Ok(*value),
457 _ => Err(ValueError::CannotConvert(
458 value.to_string(),
459 "Scalar".into(),
460 )),
461 }
462 }
463}
464
465impl TryFrom<Value> for Scalar {
466 type Error = ValueError;
467
468 fn try_from(value: Value) -> Result<Self, Self::Error> {
469 match value {
470 Value::Integer(i) => Ok(i as Scalar),
471 Value::Quantity(Quantity {
472 value,
473 quantity_type: QuantityType::Scalar,
474 ..
475 }) => Ok(value),
476 _ => Err(ValueError::CannotConvert(
477 value.to_string(),
478 "Scalar".into(),
479 )),
480 }
481 }
482}
483
484impl TryFrom<&Value> for Angle {
485 type Error = ValueError;
486
487 fn try_from(value: &Value) -> Result<Self, Self::Error> {
488 match value {
489 Value::Quantity(Quantity {
490 value,
491 quantity_type: QuantityType::Angle,
492 ..
493 }) => Ok(cgmath::Rad(*value)),
494 _ => Err(ValueError::CannotConvert(value.to_string(), "Angle".into())),
495 }
496 }
497}
498
499impl TryFrom<&Value> for Length {
500 type Error = ValueError;
501
502 fn try_from(value: &Value) -> Result<Self, Self::Error> {
503 match value {
504 Value::Quantity(Quantity {
505 value,
506 quantity_type: QuantityType::Length,
507 ..
508 }) => Ok(Length(*value)),
509 _ => Err(ValueError::CannotConvert(
510 value.to_string(),
511 "Length".into(),
512 )),
513 }
514 }
515}
516
517impl TryFrom<&Value> for Size2 {
518 type Error = ValueError;
519
520 fn try_from(value: &Value) -> Result<Self, Self::Error> {
521 match value {
522 Value::Tuple(tuple) => Ok(tuple.as_ref().try_into()?),
523 _ => Err(ValueError::CannotConvert(value.to_string(), "Size2".into())),
524 }
525 }
526}
527
528impl TryFrom<&Value> for Mat3 {
529 type Error = ValueError;
530
531 fn try_from(value: &Value) -> Result<Self, Self::Error> {
532 if let Value::Matrix(m) = value {
533 if let Matrix::Matrix3(matrix3) = m.as_ref() {
534 return Ok(*matrix3);
535 }
536 }
537
538 Err(ValueError::CannotConvert(
539 value.to_string(),
540 "Matrix3".into(),
541 ))
542 }
543}
544
545impl From<usize> for Value {
546 fn from(value: usize) -> Self {
547 Value::Integer(value as Integer)
548 }
549}
550
551impl From<f32> for Value {
552 fn from(f: f32) -> Self {
553 Value::Quantity((f as Scalar).into())
554 }
555}
556
557impl From<Scalar> for Value {
558 fn from(scalar: Scalar) -> Self {
559 Value::Quantity(scalar.into())
560 }
561}
562
563impl From<Length> for Value {
564 fn from(length: Length) -> Self {
565 Value::Quantity(length.into())
566 }
567}
568
569impl From<Size2> for Value {
570 fn from(value: Size2) -> Self {
571 Self::Tuple(Box::new(value.into()))
572 }
573}
574
575impl From<Color> for Value {
576 fn from(color: Color) -> Self {
577 Self::Tuple(Box::new(color.into()))
578 }
579}
580
581impl From<Vec3> for Value {
582 fn from(v: Vec3) -> Self {
583 Self::Tuple(Box::new(v.into()))
584 }
585}
586
587impl FromIterator<Value> for Value {
588 fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
589 Self::Array(iter.into_iter().collect())
590 }
591}
592
593impl model::AttributesAccess for Value {
594 fn get_attributes_by_id(&self, id: &ir::Identifier) -> Vec<crate::model::Attribute> {
595 match self {
596 Value::Model(model) => model.get_attributes_by_id(id),
597 _ => Vec::default(),
598 }
599 }
600}
601
602#[cfg(test)]
603fn integer(value: i64) -> Value {
604 Value::Integer(value)
605}
606
607#[cfg(test)]
608fn scalar(value: f64) -> Value {
609 Value::Quantity(Quantity::new(value, QuantityType::Scalar))
610}
611
612#[cfg(test)]
613fn check(result: ValueResult, value: Value) {
614 let result = result.expect("error result");
615 assert_eq!(result, value);
616}
617
618#[test]
619fn test_value_integer() {
620 let u = || integer(2);
621 let v = || integer(5);
622 let w = || scalar(5.0);
623
624 check(u() + v(), integer(2 + 5));
626 check(u() - v(), integer(2 - 5));
627 check(u() * v(), integer(2 * 5));
628 check(u() / v(), scalar(2.0 / 5.0));
629 check(-u(), integer(-2));
630
631 check(u() + w(), scalar(2 as Scalar + 5.0));
633 check(u() - w(), scalar(2 as Scalar - 5.0));
634 check(u() * w(), scalar(2 as Scalar * 5.0));
635 check(u() / w(), scalar(2.0 / 5.0));
636}
637
638#[test]
639fn test_value_scalar() {
640 let u = || scalar(2.0);
641 let v = || scalar(5.0);
642 let w = || integer(5);
643
644 check(u() + v(), scalar(2.0 + 5.0));
646 check(u() - v(), scalar(2.0 - 5.0));
647 check(u() * v(), scalar(2.0 * 5.0));
648 check(u() / v(), scalar(2.0 / 5.0));
649 check(-u(), scalar(-2.0));
650
651 check(u() + w(), scalar(2.0 + 5.0));
653 check(u() - w(), scalar(2.0 - 5.0));
654 check(u() * w(), scalar(2.0 * 5.0));
655 check(u() / w(), scalar(2.0 / 5.0));
656}