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 }