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#[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 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 match self {
48 Value::Unknown => write!(f, "unknown"),
49 Value::Bool(b) => {
50 b.fmt(f)
52 }
53 Value::Str(s) => {
54 write!(f, "{}", short_quote_str(s, 72))
56 }
57 Value::Int(s) => {
58 s.fmt(f)
60 }
61 Value::Rat(r) => {
62 r.fmt(f)
64 }
65 Value::Float(s) => {
66 s.fmt(f)
68 }
69 Value::Complex(r, i) => {
70 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; }
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 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 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 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 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, _ => panic!("{} not numeric", self),
357 }
358 }
359
360 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), 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 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 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 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 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(), Value::Unknown => "".to_string(),
578 _ => panic!("not a string"),
579 }
580 }
581
582 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 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 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 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 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
773pub 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}