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