Module: Cel::Extensions::Math

Defined in:
lib/cel/extensions/math.rb

Class Method Summary collapse

Class Method Details

.__check(funcall, checker:) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/cel/extensions/math.rb', line 8

def __check(funcall, checker:)
  func = funcall.func
  args = funcall.args

  case func
  when :round, :trunc, :floor, :ceil
    checker.check_arity(func, args, 1)
    arg = checker.call(args.first)
    return TYPES[:double] if checker.find_match_all_types(i[double], arg)
  when :isInf, :isNaN, :isFinite
    checker.check_arity(func, args, 1)
    arg = checker.call(args.first)
    return TYPES[:bool] if checker.find_match_all_types(i[double], arg)
  when :bitNot
    checker.check_arity(func, args, 1)
    arg = checker.call(args.first)
    return TYPES[:int] if checker.find_match_all_types(i[int uint], arg)
  when :bitOr, :bitAnd, :bitXor
    checker.check_arity(func, args, 2)
    args = args.map(&checker.method(:call))

    type = checker.find_match_all_types(i[int uint], args)
    return type if type
  when :sign, :abs
    checker.check_arity(func, args, 1)
    arg = checker.call(args.first)
    type = checker.find_match_all_types(i[double int uint], arg)
    return if type
  when :least, :greatest
    checker.check_arity_any(func, args)
    args = args.map(&checker.method(:call))

    return TYPES[:any] if args.all? do |arg|
      case arg
      when TYPES[:any], TYPES[:int], TYPES[:uint], TYPES[:double],
           TYPES[:list, :int], TYPES[:list, :uint], TYPES[:list, :double], TYPES[:list, :any]
        true
      else
        false
      end
    end
  when :bitShiftRight, :bitShiftLeft
    checker.check_arity(func, args, 2)
    num, amount_of_bits = args.map(&checker.method(:call))

    return num if checker.find_match_all_types(i[int uint],
                                               num) && checker.find_match_all_types(i[int], amount_of_bits)
  else
    checker.unsupported_operation(funcall)
  end

  checker.unsupported_operation(funcall)
end

.abs(num, program:) ⇒ Object

Raises:



62
63
64
65
66
67
68
# File 'lib/cel/extensions/math.rb', line 62

def abs(num, program:)
  num = program.call(num)

  raise EvaluateError, "out of range" unless num.value.between?(-MAX_INT + 1, MAX_INT - 1)

  Number.new(num.type, num.value.abs)
end

.bitAnd(lhs, rhs, program:) ⇒ Object



111
112
113
114
115
# File 'lib/cel/extensions/math.rb', line 111

def bitAnd(lhs, rhs, program:)
  lhs = program.call(lhs)
  rhs = program.call(rhs)
  Number.new(lhs.type, lhs & rhs)
end

.bitNot(num, program:) ⇒ Object



94
95
96
97
98
99
100
101
102
103
# File 'lib/cel/extensions/math.rb', line 94

def bitNot(num, program:)
  val = program.call(num).value

  case num.type
  when TYPES[:int]
    Number.new(:int, ~val)
  when TYPES[:uint]
    Number.new(:uint, ((2**64) - 1) - val)
  end
end

.bitOr(lhs, rhs, program:) ⇒ Object



105
106
107
108
109
# File 'lib/cel/extensions/math.rb', line 105

def bitOr(lhs, rhs, program:)
  lhs = program.call(lhs)
  rhs = program.call(rhs)
  Number.new(lhs.type, lhs | rhs)
end

.bitShiftLeft(num, amount_of_bits, program:) ⇒ Object

Raises:



178
179
180
181
182
183
184
185
186
187
188
# File 'lib/cel/extensions/math.rb', line 178

