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