cel 0.1.2 → 0.2.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 +85 -0
- data/README.md +33 -6
- data/lib/cel/ast/elements/protobuf.rb +127 -0
- data/lib/cel/ast/elements.rb +258 -4
- data/lib/cel/ast/types.rb +49 -2
- data/lib/cel/checker.rb +116 -38
- data/lib/cel/context.rb +8 -3
- data/lib/cel/encoder.rb +102 -0
- data/lib/cel/environment.rb +19 -6
- data/lib/cel/parser.rb +28 -12
- data/lib/cel/program.rb +20 -6
- data/lib/cel/version.rb +1 -1
- data/lib/cel.rb +1 -6
- metadata +19 -4
- data/lib/cel/protobuf.rb +0 -175
data/lib/cel/ast/types.rb
CHANGED
@@ -14,6 +14,8 @@ module Cel
|
|
14
14
|
@type.to_s
|
15
15
|
end
|
16
16
|
|
17
|
+
alias_method :to_s, :to_str
|
18
|
+
|
17
19
|
def type
|
18
20
|
TYPES[:type]
|
19
21
|
end
|
@@ -32,6 +34,10 @@ module Cel
|
|
32
34
|
Bytes.new(value.bytes)
|
33
35
|
when :bool
|
34
36
|
Bool.new(value)
|
37
|
+
when :timestamp
|
38
|
+
Timestamp.new(value)
|
39
|
+
when :duration
|
40
|
+
Duration.new(value)
|
35
41
|
when :any
|
36
42
|
value
|
37
43
|
else
|
@@ -52,6 +58,14 @@ module Cel
|
|
52
58
|
def get(idx)
|
53
59
|
@type_list[idx]
|
54
60
|
end
|
61
|
+
|
62
|
+
def ==(other)
|
63
|
+
other == :list || super
|
64
|
+
end
|
65
|
+
|
66
|
+
def cast(value)
|
67
|
+
List.new(value)
|
68
|
+
end
|
55
69
|
end
|
56
70
|
|
57
71
|
class MapType < Type
|
@@ -67,12 +81,45 @@ module Cel
|
|
67
81
|
_, value = @type_map.find { |k, _| k == attrib.to_s }
|
68
82
|
value
|
69
83
|
end
|
84
|
+
|
85
|
+
def ==(other)
|
86
|
+
other == :map || super
|
87
|
+
end
|
88
|
+
|
89
|
+
def cast(value)
|
90
|
+
Map.new(value)
|
91
|
+
end
|
70
92
|
end
|
71
93
|
|
72
94
|
# Primitive Cel Types
|
73
95
|
|
74
|
-
PRIMITIVE_TYPES = %i[int uint double bool string bytes list map null_type type].freeze
|
75
|
-
|
96
|
+
PRIMITIVE_TYPES = %i[int uint double bool string bytes list map timestamp duration null_type type].freeze
|
97
|
+
COLTYPES = %i[list map].freeze
|
98
|
+
TYPES = (PRIMITIVE_TYPES - COLTYPES).to_h { |typ| [typ, Type.new(typ)] }
|
76
99
|
TYPES[:type] = Type.new(:type)
|
77
100
|
TYPES[:any] = Type.new(:any)
|
101
|
+
|
102
|
+
module CollectionTypeFetch
|
103
|
+
def [](*args)
|
104
|
+
col_type, elem_type = args
|
105
|
+
|
106
|
+
return super unless COLTYPES.include?(col_type)
|
107
|
+
|
108
|
+
return super if args.size > 2
|
109
|
+
|
110
|
+
elem_type ||= :any
|
111
|
+
|
112
|
+
type = case col_type
|
113
|
+
when :list
|
114
|
+
ListType.new([])
|
115
|
+
when :map
|
116
|
+
MapType.new({})
|
117
|
+
end
|
118
|
+
|
119
|
+
type.element_type = super(*elem_type)
|
120
|
+
type
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
TYPES.singleton_class.prepend(CollectionTypeFetch)
|
78
125
|
end
|
data/lib/cel/checker.rb
CHANGED
@@ -31,10 +31,9 @@ module Cel
|
|
31
31
|
Checker.new(@declarations ? @declarations.merge(declarations) : declarations)
|
32
32
|
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
SUB_EXPECTED_TYPES = %i[int uint double].freeze
|
34
|
+
LOGICAL_EXPECTED_TYPES = %i[bool int uint double string bytes timestamp duration].freeze
|
35
|
+
ADD_EXPECTED_TYPES = %i[int uint double string bytes list duration].freeze
|
36
|
+
SUB_EXPECTED_TYPES = %i[int uint double duration].freeze
|
38
37
|
MULTIDIV_EXPECTED_TYPES = %i[int uint double].freeze
|
39
38
|
REMAINDER_EXPECTED_TYPES = %i[int uint].freeze
|
40
39
|
|
@@ -73,26 +72,48 @@ module Cel
|
|
73
72
|
else
|
74
73
|
|
75
74
|
case op
|
76
|
-
when "&&", "||", "
|
77
|
-
return TYPES[:bool]
|
75
|
+
when "&&", "||", "<", "<=", ">=", ">"
|
76
|
+
return TYPES[:bool] if find_match_all_types(LOGICAL_EXPECTED_TYPES, values) || values.include?(:any)
|
77
|
+
when "!=", "=="
|
78
|
+
return TYPES[:bool] if values.uniq.size == 1 ||
|
79
|
+
values.all? { |v| v == :list } ||
|
80
|
+
values.all? { |v| v == :map } ||
|
81
|
+
values.include?(:any)
|
78
82
|
when "in"
|
79
|
-
return TYPES[:bool] if find_match_all_types(%i[list map], values.last)
|
83
|
+
return TYPES[:bool] if find_match_all_types(%i[list map any], values.last)
|
80
84
|
when "+"
|
81
|
-
if (type = find_match_all_types(ADD_EXPECTED_TYPES, values))
|
82
|
-
|
83
|
-
|
85
|
+
return type if (type = find_match_all_types(ADD_EXPECTED_TYPES, values))
|
86
|
+
|
87
|
+
return TYPES[:timestamp] if %i[timestamp duration].any? { |typ| values.first == typ }
|
88
|
+
|
89
|
+
return values.last if values.first == :any
|
90
|
+
|
84
91
|
when "-"
|
85
|
-
if (type = find_match_all_types(SUB_EXPECTED_TYPES, values))
|
86
|
-
|
92
|
+
return type if (type = find_match_all_types(SUB_EXPECTED_TYPES, values))
|
93
|
+
|
94
|
+
case values.first
|
95
|
+
when TYPES[:timestamp]
|
96
|
+
return TYPES[:duration] if values.last == :timestamp
|
97
|
+
|
98
|
+
return TYPES[:timestamp] if values.last == :duration
|
99
|
+
|
100
|
+
return TYPES[:any] if values.last == :any
|
101
|
+
|
102
|
+
when TYPES[:any]
|
103
|
+
return values.last
|
87
104
|
end
|
88
105
|
when "*", "/"
|
89
|
-
if (type = find_match_all_types(MULTIDIV_EXPECTED_TYPES, values))
|
90
|
-
|
91
|
-
|
106
|
+
return type if (type = find_match_all_types(MULTIDIV_EXPECTED_TYPES, values))
|
107
|
+
|
108
|
+
values.include?(:any)
|
109
|
+
values.find { |typ| typ != :any } || TYPES[:any]
|
110
|
+
|
92
111
|
when "%"
|
93
|
-
if (type = find_match_all_types(REMAINDER_EXPECTED_TYPES, values))
|
94
|
-
|
95
|
-
|
112
|
+
return type if (type = find_match_all_types(REMAINDER_EXPECTED_TYPES, values))
|
113
|
+
|
114
|
+
values.include?(:any)
|
115
|
+
values.find { |typ| typ != :any } || TYPES[:any]
|
116
|
+
|
96
117
|
else
|
97
118
|
unsupported_type(operation)
|
98
119
|
end
|
@@ -100,6 +121,17 @@ module Cel
|
|
100
121
|
unsupported_type(operation)
|
101
122
|
end
|
102
123
|
|
124
|
+
def infer_variable_type(var)
|
125
|
+
case var
|
126
|
+
when Identifier
|
127
|
+
check_identifier(var)
|
128
|
+
when Invoke
|
129
|
+
check_invoke(var)
|
130
|
+
else
|
131
|
+
var.type
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
103
135
|
def check_invoke(funcall, var_type = nil)
|
104
136
|
var = funcall.var
|
105
137
|
func = funcall.func
|
@@ -107,14 +139,7 @@ module Cel
|
|
107
139
|
|
108
140
|
return check_standard_func(funcall) unless var
|
109
141
|
|
110
|
-
var_type ||=
|
111
|
-
when Identifier
|
112
|
-
check_identifier(var)
|
113
|
-
when Invoke
|
114
|
-
check_invoke(var)
|
115
|
-
else
|
116
|
-
var.type
|
117
|
-
end
|
142
|
+
var_type ||= infer_variable_type(var)
|
118
143
|
|
119
144
|
case var_type
|
120
145
|
when MapType
|
@@ -123,7 +148,7 @@ module Cel
|
|
123
148
|
case func
|
124
149
|
when :[]
|
125
150
|
attribute = var_type.get(args)
|
126
|
-
|
151
|
+
return TYPES[:any] unless attribute
|
127
152
|
when :all, :exists, :exists_one
|
128
153
|
check_arity(funcall, args, 2)
|
129
154
|
identifier, predicate = args
|
@@ -137,7 +162,7 @@ module Cel
|
|
137
162
|
return TYPES[:bool]
|
138
163
|
else
|
139
164
|
attribute = var_type.get(func)
|
140
|
-
|
165
|
+
return TYPES[:any] unless attribute
|
141
166
|
end
|
142
167
|
|
143
168
|
call(attribute)
|
@@ -153,6 +178,8 @@ module Cel
|
|
153
178
|
|
154
179
|
unsupported_type(funcall) unless identifier.is_a?(Identifier)
|
155
180
|
|
181
|
+
identifier.type = var_type.element_type
|
182
|
+
|
156
183
|
element_checker = merge(identifier.to_sym => var_type.element_type)
|
157
184
|
|
158
185
|
unsupported_type(funcall) if element_checker.check(predicate) != :bool
|
@@ -195,17 +222,38 @@ module Cel
|
|
195
222
|
unsupported_type(funcall)
|
196
223
|
end
|
197
224
|
unsupported_operation(funcall)
|
225
|
+
when TYPES[:timestamp]
|
226
|
+
case func
|
227
|
+
when :getDate, :getDayOfMonth, :getDayOfWeek, :getDayOfYear, :getFullYear, :getHours,
|
228
|
+
:getMilliseconds, :getMinutes, :getMonth, :getSeconds
|
229
|
+
check_arity(func, args, 0..1)
|
230
|
+
return TYPES[:int] if args.empty? || (args.size.positive? && args[0] == :string)
|
231
|
+
else
|
232
|
+
unsupported_type(funcall)
|
233
|
+
end
|
234
|
+
unsupported_operation(funcall)
|
235
|
+
when TYPES[:duration]
|
236
|
+
case func
|
237
|
+
when :getMilliseconds, :getMinutes, :getHours, :getSeconds
|
238
|
+
check_arity(func, args, 0)
|
239
|
+
return TYPES[:int]
|
240
|
+
else
|
241
|
+
unsupported_type(funcall)
|
242
|
+
end
|
243
|
+
unsupported_operation(funcall)
|
198
244
|
else
|
199
245
|
TYPES[:any]
|
200
246
|
end
|
201
247
|
end
|
202
248
|
|
203
249
|
CAST_ALLOWED_TYPES = {
|
204
|
-
int: %i[uint double string], # TODO: enum
|
250
|
+
int: %i[uint double string timestamp], # TODO: enum
|
205
251
|
uint: %i[int double string],
|
206
|
-
string: %i[int uint double bytes
|
252
|
+
string: %i[int uint double bytes timestamp duration],
|
207
253
|
double: %i[int uint string],
|
208
254
|
bytes: %i[string],
|
255
|
+
duration: %i[string],
|
256
|
+
timestamp: %i[string],
|
209
257
|
}.freeze
|
210
258
|
|
211
259
|
def check_standard_func(funcall)
|
@@ -223,15 +271,18 @@ module Cel
|
|
223
271
|
return TYPES[:bool]
|
224
272
|
when :size
|
225
273
|
check_arity(func, args, 1)
|
226
|
-
|
227
|
-
|
274
|
+
|
275
|
+
arg = call(args.first)
|
276
|
+
return TYPES[:int] if find_match_all_types(%i[string bytes list map], arg)
|
277
|
+
when *CAST_ALLOWED_TYPES.keys
|
228
278
|
check_arity(func, args, 1)
|
229
279
|
allowed_types = CAST_ALLOWED_TYPES[func]
|
230
280
|
|
231
|
-
|
281
|
+
arg = call(args.first)
|
282
|
+
return TYPES[func] if find_match_all_types(allowed_types, arg)
|
232
283
|
when :matches
|
233
284
|
check_arity(func, args, 2)
|
234
|
-
return TYPES[:bool] if find_match_all_types(%i[string], args.map
|
285
|
+
return TYPES[:bool] if find_match_all_types(%i[string], args.map(&method(:call)))
|
235
286
|
when :dyn
|
236
287
|
check_arity(func, args, 1)
|
237
288
|
arg_type = call(args.first)
|
@@ -241,14 +292,37 @@ module Cel
|
|
241
292
|
end
|
242
293
|
return arg_type
|
243
294
|
else
|
295
|
+
return check_custom_func(@declarations[func], funcall) if @declarations.key?(func)
|
296
|
+
|
244
297
|
unsupported_type(funcall)
|
245
298
|
end
|
246
299
|
|
247
300
|
unsupported_operation(funcall)
|
248
301
|
end
|
249
302
|
|
303
|
+
def check_custom_func(func, funcall)
|
304
|
+
args = funcall.args
|
305
|
+
|
306
|
+
unless func.is_a?(Cel::Function)
|
307
|
+
raise CheckError, "#{func} must respond to #call" unless func.respond_to?(:call)
|
308
|
+
|
309
|
+
func = Cel::Function(&func)
|
310
|
+
end
|
311
|
+
|
312
|
+
unless func.types.empty?
|
313
|
+
unsupported_type(funcall) unless func.types.zip(args.map(&method(:call)))
|
314
|
+
.all? do |expected_type, type|
|
315
|
+
expected_type == :any || expected_type == type
|
316
|
+
end
|
317
|
+
|
318
|
+
return func.type
|
319
|
+
end
|
320
|
+
|
321
|
+
unsupported_operation(funcall)
|
322
|
+
end
|
323
|
+
|
250
324
|
def check_identifier(identifier)
|
251
|
-
return unless identifier.type == :any
|
325
|
+
return identifier.type unless identifier.type == :any
|
252
326
|
|
253
327
|
return TYPES[:type] if Cel::PRIMITIVE_TYPES.include?(identifier.to_sym)
|
254
328
|
|
@@ -262,6 +336,10 @@ module Cel
|
|
262
336
|
end
|
263
337
|
|
264
338
|
def check_condition(condition)
|
339
|
+
if_type = call(condition.if)
|
340
|
+
|
341
|
+
raise CheckError, "`#{condition.if}` must evaluate to a bool" unless if_type == :bool
|
342
|
+
|
265
343
|
then_type = call(condition.then)
|
266
344
|
else_type = call(condition.else)
|
267
345
|
|
@@ -286,7 +364,7 @@ module Cel
|
|
286
364
|
case typ
|
287
365
|
when Symbol
|
288
366
|
TYPES[typ] or
|
289
|
-
raise CheckError, "#{typ} is not
|
367
|
+
raise CheckError, "#{typ} is not a valid type"
|
290
368
|
else
|
291
369
|
typ
|
292
370
|
end
|
@@ -303,11 +381,11 @@ module Cel
|
|
303
381
|
end
|
304
382
|
end
|
305
383
|
|
306
|
-
TYPES[type]
|
384
|
+
type && types.is_a?(Type) ? types : TYPES[type]
|
307
385
|
end
|
308
386
|
|
309
387
|
def check_arity(func, args, arity)
|
310
|
-
return if args.size
|
388
|
+
return if arity === args.size # rubocop:disable Style/CaseEquality
|
311
389
|
|
312
390
|
raise CheckError, "`#{func}` invoked with wrong number of arguments (should be #{arity})"
|
313
391
|
end
|
data/lib/cel/context.rb
CHANGED
@@ -2,13 +2,18 @@
|
|
2
2
|
|
3
3
|
module Cel
|
4
4
|
class Context
|
5
|
-
|
5
|
+
attr_reader :declarations
|
6
|
+
|
7
|
+
def initialize(declarations, bindings)
|
8
|
+
@declarations = declarations
|
6
9
|
@bindings = bindings.dup
|
7
10
|
|
8
11
|
return unless @bindings
|
9
12
|
|
10
13
|
@bindings.each do |k, v|
|
11
|
-
|
14
|
+
val = to_cel_type(v)
|
15
|
+
val = TYPES[@declarations[k]].cast(val) if @declarations && @declarations.key?(k)
|
16
|
+
@bindings[k] = val
|
12
17
|
end
|
13
18
|
end
|
14
19
|
|
@@ -24,7 +29,7 @@ module Cel
|
|
24
29
|
end
|
25
30
|
|
26
31
|
def merge(bindings)
|
27
|
-
Context.new(@bindings ? @bindings.merge(bindings) : bindings)
|
32
|
+
Context.new(@declarations, @bindings ? @bindings.merge(bindings) : bindings)
|
28
33
|
end
|
29
34
|
|
30
35
|
private
|
data/lib/cel/encoder.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cel
|
4
|
+
module Encoder
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def encode(expr)
|
8
|
+
case expr
|
9
|
+
when Group
|
10
|
+
["group", encode(expr.value)]
|
11
|
+
when Invoke
|
12
|
+
enc = [
|
13
|
+
"inv",
|
14
|
+
(encode(expr.var) if expr.var),
|
15
|
+
expr.func.to_s,
|
16
|
+
*(if expr.args
|
17
|
+
expr.func == :[] ? [encode(expr.args)] : expr.args.map(&method(:encode))
|
18
|
+
end),
|
19
|
+
]
|
20
|
+
enc.compact!
|
21
|
+
enc
|
22
|
+
when Operation
|
23
|
+
[
|
24
|
+
"op",
|
25
|
+
expr.op.to_s,
|
26
|
+
*expr.operands.map(&method(:encode)),
|
27
|
+
]
|
28
|
+
when Condition
|
29
|
+
[
|
30
|
+
"cond",
|
31
|
+
encode(expr.if),
|
32
|
+
encode(expr.then),
|
33
|
+
encode(expr.else),
|
34
|
+
]
|
35
|
+
when Identifier
|
36
|
+
[
|
37
|
+
"id",
|
38
|
+
expr.type.to_s,
|
39
|
+
expr.id.to_s,
|
40
|
+
]
|
41
|
+
when List
|
42
|
+
["lit",
|
43
|
+
expr.type.to_s,
|
44
|
+
*expr.value.map(&method(:encode))]
|
45
|
+
when Map
|
46
|
+
["lit",
|
47
|
+
expr.type.to_s,
|
48
|
+
*expr.value.map { |kv| kv.map(&method(:encode)) }]
|
49
|
+
when Number, Bool, String, Bytes
|
50
|
+
["lit", expr.type.to_s, expr.value]
|
51
|
+
when Null
|
52
|
+
%w[lit null]
|
53
|
+
when Type
|
54
|
+
["lit", "type", expr.to_s]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def decode(enc)
|
59
|
+
case enc
|
60
|
+
in ["group", stmt]
|
61
|
+
Group.new(decode(stmt))
|
62
|
+
in ["inv", var, ::String => func, *args]
|
63
|
+
args = if func == "[]" && args.size == 1
|
64
|
+
decode(args.first)
|
65
|
+
elsif args.empty?
|
66
|
+
nil
|
67
|
+
else
|
68
|
+
args.map(&method(:decode))
|
69
|
+
end
|
70
|
+
Invoke.new(func: func, var: decode(var), args: args)
|
71
|
+
in ["inv", ::String => func, *args]
|
72
|
+
args = nil if args.empty?
|
73
|
+
Invoke.new(func: func, args: args.map(&method(:decode)))
|
74
|
+
in ["op", ::String => op, *args]
|
75
|
+
Operation.new(op, args.map(&method(:decode)))
|
76
|
+
in ["cond", f, th, el]
|
77
|
+
Condition.new(decode(f), decode(th), decode(el))
|
78
|
+
in ["id", ::String => type, ::String => val]
|
79
|
+
id = Identifier.new(val)
|
80
|
+
id.type = TYPES[type.to_sym]
|
81
|
+
id
|
82
|
+
in ["lit", "list", *items]
|
83
|
+
list = List.new(items.map(&method(:decode)))
|
84
|
+
list
|
85
|
+
in ["lit", "map", items]
|
86
|
+
Map.new(items.map(&method(:decode)).each_slice(2))
|
87
|
+
in ["lit", /\Aint|uint|double\z/ => type, Integer => val]
|
88
|
+
Number.new(type.to_sym, val)
|
89
|
+
in ["lit", "bool", val]
|
90
|
+
Bool.new(val)
|
91
|
+
in ["lit", "string", val]
|
92
|
+
String.new(val)
|
93
|
+
in ["lit", "bytes", val]
|
94
|
+
Bytes.new(val)
|
95
|
+
in ["lit", "null"]
|
96
|
+
Null.new
|
97
|
+
in ["lit", "type", type]
|
98
|
+
TYPES[type.to_sym]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/lib/cel/environment.rb
CHANGED
@@ -14,19 +14,31 @@ module Cel
|
|
14
14
|
ast
|
15
15
|
end
|
16
16
|
|
17
|
+
def encode(expr)
|
18
|
+
Encoder.encode(compile(expr))
|
19
|
+
end
|
20
|
+
|
21
|
+
def decode(encoded_expr)
|
22
|
+
ast = Encoder.decode(encoded_expr)
|
23
|
+
@checker.check(ast)
|
24
|
+
ast
|
25
|
+
end
|
26
|
+
|
17
27
|
def check(expr)
|
18
28
|
ast = @parser.parse(expr)
|
19
29
|
@checker.check(ast)
|
20
30
|
end
|
21
31
|
|
22
32
|
def program(expr)
|
23
|
-
expr =
|
24
|
-
|
33
|
+
expr = @parser.parse(expr) if expr.is_a?(::String)
|
34
|
+
@checker.check(expr)
|
35
|
+
Runner.new(@declarations, expr)
|
25
36
|
end
|
26
37
|
|
27
38
|
def evaluate(expr, bindings = nil)
|
28
|
-
context = Context.new(bindings)
|
29
|
-
expr =
|
39
|
+
context = Context.new(@declarations, bindings)
|
40
|
+
expr = @parser.parse(expr) if expr.is_a?(::String)
|
41
|
+
@checker.check(expr)
|
30
42
|
Program.new(context).evaluate(expr)
|
31
43
|
end
|
32
44
|
|
@@ -36,12 +48,13 @@ module Cel
|
|
36
48
|
end
|
37
49
|
|
38
50
|
class Runner
|
39
|
-
def initialize(ast)
|
51
|
+
def initialize(declarations, ast)
|
52
|
+
@declarations = declarations
|
40
53
|
@ast = ast
|
41
54
|
end
|
42
55
|
|
43
56
|
def evaluate(bindings = nil)
|
44
|
-
context = Context.new(bindings)
|
57
|
+
context = Context.new(@declarations, bindings)
|
45
58
|
Program.new(context).evaluate(@ast)
|
46
59
|
end
|
47
60
|
end
|
data/lib/cel/parser.rb
CHANGED
@@ -63,9 +63,18 @@ def parse(str)
|
|
63
63
|
tokenize(str)
|
64
64
|
do_parse
|
65
65
|
rescue Racc::ParseError => err
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
raise parse_error(err)
|
67
|
+
end
|
68
|
+
|
69
|
+
def parse_error(error)
|
70
|
+
parse_error = case error.message
|
71
|
+
when /parse error on value "([^"]+)" \(tRESERVED\)/
|
72
|
+
Cel::ParseError.new("invalid usage of the reserved word \"#{$1}\"")
|
73
|
+
else
|
74
|
+
Cel::ParseError.new(error.message)
|
75
|
+
end
|
76
|
+
parse_error.set_backtrace(error.backtrace)
|
77
|
+
parse_error
|
69
78
|
end
|
70
79
|
|
71
80
|
def tokenize(str)
|
@@ -83,10 +92,6 @@ def tokenize(str)
|
|
83
92
|
# skip comment lines
|
84
93
|
when scanner.scan(NUMBER_REGEX)
|
85
94
|
@q << convert_to_number(scanner)
|
86
|
-
when scanner.scan(/true|false/)
|
87
|
-
@q << [:tBOOL, scanner.matched == "true"]
|
88
|
-
when scanner.scan(/null/)
|
89
|
-
@q << [:tNULL, nil]
|
90
95
|
when scanner.scan(/[bB]?[rR]?#{STRING_LIT_REGEX}/) # string
|
91
96
|
# s = scanner.matched.yield_self {|s| s[1, s.length - 2] }
|
92
97
|
# .gsub(DBL_QUOTE_STR_ESCAPE_SEQUENCES_RE) do |match|
|
@@ -115,7 +120,13 @@ def tokenize(str)
|
|
115
120
|
end
|
116
121
|
when scanner.scan(IDENTIFIER_REGEX)
|
117
122
|
word = scanner.matched
|
118
|
-
if
|
123
|
+
if word == "null"
|
124
|
+
@q << [:tNULL, nil]
|
125
|
+
elsif word == "true"
|
126
|
+
@q << [:tBOOL, true]
|
127
|
+
elsif word == "false"
|
128
|
+
@q << [:tBOOL, false]
|
129
|
+
elsif RESERVED.include?(word)
|
119
130
|
@q << [:tRESERVED, scanner.matched]
|
120
131
|
elsif word == "in"
|
121
132
|
@q << [OPERATORS[scanner.matched], scanner.matched]
|
@@ -470,7 +481,7 @@ racc_reduce_table = [
|
|
470
481
|
1, 49, :_reduce_42,
|
471
482
|
0, 45, :_reduce_43,
|
472
483
|
1, 45, :_reduce_none,
|
473
|
-
5, 51, :
|
484
|
+
5, 51, :_reduce_45,
|
474
485
|
3, 51, :_reduce_46,
|
475
486
|
5, 50, :_reduce_47,
|
476
487
|
3, 50, :_reduce_48,
|
@@ -738,7 +749,7 @@ module_eval(<<'.,.,', 'parser.ry', 54)
|
|
738
749
|
|
739
750
|
module_eval(<<'.,.,', 'parser.ry', 55)
|
740
751
|
def _reduce_30(val, _values, result)
|
741
|
-
|
752
|
+
result = Cel::Invoke.new(func: val[0], args: [val[2]].flatten(1))
|
742
753
|
result
|
743
754
|
end
|
744
755
|
.,.,
|
@@ -774,7 +785,7 @@ module_eval(<<'.,.,', 'parser.ry', 58)
|
|
774
785
|
|
775
786
|
module_eval(<<'.,.,', 'parser.ry', 65)
|
776
787
|
def _reduce_38(val, _values, result)
|
777
|
-
result =
|
788
|
+
result = []
|
778
789
|
result
|
779
790
|
end
|
780
791
|
.,.,
|
@@ -811,7 +822,12 @@ module_eval(<<'.,.,', 'parser.ry', 73)
|
|
811
822
|
|
812
823
|
# reduce 44 omitted
|
813
824
|
|
814
|
-
|
825
|
+
module_eval(<<'.,.,', 'parser.ry', 76)
|
826
|
+
def _reduce_45(val, _values, result)
|
827
|
+
result = val[0].merge(Cel::Identifier.new(val[2]) => val[4])
|
828
|
+
result
|
829
|
+
end
|
830
|
+
.,.,
|
815
831
|
|
816
832
|
module_eval(<<'.,.,', 'parser.ry', 77)
|
817
833
|
def _reduce_46(val, _values, result)
|
data/lib/cel/program.rb
CHANGED
@@ -40,7 +40,7 @@ module Cel
|
|
40
40
|
def evaluate_literal(val)
|
41
41
|
case val
|
42
42
|
when List
|
43
|
-
List.new(val.value.map
|
43
|
+
List.new(val.value.map(&method(:call)))
|
44
44
|
else
|
45
45
|
val
|
46
46
|
end
|
@@ -93,7 +93,7 @@ module Cel
|
|
93
93
|
when String
|
94
94
|
raise EvaluateError, "#{invoke} is not supported" unless String.method_defined?(func, false)
|
95
95
|
|
96
|
-
var.public_send(func, *args)
|
96
|
+
var.public_send(func, *args.map(&method(:call)))
|
97
97
|
when Message
|
98
98
|
# If e evaluates to a message and f is not declared in this message, the
|
99
99
|
# runtime error no_such_field is raised.
|
@@ -110,6 +110,10 @@ module Cel
|
|
110
110
|
args ?
|
111
111
|
var.public_send(func, *args) :
|
112
112
|
var.public_send(func)
|
113
|
+
when Timestamp, Duration
|
114
|
+
raise EvaluateError, "#{invoke} is not supported" unless var.class.method_defined?(func, false)
|
115
|
+
|
116
|
+
var.public_send(func, *args)
|
113
117
|
else
|
114
118
|
raise EvaluateError, "#{invoke} is not supported"
|
115
119
|
end
|
@@ -130,18 +134,28 @@ module Cel
|
|
130
134
|
|
131
135
|
val.class
|
132
136
|
# MACROS
|
133
|
-
when :has
|
134
|
-
Macro.__send__(func, *args)
|
137
|
+
when :has
|
138
|
+
Bool.new(Macro.__send__(func, *args))
|
139
|
+
when :size
|
140
|
+
Cel::Number.new(:int, Macro.__send__(func, *args))
|
135
141
|
when :matches
|
136
|
-
Macro.__send__(func, *args.map
|
137
|
-
when :int, :uint, :string, :double, :bytes
|
142
|
+
Bool.new(Macro.__send__(func, *args.map(&method(:call))))
|
143
|
+
when :int, :uint, :string, :double, :bytes, :duration, :timestamp
|
138
144
|
type = TYPES[func]
|
139
145
|
type.cast(call(args.first))
|
140
146
|
when :dyn
|
141
147
|
call(args.first)
|
142
148
|
else
|
149
|
+
return evaluate_custom_func(@context.declarations[func], funcall) if @context.declarations.key?(func)
|
150
|
+
|
143
151
|
raise EvaluateError, "#{funcall} is not supported"
|
144
152
|
end
|
145
153
|
end
|
154
|
+
|
155
|
+
def evaluate_custom_func(func, funcall)
|
156
|
+
args = funcall.args
|
157
|
+
|
158
|
+
func.call(*args.map(&method(:call)).map(&:to_ruby_type))
|
159
|
+
end
|
146
160
|
end
|
147
161
|
end
|