def bitShiftLeft(num, amount_of_bits, program:)
  num = program.call(num)
  amount_of_bits = program.call(amount_of_bits).value

  raise EvaluateError, "math.#{__method__}() negative offset: #{amount_of_bits}" if amount_of_bits.negative?

  # When the second parameter is 64 or greater, 0 will always be returned
  return Number.new(num.type, 0) if amount_of_bits >= 64

  Number.new(num.type, num.value << amount_of_bits)
end

.bitShiftRight(num, amount_of_bits, program:) ⇒ Object

Raises:



164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/cel/extensions/math.rb', line 164

def bitShiftRight(num, amount_of_bits, program:)
  num = program.call(num)
  amount_of_bits = program.call(amount_of_bits).value

  raise EvaluateError, "math.#{__method__}() negative offset: #{amount_of_bits}" if amount_of_bits.negative?

  # When the second parameter is 64 or greater, 0 will always be returned
  return Number.new(num.type, 0) if amount_of_bits >= 64

  value = num.value.negative? ? ((2**64) - 1) & num.value : num.value

  Number.new(num.type, value >> amount_of_bits)
end

.bitXor(lhs, rhs, program:) ⇒ Object



117
118
119
120
121
# File 'lib/cel/extensions/math.rb', line 117

def bitXor(lhs, rhs, program:)
  lhs = program.call(lhs)
  rhs = program.call(rhs)
  Number.new(lhs.type, lhs ^ rhs)
end

.ceil(num, program:) ⇒ Object



88
89
90
91
92
# File 'lib/cel/extensions/math.rb', line 88

def ceil(num, program:)
  num = program.call(num)

  Number.new(:double, num.value.ceil)
end

.floor(num, program:) ⇒ Object



82
83
84
85
86
# File 'lib/cel/extensions/math.rb', line 82

def floor(num, program:)
  num = program.call(num)

  Number.new(:double, num.value.floor)
end

.greatest(*args, program:) ⇒ Object



149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/cel/extensions/math.rb', line 149

def greatest(*args, program:)
  args = args.map(&program.method(:call))

  return args.max if args.size > 1

  arg = args.first

  case arg
  when List
    greatest(*arg.value, program: program)
  else
    arg
  end
end

.isFinite(num, program:) ⇒ Object



204
205
206
207
208
# File 'lib/cel/extensions/math.rb', line 204

def isFinite(num, program:)
  val = program.call(num).value

  Bool.cast(!val.infinite? && !val.nan?)
end

.isInf(num, program:) ⇒ Object



190
191
192
193
194
# File 'lib/cel/extensions/math.rb', line 190

def isInf(num, program:)
  val = program.call(num).value

  Bool.cast(val.infinite?)
end

.isNaN(num, program:) ⇒ Object



196
197
198
199
200
201
202
# File 'lib/cel/extensions/math.rb', line 196

def isNaN(num, program:)
  val = program.call(num).value

  Bool.cast(val.nan?)
rescue FloatDomainError
  Bool.cast(true)
end

.least(*args, program:) ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/cel/extensions/math.rb', line 134

def least(*args, program:)
  args = args.map(&program.method(:call))

  return args.min if args.size > 1

  arg = args.first

  case arg
  when List
    least(*arg.value, program: program)
  else
    arg
  end
end

.round(num, program:) ⇒ Object



70
71
72
73
74
# File 'lib/cel/extensions/math.rb', line 70

def round(num, program:)
  num = program.call(num)

  Number.new(:double, num.value.round)
end

.sign(num, program:) ⇒ Object



123
124
125
126
127
128
129
130
131
132
# File 'lib/cel/extensions/math.rb', line 123

def sign(num, program:)
  num = program.call(num)
  value = num.value

  Number.new(num.type, if value.negative?
    -1
  else
    value.positive? ? 1 : 0
  end)
end

.trunc(num, program:) ⇒ Object



76
77
78
79
80
# File 'lib/cel/extensions/math.rb', line 76

def trunc(num, program:)
  num = program.call(num)

  Number.new(:double, num.value.truncate)
end