1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
# frozen_string_literal: true
module Dry
module Logic
class Rule
class Interface < ::Module
SPLAT = ["*rest"].freeze
attr_reader :arity
attr_reader :curried
def initialize(arity, curried)
@arity = arity
@curried = curried
if !variable_arity? && curried > arity
raise ArgumentError, "wrong number of arguments (#{curried} for #{arity})"
end
define_constructor if curried?
if constant?
define_constant_application
else
define_application
end
end
def constant?
arity.zero?
end
def variable_arity?
arity.negative?
end
def curried?
!curried.zero?
end
def unapplied
if variable_arity?
unapplied = arity.abs - 1 - curried
if unapplied.negative?
0
else
unapplied
end
else
arity - curried
end
end
def name
if constant?
"Constant"
else
arity_str =
if variable_arity?
"Variable#{arity.abs - 1}Arity"
else
"#{arity}Arity"
end
curried_str =
if curried?
"#{curried}Curried"
else
EMPTY_STRING
end
"#{arity_str}#{curried_str}"
end
end
def define_constructor
assignment =
if curried.equal?(1)
"@arg0 = @args[0]"
else
"#{curried_args.join(", ")} = @args"
end
module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
def initialize(*)
super
#{assignment}
end
RUBY
end
def define_constant_application
module_exec do
def call(*)
if @predicate[]
Result::SUCCESS
else
Result.new(false, id) { ast }
end
end
def [](*)
@predicate[]
end
end
end
def define_application
splat = variable_arity? ? SPLAT : EMPTY_ARRAY
parameters = (unapplied_args + splat).join(", ")
application = "@predicate[#{(curried_args + unapplied_args + splat).join(", ")}]"
module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
def call(#{parameters})
if #{application}
Result::SUCCESS
else
Result.new(false, id) { ast(#{parameters}) }
end
end
def [](#{parameters})
#{application}
end
RUBY
end
def curried_args
@curried_args ||= ::Array.new(curried) { |i| "@arg#{i}" }
end
def unapplied_args
@unapplied_args ||= ::Array.new(unapplied) { |i| "input#{i}" }
end
end
end
end
end
|