ruby-rego 0.1.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 +7 -0
- data/.reek.yml +80 -0
- data/.vscode/extensions.json +19 -0
- data/.vscode/launch.json +35 -0
- data/.vscode/settings.json +25 -0
- data/.vscode/tasks.json +117 -0
- data/.yardopts +12 -0
- data/ARCHITECTURE.md +39 -0
- data/CHANGELOG.md +25 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +183 -0
- data/RELEASING.md +37 -0
- data/Rakefile +38 -0
- data/SECURITY.md +26 -0
- data/Steepfile +10 -0
- data/TODO.md +35 -0
- data/benchmark/builtin_calls.rb +29 -0
- data/benchmark/complex_policy.rb +19 -0
- data/benchmark/comprehensions.rb +19 -0
- data/benchmark/simple_rules.rb +20 -0
- data/examples/README.md +27 -0
- data/examples/sample_config.yaml +2 -0
- data/examples/simple_policy.rego +7 -0
- data/examples/validation_policy.rego +11 -0
- data/exe/rego-validate +6 -0
- data/lib/ruby/rego/ast/base.rb +95 -0
- data/lib/ruby/rego/ast/binary_op.rb +64 -0
- data/lib/ruby/rego/ast/call.rb +27 -0
- data/lib/ruby/rego/ast/composite.rb +48 -0
- data/lib/ruby/rego/ast/comprehension.rb +63 -0
- data/lib/ruby/rego/ast/every.rb +37 -0
- data/lib/ruby/rego/ast/import.rb +32 -0
- data/lib/ruby/rego/ast/literal.rb +70 -0
- data/lib/ruby/rego/ast/module.rb +32 -0
- data/lib/ruby/rego/ast/package.rb +22 -0
- data/lib/ruby/rego/ast/query.rb +63 -0
- data/lib/ruby/rego/ast/reference.rb +58 -0
- data/lib/ruby/rego/ast/rule.rb +114 -0
- data/lib/ruby/rego/ast/unary_op.rb +42 -0
- data/lib/ruby/rego/ast/variable.rb +22 -0
- data/lib/ruby/rego/ast.rb +17 -0
- data/lib/ruby/rego/builtins/aggregates.rb +124 -0
- data/lib/ruby/rego/builtins/base.rb +95 -0
- data/lib/ruby/rego/builtins/collections/array_ops.rb +103 -0
- data/lib/ruby/rego/builtins/collections/object_ops.rb +120 -0
- data/lib/ruby/rego/builtins/collections/set_ops.rb +51 -0
- data/lib/ruby/rego/builtins/collections.rb +137 -0
- data/lib/ruby/rego/builtins/comparisons/casts.rb +139 -0
- data/lib/ruby/rego/builtins/comparisons.rb +84 -0
- data/lib/ruby/rego/builtins/numeric_helpers.rb +56 -0
- data/lib/ruby/rego/builtins/registry.rb +199 -0
- data/lib/ruby/rego/builtins/registry_helpers.rb +27 -0
- data/lib/ruby/rego/builtins/strings/case_ops.rb +22 -0
- data/lib/ruby/rego/builtins/strings/concat.rb +19 -0
- data/lib/ruby/rego/builtins/strings/formatting.rb +35 -0
- data/lib/ruby/rego/builtins/strings/helpers.rb +62 -0
- data/lib/ruby/rego/builtins/strings/number_helpers.rb +48 -0
- data/lib/ruby/rego/builtins/strings/search.rb +63 -0
- data/lib/ruby/rego/builtins/strings/split.rb +19 -0
- data/lib/ruby/rego/builtins/strings/substring.rb +22 -0
- data/lib/ruby/rego/builtins/strings/trim.rb +42 -0
- data/lib/ruby/rego/builtins/strings/trim_helpers.rb +62 -0
- data/lib/ruby/rego/builtins/strings.rb +58 -0
- data/lib/ruby/rego/builtins/types.rb +89 -0
- data/lib/ruby/rego/call_name.rb +55 -0
- data/lib/ruby/rego/cli.rb +1122 -0
- data/lib/ruby/rego/compiled_module.rb +114 -0
- data/lib/ruby/rego/compiler.rb +1097 -0
- data/lib/ruby/rego/environment/overrides.rb +33 -0
- data/lib/ruby/rego/environment/reference_resolution.rb +86 -0
- data/lib/ruby/rego/environment.rb +230 -0
- data/lib/ruby/rego/environment_pool.rb +71 -0
- data/lib/ruby/rego/error_handling.rb +58 -0
- data/lib/ruby/rego/error_payload.rb +34 -0
- data/lib/ruby/rego/errors.rb +196 -0
- data/lib/ruby/rego/evaluator/assignment_support.rb +126 -0
- data/lib/ruby/rego/evaluator/binding_helpers.rb +60 -0
- data/lib/ruby/rego/evaluator/comprehension_evaluator.rb +182 -0
- data/lib/ruby/rego/evaluator/expression_dispatch.rb +45 -0
- data/lib/ruby/rego/evaluator/expression_evaluator.rb +492 -0
- data/lib/ruby/rego/evaluator/object_literal_evaluator.rb +52 -0
- data/lib/ruby/rego/evaluator/operator_evaluator.rb +163 -0
- data/lib/ruby/rego/evaluator/query_node_builder.rb +38 -0
- data/lib/ruby/rego/evaluator/reference_key_resolver.rb +50 -0
- data/lib/ruby/rego/evaluator/reference_resolver.rb +352 -0
- data/lib/ruby/rego/evaluator/rule_evaluator/bindings.rb +70 -0
- data/lib/ruby/rego/evaluator/rule_evaluator.rb +550 -0
- data/lib/ruby/rego/evaluator/rule_value_provider.rb +56 -0
- data/lib/ruby/rego/evaluator/variable_collector.rb +221 -0
- data/lib/ruby/rego/evaluator.rb +174 -0
- data/lib/ruby/rego/lexer/number_reader.rb +68 -0
- data/lib/ruby/rego/lexer/stream.rb +137 -0
- data/lib/ruby/rego/lexer/string_reader.rb +90 -0
- data/lib/ruby/rego/lexer/template_string_reader.rb +62 -0
- data/lib/ruby/rego/lexer.rb +206 -0
- data/lib/ruby/rego/location.rb +73 -0
- data/lib/ruby/rego/memoization.rb +67 -0
- data/lib/ruby/rego/parser/collections.rb +173 -0
- data/lib/ruby/rego/parser/expressions.rb +216 -0
- data/lib/ruby/rego/parser/precedence.rb +42 -0
- data/lib/ruby/rego/parser/query.rb +139 -0
- data/lib/ruby/rego/parser/references.rb +115 -0
- data/lib/ruby/rego/parser/rules.rb +310 -0
- data/lib/ruby/rego/parser.rb +210 -0
- data/lib/ruby/rego/policy.rb +50 -0
- data/lib/ruby/rego/result.rb +91 -0
- data/lib/ruby/rego/token.rb +206 -0
- data/lib/ruby/rego/unifier.rb +451 -0
- data/lib/ruby/rego/value.rb +379 -0
- data/lib/ruby/rego/version.rb +7 -0
- data/lib/ruby/rego/with_modifiers/with_modifier.rb +37 -0
- data/lib/ruby/rego/with_modifiers/with_modifier_applier.rb +48 -0
- data/lib/ruby/rego/with_modifiers/with_modifier_builtin_override.rb +128 -0
- data/lib/ruby/rego/with_modifiers/with_modifier_context.rb +120 -0
- data/lib/ruby/rego/with_modifiers/with_modifier_path_key_resolver.rb +42 -0
- data/lib/ruby/rego/with_modifiers/with_modifier_path_override.rb +99 -0
- data/lib/ruby/rego/with_modifiers/with_modifier_root_scope.rb +58 -0
- data/lib/ruby/rego.rb +72 -0
- data/sig/objspace.rbs +4 -0
- data/sig/psych.rbs +7 -0
- data/sig/rego_validate.rbs +382 -0
- data/sig/ruby/rego.rbs +2150 -0
- metadata +172 -0
data/Steepfile
ADDED
data/TODO.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# TODO
|
|
2
|
+
|
|
3
|
+
## Phase 2 features
|
|
4
|
+
|
|
5
|
+
- Full `every` keyword semantics and test coverage.
|
|
6
|
+
- Rule heads with references (indexing and evaluation).
|
|
7
|
+
- Advanced pattern matching and destructuring in rule bodies.
|
|
8
|
+
- Expanded built-in function set (strings, objects, arrays, conversions).
|
|
9
|
+
- Broader `with` keyword support across evaluator paths.
|
|
10
|
+
|
|
11
|
+
## Phase 3 features
|
|
12
|
+
|
|
13
|
+
- Complete OPA built-in function coverage.
|
|
14
|
+
- Full compliance with OPA test suites and edge cases.
|
|
15
|
+
- Partial evaluation and optimization passes.
|
|
16
|
+
- JSON Schema integration and annotations.
|
|
17
|
+
- Policy compiler optimizations for large rule sets.
|
|
18
|
+
|
|
19
|
+
## Known limitations
|
|
20
|
+
|
|
21
|
+
- `with` modifiers are limited and may reset memoization caches.
|
|
22
|
+
- Performance is slower than OPA for heavy comprehensions.
|
|
23
|
+
- Not all OPA built-ins and keywords are implemented yet.
|
|
24
|
+
|
|
25
|
+
## Community requests
|
|
26
|
+
|
|
27
|
+
- Richer CLI output formats and policy explanations.
|
|
28
|
+
- Deterministic pretty-printer for AST and policies.
|
|
29
|
+
- Better compatibility tooling for OPA policy validation.
|
|
30
|
+
|
|
31
|
+
## Performance improvements
|
|
32
|
+
|
|
33
|
+
- Memoization improvements for nested rule dependencies.
|
|
34
|
+
- Reduce object allocations in evaluator hot paths.
|
|
35
|
+
- Add benchmarks for real-world policy suites.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "benchmark/ips"
|
|
4
|
+
require "ruby/rego"
|
|
5
|
+
|
|
6
|
+
policy = <<~REGO
|
|
7
|
+
package bench
|
|
8
|
+
result {
|
|
9
|
+
count(input.items) == 100
|
|
10
|
+
sum(input.numbers) > 2000
|
|
11
|
+
max(input.numbers) == 200
|
|
12
|
+
startswith(input.name, "user")
|
|
13
|
+
lower(input.name) == "user-1"
|
|
14
|
+
}
|
|
15
|
+
REGO
|
|
16
|
+
|
|
17
|
+
compiled = Ruby::Rego.compile(policy)
|
|
18
|
+
input = {
|
|
19
|
+
"items" => Array.new(100, "item"),
|
|
20
|
+
"numbers" => (1..200).to_a,
|
|
21
|
+
"name" => "User-1"
|
|
22
|
+
}
|
|
23
|
+
query = "data.bench.result"
|
|
24
|
+
evaluator = Ruby::Rego::Evaluator.new(compiled, input: input)
|
|
25
|
+
|
|
26
|
+
Benchmark.ips do |x|
|
|
27
|
+
x.report("builtin calls") { evaluator.evaluate(query) }
|
|
28
|
+
x.compare!
|
|
29
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "benchmark/ips"
|
|
4
|
+
require "yaml"
|
|
5
|
+
require "ruby/rego"
|
|
6
|
+
|
|
7
|
+
policy_path = File.join(__dir__, "..", "examples", "validation_policy.rego")
|
|
8
|
+
config_path = File.join(__dir__, "..", "examples", "sample_config.yaml")
|
|
9
|
+
|
|
10
|
+
policy = File.read(policy_path)
|
|
11
|
+
input = YAML.safe_load_file(config_path)
|
|
12
|
+
compiled = Ruby::Rego.compile(policy)
|
|
13
|
+
query = "data.validation.deny"
|
|
14
|
+
evaluator = Ruby::Rego::Evaluator.new(compiled, input: input)
|
|
15
|
+
|
|
16
|
+
Benchmark.ips do |x|
|
|
17
|
+
x.report("complex policy") { evaluator.evaluate(query) }
|
|
18
|
+
x.compare!
|
|
19
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "benchmark/ips"
|
|
4
|
+
require "ruby/rego"
|
|
5
|
+
|
|
6
|
+
policy = <<~REGO
|
|
7
|
+
package bench
|
|
8
|
+
evens := [n | some n in input.numbers; n % 2 == 0]
|
|
9
|
+
REGO
|
|
10
|
+
|
|
11
|
+
compiled = Ruby::Rego.compile(policy)
|
|
12
|
+
input = { "numbers" => (1..200).to_a }
|
|
13
|
+
query = "data.bench.evens"
|
|
14
|
+
evaluator = Ruby::Rego::Evaluator.new(compiled, input: input)
|
|
15
|
+
|
|
16
|
+
Benchmark.ips do |x|
|
|
17
|
+
x.report("comprehension") { evaluator.evaluate(query) }
|
|
18
|
+
x.compare!
|
|
19
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "benchmark/ips"
|
|
4
|
+
require "ruby/rego"
|
|
5
|
+
|
|
6
|
+
policy = <<~REGO
|
|
7
|
+
package bench
|
|
8
|
+
default allow = false
|
|
9
|
+
allow { input.user == "admin" }
|
|
10
|
+
REGO
|
|
11
|
+
|
|
12
|
+
compiled = Ruby::Rego.compile(policy)
|
|
13
|
+
input = { "user" => "admin" }
|
|
14
|
+
query = "data.bench.allow"
|
|
15
|
+
evaluator = Ruby::Rego::Evaluator.new(compiled, input: input)
|
|
16
|
+
|
|
17
|
+
Benchmark.ips do |x|
|
|
18
|
+
x.report("simple rule") { evaluator.evaluate(query) }
|
|
19
|
+
x.compare!
|
|
20
|
+
end
|
data/examples/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
## CLI validation example
|
|
4
|
+
|
|
5
|
+
From the repository root:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bundle exec exe/rego-validate --policy examples/validation_policy.rego --config examples/sample_config.yaml
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Override the default query:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bundle exec exe/rego-validate --policy examples/validation_policy.rego --config examples/sample_config.yaml --query data.validation.deny
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Ruby API example
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
require "ruby/rego"
|
|
21
|
+
|
|
22
|
+
policy = File.read("examples/simple_policy.rego")
|
|
23
|
+
input = {"user" => "admin"}
|
|
24
|
+
|
|
25
|
+
result = Ruby::Rego.evaluate(policy, input: input, query: "data.example.allow")
|
|
26
|
+
puts result.value.to_ruby
|
|
27
|
+
```
|
data/exe/rego-validate
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ruby
|
|
4
|
+
module Rego
|
|
5
|
+
module AST
|
|
6
|
+
# Base class for all AST nodes.
|
|
7
|
+
#
|
|
8
|
+
# Provides location tracking, a visitor entry point, and common debugging
|
|
9
|
+
# helpers.
|
|
10
|
+
class Base
|
|
11
|
+
# @param location [Location, nil]
|
|
12
|
+
def initialize(location: nil)
|
|
13
|
+
@location = location
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @return [Location, nil]
|
|
17
|
+
attr_reader :location
|
|
18
|
+
|
|
19
|
+
# @param visitor [Object]
|
|
20
|
+
# @return [Object]
|
|
21
|
+
def accept(visitor)
|
|
22
|
+
visitor.visit(self)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @param keys [Array<Symbol>, nil]
|
|
26
|
+
# @return [Hash<Symbol, Object>]
|
|
27
|
+
def deconstruct_keys(keys)
|
|
28
|
+
attributes = deconstruct_attributes
|
|
29
|
+
allowed = deconstructable_keys
|
|
30
|
+
filtered = attributes.slice(*allowed)
|
|
31
|
+
keys ? filtered.slice(*keys) : filtered
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def deconstruct_attributes
|
|
35
|
+
attributes = {} # @type var attributes: Hash[Symbol, Object]
|
|
36
|
+
instance_variables.each_with_object(attributes) do |variable, result|
|
|
37
|
+
key = variable.to_s.delete_prefix("@").to_sym
|
|
38
|
+
result[key] = instance_variable_get(variable)
|
|
39
|
+
end
|
|
40
|
+
attributes
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def deconstructable_keys
|
|
44
|
+
instance_variables.map { |variable| variable.to_s.delete_prefix("@").to_sym }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private :deconstruct_attributes, :deconstructable_keys
|
|
48
|
+
|
|
49
|
+
# @return [String]
|
|
50
|
+
def to_s
|
|
51
|
+
klass = self.class
|
|
52
|
+
attributes = instance_variables.sort.map do |variable|
|
|
53
|
+
value = instance_variable_get(variable)
|
|
54
|
+
"#{variable.to_s.delete_prefix("@")}=#{klass.format_value(value)}"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
"#{klass.name}(#{attributes.join(", ")})"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @param other [Object]
|
|
61
|
+
# @return [Boolean]
|
|
62
|
+
def ==(other)
|
|
63
|
+
return false unless other.instance_of?(self.class)
|
|
64
|
+
|
|
65
|
+
instance_variables.sort.all? do |variable|
|
|
66
|
+
instance_variable_get(variable) == other.instance_variable_get(variable)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @param other [Object]
|
|
71
|
+
# @return [Boolean]
|
|
72
|
+
def eql?(other)
|
|
73
|
+
self == other
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @return [Integer]
|
|
77
|
+
def hash
|
|
78
|
+
values = instance_variables.sort.map { |variable| instance_variable_get(variable) }
|
|
79
|
+
[self.class, values].hash
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# @param value [Object]
|
|
83
|
+
# @return [String]
|
|
84
|
+
def self.format_value(value)
|
|
85
|
+
case value
|
|
86
|
+
when String, Symbol, Numeric, Array, Hash, TrueClass, FalseClass, NilClass
|
|
87
|
+
value.inspect
|
|
88
|
+
else
|
|
89
|
+
value.to_s
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Ruby
|
|
6
|
+
module Rego
|
|
7
|
+
module AST
|
|
8
|
+
# Represents a binary operation.
|
|
9
|
+
class BinaryOp < Base
|
|
10
|
+
OPERATORS = %i[
|
|
11
|
+
eq
|
|
12
|
+
neq
|
|
13
|
+
and
|
|
14
|
+
or
|
|
15
|
+
lt
|
|
16
|
+
lte
|
|
17
|
+
gt
|
|
18
|
+
gte
|
|
19
|
+
in
|
|
20
|
+
plus
|
|
21
|
+
minus
|
|
22
|
+
mult
|
|
23
|
+
div
|
|
24
|
+
mod
|
|
25
|
+
assign
|
|
26
|
+
unify
|
|
27
|
+
].freeze
|
|
28
|
+
|
|
29
|
+
# @param operator [Symbol]
|
|
30
|
+
# @param left [Object]
|
|
31
|
+
# @param right [Object]
|
|
32
|
+
# @param location [Location, nil]
|
|
33
|
+
def initialize(operator:, left:, right:, location: nil)
|
|
34
|
+
@operator = operator
|
|
35
|
+
validate_operator!
|
|
36
|
+
super(location: location)
|
|
37
|
+
@left = left
|
|
38
|
+
@right = right
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @return [Symbol]
|
|
42
|
+
attr_reader :operator
|
|
43
|
+
|
|
44
|
+
# @return [Object]
|
|
45
|
+
attr_reader :left
|
|
46
|
+
|
|
47
|
+
# @return [Object]
|
|
48
|
+
attr_reader :right
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def validate_operator # rubocop:disable Naming/PredicateMethod
|
|
53
|
+
OPERATORS.include?(@operator)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def validate_operator!
|
|
57
|
+
return if validate_operator
|
|
58
|
+
|
|
59
|
+
raise ArgumentError, "Unknown binary operator: #{@operator.inspect}"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Ruby
|
|
6
|
+
module Rego
|
|
7
|
+
module AST
|
|
8
|
+
# Represents a function or built-in call.
|
|
9
|
+
class Call < Base
|
|
10
|
+
# @param name [Object]
|
|
11
|
+
# @param args [Array<Object>]
|
|
12
|
+
# @param location [Location, nil]
|
|
13
|
+
def initialize(name:, args:, location: nil)
|
|
14
|
+
super(location: location)
|
|
15
|
+
@name = name
|
|
16
|
+
@args = args.dup.freeze
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @return [Object]
|
|
20
|
+
attr_reader :name
|
|
21
|
+
|
|
22
|
+
# @return [Array<Object>]
|
|
23
|
+
attr_reader :args
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Ruby
|
|
6
|
+
module Rego
|
|
7
|
+
module AST
|
|
8
|
+
# Represents an array literal.
|
|
9
|
+
class ArrayLiteral < Base
|
|
10
|
+
# @param elements [Array<Object>]
|
|
11
|
+
# @param location [Location, nil]
|
|
12
|
+
def initialize(elements:, location: nil)
|
|
13
|
+
super(location: location)
|
|
14
|
+
@elements = elements.dup.freeze
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @return [Array<Object>]
|
|
18
|
+
attr_reader :elements
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Represents an object literal.
|
|
22
|
+
class ObjectLiteral < Base
|
|
23
|
+
# @param pairs [Array<Array(Object, Object)>]
|
|
24
|
+
# @param location [Location, nil]
|
|
25
|
+
def initialize(pairs:, location: nil)
|
|
26
|
+
super(location: location)
|
|
27
|
+
@pairs = pairs.map { |pair| pair.dup.freeze }.freeze
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [Array<Array(Object, Object)>]
|
|
31
|
+
attr_reader :pairs
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Represents a set literal.
|
|
35
|
+
class SetLiteral < Base
|
|
36
|
+
# @param elements [Array<Object>]
|
|
37
|
+
# @param location [Location, nil]
|
|
38
|
+
def initialize(elements:, location: nil)
|
|
39
|
+
super(location: location)
|
|
40
|
+
@elements = elements.dup.freeze
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @return [Array<Object>]
|
|
44
|
+
attr_reader :elements
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Ruby
|
|
6
|
+
module Rego
|
|
7
|
+
module AST
|
|
8
|
+
# Represents an array comprehension.
|
|
9
|
+
class ArrayComprehension < Base
|
|
10
|
+
# @param term [Object]
|
|
11
|
+
# @param body [Array<Object>]
|
|
12
|
+
# @param location [Location, nil]
|
|
13
|
+
def initialize(term:, body:, location: nil)
|
|
14
|
+
super(location: location)
|
|
15
|
+
@term = term
|
|
16
|
+
@body = body.dup.freeze
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @return [Object]
|
|
20
|
+
attr_reader :term
|
|
21
|
+
|
|
22
|
+
# @return [Object]
|
|
23
|
+
attr_reader :body
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Represents an object comprehension.
|
|
27
|
+
class ObjectComprehension < Base
|
|
28
|
+
# @param term [Object]
|
|
29
|
+
# @param body [Array<Object>]
|
|
30
|
+
# @param location [Location, nil]
|
|
31
|
+
def initialize(term:, body:, location: nil)
|
|
32
|
+
super(location: location)
|
|
33
|
+
@term = term
|
|
34
|
+
@body = body.dup.freeze
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @return [Object]
|
|
38
|
+
attr_reader :term
|
|
39
|
+
|
|
40
|
+
# @return [Object]
|
|
41
|
+
attr_reader :body
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Represents a set comprehension.
|
|
45
|
+
class SetComprehension < Base
|
|
46
|
+
# @param term [Object]
|
|
47
|
+
# @param body [Array<Object>]
|
|
48
|
+
# @param location [Location, nil]
|
|
49
|
+
def initialize(term:, body:, location: nil)
|
|
50
|
+
super(location: location)
|
|
51
|
+
@term = term
|
|
52
|
+
@body = body.dup.freeze
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @return [Object]
|
|
56
|
+
attr_reader :term
|
|
57
|
+
|
|
58
|
+
# @return [Object]
|
|
59
|
+
attr_reader :body
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Ruby
|
|
6
|
+
module Rego
|
|
7
|
+
module AST
|
|
8
|
+
# Represents an `every` expression.
|
|
9
|
+
class Every < Base
|
|
10
|
+
# @param value_var [Variable]
|
|
11
|
+
# @param domain [Object]
|
|
12
|
+
# @param body [Array<Object>]
|
|
13
|
+
# @param key_var [Variable, nil]
|
|
14
|
+
# @param location [Location, nil]
|
|
15
|
+
def initialize(value_var:, domain:, body:, key_var: nil, location: nil)
|
|
16
|
+
super(location: location)
|
|
17
|
+
@key_var = key_var
|
|
18
|
+
@value_var = value_var
|
|
19
|
+
@domain = domain
|
|
20
|
+
@body = body.dup.freeze
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @return [Variable, nil]
|
|
24
|
+
attr_reader :key_var
|
|
25
|
+
|
|
26
|
+
# @return [Variable]
|
|
27
|
+
attr_reader :value_var
|
|
28
|
+
|
|
29
|
+
# @return [Object]
|
|
30
|
+
attr_reader :domain
|
|
31
|
+
|
|
32
|
+
# @return [Array<Object>]
|
|
33
|
+
attr_reader :body
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Ruby
|
|
6
|
+
module Rego
|
|
7
|
+
module AST
|
|
8
|
+
# Represents an import declaration.
|
|
9
|
+
class Import < Base
|
|
10
|
+
# @param path [Array<String> | String]
|
|
11
|
+
# @param alias_name [String, nil]
|
|
12
|
+
# @param location [Location, nil]
|
|
13
|
+
def initialize(path:, alias_name: nil, location: nil)
|
|
14
|
+
super(location: location)
|
|
15
|
+
@path = path
|
|
16
|
+
@alias = alias_name
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @return [Array<String> | String]
|
|
20
|
+
attr_reader :path
|
|
21
|
+
|
|
22
|
+
# @return [String, nil]
|
|
23
|
+
attr_reader :alias
|
|
24
|
+
|
|
25
|
+
# @return [String, nil]
|
|
26
|
+
def alias_name
|
|
27
|
+
self.alias
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Ruby
|
|
6
|
+
module Rego
|
|
7
|
+
module AST
|
|
8
|
+
# Base class for literal values.
|
|
9
|
+
class Literal < Base
|
|
10
|
+
# @param value [Object]
|
|
11
|
+
# @param location [Location, nil]
|
|
12
|
+
def initialize(value:, location: nil)
|
|
13
|
+
super(location: location)
|
|
14
|
+
@value = value
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @return [Object]
|
|
18
|
+
attr_reader :value
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Represents a string literal.
|
|
22
|
+
class StringLiteral < Literal
|
|
23
|
+
# @param value [String]
|
|
24
|
+
# @param location [Location, nil]
|
|
25
|
+
def initialize(value:, location: nil)
|
|
26
|
+
super
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Represents a template string with interpolations.
|
|
31
|
+
class TemplateString < Base
|
|
32
|
+
# @param parts [Array<Object>]
|
|
33
|
+
# @param location [Location, nil]
|
|
34
|
+
def initialize(parts:, location: nil)
|
|
35
|
+
super(location: location)
|
|
36
|
+
@parts = parts.dup.freeze
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @return [Array<Object>]
|
|
40
|
+
attr_reader :parts
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Represents a numeric literal.
|
|
44
|
+
class NumberLiteral < Literal
|
|
45
|
+
# @param value [Numeric]
|
|
46
|
+
# @param location [Location, nil]
|
|
47
|
+
def initialize(value:, location: nil)
|
|
48
|
+
super
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Represents a boolean literal.
|
|
53
|
+
class BooleanLiteral < Literal
|
|
54
|
+
# @param value [Boolean]
|
|
55
|
+
# @param location [Location, nil]
|
|
56
|
+
def initialize(value:, location: nil)
|
|
57
|
+
super
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Represents a null literal.
|
|
62
|
+
class NullLiteral < Literal
|
|
63
|
+
# @param location [Location, nil]
|
|
64
|
+
def initialize(location: nil)
|
|
65
|
+
super(value: nil, location: location)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Ruby
|
|
6
|
+
module Rego
|
|
7
|
+
module AST
|
|
8
|
+
# Represents a complete Rego module.
|
|
9
|
+
class Module < Base
|
|
10
|
+
# @param package [Package]
|
|
11
|
+
# @param imports [Array<Import>]
|
|
12
|
+
# @param rules [Array<Rule>]
|
|
13
|
+
# @param location [Location, nil]
|
|
14
|
+
def initialize(package:, imports:, rules:, location: nil)
|
|
15
|
+
super(location: location)
|
|
16
|
+
@package = package
|
|
17
|
+
@imports = imports
|
|
18
|
+
@rules = rules
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [Package]
|
|
22
|
+
attr_reader :package
|
|
23
|
+
|
|
24
|
+
# @return [Array<Import>]
|
|
25
|
+
attr_reader :imports
|
|
26
|
+
|
|
27
|
+
# @return [Array<Rule>]
|
|
28
|
+
attr_reader :rules
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Ruby
|
|
6
|
+
module Rego
|
|
7
|
+
module AST
|
|
8
|
+
# Represents a package declaration.
|
|
9
|
+
class Package < Base
|
|
10
|
+
# @param path [Array<String>]
|
|
11
|
+
# @param location [Location, nil]
|
|
12
|
+
def initialize(path:, location: nil)
|
|
13
|
+
super(location: location)
|
|
14
|
+
@path = path
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @return [Array<String>]
|
|
18
|
+
attr_reader :path
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|