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