predicate 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +2 -0
- data/LICENSE.md +22 -0
- data/Rakefile +11 -0
- data/lib/predicate/factory.rb +107 -0
- data/lib/predicate/grammar.rb +33 -0
- data/lib/predicate/grammar.sexp.yml +58 -0
- data/lib/predicate/nodes/and.rb +23 -0
- data/lib/predicate/nodes/contradiction.rb +34 -0
- data/lib/predicate/nodes/dyadic_comp.rb +26 -0
- data/lib/predicate/nodes/eq.rb +15 -0
- data/lib/predicate/nodes/expr.rb +68 -0
- data/lib/predicate/nodes/gt.rb +10 -0
- data/lib/predicate/nodes/gte.rb +10 -0
- data/lib/predicate/nodes/identifier.rb +18 -0
- data/lib/predicate/nodes/in.rb +26 -0
- data/lib/predicate/nodes/literal.rb +18 -0
- data/lib/predicate/nodes/lt.rb +10 -0
- data/lib/predicate/nodes/lte.rb +10 -0
- data/lib/predicate/nodes/nadic_bool.rb +16 -0
- data/lib/predicate/nodes/native.rb +30 -0
- data/lib/predicate/nodes/neq.rb +10 -0
- data/lib/predicate/nodes/not.rb +22 -0
- data/lib/predicate/nodes/or.rb +10 -0
- data/lib/predicate/nodes/qualified_identifier.rb +22 -0
- data/lib/predicate/nodes/tautology.rb +30 -0
- data/lib/predicate/processors/qualifier.rb +23 -0
- data/lib/predicate/processors/renamer.rb +25 -0
- data/lib/predicate/processors/to_ruby_code.rb +71 -0
- data/lib/predicate/processors.rb +3 -0
- data/lib/predicate/version.rb +8 -0
- data/lib/predicate.rb +113 -0
- data/spec/expr/test_to_proc.rb +16 -0
- data/spec/expr/test_to_ruby_code.rb +152 -0
- data/spec/factory/shared/a_comparison_factory_method.rb +35 -0
- data/spec/factory/shared/a_predicate_ast_node.rb +20 -0
- data/spec/factory/test_and.rb +13 -0
- data/spec/factory/test_between.rb +12 -0
- data/spec/factory/test_comp.rb +35 -0
- data/spec/factory/test_contradiction.rb +11 -0
- data/spec/factory/test_eq.rb +9 -0
- data/spec/factory/test_factor_predicate.rb +50 -0
- data/spec/factory/test_gt.rb +9 -0
- data/spec/factory/test_gte.rb +9 -0
- data/spec/factory/test_identifier.rb +13 -0
- data/spec/factory/test_in.rb +12 -0
- data/spec/factory/test_literal.rb +13 -0
- data/spec/factory/test_lt.rb +9 -0
- data/spec/factory/test_lte.rb +9 -0
- data/spec/factory/test_native.rb +19 -0
- data/spec/factory/test_neq.rb +9 -0
- data/spec/factory/test_not.rb +13 -0
- data/spec/factory/test_or.rb +13 -0
- data/spec/factory/test_qualified_identifier.rb +15 -0
- data/spec/factory/test_tautology.rb +12 -0
- data/spec/grammar/test_match.rb +93 -0
- data/spec/grammar/test_sexpr.rb +103 -0
- data/spec/nodes/and/test_and_split.rb +66 -0
- data/spec/nodes/dyadic_comp/test_and_split.rb +45 -0
- data/spec/nodes/identifier/test_and_split.rb +23 -0
- data/spec/nodes/identifier/test_free_variables.rb +12 -0
- data/spec/nodes/identifier/test_name.rb +12 -0
- data/spec/nodes/nadic_bool/test_free_variables.rb +14 -0
- data/spec/nodes/qualified_identifier/test_and_split.rb +23 -0
- data/spec/nodes/qualified_identifier/test_free_variables.rb +12 -0
- data/spec/nodes/qualified_identifier/test_name.rb +12 -0
- data/spec/nodes/qualified_identifier/test_qualifier.rb +12 -0
- data/spec/predicate/test_and_split.rb +57 -0
- data/spec/predicate/test_bool_and.rb +34 -0
- data/spec/predicate/test_bool_not.rb +68 -0
- data/spec/predicate/test_bool_or.rb +34 -0
- data/spec/predicate/test_coerce.rb +75 -0
- data/spec/predicate/test_constant_variables.rb +52 -0
- data/spec/predicate/test_contradiction.rb +24 -0
- data/spec/predicate/test_evaluate.rb +66 -0
- data/spec/predicate/test_factory_methods.rb +77 -0
- data/spec/predicate/test_free_variables.rb +14 -0
- data/spec/predicate/test_hash_and_equal.rb +26 -0
- data/spec/predicate/test_qualify.rb +34 -0
- data/spec/predicate/test_rename.rb +76 -0
- data/spec/predicate/test_tautology.rb +24 -0
- data/spec/predicate/test_to_proc.rb +14 -0
- data/spec/predicate/test_to_ruby_code.rb +20 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/test_predicate.rb +127 -0
- data/tasks/test.rake +11 -0
- metadata +186 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: '07778e150b98d73bf35ce337d9874395f1f58e1c'
|
4
|
+
data.tar.gz: 9d0e523c2f41b8b5c530e67a14a69f3dbdf31914
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 84111b7fe5dc17da15f9cb3afb1cee966cedb9a29ed2e420348071c348d6f7c0cd94265c116afc7cae987ca7a96f6f29e52035c9540db85b817ee219da958c59
|
7
|
+
data.tar.gz: cb5d7863db1db730e22b7fd6fe1b7023b89a8a2ef442333d8762ff1fe0b585805d10a2dd832ab07fc98453d7186daeac793c8963e4e38da2ea94fdb94c73db3a
|
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# The MIT Licence
|
2
|
+
|
3
|
+
Copyright (c) 2017 - Enspirit SPRL (Bernard Lambeau)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
class Predicate
|
2
|
+
module Factory
|
3
|
+
|
4
|
+
def tautology
|
5
|
+
_factor_predicate([:tautology, true])
|
6
|
+
end
|
7
|
+
|
8
|
+
def contradiction
|
9
|
+
_factor_predicate([:contradiction, false])
|
10
|
+
end
|
11
|
+
|
12
|
+
def identifier(name)
|
13
|
+
_factor_predicate([:identifier, name])
|
14
|
+
end
|
15
|
+
|
16
|
+
def qualified_identifier(qualifier, name)
|
17
|
+
_factor_predicate([:qualified_identifier, qualifier, name])
|
18
|
+
end
|
19
|
+
|
20
|
+
def and(left, right = nil)
|
21
|
+
_factor_predicate([:and, sexpr(left), sexpr(right)])
|
22
|
+
end
|
23
|
+
|
24
|
+
def or(left, right = nil)
|
25
|
+
_factor_predicate([:or, sexpr(left), sexpr(right)])
|
26
|
+
end
|
27
|
+
|
28
|
+
def not(operand)
|
29
|
+
_factor_predicate([:not, sexpr(operand)])
|
30
|
+
end
|
31
|
+
|
32
|
+
def relation(r)
|
33
|
+
tuples = r.to_a
|
34
|
+
case tuples.size
|
35
|
+
when 0 then contradiction
|
36
|
+
when 1 then eq(tuples.first)
|
37
|
+
else
|
38
|
+
if tuples.first.size==1
|
39
|
+
k = tuples.first.keys.first
|
40
|
+
self.in(k, tuples.map{|t| t[k]})
|
41
|
+
else
|
42
|
+
tuples.inject(contradiction){|p,t| p | eq(t) }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def in(identifier, values)
|
48
|
+
identifier = sexpr(identifier) if identifier.is_a?(Symbol)
|
49
|
+
_factor_predicate([:in, identifier, values])
|
50
|
+
end
|
51
|
+
alias :among :in
|
52
|
+
|
53
|
+
def comp(op, h)
|
54
|
+
h = h.to_hash
|
55
|
+
if h.empty?
|
56
|
+
return tautology
|
57
|
+
elsif h.size==1
|
58
|
+
_factor_predicate [op, sexpr(h.keys.first), sexpr(h.values.last)]
|
59
|
+
else
|
60
|
+
terms = h.to_a.inject([:and]) do |anded,pair|
|
61
|
+
anded << ([op] << sexpr(pair.first) << sexpr(pair.last))
|
62
|
+
end
|
63
|
+
_factor_predicate terms
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
[ :eq, :neq, :lt, :lte, :gt, :gte ].each do |m|
|
68
|
+
define_method(m) do |left, right=nil|
|
69
|
+
return comp(m, left) if TupleLike===left && right.nil?
|
70
|
+
_factor_predicate([m, sexpr(left), sexpr(right)])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def between(middle, lower_bound, upper_bound)
|
75
|
+
_factor_predicate [:and, [:gte, sexpr(middle), sexpr(lower_bound)],
|
76
|
+
[:lte, sexpr(middle), sexpr(upper_bound)]]
|
77
|
+
end
|
78
|
+
|
79
|
+
def literal(literal)
|
80
|
+
_factor_predicate([:literal, literal])
|
81
|
+
end
|
82
|
+
|
83
|
+
def native(arg)
|
84
|
+
_factor_predicate([:native, arg])
|
85
|
+
end
|
86
|
+
|
87
|
+
def sexpr(expr)
|
88
|
+
case expr
|
89
|
+
when Expr then expr
|
90
|
+
when Predicate then expr.expr
|
91
|
+
when TrueClass then Grammar.sexpr([:tautology, true])
|
92
|
+
when FalseClass then Grammar.sexpr([:contradiction, false])
|
93
|
+
when Symbol then Grammar.sexpr([:identifier, expr])
|
94
|
+
when Proc then Grammar.sexpr([:native, expr])
|
95
|
+
when Array then Grammar.sexpr(expr)
|
96
|
+
else
|
97
|
+
Grammar.sexpr([:literal, expr])
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def _factor_predicate(arg)
|
102
|
+
sexpr(arg)
|
103
|
+
end
|
104
|
+
|
105
|
+
extend(self)
|
106
|
+
end # module Factory
|
107
|
+
end # class Predicate
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Predicate
|
2
|
+
Grammar = Sexpr.load File.expand_path('../grammar.sexp.yml', __FILE__)
|
3
|
+
module Grammar
|
4
|
+
|
5
|
+
def tagging_reference
|
6
|
+
Predicate
|
7
|
+
end
|
8
|
+
|
9
|
+
def default_tagging_module
|
10
|
+
Expr
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end # class Predicate
|
15
|
+
require_relative 'nodes/expr'
|
16
|
+
require_relative 'nodes/dyadic_comp'
|
17
|
+
require_relative 'nodes/nadic_bool'
|
18
|
+
require_relative 'nodes/tautology'
|
19
|
+
require_relative 'nodes/contradiction'
|
20
|
+
require_relative 'nodes/identifier'
|
21
|
+
require_relative 'nodes/qualified_identifier'
|
22
|
+
require_relative 'nodes/and'
|
23
|
+
require_relative 'nodes/or'
|
24
|
+
require_relative 'nodes/not'
|
25
|
+
require_relative 'nodes/eq'
|
26
|
+
require_relative 'nodes/neq'
|
27
|
+
require_relative 'nodes/gt'
|
28
|
+
require_relative 'nodes/gte'
|
29
|
+
require_relative 'nodes/lt'
|
30
|
+
require_relative 'nodes/lte'
|
31
|
+
require_relative 'nodes/in'
|
32
|
+
require_relative 'nodes/literal'
|
33
|
+
require_relative 'nodes/native'
|
@@ -0,0 +1,58 @@
|
|
1
|
+
rules:
|
2
|
+
predicate:
|
3
|
+
- tautology
|
4
|
+
- contradiction
|
5
|
+
- identifier
|
6
|
+
- not
|
7
|
+
- and
|
8
|
+
- or
|
9
|
+
- eq
|
10
|
+
- neq
|
11
|
+
- lt
|
12
|
+
- lte
|
13
|
+
- gt
|
14
|
+
- gte
|
15
|
+
- in
|
16
|
+
- native
|
17
|
+
tautology:
|
18
|
+
- [ true ]
|
19
|
+
contradiction:
|
20
|
+
- [ false ]
|
21
|
+
identifier:
|
22
|
+
- [ name ]
|
23
|
+
qualified_identifier:
|
24
|
+
- [ name, name ]
|
25
|
+
not:
|
26
|
+
- [ predicate ]
|
27
|
+
and:
|
28
|
+
- [ predicate+ ]
|
29
|
+
or:
|
30
|
+
- [ predicate+ ]
|
31
|
+
eq:
|
32
|
+
- [ term, term ]
|
33
|
+
neq:
|
34
|
+
- [ term, term ]
|
35
|
+
lt:
|
36
|
+
- [ term, term ]
|
37
|
+
lte:
|
38
|
+
- [ term, term ]
|
39
|
+
gt:
|
40
|
+
- [ term, term ]
|
41
|
+
gte:
|
42
|
+
- [ term, term ]
|
43
|
+
in:
|
44
|
+
- [ varref, values ]
|
45
|
+
term:
|
46
|
+
- varref
|
47
|
+
- literal
|
48
|
+
varref:
|
49
|
+
- qualified_identifier
|
50
|
+
- identifier
|
51
|
+
native:
|
52
|
+
- [ "::Proc" ]
|
53
|
+
literal:
|
54
|
+
- "::Object"
|
55
|
+
values:
|
56
|
+
- "::Object"
|
57
|
+
name:
|
58
|
+
!ruby/regexp /^[a-zA-Z0-9_]+[?!]?$/
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Predicate
|
2
|
+
module And
|
3
|
+
include NadicBool
|
4
|
+
|
5
|
+
def operator_symbol
|
6
|
+
:'&&'
|
7
|
+
end
|
8
|
+
|
9
|
+
def and_split(attr_list)
|
10
|
+
sexpr_body.inject([tautology, tautology]) do |(top,down),term|
|
11
|
+
pair = term.and_split(attr_list)
|
12
|
+
[top & pair.first, down & pair.last]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def constant_variables
|
17
|
+
sexpr_body.inject([]) do |cvars,expr|
|
18
|
+
cvars | expr.constant_variables
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Predicate
|
2
|
+
module Contradiction
|
3
|
+
include Expr
|
4
|
+
|
5
|
+
def contradiction?
|
6
|
+
true
|
7
|
+
end
|
8
|
+
|
9
|
+
def !
|
10
|
+
tautology
|
11
|
+
end
|
12
|
+
|
13
|
+
def &(other)
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def |(other)
|
18
|
+
other
|
19
|
+
end
|
20
|
+
|
21
|
+
def priority
|
22
|
+
100
|
23
|
+
end
|
24
|
+
|
25
|
+
def free_variables
|
26
|
+
@free_variables ||= []
|
27
|
+
end
|
28
|
+
|
29
|
+
def and_split(*args)
|
30
|
+
[tautology, self]
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Predicate
|
2
|
+
module DyadicComp
|
3
|
+
include Expr
|
4
|
+
|
5
|
+
def priority
|
6
|
+
50
|
7
|
+
end
|
8
|
+
|
9
|
+
def !
|
10
|
+
Factory.send(OP_NEGATIONS[first], self[1], self[2])
|
11
|
+
end
|
12
|
+
|
13
|
+
def left
|
14
|
+
self[1]
|
15
|
+
end
|
16
|
+
|
17
|
+
def right
|
18
|
+
self[2]
|
19
|
+
end
|
20
|
+
|
21
|
+
def free_variables
|
22
|
+
@free_variables ||= left.free_variables | right.free_variables
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class Predicate
|
2
|
+
module Expr
|
3
|
+
include Factory
|
4
|
+
|
5
|
+
OP_NEGATIONS = {
|
6
|
+
:eq => :neq,
|
7
|
+
:neq => :eq,
|
8
|
+
:lt => :gte,
|
9
|
+
:lte => :gt,
|
10
|
+
:gt => :lte,
|
11
|
+
:gte => :lt
|
12
|
+
}
|
13
|
+
|
14
|
+
def tautology?
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def contradiction?
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
def !
|
23
|
+
sexpr([:not, self])
|
24
|
+
end
|
25
|
+
|
26
|
+
def &(other)
|
27
|
+
return other if other.contradiction?
|
28
|
+
return self if other.tautology?
|
29
|
+
sexpr([:and, self, other])
|
30
|
+
end
|
31
|
+
|
32
|
+
def |(other)
|
33
|
+
return other if other.tautology?
|
34
|
+
return self if other.contradiction?
|
35
|
+
sexpr([:or, self, other])
|
36
|
+
end
|
37
|
+
|
38
|
+
def and_split(attr_list)
|
39
|
+
(free_variables & attr_list).empty? ? [ tautology, self ] : [ self, tautology ]
|
40
|
+
end
|
41
|
+
|
42
|
+
def rename(renaming)
|
43
|
+
Renamer.call(self, :renaming => renaming)
|
44
|
+
end
|
45
|
+
|
46
|
+
def qualify(qualifier)
|
47
|
+
Qualifier.new(qualifier).call(self)
|
48
|
+
end
|
49
|
+
|
50
|
+
def constant_variables
|
51
|
+
[]
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_ruby_code(scope = 't')
|
55
|
+
code = ToRubyCode.call(self, scope: scope)
|
56
|
+
"->(t){ #{code} }"
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_proc(scope = 't')
|
60
|
+
Kernel.eval(to_ruby_code(scope))
|
61
|
+
end
|
62
|
+
|
63
|
+
def sexpr(arg)
|
64
|
+
Factory.sexpr(arg)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Predicate
|
2
|
+
module In
|
3
|
+
include Expr
|
4
|
+
|
5
|
+
def priority
|
6
|
+
80
|
7
|
+
end
|
8
|
+
|
9
|
+
def identifier
|
10
|
+
self[1]
|
11
|
+
end
|
12
|
+
|
13
|
+
def values
|
14
|
+
self[2]
|
15
|
+
end
|
16
|
+
|
17
|
+
def free_variables
|
18
|
+
@free_variables ||= identifier.free_variables
|
19
|
+
end
|
20
|
+
|
21
|
+
def constant_variables
|
22
|
+
values.size == 1 ? free_variables : []
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Predicate
|
2
|
+
module Native
|
3
|
+
include Expr
|
4
|
+
|
5
|
+
def priority
|
6
|
+
90
|
7
|
+
end
|
8
|
+
|
9
|
+
def proc
|
10
|
+
self[1]
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_ruby_code(scope = 't')
|
14
|
+
if proc.respond_to?(:source_code)
|
15
|
+
code = proc.source_code
|
16
|
+
return code if code
|
17
|
+
end
|
18
|
+
raise NotSupportedError
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_proc(scope = 't')
|
22
|
+
proc
|
23
|
+
end
|
24
|
+
|
25
|
+
def free_variables
|
26
|
+
raise NotSupportedError
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Predicate
|
2
|
+
module QualifiedIdentifier
|
3
|
+
include Expr
|
4
|
+
|
5
|
+
def priority
|
6
|
+
100
|
7
|
+
end
|
8
|
+
|
9
|
+
def qualifier
|
10
|
+
self[1]
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
self[2]
|
15
|
+
end
|
16
|
+
|
17
|
+
def free_variables
|
18
|
+
@free_variables ||= [ name ]
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Predicate
|
2
|
+
module Tautology
|
3
|
+
include Expr
|
4
|
+
|
5
|
+
def tautology?
|
6
|
+
true
|
7
|
+
end
|
8
|
+
|
9
|
+
def !
|
10
|
+
contradiction
|
11
|
+
end
|
12
|
+
|
13
|
+
def &(other)
|
14
|
+
other
|
15
|
+
end
|
16
|
+
|
17
|
+
def |(other)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def priority
|
22
|
+
100
|
23
|
+
end
|
24
|
+
|
25
|
+
def free_variables
|
26
|
+
@free_variables ||= []
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|