cel 0.2.3 → 0.3.0
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 +17 -0
- data/README.md +23 -1
- data/lib/cel/ast/elements/protobuf.rb +411 -66
- data/lib/cel/ast/elements.rb +339 -113
- data/lib/cel/ast/types.rb +151 -15
- data/lib/cel/checker.rb +133 -30
- data/lib/cel/context.rb +55 -6
- data/lib/cel/encoder.rb +31 -13
- data/lib/cel/environment.rb +58 -13
- data/lib/cel/errors.rb +19 -1
- data/lib/cel/macro.rb +91 -26
- data/lib/cel/parser.rb +428 -396
- data/lib/cel/program.rb +255 -48
- data/lib/cel/version.rb +1 -1
- data/lib/cel.rb +232 -1
- metadata +18 -9
- data/lib/cel/parser.tab.rb +0 -1023
data/lib/cel/ast/types.rb
CHANGED
@@ -7,11 +7,22 @@ module Cel
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def ==(other)
|
10
|
-
other == @type || super
|
10
|
+
(other.is_a?(Symbol) && other == @type) || super
|
11
11
|
end
|
12
12
|
|
13
13
|
def to_str
|
14
|
-
@type
|
14
|
+
case @type
|
15
|
+
when :timestamp
|
16
|
+
"google.protobuf.Timestamp"
|
17
|
+
when :duration
|
18
|
+
"google.protobuf.Duration"
|
19
|
+
else
|
20
|
+
@type.to_s
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_sym
|
25
|
+
@type
|
15
26
|
end
|
16
27
|
|
17
28
|
alias_method :to_s, :to_str
|
@@ -21,25 +32,122 @@ module Cel
|
|
21
32
|
end
|
22
33
|
|
23
34
|
def cast(value)
|
24
|
-
|
35
|
+
type = nil
|
36
|
+
type = value.type.to_sym if value.is_a?(Literal)
|
25
37
|
|
26
38
|
case @type
|
27
39
|
when :int
|
28
|
-
|
40
|
+
case type
|
41
|
+
when :int, :uint, :string
|
42
|
+
value = Integer(value.value)
|
43
|
+
|
44
|
+
raise "Type conversion range error" unless (-(MAX_INT - 1)...MAX_INT).cover?(value)
|
45
|
+
|
46
|
+
Number.new(:int, value)
|
47
|
+
when :double
|
48
|
+
value = value.value
|
49
|
+
|
50
|
+
raise "Type conversion range error" unless (-(MAX_FLOAT - 1)...MAX_FLOAT).cover?(value)
|
51
|
+
|
52
|
+
Number.new(:int, Integer(value))
|
53
|
+
when :timestamp
|
54
|
+
Number.new(:int, value.value.to_i)
|
55
|
+
else
|
56
|
+
raise EvaluateError, "Type conversion error"
|
57
|
+
end
|
29
58
|
when :uint
|
30
|
-
|
59
|
+
case type
|
60
|
+
when :int, :uint, :string
|
61
|
+
value = Integer(value.value)
|
62
|
+
|
63
|
+
raise EvaluateError, "Type conversion range error" unless (0...MAX_INT).cover?(value)
|
64
|
+
|
65
|
+
Number.new(:uint, value)
|
66
|
+
when :double
|
67
|
+
value = value.value
|
68
|
+
|
69
|
+
raise EvaluateError, "Type conversion range error" unless (0...MAX_FLOAT).cover?(value)
|
70
|
+
|
71
|
+
Number.new(:uint, Integer(value))
|
72
|
+
else
|
73
|
+
raise EvaluateError, "Type conversion error"
|
74
|
+
end
|
31
75
|
when :double
|
32
|
-
|
76
|
+
case type
|
77
|
+
when :double, :int, :uint
|
78
|
+
Number.new(:double, Float(value.value))
|
79
|
+
when :string
|
80
|
+
case value
|
81
|
+
when "NaN"
|
82
|
+
raise Error, "unsupported cast operation to #{@type}" unless defined?(Float::NAN)
|
83
|
+
|
84
|
+
Number.new(:double, Float::NAN)
|
85
|
+
else
|
86
|
+
Number.new(:double, Float(value.value))
|
87
|
+
end
|
88
|
+
else
|
89
|
+
raise EvaluateError, "Type conversion error"
|
90
|
+
end
|
33
91
|
when :string
|
34
|
-
|
92
|
+
case type
|
93
|
+
when :bytes
|
94
|
+
value = value.string.force_encoding(Encoding::UTF_8)
|
95
|
+
|
96
|
+
raise EvaluateError, "Type conversion invalid UTF-8" unless value.valid_encoding?
|
97
|
+
|
98
|
+
String.new(value)
|
99
|
+
when :timestamp
|
100
|
+
String.new(value.value.iso8601(9).sub(/\.0+Z/, "Z"))
|
101
|
+
when :duration
|
102
|
+
String.new(value.to_s)
|
103
|
+
else
|
104
|
+
String.new(String(value.value))
|
105
|
+
end
|
35
106
|
when :bytes
|
36
|
-
|
107
|
+
case type
|
108
|
+
when :bytes
|
109
|
+
value
|
110
|
+
when :string
|
111
|
+
Bytes.new(value.value.bytes)
|
112
|
+
else
|
113
|
+
raise EvaluateError, "Type conversion error"
|
114
|
+
end
|
37
115
|
when :bool
|
38
|
-
|
116
|
+
case type
|
117
|
+
when :bool
|
118
|
+
value
|
119
|
+
when :string
|
120
|
+
case value.value
|
121
|
+
when "1", "t", "true", "TRUE", "True"
|
122
|
+
Bool.new(true)
|
123
|
+
when "0", "f", "false", "FALSE", "False"
|
124
|
+
Bool.new(false)
|
125
|
+
else
|
126
|
+
raise EvaluateError, "Type conversion error"
|
127
|
+
end
|
128
|
+
else
|
129
|
+
raise EvaluateError, "Type conversion error"
|
130
|
+
end
|
131
|
+
when :null_type
|
132
|
+
Null::INSTANCE
|
39
133
|
when :timestamp
|
40
|
-
|
134
|
+
case type
|
135
|
+
when :timestamp
|
136
|
+
value
|
137
|
+
when :int, :string
|
138
|
+
Timestamp.new(value.value)
|
139
|
+
else
|
140
|
+
raise EvaluateError, "Type conversion error"
|
141
|
+
end
|
41
142
|
when :duration
|
42
|
-
|
143
|
+
case type
|
144
|
+
when :duration
|
145
|
+
value
|
146
|
+
when :string
|
147
|
+
Duration.new(value.value)
|
148
|
+
else
|
149
|
+
raise EvaluateError, "Type conversion error"
|
150
|
+
end
|
43
151
|
when :any
|
44
152
|
value
|
45
153
|
else
|
@@ -58,11 +166,13 @@ module Cel
|
|
58
166
|
end
|
59
167
|
|
60
168
|
def get(idx)
|
169
|
+
return @element_type if @type_list.empty?
|
170
|
+
|
61
171
|
@type_list[idx]
|
62
172
|
end
|
63
173
|
|
64
174
|
def ==(other)
|
65
|
-
other ==
|
175
|
+
(other.is_a?(self.class) && other.element_type == @element_type) || super
|
66
176
|
end
|
67
177
|
|
68
178
|
def cast(value)
|
@@ -73,18 +183,22 @@ module Cel
|
|
73
183
|
class MapType < Type
|
74
184
|
attr_accessor :element_type
|
75
185
|
|
186
|
+
attr_reader :type_map
|
187
|
+
protected :type_map
|
188
|
+
|
76
189
|
def initialize(type_map)
|
77
190
|
super(:map)
|
78
191
|
@type_map = type_map
|
79
|
-
@element_type = @type_map.empty? ? TYPES[:any] : @type_map.
|
192
|
+
@element_type = @type_map.empty? ? TYPES[:any] : @type_map.sample.first.type
|
80
193
|
end
|
81
194
|
|
82
195
|
def get(attrib)
|
83
|
-
_, value = @type_map.find { |k, _| k == attrib
|
196
|
+
_, value = @type_map.find { |k, _| k == attrib }
|
84
197
|
value
|
85
198
|
end
|
86
199
|
|
87
200
|
def ==(other)
|
201
|
+
(other.is_a?(self.class) && other.element_type == @element_type && other.type_map == @type_map) || super
|
88
202
|
other == :map || super
|
89
203
|
end
|
90
204
|
|
@@ -93,6 +207,12 @@ module Cel
|
|
93
207
|
end
|
94
208
|
end
|
95
209
|
|
210
|
+
class AbstractType < Type
|
211
|
+
def initialize(name, *params)
|
212
|
+
super(name)
|
213
|
+
@params = params
|
214
|
+
end
|
215
|
+
end
|
96
216
|
# Primitive Cel Types
|
97
217
|
|
98
218
|
PRIMITIVE_TYPES = %i[int uint double bool string bytes list map timestamp duration null_type type].freeze
|
@@ -118,10 +238,26 @@ module Cel
|
|
118
238
|
MapType.new({})
|
119
239
|
end
|
120
240
|
|
121
|
-
type.element_type =
|
241
|
+
type.element_type = elem_type.is_a?(Type) || (elem_type.is_a?(Class) && elem_type < Protobuf.base_class) ?
|
242
|
+
elem_type :
|
243
|
+
super(*elem_type)
|
122
244
|
type
|
123
245
|
end
|
124
246
|
end
|
125
247
|
|
126
248
|
TYPES.singleton_class.prepend(CollectionTypeFetch)
|
249
|
+
|
250
|
+
# override == to ensure that cel timestamp/duration types
|
251
|
+
# compare positively with the protobuf counterparts.
|
252
|
+
timestamp_class = TYPES[:timestamp]
|
253
|
+
|
254
|
+
def timestamp_class.==(other)
|
255
|
+
other == Protobuf.timestamp_class || super
|
256
|
+
end
|
257
|
+
|
258
|
+
duration_class = TYPES[:duration]
|
259
|
+
|
260
|
+
def duration_class.==(other)
|
261
|
+
other == Protobuf.duration_class || super
|
262
|
+
end
|
127
263
|
end
|
data/lib/cel/checker.rb
CHANGED
@@ -2,11 +2,35 @@
|
|
2
2
|
|
3
3
|
module Cel
|
4
4
|
class Checker
|
5
|
-
|
5
|
+
LOGICAL_EXPECTED_TYPES = %i[bool int uint double string bytes timestamp duration].freeze
|
6
|
+
ADD_EXPECTED_TYPES = %i[int uint double string bytes list duration].freeze
|
7
|
+
SUB_EXPECTED_TYPES = %i[int uint double duration].freeze
|
8
|
+
MULTIDIV_EXPECTED_TYPES = %i[int uint double].freeze
|
9
|
+
REMAINDER_EXPECTED_TYPES = %i[int uint].freeze
|
10
|
+
|
11
|
+
BOOLABLE_OPERATORS = %w[&& || == != < <= >= >].freeze
|
12
|
+
|
13
|
+
CAST_ALLOWED_TYPES = {
|
14
|
+
int: %i[int uint double string timestamp], # TODO: enum
|
15
|
+
uint: %i[int uint double string],
|
16
|
+
string: %i[int uint double bytes bool bytes string timestamp duration],
|
17
|
+
double: %i[double int uint string],
|
18
|
+
bytes: %i[bytes string],
|
19
|
+
bool: %i[bool string],
|
20
|
+
duration: %i[string duration],
|
21
|
+
timestamp: %i[int string timestamp],
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
attr_reader :declarations
|
25
|
+
|
26
|
+
def initialize(environment, declarations = environment.declarations)
|
27
|
+
@environment = environment
|
6
28
|
@declarations = declarations
|
7
29
|
end
|
8
30
|
|
9
31
|
def check(ast)
|
32
|
+
return ast if ast.is_a?(Class) && ast < Protobuf.base_class
|
33
|
+
|
10
34
|
case ast
|
11
35
|
when Group
|
12
36
|
check(ast.value)
|
@@ -15,7 +39,9 @@ module Cel
|
|
15
39
|
when Operation
|
16
40
|
check_operation(ast)
|
17
41
|
when Literal
|
18
|
-
ast
|
42
|
+
check_literal(ast)
|
43
|
+
when Message
|
44
|
+
check_message(ast)
|
19
45
|
when Identifier
|
20
46
|
check_identifier(ast)
|
21
47
|
when Condition
|
@@ -28,14 +54,32 @@ module Cel
|
|
28
54
|
private
|
29
55
|
|
30
56
|
def merge(declarations)
|
31
|
-
Checker.new(@declarations ? @declarations.merge(declarations) : declarations)
|
57
|
+
Checker.new(@environment, @declarations ? @declarations.merge(declarations) : declarations)
|
32
58
|
end
|
33
59
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
60
|
+
def check_literal(literal)
|
61
|
+
case literal
|
62
|
+
when List
|
63
|
+
lit = ListType.new(literal.value)
|
64
|
+
elem_types = literal.value.map(&method(:call))
|
65
|
+
|
66
|
+
if !literal.value.empty? && elem_types.map do |type|
|
67
|
+
type.respond_to?(:to_sym) ? type.to_sym : type
|
68
|
+
end.uniq.size == 1
|
69
|
+
elem = literal.by_max_depth
|
70
|
+
lit.element_type = call(elem)
|
71
|
+
end
|
72
|
+
lit
|
73
|
+
when Map
|
74
|
+
MapType.new(literal.value)
|
75
|
+
else
|
76
|
+
literal.type
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def check_message(literal)
|
81
|
+
literal.type
|
82
|
+
end
|
39
83
|
|
40
84
|
def check_operation(operation)
|
41
85
|
type = infer_operation_type(operation)
|
@@ -43,8 +87,6 @@ module Cel
|
|
43
87
|
type
|
44
88
|
end
|
45
89
|
|
46
|
-
BOOLABLE_OPERATORS = %w[&& || == != < <= >= >].freeze
|
47
|
-
|
48
90
|
def infer_operation_type(operation)
|
49
91
|
op = operation.op
|
50
92
|
|
@@ -78,11 +120,18 @@ module Cel
|
|
78
120
|
return TYPES[:bool] if values.uniq.size == 1 ||
|
79
121
|
values.all? { |v| v == :list } ||
|
80
122
|
values.all? { |v| v == :map } ||
|
123
|
+
# comparison with null is allowed for legacy reasons
|
124
|
+
# https://github.com/google/cel-spec/issues/361
|
125
|
+
values.one? { |v| v == :null_type } ||
|
81
126
|
values.include?(:any)
|
82
127
|
when "in"
|
83
128
|
return TYPES[:bool] if find_match_all_types(%i[list map any], values.last)
|
84
129
|
when "+"
|
85
|
-
|
130
|
+
if (type = find_match_all_types(ADD_EXPECTED_TYPES, values))
|
131
|
+
return type unless type == :list
|
132
|
+
|
133
|
+
return values.find { |v| v.element_type != :any } || type
|
134
|
+
end
|
86
135
|
|
87
136
|
return TYPES[:timestamp] if %i[timestamp duration].any? { |typ| values.first == typ }
|
88
137
|
|
@@ -127,6 +176,12 @@ module Cel
|
|
127
176
|
check_identifier(var)
|
128
177
|
when Invoke
|
129
178
|
check_invoke(var)
|
179
|
+
when Literal
|
180
|
+
check_literal(var)
|
181
|
+
when Group
|
182
|
+
check(var.value)
|
183
|
+
when Protobuf.base_class
|
184
|
+
var.class
|
130
185
|
else
|
131
186
|
var.type
|
132
187
|
end
|
@@ -147,9 +202,15 @@ module Cel
|
|
147
202
|
# to maps. For maps, selection is interpreted as the field being a string key.
|
148
203
|
case func
|
149
204
|
when :[]
|
205
|
+
if args.is_a?(Invoke)
|
206
|
+
args = call(args)
|
207
|
+
return TYPES[:any] if args == TYPES[:any]
|
208
|
+
end
|
150
209
|
attribute = var_type.get(args)
|
151
210
|
return TYPES[:any] unless attribute
|
152
|
-
when :
|
211
|
+
when :exists, :all
|
212
|
+
return TYPES[:bool]
|
213
|
+
when :exists_one
|
153
214
|
check_arity(funcall, args, 2)
|
154
215
|
identifier, predicate = args
|
155
216
|
|
@@ -169,10 +230,25 @@ module Cel
|
|
169
230
|
when ListType
|
170
231
|
case func
|
171
232
|
when :[]
|
233
|
+
if args.is_a?(Invoke)
|
234
|
+
args = call(args)
|
235
|
+
return TYPES[:any] if args == TYPES[:any]
|
236
|
+
end
|
237
|
+
|
238
|
+
if args.is_a?(Type)
|
239
|
+
unsupported_operation(funcall) unless args == TYPES[:int]
|
240
|
+
|
241
|
+
return var_type.element_type
|
242
|
+
end
|
243
|
+
|
172
244
|
attribute = var_type.get(args)
|
245
|
+
|
173
246
|
unsupported_operation(funcall) unless attribute
|
247
|
+
|
174
248
|
call(attribute)
|
175
|
-
when :
|
249
|
+
when :exists, :all
|
250
|
+
TYPES[:bool]
|
251
|
+
when :exists_one
|
176
252
|
check_arity(funcall, args, 2)
|
177
253
|
identifier, predicate = args
|
178
254
|
|
@@ -227,7 +303,8 @@ module Cel
|
|
227
303
|
when :getDate, :getDayOfMonth, :getDayOfWeek, :getDayOfYear, :getFullYear, :getHours,
|
228
304
|
:getMilliseconds, :getMinutes, :getMonth, :getSeconds
|
229
305
|
check_arity(func, args, 0..1)
|
230
|
-
|
306
|
+
# TODO: verify if it's a valid tz
|
307
|
+
return TYPES[:int] if args.empty? || (args.size.positive? && call(args.first) == :string)
|
231
308
|
else
|
232
309
|
unsupported_type(funcall)
|
233
310
|
end
|
@@ -241,25 +318,41 @@ module Cel
|
|
241
318
|
unsupported_type(funcall)
|
242
319
|
end
|
243
320
|
unsupported_operation(funcall)
|
321
|
+
when Class
|
322
|
+
# Protobuf property
|
323
|
+
if var_type.respond_to?(:descriptor)
|
324
|
+
return Protobuf.convert_to_cel_type(
|
325
|
+
var_type.descriptor.lookup(func.to_s),
|
326
|
+
@environment.package
|
327
|
+
)
|
328
|
+
end
|
329
|
+
|
330
|
+
TYPES[:any]
|
331
|
+
when Module
|
332
|
+
# Protobuf enum access
|
333
|
+
return TYPES[:int] if var_type.const_defined?(func)
|
334
|
+
|
335
|
+
TYPES[:any]
|
244
336
|
else
|
245
337
|
TYPES[:any]
|
246
338
|
end
|
247
339
|
end
|
248
340
|
|
249
|
-
CAST_ALLOWED_TYPES = {
|
250
|
-
int: %i[uint double string timestamp], # TODO: enum
|
251
|
-
uint: %i[int double string],
|
252
|
-
string: %i[int uint double bytes timestamp duration],
|
253
|
-
double: %i[int uint string],
|
254
|
-
bytes: %i[string],
|
255
|
-
duration: %i[string],
|
256
|
-
timestamp: %i[string],
|
257
|
-
}.freeze
|
258
|
-
|
259
341
|
def check_standard_func(funcall)
|
260
342
|
func = funcall.func
|
261
343
|
args = funcall.args
|
262
344
|
|
345
|
+
# check if protobuf conversion
|
346
|
+
if (proto_type = Protobuf.convert_to_proto_type(func.to_s, @environment.package))
|
347
|
+
# TODO: fixit
|
348
|
+
raise "unsupported" unless proto_type.respond_to?(:resolve)
|
349
|
+
|
350
|
+
check_arity(func, args, 1)
|
351
|
+
|
352
|
+
arg = call(args.first)
|
353
|
+
return proto_type.descriptor.name if find_match_all_types(%i[int], arg)
|
354
|
+
end
|
355
|
+
|
263
356
|
case func
|
264
357
|
when :type
|
265
358
|
check_arity(func, args, 1)
|
@@ -279,16 +372,23 @@ module Cel
|
|
279
372
|
allowed_types = CAST_ALLOWED_TYPES[func]
|
280
373
|
|
281
374
|
arg = call(args.first)
|
375
|
+
|
282
376
|
return TYPES[func] if find_match_all_types(allowed_types, arg)
|
283
377
|
when :matches
|
284
378
|
check_arity(func, args, 2)
|
285
379
|
return TYPES[:bool] if find_match_all_types(%i[string], args.map(&method(:call)))
|
286
380
|
when :dyn
|
287
381
|
check_arity(func, args, 1)
|
288
|
-
arg_type =
|
382
|
+
arg_type = begin
|
383
|
+
call(args.first)
|
384
|
+
rescue StandardError
|
385
|
+
TYPES[:any]
|
386
|
+
end
|
289
387
|
case arg_type
|
290
388
|
when ListType, MapType
|
291
389
|
arg_type.element_type = TYPES[:any]
|
390
|
+
else
|
391
|
+
return TYPES[:any]
|
292
392
|
end
|
293
393
|
return arg_type
|
294
394
|
else
|
@@ -326,6 +426,11 @@ module Cel
|
|
326
426
|
|
327
427
|
return TYPES[:type] if Cel::PRIMITIVE_TYPES.include?(identifier.to_sym)
|
328
428
|
|
429
|
+
proto_type = identifier.try_convert_to_proto_type
|
430
|
+
|
431
|
+
# protobuf enum
|
432
|
+
return proto_type if proto_type
|
433
|
+
|
329
434
|
id_type = infer_dec_type(identifier.id)
|
330
435
|
|
331
436
|
return TYPES[:any] unless id_type
|
@@ -341,11 +446,9 @@ module Cel
|
|
341
446
|
raise CheckError, "`#{condition.if}` must evaluate to a bool" unless if_type == :bool
|
342
447
|
|
343
448
|
then_type = call(condition.then)
|
344
|
-
|
345
|
-
|
346
|
-
return then_type if then_type == else_type
|
449
|
+
call(condition.else)
|
347
450
|
|
348
|
-
|
451
|
+
then_type
|
349
452
|
end
|
350
453
|
|
351
454
|
def infer_dec_type(id)
|
@@ -391,7 +494,7 @@ module Cel
|
|
391
494
|
end
|
392
495
|
|
393
496
|
def unsupported_type(op)
|
394
|
-
raise
|
497
|
+
raise CheckError, "no matching overload: #{op}"
|
395
498
|
end
|
396
499
|
|
397
500
|
def unsupported_operation(op)
|
data/lib/cel/context.rb
CHANGED
@@ -11,8 +11,17 @@ module Cel
|
|
11
11
|
return unless @bindings
|
12
12
|
|
13
13
|
@bindings.each do |k, v|
|
14
|
-
|
15
|
-
|
14
|
+
if @declarations && (type = @declarations[k])
|
15
|
+
type = TYPES[type] if type.is_a?(Symbol)
|
16
|
+
|
17
|
+
val = if type.is_a?(Class) && type < Protobuf.base_class
|
18
|
+
Protobuf.convert_to_proto(type, v)
|
19
|
+
else
|
20
|
+
type.cast(to_cel_type(v))
|
21
|
+
end
|
22
|
+
else
|
23
|
+
val = to_cel_type(v)
|
24
|
+
end
|
16
25
|
@bindings[k] = val
|
17
26
|
end
|
18
27
|
end
|
@@ -20,12 +29,52 @@ module Cel
|
|
20
29
|
def lookup(identifier)
|
21
30
|
raise EvaluateError, "no value in context for #{identifier}" unless @bindings
|
22
31
|
|
23
|
-
id = identifier.
|
24
|
-
|
32
|
+
id = identifier.to_s
|
33
|
+
|
34
|
+
lookup_keys = id.split(".")
|
35
|
+
|
36
|
+
val = @bindings
|
37
|
+
|
38
|
+
loop do
|
39
|
+
fetched = false
|
40
|
+
(0...lookup_keys.size).reverse_each do |idx|
|
41
|
+
key = lookup_keys[0..idx].join(".").to_sym
|
42
|
+
|
43
|
+
val = if val.respond_to?(:key?)
|
44
|
+
# hash
|
45
|
+
next unless val.key?(key)
|
46
|
+
|
47
|
+
val[key]
|
48
|
+
else
|
49
|
+
next unless val.respond_to?(key)
|
50
|
+
|
51
|
+
case val
|
52
|
+
when Protobuf.base_class
|
53
|
+
Protobuf.lookup(val, key)
|
54
|
+
else
|
55
|
+
val.__send__(key)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
lookup_keys = lookup_keys[idx + 1..]
|
60
|
+
fetched = true
|
61
|
+
break
|
62
|
+
end
|
63
|
+
|
64
|
+
break unless fetched
|
65
|
+
|
66
|
+
break if lookup_keys.empty?
|
67
|
+
end
|
68
|
+
|
69
|
+
raise EvaluateError, "no value in context for #{id}" if val == @bindings
|
70
|
+
|
71
|
+
# lookup_keys.each do |key|
|
72
|
+
# raise EvaluateError, "no value in context for #{id}" unless val.key?(key)
|
25
73
|
|
26
|
-
|
74
|
+
# val = val[key]
|
75
|
+
# end
|
27
76
|
|
28
|
-
val
|
77
|
+
[val, lookup_keys.empty? ? nil : lookup_keys.join(".")]
|
29
78
|
end
|
30
79
|
|
31
80
|
def merge(bindings)
|
data/lib/cel/encoder.rb
CHANGED
@@ -38,20 +38,30 @@ module Cel
|
|
38
38
|
expr.type.to_s,
|
39
39
|
expr.id.to_s,
|
40
40
|
]
|
41
|
-
when List
|
42
|
-
[
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
41
|
+
when List, Map
|
42
|
+
[
|
43
|
+
"lit",
|
44
|
+
expr.type.to_s,
|
45
|
+
*encode(expr.value),
|
46
|
+
]
|
47
|
+
when Message
|
48
|
+
[
|
49
|
+
"message",
|
50
|
+
expr.name.to_s,
|
51
|
+
encode(expr.struct),
|
52
|
+
]
|
49
53
|
when Number, Bool, String, Bytes
|
50
54
|
["lit", expr.type.to_s, expr.value]
|
51
55
|
when Null
|
52
56
|
%w[lit null]
|
53
57
|
when Type
|
54
58
|
["lit", "type", expr.to_s]
|
59
|
+
when Array
|
60
|
+
expr.map(&method(:encode))
|
61
|
+
when Hash
|
62
|
+
expr.to_h { |*kv| kv.map(&method(:encode)) }
|
63
|
+
else
|
64
|
+
expr
|
55
65
|
end
|
56
66
|
end
|
57
67
|
|
@@ -80,22 +90,30 @@ module Cel
|
|
80
90
|
id.type = TYPES[type.to_sym]
|
81
91
|
id
|
82
92
|
in ["lit", "list", *items]
|
83
|
-
|
84
|
-
|
93
|
+
List.new(items.map(&method(:decode)))
|
94
|
+
|
85
95
|
in ["lit", "map", items]
|
86
|
-
Map.new(
|
96
|
+
Map.new(decode(items))
|
87
97
|
in ["lit", /\Aint|uint|double\z/ => type, Integer => val]
|
88
98
|
Number.new(type.to_sym, val)
|
89
99
|
in ["lit", "bool", val]
|
90
|
-
Bool.
|
100
|
+
Bool.cast(val)
|
91
101
|
in ["lit", "string", val]
|
92
102
|
String.new(val)
|
93
103
|
in ["lit", "bytes", val]
|
94
104
|
Bytes.new(val)
|
95
105
|
in ["lit", "null"]
|
96
|
-
Null
|
106
|
+
Null::INSTANCE
|
97
107
|
in ["lit", "type", type]
|
98
108
|
TYPES[type.to_sym]
|
109
|
+
in ["message", name, struct]
|
110
|
+
Cel::Message.new(name, decode(struct))
|
111
|
+
in **items
|
112
|
+
items.to_h { |*kv| kv.map(&method(:decode)) }
|
113
|
+
in *items
|
114
|
+
items.map(&method(:decode)).each_slice(2)
|
115
|
+
else
|
116
|
+
enc
|
99
117
|
end
|
100
118
|
end
|
101
119
|
end
|