math.go (3801B)
1 // Copyright 2018 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package math 15 16 import ( 17 "errors" 18 "reflect" 19 ) 20 21 // DoArithmetic performs arithmetic operations (+,-,*,/) using reflection to 22 // determine the type of the two terms. 23 func DoArithmetic(a, b any, op rune) (any, error) { 24 av := reflect.ValueOf(a) 25 bv := reflect.ValueOf(b) 26 var ai, bi int64 27 var af, bf float64 28 var au, bu uint64 29 switch av.Kind() { 30 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 31 ai = av.Int() 32 switch bv.Kind() { 33 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 34 bi = bv.Int() 35 case reflect.Float32, reflect.Float64: 36 af = float64(ai) // may overflow 37 ai = 0 38 bf = bv.Float() 39 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 40 bu = bv.Uint() 41 if ai >= 0 { 42 au = uint64(ai) 43 ai = 0 44 } else { 45 bi = int64(bu) // may overflow 46 bu = 0 47 } 48 default: 49 return nil, errors.New("can't apply the operator to the values") 50 } 51 case reflect.Float32, reflect.Float64: 52 af = av.Float() 53 switch bv.Kind() { 54 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 55 bf = float64(bv.Int()) // may overflow 56 case reflect.Float32, reflect.Float64: 57 bf = bv.Float() 58 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 59 bf = float64(bv.Uint()) // may overflow 60 default: 61 return nil, errors.New("can't apply the operator to the values") 62 } 63 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 64 au = av.Uint() 65 switch bv.Kind() { 66 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 67 bi = bv.Int() 68 if bi >= 0 { 69 bu = uint64(bi) 70 bi = 0 71 } else { 72 ai = int64(au) // may overflow 73 au = 0 74 } 75 case reflect.Float32, reflect.Float64: 76 af = float64(au) // may overflow 77 au = 0 78 bf = bv.Float() 79 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 80 bu = bv.Uint() 81 default: 82 return nil, errors.New("can't apply the operator to the values") 83 } 84 case reflect.String: 85 as := av.String() 86 if bv.Kind() == reflect.String && op == '+' { 87 bs := bv.String() 88 return as + bs, nil 89 } 90 return nil, errors.New("can't apply the operator to the values") 91 default: 92 return nil, errors.New("can't apply the operator to the values") 93 } 94 95 switch op { 96 case '+': 97 if ai != 0 || bi != 0 { 98 return ai + bi, nil 99 } else if af != 0 || bf != 0 { 100 return af + bf, nil 101 } else if au != 0 || bu != 0 { 102 return au + bu, nil 103 } 104 return 0, nil 105 case '-': 106 if ai != 0 || bi != 0 { 107 return ai - bi, nil 108 } else if af != 0 || bf != 0 { 109 return af - bf, nil 110 } else if au != 0 || bu != 0 { 111 return au - bu, nil 112 } 113 return 0, nil 114 case '*': 115 if ai != 0 || bi != 0 { 116 return ai * bi, nil 117 } else if af != 0 || bf != 0 { 118 return af * bf, nil 119 } else if au != 0 || bu != 0 { 120 return au * bu, nil 121 } 122 return 0, nil 123 case '/': 124 if bi != 0 { 125 return ai / bi, nil 126 } else if bf != 0 { 127 return af / bf, nil 128 } else if bu != 0 { 129 return au / bu, nil 130 } 131 return nil, errors.New("can't divide the value by 0") 132 default: 133 return nil, errors.New("there is no such an operation") 134 } 135 }