cel 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -1
- data/README.md +26 -3
- data/lib/cel/ast/cel_methods.rb +58 -0
- data/lib/cel/ast/elements/bool.rb +34 -0
- data/lib/cel/ast/elements/bytes.rb +34 -0
- data/lib/cel/ast/elements/condition.rb +22 -0
- data/lib/cel/ast/elements/duration.rb +114 -0
- data/lib/cel/ast/elements/function.rb +33 -0
- data/lib/cel/ast/elements/group.rb +19 -0
- data/lib/cel/ast/elements/identifier.rb +32 -0
- data/lib/cel/ast/elements/invoke.rb +64 -0
- data/lib/cel/ast/elements/list.rb +70 -0
- data/lib/cel/ast/elements/literal.rb +74 -0
- data/lib/cel/ast/elements/map.rb +120 -0
- data/lib/cel/ast/elements/message.rb +50 -0
- data/lib/cel/ast/elements/null.rb +11 -0
- data/lib/cel/ast/elements/number.rb +70 -0
- data/lib/cel/ast/elements/operation.rb +39 -0
- data/lib/cel/ast/elements/protobuf.rb +4 -0
- data/lib/cel/ast/elements/string.rb +54 -0
- data/lib/cel/ast/elements/timestamp.rb +109 -0
- data/lib/cel/ast/elements.rb +18 -828
- data/lib/cel/ast/types.rb +49 -4
- data/lib/cel/checker.rb +47 -31
- data/lib/cel/context.rb +1 -1
- data/lib/cel/environment.rb +15 -2
- data/lib/cel/errors.rb +11 -0
- data/lib/cel/extensions/bind.rb +35 -0
- data/lib/cel/extensions/encoders.rb +41 -0
- data/lib/cel/extensions/math.rb +211 -0
- data/lib/cel/extensions/string.rb +230 -0
- data/lib/cel/extensions.rb +15 -0
- data/lib/cel/parser.rb +14 -13
- data/lib/cel/program.rb +28 -13
- data/lib/cel/version.rb +1 -1
- data/lib/cel.rb +27 -12
- metadata +39 -2
data/lib/cel/ast/types.rb
CHANGED
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
module Cel
|
|
4
4
|
class Type
|
|
5
|
+
include CelMethods
|
|
6
|
+
|
|
5
7
|
def initialize(type)
|
|
6
8
|
@type = type
|
|
7
9
|
end
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
(other.is_a?(Symbol) && other == @type) || super
|
|
11
|
+
define_cel_method(:==) do |other|
|
|
12
|
+
(other.is_a?(Symbol) && other == @type) || super(other)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
define_cel_method(:"!=") do |other|
|
|
16
|
+
!cel_send(:==, other)
|
|
11
17
|
end
|
|
12
18
|
|
|
13
19
|
def to_str
|
|
@@ -154,6 +160,29 @@ module Cel
|
|
|
154
160
|
raise Error, "unsupported cast operation to #{@type}"
|
|
155
161
|
end
|
|
156
162
|
end
|
|
163
|
+
|
|
164
|
+
def convert(primitive_value)
|
|
165
|
+
case @type
|
|
166
|
+
when :int, :uint, :double
|
|
167
|
+
Number.new(@type, primitive_value)
|
|
168
|
+
when :string
|
|
169
|
+
String.new(primitive_value)
|
|
170
|
+
when :bytes
|
|
171
|
+
Bytes.new(primitive_value)
|
|
172
|
+
when :bool
|
|
173
|
+
Bool.new(primitive_value)
|
|
174
|
+
when :null_type
|
|
175
|
+
Null::INSTANCE
|
|
176
|
+
when :timestamp
|
|
177
|
+
Timestamp.new(primitive_value)
|
|
178
|
+
when :duration
|
|
179
|
+
Duration.new(primitive_value)
|
|
180
|
+
when :any
|
|
181
|
+
Literal.to_cel_type(primitive_value)
|
|
182
|
+
else
|
|
183
|
+
raise EvaluateError, "Type conversion error"
|
|
184
|
+
end
|
|
185
|
+
end
|
|
157
186
|
end
|
|
158
187
|
|
|
159
188
|
class ListType < Type
|
|
@@ -176,7 +205,11 @@ module Cel
|
|
|
176
205
|
end
|
|
177
206
|
|
|
178
207
|
def cast(value)
|
|
179
|
-
value.is_a?(List) ? value :
|
|
208
|
+
value.is_a?(List) ? value : convert(value)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def convert(primitive_value)
|
|
212
|
+
List.new(primitive_value)
|
|
180
213
|
end
|
|
181
214
|
end
|
|
182
215
|
|
|
@@ -203,15 +236,27 @@ module Cel
|
|
|
203
236
|
end
|
|
204
237
|
|
|
205
238
|
def cast(value)
|
|
206
|
-
value.is_a?(Map) ? value :
|
|
239
|
+
value.is_a?(Map) ? value : convert(value)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def convert(primitive_value)
|
|
243
|
+
Map.new(primitive_value)
|
|
207
244
|
end
|
|
208
245
|
end
|
|
209
246
|
|
|
210
247
|
class AbstractType < Type
|
|
248
|
+
attr_reader :params
|
|
249
|
+
protected :params
|
|
211
250
|
def initialize(name, *params)
|
|
212
251
|
super(name)
|
|
213
252
|
@params = params
|
|
214
253
|
end
|
|
254
|
+
|
|
255
|
+
define_cel_method(:==) do |other|
|
|
256
|
+
return super(other) unless other.is_a?(AbstractType)
|
|
257
|
+
|
|
258
|
+
other.type && @type && other.params == @params
|
|
259
|
+
end
|
|
215
260
|
end
|
|
216
261
|
# Primitive Cel Types
|
|
217
262
|
|
data/lib/cel/checker.rb
CHANGED
|
@@ -21,7 +21,7 @@ module Cel
|
|
|
21
21
|
timestamp: %i[int string timestamp],
|
|
22
22
|
}.freeze
|
|
23
23
|
|
|
24
|
-
attr_reader :declarations
|
|
24
|
+
attr_reader :environment, :declarations
|
|
25
25
|
|
|
26
26
|
def initialize(environment, declarations = environment.declarations)
|
|
27
27
|
@environment = environment
|
|
@@ -51,6 +51,40 @@ module Cel
|
|
|
51
51
|
|
|
52
52
|
alias_method :call, :check
|
|
53
53
|
|
|
54
|
+
def find_match_all_types(expected, types)
|
|
55
|
+
# at least an expected type must match all values
|
|
56
|
+
type = expected.find do |expected_type|
|
|
57
|
+
case types
|
|
58
|
+
when Array
|
|
59
|
+
types.all? { |typ| typ == expected_type }
|
|
60
|
+
else
|
|
61
|
+
types == expected_type
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
type && types.is_a?(Type) ? types : TYPES[type]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def check_arity(func, args, arity, op = :===)
|
|
69
|
+
return if arity.__send__(op, args.size)
|
|
70
|
+
|
|
71
|
+
raise CheckError, "`#{func}` invoked with wrong number of arguments (should be #{arity})"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def check_arity_any(func, args)
|
|
75
|
+
return if args.size.positive?
|
|
76
|
+
|
|
77
|
+
raise CheckError, "`#{func}` invoked with no arguments"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def unsupported_type(op)
|
|
81
|
+
raise CheckError, "no matching overload: #{op}"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def unsupported_operation(op)
|
|
85
|
+
raise CheckError, "unsupported operation (#{op})"
|
|
86
|
+
end
|
|
87
|
+
|
|
54
88
|
private
|
|
55
89
|
|
|
56
90
|
def merge(declarations)
|
|
@@ -194,6 +228,10 @@ module Cel
|
|
|
194
228
|
|
|
195
229
|
return check_standard_func(funcall) unless var
|
|
196
230
|
|
|
231
|
+
if var.is_a?(Identifier) && Cel::EXTENSIONS.include?(var.to_sym)
|
|
232
|
+
return Cel::EXTENSIONS[var.to_sym].__check(funcall, checker: self)
|
|
233
|
+
end
|
|
234
|
+
|
|
197
235
|
var_type ||= infer_variable_type(var)
|
|
198
236
|
|
|
199
237
|
case var_type
|
|
@@ -283,6 +321,8 @@ module Cel
|
|
|
283
321
|
var_type.element_type = element_checker.check(predicate)
|
|
284
322
|
var_type
|
|
285
323
|
else
|
|
324
|
+
return Cel::EXTENSIONS[:strings].__check(funcall, checker: self) if Cel::EXTENSIONS.key?(:strings)
|
|
325
|
+
|
|
286
326
|
unsupported_operation(funcall)
|
|
287
327
|
end
|
|
288
328
|
when TYPES[:string]
|
|
@@ -295,6 +335,8 @@ module Cel
|
|
|
295
335
|
# TODO: verify if string can be transformed into a regex
|
|
296
336
|
return TYPES[:bool] if find_match_all_types(%i[string], call(args.first))
|
|
297
337
|
else
|
|
338
|
+
return Cel::EXTENSIONS[:strings].__check(funcall, checker: self) if Cel::EXTENSIONS.key?(:strings)
|
|
339
|
+
|
|
298
340
|
unsupported_type(funcall)
|
|
299
341
|
end
|
|
300
342
|
unsupported_operation(funcall)
|
|
@@ -373,7 +415,7 @@ module Cel
|
|
|
373
415
|
|
|
374
416
|
arg = call(args.first)
|
|
375
417
|
|
|
376
|
-
return TYPES[func] if find_match_all_types(allowed_types, arg)
|
|
418
|
+
return TYPES[func] if find_match_all_types(allowed_types, arg) || arg == TYPES[:any]
|
|
377
419
|
when :matches
|
|
378
420
|
check_arity(func, args, 2)
|
|
379
421
|
return TYPES[:bool] if find_match_all_types(%i[string], args.map(&method(:call)))
|
|
@@ -424,7 +466,9 @@ module Cel
|
|
|
424
466
|
def check_identifier(identifier)
|
|
425
467
|
return identifier.type unless identifier.type == :any
|
|
426
468
|
|
|
427
|
-
|
|
469
|
+
id_sym = identifier.to_sym
|
|
470
|
+
|
|
471
|
+
return TYPES[:type] if Cel::PRIMITIVE_TYPES.include?(id_sym)
|
|
428
472
|
|
|
429
473
|
proto_type = identifier.try_convert_to_proto_type
|
|
430
474
|
|
|
@@ -472,33 +516,5 @@ module Cel
|
|
|
472
516
|
typ
|
|
473
517
|
end
|
|
474
518
|
end
|
|
475
|
-
|
|
476
|
-
def find_match_all_types(expected, types)
|
|
477
|
-
# at least an expected type must match all values
|
|
478
|
-
type = expected.find do |expected_type|
|
|
479
|
-
case types
|
|
480
|
-
when Array
|
|
481
|
-
types.all? { |typ| typ == expected_type }
|
|
482
|
-
else
|
|
483
|
-
types == expected_type
|
|
484
|
-
end
|
|
485
|
-
end
|
|
486
|
-
|
|
487
|
-
type && types.is_a?(Type) ? types : TYPES[type]
|
|
488
|
-
end
|
|
489
|
-
|
|
490
|
-
def check_arity(func, args, arity)
|
|
491
|
-
return if arity === args.size # rubocop:disable Style/CaseEquality
|
|
492
|
-
|
|
493
|
-
raise CheckError, "`#{func}` invoked with wrong number of arguments (should be #{arity})"
|
|
494
|
-
end
|
|
495
|
-
|
|
496
|
-
def unsupported_type(op)
|
|
497
|
-
raise CheckError, "no matching overload: #{op}"
|
|
498
|
-
end
|
|
499
|
-
|
|
500
|
-
def unsupported_operation(op)
|
|
501
|
-
raise CheckError, "unsupported operation (#{op})"
|
|
502
|
-
end
|
|
503
519
|
end
|
|
504
520
|
end
|
data/lib/cel/context.rb
CHANGED
data/lib/cel/environment.rb
CHANGED
|
@@ -53,8 +53,8 @@ module Cel
|
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def check(expr)
|
|
56
|
-
|
|
57
|
-
@checker.check(
|
|
56
|
+
expr = @parser.parse(expr) if expr.is_a?(::String)
|
|
57
|
+
@checker.check(expr)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
def program(expr)
|
|
@@ -91,6 +91,19 @@ module Cel
|
|
|
91
91
|
[declarations, bindings]
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
+
def with(declarations:, disable_check: @disable_check)
|
|
95
|
+
prev_declarations = @declarations
|
|
96
|
+
prev_disable_check = @disable_check
|
|
97
|
+
|
|
98
|
+
@declarations = declarations.merge(declarations)
|
|
99
|
+
@disable_check = disable_check
|
|
100
|
+
|
|
101
|
+
yield
|
|
102
|
+
ensure
|
|
103
|
+
@declarations = prev_declarations
|
|
104
|
+
@disable_check = prev_disable_check
|
|
105
|
+
end
|
|
106
|
+
|
|
94
107
|
private
|
|
95
108
|
|
|
96
109
|
def validate(ast, structs); end
|
data/lib/cel/errors.rb
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
module Cel
|
|
4
4
|
class Error < StandardError; end
|
|
5
5
|
|
|
6
|
+
class NoCelMethodError < Error; end
|
|
7
|
+
|
|
6
8
|
class ParseError < Error; end
|
|
7
9
|
|
|
8
10
|
class MaxRecursionDepthExceededError < ParseError; end
|
|
@@ -48,5 +50,14 @@ module Cel
|
|
|
48
50
|
end
|
|
49
51
|
end
|
|
50
52
|
|
|
53
|
+
class NoOverloadError < EvaluateError
|
|
54
|
+
attr_reader :code
|
|
55
|
+
|
|
56
|
+
def initialize
|
|
57
|
+
super("No such overload")
|
|
58
|
+
@code = :no_overload
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
51
62
|
class BindingError < EvaluateError; end
|
|
52
63
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cel
|
|
4
|
+
module Extensions
|
|
5
|
+
module Bind
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def __check(funcall, checker:)
|
|
9
|
+
func = funcall.func
|
|
10
|
+
args = funcall.args
|
|
11
|
+
|
|
12
|
+
return checker.unsupported_operation(funcall) unless func == :bind
|
|
13
|
+
|
|
14
|
+
checker.check_arity(func, args, 3)
|
|
15
|
+
|
|
16
|
+
id, type, expr = args
|
|
17
|
+
|
|
18
|
+
return checker.unsupported_operation(funcall) unless id.is_a?(Identifier)
|
|
19
|
+
|
|
20
|
+
type = checker.call(type)
|
|
21
|
+
|
|
22
|
+
checker.environment.with(declarations: { id => type }) do
|
|
23
|
+
checker.environment.check(expr)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def bind(var, val, expr, program:)
|
|
28
|
+
program.environment.with(declarations: { var.to_sym => val.type }, disable_check: false) do
|
|
29
|
+
bindings = program.context.bindings.merge({ var.to_sym => val })
|
|
30
|
+
program.environment.evaluate(expr, bindings)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cel
|
|
4
|
+
module Extensions
|
|
5
|
+
module Encoders
|
|
6
|
+
module Base64
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def __check(funcall, checker:)
|
|
10
|
+
func = funcall.func
|
|
11
|
+
args = funcall.args
|
|
12
|
+
|
|
13
|
+
case func
|
|
14
|
+
when :encode
|
|
15
|
+
checker.check_arity(func, args, 1)
|
|
16
|
+
arg = checker.call(args.first)
|
|
17
|
+
return TYPES[:string] if checker.find_match_all_types(%i[bytes], arg)
|
|
18
|
+
when :decode
|
|
19
|
+
checker.check_arity(func, args, 1)
|
|
20
|
+
arg = checker.call(args.first)
|
|
21
|
+
return TYPES[:bytes] if checker.find_match_all_types(%i[string], arg)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
checker.unsupported_operation(funcall)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def encode(str, program:)
|
|
28
|
+
value = program.call(str).value
|
|
29
|
+
|
|
30
|
+
Cel::String.new([value.pack("C*")].pack("m0"))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def decode(str, program:)
|
|
34
|
+
value = program.call(str).value
|
|
35
|
+
|
|
36
|
+
Cel::Bytes.new(value.unpack1("m").unpack("C*"))
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cel
|
|
4
|
+
module Extensions
|
|
5
|
+
module Math
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def __check(funcall, checker:)
|
|
9
|
+
func = funcall.func
|
|
10
|
+
args = funcall.args
|
|
11
|
+
|
|
12
|
+
case func
|
|
13
|
+
when :round, :trunc, :floor, :ceil
|
|
14
|
+
checker.check_arity(func, args, 1)
|
|
15
|
+
arg = checker.call(args.first)
|
|
16
|
+
return TYPES[:double] if checker.find_match_all_types(%i[double], arg)
|
|
17
|
+
when :isInf, :isNaN, :isFinite
|
|
18
|
+
checker.check_arity(func, args, 1)
|
|
19
|
+
arg = checker.call(args.first)
|
|
20
|
+
return TYPES[:bool] if checker.find_match_all_types(%i[double], arg)
|
|
21
|
+
when :bitNot
|
|
22
|
+
checker.check_arity(func, args, 1)
|
|
23
|
+
arg = checker.call(args.first)
|
|
24
|
+
return TYPES[:int] if checker.find_match_all_types(%i[int uint], arg)
|
|
25
|
+
when :bitOr, :bitAnd, :bitXor
|
|
26
|
+
checker.check_arity(func, args, 2)
|
|
27
|
+
args = args.map(&checker.method(:call))
|
|
28
|
+
|
|
29
|
+
type = checker.find_match_all_types(%i[int uint], args)
|
|
30
|
+
return type if type
|
|
31
|
+
when :sign, :abs
|
|
32
|
+
checker.check_arity(func, args, 1)
|
|
33
|
+
arg = checker.call(args.first)
|
|
34
|
+
type = checker.find_match_all_types(%i[double int uint], arg)
|
|
35
|
+
return if type
|
|
36
|
+
when :least, :greatest
|
|
37
|
+
checker.check_arity_any(func, args)
|
|
38
|
+
args = args.map(&checker.method(:call))
|
|
39
|
+
|
|
40
|
+
return TYPES[:any] if args.all? do |arg|
|
|
41
|
+
case arg
|
|
42
|
+
when TYPES[:any], TYPES[:int], TYPES[:uint], TYPES[:double],
|
|
43
|
+
TYPES[:list, :int], TYPES[:list, :uint], TYPES[:list, :double], TYPES[:list, :any]
|
|
44
|
+
true
|
|
45
|
+
else
|
|
46
|
+
false
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
when :bitShiftRight, :bitShiftLeft
|
|
50
|
+
checker.check_arity(func, args, 2)
|
|
51
|
+
num, amount_of_bits = args.map(&checker.method(:call))
|
|
52
|
+
|
|
53
|
+
return num if checker.find_match_all_types(%i[int uint],
|
|
54
|
+
num) && checker.find_match_all_types(%i[int], amount_of_bits)
|
|
55
|
+
else
|
|
56
|
+
checker.unsupported_operation(funcall)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
checker.unsupported_operation(funcall)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def abs(num, program:)
|
|
63
|
+
num = program.call(num)
|
|
64
|
+
|
|
65
|
+
raise EvaluateError, "out of range" unless num.value.between?(-MAX_INT + 1, MAX_INT - 1)
|
|
66
|
+
|
|
67
|
+
Number.new(num.type, num.value.abs)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def round(num, program:)
|
|
71
|
+
num = program.call(num)
|
|
72
|
+
|
|
73
|
+
Number.new(:double, num.value.round)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def trunc(num, program:)
|
|
77
|
+
num = program.call(num)
|
|
78
|
+
|
|
79
|
+
Number.new(:double, num.value.truncate)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def floor(num, program:)
|
|
83
|
+
num = program.call(num)
|
|
84
|
+
|
|
85
|
+
Number.new(:double, num.value.floor)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def ceil(num, program:)
|
|
89
|
+
num = program.call(num)
|
|
90
|
+
|
|
91
|
+
Number.new(:double, num.value.ceil)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def bitNot(num, program:)
|
|
95
|
+
val = program.call(num).value
|
|
96
|
+
|
|
97
|
+
case num.type
|
|
98
|
+
when TYPES[:int]
|
|
99
|
+
Number.new(:int, ~val)
|
|
100
|
+
when TYPES[:uint]
|
|
101
|
+
Number.new(:uint, ((2**64) - 1) - val)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def bitOr(lhs, rhs, program:)
|
|
106
|
+
lhs = program.call(lhs)
|
|
107
|
+
rhs = program.call(rhs)
|
|
108
|
+
Number.new(lhs.type, lhs | rhs)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def bitAnd(lhs, rhs, program:)
|
|
112
|
+
lhs = program.call(lhs)
|
|
113
|
+
rhs = program.call(rhs)
|
|
114
|
+
Number.new(lhs.type, lhs & rhs)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def bitXor(lhs, rhs, program:)
|
|
118
|
+
lhs = program.call(lhs)
|
|
119
|
+
rhs = program.call(rhs)
|
|
120
|
+
Number.new(lhs.type, lhs ^ rhs)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def sign(num, program:)
|
|
124
|
+
num = program.call(num)
|
|
125
|
+
value = num.value
|
|
126
|
+
|
|
127
|
+
Number.new(num.type, if value.negative?
|
|
128
|
+
-1
|
|
129
|
+
else
|
|
130
|
+
value.positive? ? 1 : 0
|
|
131
|
+
end)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def least(*args, program:)
|
|
135
|
+
args = args.map(&program.method(:call))
|
|
136
|
+
|
|
137
|
+
return args.min if args.size > 1
|
|
138
|
+
|
|
139
|
+
arg = args.first
|
|
140
|
+
|
|
141
|
+
case arg
|
|
142
|
+
when List
|
|
143
|
+
least(*arg.value, program: program)
|
|
144
|
+
else
|
|
145
|
+
arg
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def greatest(*args, program:)
|
|
150
|
+
args = args.map(&program.method(:call))
|
|
151
|
+
|
|
152
|
+
return args.max if args.size > 1
|
|
153
|
+
|
|
154
|
+
arg = args.first
|
|
155
|
+
|
|
156
|
+
case arg
|
|
157
|
+
when List
|
|
158
|
+
greatest(*arg.value, program: program)
|
|
159
|
+
else
|
|
160
|
+
arg
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def bitShiftRight(num, amount_of_bits, program:)
|
|
165
|
+
num = program.call(num)
|
|
166
|
+
amount_of_bits = program.call(amount_of_bits).value
|
|
167
|
+
|
|
168
|
+
raise EvaluateError, "math.#{__method__}() negative offset: #{amount_of_bits}" if amount_of_bits.negative?
|
|
169
|
+
|
|
170
|
+
# When the second parameter is 64 or greater, 0 will always be returned
|
|
171
|
+
return Number.new(num.type, 0) if amount_of_bits >= 64
|
|
172
|
+
|
|
173
|
+
value = num.value.negative? ? ((2**64) - 1) & num.value : num.value
|
|
174
|
+
|
|
175
|
+
Number.new(num.type, value >> amount_of_bits)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def bitShiftLeft(num, amount_of_bits, program:)
|
|
179
|
+
num = program.call(num)
|
|
180
|
+
amount_of_bits = program.call(amount_of_bits).value
|
|
181
|
+
|
|
182
|
+
raise EvaluateError, "math.#{__method__}() negative offset: #{amount_of_bits}" if amount_of_bits.negative?
|
|
183
|
+
|
|
184
|
+
# When the second parameter is 64 or greater, 0 will always be returned
|
|
185
|
+
return Number.new(num.type, 0) if amount_of_bits >= 64
|
|
186
|
+
|
|
187
|
+
Number.new(num.type, num.value << amount_of_bits)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def isInf(num, program:)
|
|
191
|
+
val = program.call(num).value
|
|
192
|
+
|
|
193
|
+
Bool.cast(val.infinite?)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def isNaN(num, program:)
|
|
197
|
+
val = program.call(num).value
|
|
198
|
+
|
|
199
|
+
Bool.cast(val.nan?)
|
|
200
|
+
rescue FloatDomainError
|
|
201
|
+
Bool.cast(true)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def isFinite(num, program:)
|
|
205
|
+
val = program.call(num).value
|
|
206
|
+
|
|
207
|
+
Bool.cast(!val.infinite? && !val.nan?)
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|