math.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. package ottl // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
  4. import (
  5. "context"
  6. "fmt"
  7. "time"
  8. )
  9. func (p *Parser[K]) evaluateMathExpression(expr *mathExpression) (Getter[K], error) {
  10. mainGetter, err := p.evaluateAddSubTerm(expr.Left)
  11. if err != nil {
  12. return nil, err
  13. }
  14. for _, rhs := range expr.Right {
  15. getter, err := p.evaluateAddSubTerm(rhs.Term)
  16. if err != nil {
  17. return nil, err
  18. }
  19. mainGetter = attemptMathOperation(mainGetter, rhs.Operator, getter)
  20. }
  21. return mainGetter, nil
  22. }
  23. func (p *Parser[K]) evaluateAddSubTerm(term *addSubTerm) (Getter[K], error) {
  24. mainGetter, err := p.evaluateMathValue(term.Left)
  25. if err != nil {
  26. return nil, err
  27. }
  28. for _, rhs := range term.Right {
  29. getter, err := p.evaluateMathValue(rhs.Value)
  30. if err != nil {
  31. return nil, err
  32. }
  33. mainGetter = attemptMathOperation(mainGetter, rhs.Operator, getter)
  34. }
  35. return mainGetter, nil
  36. }
  37. func (p *Parser[K]) evaluateMathValue(val *mathValue) (Getter[K], error) {
  38. switch {
  39. case val.Literal != nil:
  40. return p.newGetter(value{Literal: val.Literal})
  41. case val.SubExpression != nil:
  42. return p.evaluateMathExpression(val.SubExpression)
  43. }
  44. return nil, fmt.Errorf("unsupported mathematical value %v", val)
  45. }
  46. func attemptMathOperation[K any](lhs Getter[K], op mathOp, rhs Getter[K]) Getter[K] {
  47. return exprGetter[K]{
  48. expr: Expr[K]{
  49. exprFunc: func(ctx context.Context, tCtx K) (any, error) {
  50. x, err := lhs.Get(ctx, tCtx)
  51. if err != nil {
  52. return nil, err
  53. }
  54. y, err := rhs.Get(ctx, tCtx)
  55. if err != nil {
  56. return nil, err
  57. }
  58. switch newX := x.(type) {
  59. case int64:
  60. switch newY := y.(type) {
  61. case int64:
  62. result, err := performOp[int64](newX, newY, op)
  63. if err != nil {
  64. return nil, err
  65. }
  66. return result, nil
  67. case float64:
  68. result, err := performOp[float64](float64(newX), newY, op)
  69. if err != nil {
  70. return nil, err
  71. }
  72. return result, nil
  73. default:
  74. return nil, fmt.Errorf("%v must be int64 or float64", y)
  75. }
  76. case float64:
  77. switch newY := y.(type) {
  78. case int64:
  79. result, err := performOp[float64](newX, float64(newY), op)
  80. if err != nil {
  81. return nil, err
  82. }
  83. return result, nil
  84. case float64:
  85. result, err := performOp[float64](newX, newY, op)
  86. if err != nil {
  87. return nil, err
  88. }
  89. return result, nil
  90. default:
  91. return nil, fmt.Errorf("%v must be int64 or float64", y)
  92. }
  93. case time.Time:
  94. return performOpTime(newX, y, op)
  95. case time.Duration:
  96. return performOpDuration(newX, y, op)
  97. default:
  98. return nil, fmt.Errorf("%v must be int64, float64, time.Time or time.Duration", x)
  99. }
  100. },
  101. },
  102. }
  103. }
  104. func performOpTime(x time.Time, y any, op mathOp) (any, error) {
  105. switch op {
  106. case ADD:
  107. switch newY := y.(type) {
  108. case time.Duration:
  109. result := x.Add(newY)
  110. return result, nil
  111. default:
  112. return nil, fmt.Errorf("time.Time must be added to time.Duration; found %v instead", y)
  113. }
  114. case SUB:
  115. switch newY := y.(type) {
  116. case time.Time:
  117. result := x.Sub(newY)
  118. return result, nil
  119. case time.Duration:
  120. result := x.Add(-1 * newY)
  121. return result, nil
  122. default:
  123. return nil, fmt.Errorf("time.Time or time.Duration must be subtracted from time.Time; found %v instead", y)
  124. }
  125. }
  126. return nil, fmt.Errorf("only addition and subtraction supported for time.Time and time.Duration")
  127. }
  128. func performOpDuration(x time.Duration, y any, op mathOp) (any, error) {
  129. switch op {
  130. case ADD:
  131. switch newY := y.(type) {
  132. case time.Duration:
  133. result := x + newY
  134. return result, nil
  135. case time.Time:
  136. result := newY.Add(x)
  137. return result, nil
  138. default:
  139. return nil, fmt.Errorf("time.Duration must be added to time.Duration or time.Time; found %v instead", y)
  140. }
  141. case SUB:
  142. switch newY := y.(type) {
  143. case time.Duration:
  144. result := x - newY
  145. return result, nil
  146. default:
  147. return nil, fmt.Errorf("time.Duration must be subtracted from time.Duration; found %v instead", y)
  148. }
  149. }
  150. return nil, fmt.Errorf("only addition and subtraction supported for time.Time and time.Duration")
  151. }
  152. func performOp[N int64 | float64](x N, y N, op mathOp) (N, error) {
  153. switch op {
  154. case ADD:
  155. return x + y, nil
  156. case SUB:
  157. return x - y, nil
  158. case MULT:
  159. return x * y, nil
  160. case DIV:
  161. if y == 0 {
  162. return 0, fmt.Errorf("attempted to divide by 0")
  163. }
  164. return x / y, nil
  165. }
  166. return 0, fmt.Errorf("invalid operation %v", op)
  167. }