goscript_types/
constant.rs

1use super::typ::{BasicDetail, BasicInfo, BasicType};
2use goscript_parser::token::Token;
3use num_bigint::{BigInt, Sign};
4use num_rational::BigRational;
5use num_traits::cast::FromPrimitive;
6use num_traits::cast::ToPrimitive;
7use num_traits::sign::Signed;
8use num_traits::Num;
9use ordered_float;
10use std::borrow::Borrow;
11use std::borrow::Cow;
12use std::fmt;
13
14type F32 = ordered_float::OrderedFloat<f32>;
15type F64 = ordered_float::OrderedFloat<f64>;
16
17/// constant implements Values representing untyped
18/// Go constants and their corresponding operations.
19///
20/// A special Unknown value may be used when a value
21/// is unknown due to an error. Operations on unknown
22/// values produce unknown values unless specified
23/// otherwise.
24///
25/// Because BigFloat library is not available at the moment(2020/5)
26/// float numbers arbitrary precision is not supported for now
27/// float numbers is simply represented as f64
28/// todo: This is against the Go specs.
29
30/// All the values involved in the evaluation
31#[derive(Clone, Debug, PartialEq, Eq, Hash)]
32pub enum Value {
33    Unknown,
34    Bool(bool),
35    Str(String),
36    Int(BigInt),
37    Rat(BigRational),
38    Float(F64),
39    Complex(Box<Value>, Box<Value>),
40}
41
42impl fmt::Display for Value {
43    /// For numeric values, the result may be an approximation;
44    /// for String values the result may be a shortened string.
45    /// Use ExactString for a string representing a value exactly.
46    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47        match self {
48            Value::Unknown => write!(f, "unknown"),
49            Value::Bool(b) => {
50                //f.write_str("bool: ")?;
51                b.fmt(f)
52            }
53            Value::Str(s) => {
54                //f.write_str("string: ")?;
55                write!(f, "{}", short_quote_str(s, 72))
56            }
57            Value::Int(s) => {
58                //f.write_str("int: ")?;
59                s.fmt(f)
60            }
61            Value::Rat(r) => {
62                //f.write_str("rat: ")?;
63                r.fmt(f)
64            }
65            Value::Float(s) => {
66                //f.write_str("float: ")?;
67                s.fmt(f)
68            }
69            Value::Complex(r, i) => {
70                //f.write_str("complex: ")?;
71                write!(f, "({} + {}i)", r, i)
72            }
73        }
74    }
75}
76
77impl Value {
78    pub fn with_bool(b: bool) -> Value {
79        Value::Bool(b)
80    }
81
82    pub fn with_str(s: String) -> Value {
83        Value::Str(s)
84    }
85
86    pub fn with_i64(i: i64) -> Value {
87        Value::Int(BigInt::from_i64(i).unwrap())
88    }
89
90    pub fn with_u64(u: u64) -> Value {
91        Value::Int(BigInt::from_u64(u).unwrap())
92    }
93
94    pub fn with_f64(f: f64) -> Value {
95        Value::Float(f.into())
96    }
97
98    pub fn with_literal(tok: &Token) -> Value {
99        match tok {
100            Token::INT(ilit) => int_from_literal(ilit.as_str()),
101            Token::FLOAT(flit) => float_from_literal(flit.as_str()),
102            Token::IMAG(imlit) => {
103                let s = imlit.as_str();
104                let v = float_from_literal(&s[..(s.len() - 1)]);
105                if let Value::Float(_) = &v {
106                    Value::Complex(Box::new(Value::with_f64(0.0)), Box::new(v))
107                } else {
108                    Value::Unknown
109                }
110            }
111            Token::CHAR(clit) => {
112                let (_, ch) = clit.as_str_char();
113                Value::with_i64(*ch as i64)
114            }
115            Token::STRING(slit) => {
116                let (_, s) = slit.as_str_str();
117                Value::with_str(s.clone())
118            }
119            _ => Value::Unknown,
120        }
121    }
122
123    pub fn is_int(&self) -> bool {
124        match self {
125            Value::Int(_) => true,
126            Value::Rat(r) => r.is_integer(),
127            _ => false,
128        }
129    }
130
131    pub fn representable(&self, base: &BasicDetail, rounded: Option<&mut Value>) -> bool {
132        if let Value::Unknown = self {
133            return true; // avoid follow-up errors
134        }
135
136        let float_representable =
137            |val: &Value, btype: BasicType, rounded: Option<&mut Value>| -> bool {
138                match val.to_float() {
139                    Value::Float(f) => match btype {
140                        BasicType::Float64 => true,
141                        BasicType::Float32 => {
142                            let f32_ = *f as f32;
143                            let ok = !f32_.is_infinite();
144                            if let Some(r) = rounded {
145                                *r = Value::Float(((*f as f32) as f64).into());
146                            }
147                            ok
148                        }
149                        BasicType::UntypedFloat => true,
150                        _ => unreachable!(),
151                    },
152                    _ => false,
153                }
154            };
155
156        match base.info() {
157            BasicInfo::IsInteger => match self.to_int().borrow() {
158                Value::Int(ival) => {
159                    if let Some(r) = rounded {
160                        *r = Value::Int(ival.clone())
161                    }
162                    match base.typ() {
163                        BasicType::Int => ival.to_isize().is_some(),
164                        BasicType::Int8 => ival.to_i8().is_some(),
165                        BasicType::Int16 => ival.to_i16().is_some(),
166                        BasicType::Int32 | BasicType::Rune => ival.to_i32().is_some(),
167                        BasicType::Int64 => ival.to_i64().is_some(),
168                        BasicType::Uint | BasicType::Uintptr => ival.to_usize().is_some(),
169                        BasicType::Uint8 | BasicType::Byte => ival.to_u8().is_some(),
170                        BasicType::Uint16 => ival.to_u16().is_some(),
171                        BasicType::Uint32 => ival.to_u32().is_some(),
172                        BasicType::Uint64 => ival.to_u64().is_some(),
173                        BasicType::UntypedInt => true,
174                        _ => unreachable!(),
175                    }
176                }
177                _ => false,
178            },
179            BasicInfo::IsFloat => float_representable(self, base.typ(), rounded),
180            BasicInfo::IsComplex => {
181                let ty = match base.typ() {
182                    BasicType::Complex64 => BasicType::Float32,
183                    BasicType::Complex128 => BasicType::Float64,
184                    BasicType::UntypedComplex => BasicType::UntypedFloat,
185                    _ => unreachable!(),
186                };
187                match self.to_complex() {
188                    Value::Complex(r, i) => {
189                        let (rrounded, irounded): (Option<&mut Value>, Option<&mut Value>) =
190                            match rounded {
191                                Some(val) => {
192                                    *val = Value::Complex(
193                                        Box::new(Value::with_f64(0.0)),
194                                        Box::new(Value::with_f64(0.0)),
195                                    );
196                                    if let Value::Complex(r, i) = &mut *val {
197                                        (Some(r.as_mut()), Some(i.as_mut()))
198                                    } else {
199                                        unreachable!()
200                                    }
201                                }
202                                None => (None, None),
203                            };
204                        let rok = float_representable(&r, ty, rrounded);
205                        let iok = float_representable(&i, ty, irounded);
206                        rok && iok
207                    }
208                    _ => false,
209                }
210            }
211            BasicInfo::IsBoolean => match self {
212                Value::Bool(_) => true,
213                _ => false,
214            },
215            BasicInfo::IsString => match self {
216                Value::Str(_) => true,
217                _ => false,
218            },
219            _ => false,
220        }
221    }
222
223    pub fn to_int(&self) -> Cow<Value> {
224        let f64_to_int = |x| -> Cow<Value> {
225            match BigRational::from_f64(x) {
226                Some(v) => {
227                    if v.is_integer() {
228                        Cow::Owned(Value::Int(v.to_integer()))
229                    } else {
230                        Cow::Owned(Value::Unknown)
231                    }
232                }
233                None => Cow::Owned(Value::Unknown),
234            }
235        };
236        match self {
237            Value::Int(_) => Cow::Borrowed(self),
238            Value::Rat(r) => {
239                if r.is_integer() {
240                    Cow::Owned(Value::Int(r.to_integer()))
241                } else {
242                    Cow::Owned(Value::Unknown)
243                }
244            }
245            Value::Float(f) => f64_to_int(**f),
246            Value::Complex(r, i) => {
247                let (ival, ok) = i.to_int().int_as_i64();
248                if ok && ival == 0 {
249                    r.to_int()
250                } else {
251                    Cow::Owned(Value::Unknown)
252                }
253            }
254            _ => Cow::Owned(Value::Unknown),
255        }
256    }
257
258    pub fn to_float(&self) -> Value {
259        let v = match self {
260            Value::Int(i) => i.to_f64(),
261            Value::Rat(r) => rat_to_f64(r),
262            Value::Float(f) => Some(**f),
263            Value::Complex(r, i) => {
264                let (ival, ok) = i.to_float().num_as_f64();
265                if ok && ival == 0.0 {
266                    let (rval, ok) = r.to_float().num_as_f64();
267                    if ok {
268                        Some(*rval)
269                    } else {
270                        None
271                    }
272                } else {
273                    None
274                }
275            }
276            _ => None,
277        };
278        v.map_or(Value::Unknown, |x| Value::Float(x.into()))
279    }
280
281    pub fn to_complex(&self) -> Value {
282        match self {
283            Value::Int(_) | Value::Rat(_) | Value::Float(_) => {
284                Value::Complex(Box::new(self.clone()), Box::new(Value::with_f64(0.0)))
285            }
286            Value::Complex(_, _) => self.clone(),
287            _ => Value::Unknown,
288        }
289    }
290
291    // make_imag returns the Complex value x*i;
292    // x must be Int, Float, or Unknown.
293    // If x is Unknown, the result is Unknown.
294    pub fn make_imag(&self) -> Value {
295        match self {
296            Value::Int(_) | Value::Float(_) | Value::Rat(_) => {
297                Value::Complex(Box::new(Value::with_f64(0.0)), Box::new(self.clone()))
298            }
299            Value::Unknown => Value::Unknown,
300            _ => panic!("{} not Int or Float", self),
301        }
302    }
303
304    /// real returns the real part of x, which must be a numeric or unknown value.
305    /// If x is Unknown, the result is Unknown.
306    pub fn real(&self) -> Value {
307        match self {
308            Value::Int(_) | Value::Float(_) | Value::Rat(_) | Value::Unknown => self.clone(),
309            Value::Complex(r, _) => *r.clone(),
310            _ => panic!("{} not numeric", self),
311        }
312    }
313
314    /// imag returns the imaginary part of x, which must be a numeric or unknown value.
315    /// If x is Unknown, the result is Unknown.
316    pub fn imag(&self) -> Value {
317        match self {
318            Value::Int(_) | Value::Float(_) | Value::Rat(_) => Value::with_f64(0.0),
319            Value::Complex(_, i) => *i.clone(),
320            Value::Unknown => Value::Unknown,
321            _ => panic!("{} not numeric", self),
322        }
323    }
324
325    /// sign returns -1, 0, or 1 depending on whether x < 0, x == 0, or x > 0;
326    /// x must be numeric or Unknown. For complex values x, the sign is 0 if x == 0,
327    /// otherwise it is != 0. If x is Unknown, the result is 1.
328    pub fn sign(&self) -> isize {
329        match self {
330            Value::Int(i) => match i.sign() {
331                Sign::Plus => 1,
332                Sign::Minus => -1,
333                Sign::NoSign => 0,
334            },
335            Value::Rat(r) => {
336                if r.is_positive() {
337                    1
338                } else if r.is_negative() {
339                    -1
340                } else {
341                    0
342                }
343            }
344            Value::Float(v) => {
345                let f: f64 = **v;
346                if f > 0.0 {
347                    1
348                } else if f < 0.0 {
349                    -1
350                } else {
351                    0
352                }
353            }
354            Value::Complex(r, i) => r.sign() | i.sign(),
355            Value::Unknown => 1, // avoid spurious division by zero errors
356            _ => panic!("{} not numeric", self),
357        }
358    }
359
360    /// binary_op returns the result of the binary expression x op y.
361    /// The operation must be defined for the operands. If one of the
362    /// operands is Unknown, the result is Unknown.
363    /// binary_op doesn't handle comparisons or shifts; use compare
364    /// or shift instead.
365    ///
366    /// To force integer division of Int operands, use op == Token::QUO_ASSIGN
367    /// instead of Token::QUO; the result is guaranteed to be Int in this case.
368    /// Division by zero leads to a run-time panic.
369    pub fn binary_op(x: &Value, op: &Token, y: &Value) -> Value {
370        let add = |x, y| Value::binary_op(x, &Token::ADD, y);
371        let sub = |x, y| Value::binary_op(x, &Token::SUB, y);
372        let mul = |x, y| Value::binary_op(x, &Token::MUL, y);
373        let div = |x, y| Value::binary_op(x, &Token::QUO, y);
374        let bx = |x| Box::new(x);
375
376        let (x, y) = Value::match_type(Cow::Borrowed(x), Cow::Borrowed(y));
377        match (&*x, &*y) {
378            (Value::Unknown, Value::Unknown) => Value::Unknown,
379            (Value::Bool(a), Value::Bool(b)) => match op {
380                Token::LAND => Value::Bool(*a && *b),
381                Token::LOR => Value::Bool(*a || *b),
382                _ => unreachable!(),
383            },
384            (Value::Int(a), Value::Int(b)) => {
385                match op {
386                    Token::ADD => Value::Int(a + b),
387                    Token::SUB => Value::Int(a - b),
388                    Token::MUL => Value::Int(a * b),
389                    Token::QUO => Value::Rat(BigRational::new(a.clone(), b.clone())),
390                    Token::QUO_ASSIGN => Value::Int(a / b), // force integer division
391                    Token::REM => Value::Int(a % b),
392                    Token::AND => Value::Int(a & b),
393                    Token::OR => Value::Int(a | b),
394                    Token::XOR => Value::Int(a ^ b),
395                    Token::AND_NOT => Value::Int(a & !b),
396                    _ => unreachable!(),
397                }
398            }
399            (Value::Rat(a), Value::Rat(b)) => match op {
400                Token::ADD => Value::Rat(a + b),
401                Token::SUB => Value::Rat(a - b),
402                Token::MUL => Value::Rat(a * b),
403                Token::QUO => Value::Rat(a / b),
404                _ => unreachable!(),
405            },
406            (Value::Float(a), Value::Float(b)) => match op {
407                Token::ADD => Value::Float(*a + *b),
408                Token::SUB => Value::Float(*a - *b),
409                Token::MUL => Value::Float(*a * *b),
410                Token::QUO => Value::Float(*a / *b),
411                _ => unreachable!(),
412            },
413            (Value::Complex(ar, ai), Value::Complex(br, bi)) => match op {
414                Token::ADD => Value::Complex(bx(add(ar, br)), bx(add(ai, bi))),
415                Token::SUB => Value::Complex(bx(sub(ar, br)), bx(sub(ai, bi))),
416                Token::MUL => {
417                    let (a, b, c, d) = (ar, ai, br, bi);
418                    let ac = mul(&a, &c);
419                    let bd = mul(&b, &d);
420                    let bc = mul(&b, &c);
421                    let ad = mul(&a, &d);
422                    Value::Complex(bx(sub(&ac, &bd)), bx(add(&bc, &ad)))
423                }
424                Token::QUO => {
425                    // (ac+bd)/s + i(bc-ad)/s, with s = cc + dd
426                    let (a, b, c, d) = (ar, ai, br, bi);
427                    let cc = mul(&c, &c);
428                    let dd = mul(&d, &d);
429                    let s = add(&cc, &dd);
430                    let ac = mul(&a, &c);
431                    let bd = mul(&b, &d);
432                    let acbd = add(&ac, &bd);
433                    let bc = mul(&b, &c);
434                    let ad = mul(&a, &d);
435                    let bcad = sub(&bc, &ad);
436                    Value::Complex(bx(div(&acbd, &s)), bx(div(&bcad, &s)))
437                }
438                _ => unreachable!(),
439            },
440            (Value::Str(a), Value::Str(b)) => match op {
441                Token::ADD => Value::Str(format!("{}{}", a, b)),
442                _ => unreachable!(),
443            },
444            _ => unreachable!(),
445        }
446    }
447
448    /// unary_op returns the result of the unary expression op y.
449    /// The operation must be defined for the operand.
450    /// If prec > 0 it specifies the ^ (xor) result size in bits.
451    /// If y is Unknown, the result is Unknown.
452    pub fn unary_op(op: &Token, y: &Value, prec: usize) -> Value {
453        match op {
454            Token::ADD => match y {
455                Value::Str(_) => unreachable!(),
456                _ => y.clone(),
457            },
458            Token::SUB => match y {
459                Value::Unknown => Value::Unknown,
460                Value::Int(i) => Value::Int(-i),
461                Value::Rat(r) => Value::Rat(-r),
462                Value::Float(f) => Value::Float(-(*f)),
463                Value::Complex(r, i) => Value::Complex(
464                    Box::new(Value::unary_op(op, r, 0)),
465                    Box::new(Value::unary_op(op, i, 0)),
466                ),
467                _ => unreachable!(),
468            },
469            Token::XOR => match y {
470                Value::Unknown => Value::Unknown,
471                Value::Int(i) => {
472                    let mut v = !i;
473                    if prec > 0 {
474                        v = v & (!(BigInt::from_i64(-1).unwrap() << prec * 8));
475                    }
476                    Value::Int(v)
477                }
478                _ => unreachable!(),
479            },
480            Token::NOT => match y {
481                Value::Unknown => Value::Unknown,
482                Value::Bool(b) => Value::Bool(!b),
483                _ => unreachable!(),
484            },
485            _ => unreachable!(),
486        }
487    }
488
489    /// compare returns the result of the comparison x op y.
490    /// The comparison must be defined for the operands.
491    /// If one of the operands is Unknown, the result is
492    /// false.
493    pub fn compare(x: &Value, op: &Token, y: &Value) -> bool {
494        let (x, y) = Value::match_type(Cow::Borrowed(x), Cow::Borrowed(y));
495        match (&*x, &*y) {
496            (Value::Unknown, _) | (_, Value::Unknown) => false,
497            (Value::Bool(a), Value::Bool(b)) => match op {
498                Token::EQL => a == b,
499                Token::NEQ => a != b,
500                _ => unreachable!(),
501            },
502            (Value::Int(a), Value::Int(b)) => match op {
503                Token::EQL => a == b,
504                Token::NEQ => a != b,
505                Token::LSS => a < b,
506                Token::LEQ => a <= b,
507                Token::GTR => a > b,
508                Token::GEQ => a >= b,
509                _ => unreachable!(),
510            },
511            (Value::Rat(a), Value::Rat(b)) => match op {
512                Token::EQL => a == b,
513                Token::NEQ => a != b,
514                Token::LSS => a < b,
515                Token::LEQ => a <= b,
516                Token::GTR => a > b,
517                Token::GEQ => a >= b,
518                _ => unreachable!(),
519            },
520            (Value::Float(a), Value::Float(b)) => match op {
521                Token::EQL => a == b,
522                Token::NEQ => a != b,
523                Token::LSS => a < b,
524                Token::LEQ => a <= b,
525                Token::GTR => a > b,
526                Token::GEQ => a >= b,
527                _ => unreachable!(),
528            },
529            (Value::Complex(ar, ai), Value::Complex(br, bi)) => {
530                let r = Value::compare(ar, op, br);
531                let i = Value::compare(ai, op, bi);
532                match op {
533                    Token::EQL => r && i,
534                    Token::NEQ => !r || !i,
535                    _ => unreachable!(),
536                }
537            }
538            (Value::Str(a), Value::Str(b)) => match op {
539                Token::EQL => a == b,
540                Token::NEQ => a != b,
541                Token::LSS => a < b,
542                Token::LEQ => a <= b,
543                Token::GTR => a > b,
544                Token::GEQ => a >= b,
545                _ => unreachable!(),
546            },
547            _ => unreachable!(),
548        }
549    }
550
551    // shift returns the result of the shift expression x op s
552    // with op == Token::SHL or Token::SHR (<< or >>). x must be
553    // an Int or an Unknown. If x is Unknown, the result is Unknown.
554    pub fn shift(x: &Value, op: &Token, s: usize) -> Value {
555        match x {
556            Value::Unknown => Value::Unknown,
557            Value::Int(i) => match op {
558                Token::SHL => Value::Int(i << s),
559                Token::SHR => Value::Int(i >> s),
560                _ => unreachable!(),
561            },
562            _ => unreachable!(),
563        }
564    }
565
566    pub fn bool_as_bool(&self) -> bool {
567        match self {
568            Value::Bool(b) => *b,
569            Value::Unknown => false,
570            _ => panic!("not a bool"),
571        }
572    }
573
574    pub fn str_as_string(&self) -> String {
575        match self {
576            Value::Str(s) => s.to_string(), //quote_str(s)
577            Value::Unknown => "".to_string(),
578            _ => panic!("not a string"),
579        }
580    }
581
582    /// int_as_u64 returns the Go uint64 value and whether the result is exact;
583    pub fn int_as_u64(&self) -> (u64, bool) {
584        match self {
585            Value::Int(i) => match i.to_u64() {
586                Some(v) => (v, true),
587                _ => (std::u64::MAX, false),
588            },
589            Value::Unknown => (0, false),
590            _ => panic!("not an integer"),
591        }
592    }
593
594    /// int_as_i64 returns the Go int64 value and whether the result is exact;
595    pub fn int_as_i64(&self) -> (i64, bool) {
596        match self {
597            Value::Int(i) => match i.to_i64() {
598                Some(v) => (v, true),
599                _ => (
600                    if self.sign() > 0 {
601                        std::i64::MAX
602                    } else {
603                        std::i64::MIN
604                    },
605                    false,
606                ),
607            },
608            Value::Unknown => (0, false),
609            _ => panic!("not an integer"),
610        }
611    }
612
613    /// num_as_f64 returns the nearest Go float64 value of x and whether the result is exact;
614    /// x must be numeric or an Unknown, but not Complex. For values too small (too close to 0)
615    /// to represent as float64, num_as_f64 silently underflows to 0. The result sign always
616    /// matches the sign of x, even for 0.
617    /// If x is Unknown, the result is (0, false).
618    pub fn num_as_f64(&self) -> (F64, bool) {
619        match self {
620            Value::Int(_) | Value::Rat(_) => {
621                let vf = self.to_float();
622                if vf == Value::Unknown {
623                    (
624                        if self.sign() > 0 {
625                            std::f64::MAX.into()
626                        } else {
627                            std::f64::MIN.into()
628                        },
629                        false,
630                    )
631                } else {
632                    vf.num_as_f64()
633                }
634            }
635            Value::Float(f) => (*f, true),
636            Value::Unknown => (0.0.into(), false),
637            _ => panic!("not a number"),
638        }
639    }
640
641    /// num_as_f32 is like num_as_f64 but for float32 instead of float64.
642    pub fn num_as_f32(&self) -> (F32, bool) {
643        match self {
644            Value::Int(_) | Value::Rat(_) => {
645                let vf = self.to_float();
646                if vf == Value::Unknown {
647                    (
648                        if self.sign() > 0 {
649                            std::f32::MAX.into()
650                        } else {
651                            std::f32::MIN.into()
652                        },
653                        false,
654                    )
655                } else {
656                    vf.num_as_f32()
657                }
658            }
659            Value::Float(v) => {
660                let min: f64 = std::f32::MIN as f64;
661                let max: f64 = std::f32::MAX as f64;
662                let f: f64 = v.into_inner();
663                if f > min && f < max {
664                    ((f as f32).into(), true)
665                } else if f < min {
666                    (std::f32::MIN.into(), false)
667                } else {
668                    (std::f32::MAX.into(), false)
669                }
670            }
671            Value::Unknown => (0.0.into(), false),
672            _ => panic!("not a number"),
673        }
674    }
675
676    pub fn complex_as_complex64(&self) -> (F32, F32, bool) {
677        match self {
678            Value::Complex(r, i) => {
679                let (num_r, exact_r) = r.num_as_f32();
680                let (num_i, exact_i) = i.num_as_f32();
681                (num_r, num_i, exact_r && exact_i)
682            }
683            _ => panic!("not a complex"),
684        }
685    }
686
687    pub fn complex_as_complex128(&self) -> (F64, F64, bool) {
688        match self {
689            Value::Complex(r, i) => {
690                let (num_r, exact_r) = r.num_as_f64();
691                let (num_i, exact_i) = i.num_as_f64();
692                (num_r, num_i, exact_r && exact_i)
693            }
694            _ => panic!("not a complex"),
695        }
696    }
697
698    fn ord(&self) -> usize {
699        match self {
700            Value::Unknown => 0,
701            Value::Bool(_) | Value::Str(_) => 1,
702            Value::Int(_) => 2,
703            Value::Rat(_) => 3,
704            Value::Float(_) => 4,
705            Value::Complex(_, _) => 5,
706        }
707    }
708
709    /// match_type returns the matching representation (same type) with the
710    /// smallest complexity for two values x and y. If one of them is
711    /// numeric, both of them must be numeric. If one of them is Unknown
712    /// both results are Unknown
713    fn match_type<'a>(x: Cow<'a, Value>, y: Cow<'a, Value>) -> (Cow<'a, Value>, Cow<'a, Value>) {
714        if x.ord() > y.ord() {
715            let (y, x) = Value::match_type(y, x);
716            return (x, y);
717        }
718        match &*x {
719            Value::Bool(_) | Value::Str(_) | Value::Complex(_, _) => (x, y),
720            Value::Int(iv) => match &*y {
721                Value::Int(_) => (x, y),
722                Value::Rat(_) => (
723                    Cow::Owned(Value::Rat(BigRational::new(iv.clone(), 1.into()))),
724                    y,
725                ),
726                Value::Float(_) => match iv.to_f64() {
727                    Some(f) => (Cow::Owned(Value::Float(f.into())), y),
728                    None => (Cow::Owned(Value::Unknown), Cow::Owned(Value::Unknown)),
729                },
730                Value::Complex(_, _) => (
731                    Cow::Owned(Value::Complex(
732                        Box::new(x.into_owned()),
733                        Box::new(Value::with_f64(0.0)),
734                    )),
735                    y,
736                ),
737                Value::Unknown => (x.clone(), x),
738                _ => unreachable!(),
739            },
740            Value::Rat(rv) => match &*y {
741                Value::Rat(_) => (x, y),
742                Value::Float(_) => match rat_to_f64(rv) {
743                    Some(f) => (Cow::Owned(Value::Float(f.into())), y),
744                    None => (Cow::Owned(Value::Unknown), Cow::Owned(Value::Unknown)),
745                },
746                Value::Complex(_, _) => (
747                    Cow::Owned(Value::Complex(
748                        Box::new(x.into_owned()),
749                        Box::new(Value::with_f64(0.0)),
750                    )),
751                    y,
752                ),
753                Value::Unknown => (x.clone(), x),
754                _ => unreachable!(),
755            },
756            Value::Float(_) => match &*y {
757                Value::Float(_) => (x, y),
758                Value::Complex(_, _) => (
759                    Cow::Owned(Value::Complex(
760                        Box::new(x.into_owned()),
761                        Box::new(Value::with_f64(0.0)),
762                    )),
763                    y,
764                ),
765                Value::Unknown => (x.clone(), x),
766                _ => unreachable!(),
767            },
768            Value::Unknown => (x.clone(), x),
769        }
770    }
771}
772
773// ----------------------------------------------------------------------------
774// utilities
775
776pub fn short_quote_str(s: &str, max: usize) -> String {
777    let result = s.escape_default().collect();
778    shorten_with_ellipsis(result, max)
779}
780
781pub fn int_from_literal(lit: &str) -> Value {
782    let result = if lit.starts_with("0x") {
783        BigInt::from_str_radix(&lit[2..], 16)
784    } else if lit.starts_with("0o") {
785        BigInt::from_str_radix(&lit[2..], 10)
786    } else if lit.starts_with("0b") {
787        BigInt::from_str_radix(&lit[2..], 2)
788    } else {
789        BigInt::from_str_radix(lit, 10)
790    };
791    match result {
792        Ok(i) => Value::Int(i),
793        Err(_) => Value::Unknown,
794    }
795}
796
797pub fn float_from_literal(lit: &str) -> Value {
798    match lit.parse::<f64>() {
799        Ok(f) => Value::with_f64(f),
800        Err(_) => Value::Unknown,
801    }
802}
803
804fn shorten_with_ellipsis(s: String, max: usize) -> String {
805    if s.len() <= max {
806        s
807    } else {
808        let mut buf: Vec<char> = s.chars().collect();
809        buf = buf[0..(buf.len() - 3)].to_vec();
810        buf.append(&mut "...".to_owned().chars().collect());
811        buf.into_iter().collect()
812    }
813}
814
815fn rat_to_f64(r: &BigRational) -> Option<f64> {
816    match (r.numer().to_f64(), r.denom().to_f64()) {
817        (Some(n), Some(d)) => Some(n / d),
818        _ => None,
819    }
820}
821
822#[cfg(test)]
823mod test {
824    #[test]
825    fn test_str_unquote() {
826        let s = "\\111";
827        dbg!(s);
828    }
829}