github.com/goplus/igop@v0.25.0/constant/constant.go (about) 1 /* 2 * Copyright (c) 2022 The GoPlus Authors (goplus.org). All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package constant 18 19 import ( 20 "fmt" 21 "go/constant" 22 "go/token" 23 "math/big" 24 "strings" 25 ) 26 27 func ExactConstant(c constant.Value) (s string) { 28 s, _ = ExactConstantEx(c, false) 29 return 30 } 31 32 func ExactConstantEx(c constant.Value, toFloat bool) (s string, exact bool) { 33 switch c.Kind() { 34 case constant.Bool: 35 if constant.BoolVal(c) { 36 return "true", true 37 } else { 38 return "false", true 39 } 40 case constant.String: 41 return constant.StringVal(c), true 42 case constant.Int: 43 return c.ExactString(), true 44 case constant.Float: 45 s := c.ExactString() 46 if pos := strings.IndexByte(s, '/'); pos >= 0 { 47 sx := s[:pos] 48 sy := s[pos+1:] 49 // simplify 314/100 => 3.14 50 // 80901699437494742410229341718281905886015458990288143106772431 51 // 50000000000000000000000000000000000000000000000000000000000000 52 if strings.HasPrefix(sy, "1") && strings.Count(sy, "0") == len(sy)-1 { 53 n := len(sy) - len(sx) 54 if n == 0 { 55 return fmt.Sprintf("%v.%v", sx[:1], sx[1:]), true 56 } else if n > 0 { 57 if n < 5 { 58 return fmt.Sprintf("0.%v%v", strings.Repeat("0", n-1), sx), true 59 } 60 if len(sx[1:]) == 0 { 61 return fmt.Sprintf("%ve-%v", sx[:1], len(sy)-len(sx)), true 62 } 63 return fmt.Sprintf("%v.%ve-%v", sx[:1], sx[1:], len(sy)-len(sx)), true 64 } 65 } else if strings.HasPrefix(sy, "5") && strings.Count(sy, "0") == len(sy)-1 { 66 if len(sx) == len(sy) { 67 c := constant.BinaryOp(constant.MakeFromLiteral(sx, token.INT, 0), token.MUL, constant.MakeInt64(2)) 68 sx = c.ExactString() 69 return fmt.Sprintf("%v.%v", sx[:1], sx[1:]), true 70 } 71 } 72 if toFloat { 73 r, ok := new(big.Rat).SetString(s) 74 if !ok { 75 panic(fmt.Errorf("parser rat %q error", s)) 76 } 77 v, _ := r.Float64() 78 return fmt.Sprintf("%v", v), false 79 } 80 return s, true 81 } 82 if pos := strings.LastIndexAny(s, "123456789"); pos != -1 { 83 sx := s[:pos+1] 84 if len(s)-1 > 5 { 85 if len(sx[1:]) == 0 { 86 return fmt.Sprintf("%ve+%v", sx[:1], len(s)-1), true 87 } 88 return fmt.Sprintf("%v.%ve+%v", sx[:1], sx[1:], len(s)-1), true 89 } 90 } 91 return s, true 92 case constant.Complex: 93 return c.ExactString(), true 94 // re, e1 := ExactConstantEx(constant.Real(c), toFloat) 95 // im, e2 := ExactConstantEx(constant.Imag(c), toFloat) 96 // return fmt.Sprintf("%v+%vi", re, im), e1 && e2 97 default: 98 panic("unreachable") 99 } 100 }