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.
Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/.reek.yml +80 -0
  3. data/.vscode/extensions.json +19 -0
  4. data/.vscode/launch.json +35 -0
  5. data/.vscode/settings.json +25 -0
  6. data/.vscode/tasks.json +117 -0
  7. data/.yardopts +12 -0
  8. data/ARCHITECTURE.md +39 -0
  9. data/CHANGELOG.md +25 -0
  10. data/CODE_OF_CONDUCT.md +10 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +183 -0
  13. data/RELEASING.md +37 -0
  14. data/Rakefile +38 -0
  15. data/SECURITY.md +26 -0
  16. data/Steepfile +10 -0
  17. data/TODO.md +35 -0
  18. data/benchmark/builtin_calls.rb +29 -0
  19. data/benchmark/complex_policy.rb +19 -0
  20. data/benchmark/comprehensions.rb +19 -0
  21. data/benchmark/simple_rules.rb +20 -0
  22. data/examples/README.md +27 -0
  23. data/examples/sample_config.yaml +2 -0
  24. data/examples/simple_policy.rego +7 -0
  25. data/examples/validation_policy.rego +11 -0
  26. data/exe/rego-validate +6 -0
  27. data/lib/ruby/rego/ast/base.rb +95 -0
  28. data/lib/ruby/rego/ast/binary_op.rb +64 -0
  29. data/lib/ruby/rego/ast/call.rb +27 -0
  30. data/lib/ruby/rego/ast/composite.rb +48 -0
  31. data/lib/ruby/rego/ast/comprehension.rb +63 -0
  32. data/lib/ruby/rego/ast/every.rb +37 -0
  33. data/lib/ruby/rego/ast/import.rb +32 -0
  34. data/lib/ruby/rego/ast/literal.rb +70 -0
  35. data/lib/ruby/rego/ast/module.rb +32 -0
  36. data/lib/ruby/rego/ast/package.rb +22 -0
  37. data/lib/ruby/rego/ast/query.rb +63 -0
  38. data/lib/ruby/rego/ast/reference.rb +58 -0
  39. data/lib/ruby/rego/ast/rule.rb +114 -0
  40. data/lib/ruby/rego/ast/unary_op.rb +42 -0
  41. data/lib/ruby/rego/ast/variable.rb +22 -0
  42. data/lib/ruby/rego/ast.rb +17 -0
  43. data/lib/ruby/rego/builtins/aggregates.rb +124 -0
  44. data/lib/ruby/rego/builtins/base.rb +95 -0
  45. data/lib/ruby/rego/builtins/collections/array_ops.rb +103 -0
  46. data/lib/ruby/rego/builtins/collections/object_ops.rb +120 -0
  47. data/lib/ruby/rego/builtins/collections/set_ops.rb +51 -0
  48. data/lib/ruby/rego/builtins/collections.rb +137 -0
  49. data/lib/ruby/rego/builtins/comparisons/casts.rb +139 -0
  50. data/lib/ruby/rego/builtins/comparisons.rb +84 -0
  51. data/lib/ruby/rego/builtins/numeric_helpers.rb +56 -0
  52. data/lib/ruby/rego/builtins/registry.rb +199 -0
  53. data/lib/ruby/rego/builtins/registry_helpers.rb +27 -0
  54. data/lib/ruby/rego/builtins/strings/case_ops.rb +22 -0
  55. data/lib/ruby/rego/builtins/strings/concat.rb +19 -0
  56. data/lib/ruby/rego/builtins/strings/formatting.rb +35 -0
  57. data/lib/ruby/rego/builtins/strings/helpers.rb +62 -0
  58. data/lib/ruby/rego/builtins/strings/number_helpers.rb +48 -0
  59. data/lib/ruby/rego/builtins/strings/search.rb +63 -0
  60. data/lib/ruby/rego/builtins/strings/split.rb +19 -0
  61. data/lib/ruby/rego/builtins/strings/substring.rb +22 -0
  62. data/lib/ruby/rego/builtins/strings/trim.rb +42 -0
  63. data/lib/ruby/rego/builtins/strings/trim_helpers.rb +62 -0
  64. data/lib/ruby/rego/builtins/strings.rb +58 -0
  65. data/lib/ruby/rego/builtins/types.rb +89 -0
  66. data/lib/ruby/rego/call_name.rb +55 -0
  67. data/lib/ruby/rego/cli.rb +1122 -0
  68. data/lib/ruby/rego/compiled_module.rb +114 -0
  69. data/lib/ruby/rego/compiler.rb +1097 -0
  70. data/lib/ruby/rego/environment/overrides.rb +33 -0
  71. data/lib/ruby/rego/environment/reference_resolution.rb +86 -0
  72. data/lib/ruby/rego/environment.rb +230 -0
  73. data/lib/ruby/rego/environment_pool.rb +71 -0
  74. data/lib/ruby/rego/error_handling.rb +58 -0
  75. data/lib/ruby/rego/error_payload.rb +34 -0
  76. data/lib/ruby/rego/errors.rb +196 -0
  77. data/lib/ruby/rego/evaluator/assignment_support.rb +126 -0
  78. data/lib/ruby/rego/evaluator/binding_helpers.rb +60 -0
  79. data/lib/ruby/rego/evaluator/comprehension_evaluator.rb +182 -0
  80. data/lib/ruby/rego/evaluator/expression_dispatch.rb +45 -0
  81. data/lib/ruby/rego/evaluator/expression_evaluator.rb +492 -0
  82. data/lib/ruby/rego/evaluator/object_literal_evaluator.rb +52 -0
  83. data/lib/ruby/rego/evaluator/operator_evaluator.rb +163 -0
  84. data/lib/ruby/rego/evaluator/query_node_builder.rb +38 -0
  85. data/lib/ruby/rego/evaluator/reference_key_resolver.rb +50 -0
  86. data/lib/ruby/rego/evaluator/reference_resolver.rb +352 -0
  87. data/lib/ruby/rego/evaluator/rule_evaluator/bindings.rb +70 -0
  88. data/lib/ruby/rego/evaluator/rule_evaluator.rb +550 -0
  89. data/lib/ruby/rego/evaluator/rule_value_provider.rb +56 -0
  90. data/lib/ruby/rego/evaluator/variable_collector.rb +221 -0
  91. data/lib/ruby/rego/evaluator.rb +174 -0
  92. data/lib/ruby/rego/lexer/number_reader.rb +68 -0
  93. data/lib/ruby/rego/lexer/stream.rb +137 -0
  94. data/lib/ruby/rego/lexer/string_reader.rb +90 -0
  95. data/lib/ruby/rego/lexer/template_string_reader.rb +62 -0
  96. data/lib/ruby/rego/lexer.rb +206 -0
  97. data/lib/ruby/rego/location.rb +73 -0
  98. data/lib/ruby/rego/memoization.rb +67 -0
  99. data/lib/ruby/rego/parser/collections.rb +173 -0
  100. data/lib/ruby/rego/parser/expressions.rb +216 -0
  101. data/lib/ruby/rego/parser/precedence.rb +42 -0
  102. data/lib/ruby/rego/parser/query.rb +139 -0
  103. data/lib/ruby/rego/parser/references.rb +115 -0
  104. data/lib/ruby/rego/parser/rules.rb +310 -0
  105. data/lib/ruby/rego/parser.rb +210 -0
  106. data/lib/ruby/rego/policy.rb +50 -0
  107. data/lib/ruby/rego/result.rb +91 -0
  108. data/lib/ruby/rego/token.rb +206 -0
  109. data/lib/ruby/rego/unifier.rb +451 -0
  110. data/lib/ruby/rego/value.rb +379 -0
  111. data/lib/ruby/rego/version.rb +7 -0
  112. data/lib/ruby/rego/with_modifiers/with_modifier.rb +37 -0
  113. data/lib/ruby/rego/with_modifiers/with_modifier_applier.rb +48 -0
  114. data/lib/ruby/rego/with_modifiers/with_modifier_builtin_override.rb +128 -0
  115. data/lib/ruby/rego/with_modifiers/with_modifier_context.rb +120 -0
  116. data/lib/ruby/rego/with_modifiers/with_modifier_path_key_resolver.rb +42 -0
  117. data/lib/ruby/rego/with_modifiers/with_modifier_path_override.rb +99 -0
  118. data/lib/ruby/rego/with_modifiers/with_modifier_root_scope.rb +58 -0
  119. data/lib/ruby/rego.rb +72 -0
  120. data/sig/objspace.rbs +4 -0
  121. data/sig/psych.rbs +7 -0
  122. data/sig/rego_validate.rbs +382 -0
  123. data/sig/ruby/rego.rbs +2150 -0
  124. metadata +172 -0
data/Steepfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ target :lib do
4
+ signature "sig"
5
+ check "lib"
6
+ library "json"
7
+ library "optparse"
8
+ library "psych"
9
+ library "yaml"
10
+ end
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
@@ -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
+ ```
@@ -0,0 +1,2 @@
1
+ enabled: false
2
+ timeout: 10
@@ -0,0 +1,7 @@
1
+ package example
2
+
3
+ default allow = false
4
+
5
+ allow {
6
+ input.user == "admin"
7
+ }
@@ -0,0 +1,11 @@
1
+ package validation
2
+
3
+ deny[msg] {
4
+ input.enabled == false
5
+ msg := "feature must be enabled"
6
+ }
7
+
8
+ deny[msg] {
9
+ input.timeout < 30
10
+ msg := "timeout must be at least 30"
11
+ }
data/exe/rego-validate ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "ruby/rego/cli"
5
+
6
+ exit RegoValidate::CLI.new(ARGV).run if $PROGRAM_NAME == __FILE__
@@ -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