predicator 1.2.1 → 2.0.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 +4 -4
- data/CHANGELOG.md +42 -0
- data/{LICENSE.txt → LICENSE} +1 -1
- data/README.md +322 -46
- data/lib/predicator/ast.rb +74 -187
- data/lib/predicator/boundary.rb +237 -0
- data/lib/predicator/civil.rb +112 -0
- data/lib/predicator/duration_text.rb +92 -0
- data/lib/predicator/emitter/chains.rb +62 -0
- data/lib/predicator/emitter/statements.rb +86 -0
- data/lib/predicator/emitter.rb +187 -0
- data/lib/predicator/errors.rb +140 -0
- data/lib/predicator/evaluator/access.rb +108 -0
- data/lib/predicator/evaluator/arithmetic.rb +132 -0
- data/lib/predicator/evaluator/calls.rb +129 -0
- data/lib/predicator/evaluator/casts.rb +158 -0
- data/lib/predicator/evaluator/chronology.rb +88 -0
- data/lib/predicator/evaluator/compare.rb +158 -0
- data/lib/predicator/evaluator/json_functions.rb +167 -0
- data/lib/predicator/evaluator/json_scan.rb +303 -0
- data/lib/predicator/evaluator/library.rb +127 -0
- data/lib/predicator/evaluator/math_functions.rb +72 -0
- data/lib/predicator/evaluator/order.rb +120 -0
- data/lib/predicator/evaluator/rich_types.rb +146 -0
- data/lib/predicator/evaluator/statements.rb +151 -0
- data/lib/predicator/evaluator.rb +391 -117
- data/lib/predicator/float_text.rb +94 -0
- data/lib/predicator/iso_text.rb +99 -0
- data/lib/predicator/lexer/literals.rb +115 -0
- data/lib/predicator/lexer/numbers.rb +91 -0
- data/lib/predicator/lexer.rb +194 -0
- data/lib/predicator/parser/durations.rb +108 -0
- data/lib/predicator/parser/operators.rb +86 -0
- data/lib/predicator/parser/postfix.rb +57 -0
- data/lib/predicator/parser/primaries.rb +122 -0
- data/lib/predicator/parser/statements.rb +114 -0
- data/lib/predicator/parser/token_text.rb +52 -0
- data/lib/predicator/parser.rb +217 -438
- data/lib/predicator/result.rb +46 -0
- data/lib/predicator/tagged/reader.rb +139 -0
- data/lib/predicator/tagged/writer.rb +106 -0
- data/lib/predicator/tagged.rb +134 -0
- data/lib/predicator/values.rb +147 -0
- data/lib/predicator/version.rb +4 -1
- data/lib/predicator.rb +384 -14
- metadata +53 -147
- data/.gitignore +0 -11
- data/.rubocop.yml +0 -46
- data/.travis.yml +0 -5
- data/CODE_OF_CONDUCT.md +0 -49
- data/Gemfile +0 -4
- data/HISTORY.md +0 -51
- data/Rakefile +0 -24
- data/lib/predicator/context.rb +0 -18
- data/lib/predicator/lexer.rex +0 -69
- data/lib/predicator/lexer.rex.rb +0 -187
- data/lib/predicator/parser.y +0 -120
- data/lib/predicator/visitors/dot.rb +0 -113
- data/lib/predicator/visitors/each.rb +0 -16
- data/lib/predicator/visitors/instructions.rb +0 -183
- data/lib/predicator/visitors/string.rb +0 -76
- data/lib/predicator/visitors/visitor.rb +0 -100
- data/lib/predicator/visitors.rb +0 -5
- data/predicator.gemspec +0 -34
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
module Predicator
|
|
2
|
-
module Visitors
|
|
3
|
-
class Instructions < Visitor
|
|
4
|
-
attr_reader :instructions
|
|
5
|
-
|
|
6
|
-
def initialize instructions=[]
|
|
7
|
-
@instructions = instructions
|
|
8
|
-
@label_locations = {}
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def accept ast
|
|
12
|
-
super
|
|
13
|
-
update_jumps
|
|
14
|
-
remove_labels
|
|
15
|
-
@instructions
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
private
|
|
19
|
-
|
|
20
|
-
def visit_AND node
|
|
21
|
-
visit node.left
|
|
22
|
-
@instructions.push jump_instruction("false", node)
|
|
23
|
-
visit node.right
|
|
24
|
-
@instructions.push label_instruction(node)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def visit_OR node
|
|
28
|
-
visit node.left
|
|
29
|
-
@instructions.push jump_instruction("true", node)
|
|
30
|
-
visit node.right
|
|
31
|
-
@instructions.push label_instruction(node)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def visit_NOT node
|
|
35
|
-
super
|
|
36
|
-
@instructions.push ["not"]
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def visit_EQ node
|
|
40
|
-
visit node.left
|
|
41
|
-
add_typecast_to_instructions node
|
|
42
|
-
visit node.right
|
|
43
|
-
@instructions.push ["compare", "EQ"]
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def visit_GT node
|
|
47
|
-
visit node.left
|
|
48
|
-
add_typecast_to_instructions node
|
|
49
|
-
visit node.right
|
|
50
|
-
@instructions.push ["compare", "GT"]
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def visit_LT node
|
|
54
|
-
visit node.left
|
|
55
|
-
add_typecast_to_instructions node
|
|
56
|
-
visit node.right
|
|
57
|
-
@instructions.push ["compare", "LT"]
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def visit_BETWEEN node
|
|
61
|
-
visit node.left
|
|
62
|
-
add_typecast_to_instructions node
|
|
63
|
-
visit node.middle
|
|
64
|
-
visit node.right
|
|
65
|
-
@instructions.push ["compare", "BETWEEN"]
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def visit_IN node
|
|
69
|
-
visit node.left
|
|
70
|
-
add_typecast_to_instructions node
|
|
71
|
-
visit node.right
|
|
72
|
-
@instructions.push ["compare", "IN"]
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def visit_NOTIN node
|
|
76
|
-
visit node.left
|
|
77
|
-
add_typecast_to_instructions node
|
|
78
|
-
visit node.right
|
|
79
|
-
@instructions.push ["compare", "NOTIN"]
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def visit_STRSTARTSWITH node
|
|
83
|
-
visit node.left
|
|
84
|
-
add_typecast_to_instructions node
|
|
85
|
-
visit node.right
|
|
86
|
-
@instructions.push ["compare", "STARTSWITH"]
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def visit_STRENDSWITH node
|
|
90
|
-
visit node.left
|
|
91
|
-
add_typecast_to_instructions node
|
|
92
|
-
visit node.right
|
|
93
|
-
@instructions.push ["compare", "ENDSWITH"]
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def visit_ARRAY node
|
|
97
|
-
contents = node.left.map{ |item| item.left }
|
|
98
|
-
@instructions.push ["array", contents]
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def visit_VARIABLE node
|
|
102
|
-
@instructions.push ["load", node.symbol]
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def visit_BOOL node
|
|
106
|
-
super
|
|
107
|
-
@instructions.push ["to_bool"]
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def visit_DATE node
|
|
111
|
-
@instructions.push ["lit", node.symbol]
|
|
112
|
-
@instructions.push ["to_date"]
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def visit_DATEAGO node
|
|
116
|
-
visit node.left
|
|
117
|
-
@instructions.push ["date_ago"]
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def visit_DATEFROMNOW node
|
|
121
|
-
visit node.left
|
|
122
|
-
@instructions.push ["date_from_now"]
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def visit_DURATION node
|
|
126
|
-
as_seconds = node.symbol.to_i * 24 * 60 * 60
|
|
127
|
-
@instructions.push ["lit", as_seconds]
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def visit_BLANK node
|
|
131
|
-
visit node.left
|
|
132
|
-
@instructions.push ["blank"]
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def visit_PRESENT node
|
|
136
|
-
visit node.left
|
|
137
|
-
@instructions.push ["present"]
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def terminal node
|
|
141
|
-
@instructions.push ["lit", node.symbol]
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def add_typecast_to_instructions node
|
|
145
|
-
type = case node.right.type.to_s
|
|
146
|
-
when /INT/ then "to_int"
|
|
147
|
-
when /STR/ then "to_str"
|
|
148
|
-
when /DATE/ then "to_date"
|
|
149
|
-
end
|
|
150
|
-
@instructions.push [type]
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def jump_instruction condition, node
|
|
154
|
-
["j#{condition}", node.object_id.to_s]
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
def label_instruction node
|
|
158
|
-
label = node.object_id.to_s
|
|
159
|
-
@label_locations[label] = @instructions.size
|
|
160
|
-
["label", label]
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
def update_jumps
|
|
164
|
-
@instructions.each_with_index do |inst, idx|
|
|
165
|
-
next unless inst.first =~ /^j/
|
|
166
|
-
label = inst.pop
|
|
167
|
-
offset = calculate_offset idx, @label_locations[label]
|
|
168
|
-
inst.push offset
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def calculate_offset from_idx, to_idx
|
|
173
|
-
offset = to_idx - from_idx
|
|
174
|
-
num_labels = @instructions[from_idx...to_idx].count{ |i| i.first == "label" }
|
|
175
|
-
offset - num_labels
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
def remove_labels
|
|
179
|
-
@instructions.delete_if{ |inst| inst.first == "label" }
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
end
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
module Predicator
|
|
2
|
-
module Visitors
|
|
3
|
-
class String < Visitor
|
|
4
|
-
private
|
|
5
|
-
|
|
6
|
-
def terminal node
|
|
7
|
-
node.left.to_s
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def visit_STRING node
|
|
11
|
-
"'#{node.left}'"
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def visit_ARRAY node
|
|
15
|
-
contents = node.left.map{ |item| visit item }.join(", ")
|
|
16
|
-
"[#{contents}]"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def visit_NOT node
|
|
20
|
-
"!#{visit node.left}"
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def visit_GROUP node
|
|
24
|
-
"(#{visit node.left})"
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def visit_EQ node
|
|
28
|
-
[visit(node.left), " = ", visit(node.right)].join
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def visit_GT node
|
|
32
|
-
[visit(node.left), " > ", visit(node.right)].join
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def visit_LT node
|
|
36
|
-
[visit(node.left), " < ", visit(node.right)].join
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def visit_AND node
|
|
40
|
-
[visit(node.left), " and ", visit(node.right)].join
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def visit_OR node
|
|
44
|
-
[visit(node.left), " or ", visit(node.right)].join
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def visit_BETWEEN node
|
|
48
|
-
[visit(node.left), " between ", visit(node.middle), " and ", visit(node.right)].join
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def visit_IN node
|
|
52
|
-
[visit(node.left), " in ", visit(node.right)].join
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def visit_NOTIN node
|
|
56
|
-
[visit(node.left), " not in ", visit(node.right)].join
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def visit_STRSTARTSWITH node
|
|
60
|
-
[visit(node.left), " starts with ", visit(node.right)].join
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def visit_STRENDSWITH node
|
|
64
|
-
[visit(node.left), " ends with ", visit(node.right)].join
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def visit_DATEAGO node
|
|
68
|
-
visit(node.left) + " ago"
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def visit_DATEFROMNOW node
|
|
72
|
-
visit(node.left) + " from now"
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
module Predicator
|
|
2
|
-
module Visitors
|
|
3
|
-
class Visitor
|
|
4
|
-
DISPATCH_CACHE = Hash.new { |h,k|
|
|
5
|
-
h[k] = "visit_#{k}"
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
def accept node
|
|
9
|
-
visit node
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
def visit node
|
|
15
|
-
send DISPATCH_CACHE[node.type], node
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def visit_children node
|
|
19
|
-
node.children.each {|child| visit child}
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def terminal node; end
|
|
23
|
-
|
|
24
|
-
def visit_ARRAY node
|
|
25
|
-
node.left.each{ |item| visit item }
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
visit_children_methods = %w(
|
|
29
|
-
visit_EQ visit_GT visit_LT
|
|
30
|
-
visit_NOT visit_GROUP visit_BOOL
|
|
31
|
-
visit_IN visit_NOTIN visit_BETWEEN
|
|
32
|
-
visit_DATEAGO visit_DATEFROMNOW
|
|
33
|
-
visit_AND visit_OR
|
|
34
|
-
visit_STRSTARTSWITH visit_STRENDSWITH
|
|
35
|
-
)
|
|
36
|
-
visit_children_methods.each do |method_name|
|
|
37
|
-
define_method method_name do |node|
|
|
38
|
-
visit_children node
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
%w( visit_INTEQ visit_STREQ visit_DATEQ ).each do |method_name|
|
|
43
|
-
define_method method_name do |node|
|
|
44
|
-
visit_EQ node
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
%w( visit_INTGT visit_STRGT visit_DATGT ).each do |method_name|
|
|
49
|
-
define_method method_name do |node|
|
|
50
|
-
visit_GT node
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
%w( visit_INTLT visit_STRLT visit_DATLT ).each do |method_name|
|
|
55
|
-
define_method method_name do |node|
|
|
56
|
-
visit_LT node
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
%w( visit_INTIN visit_STRIN ).each do |method_name|
|
|
61
|
-
define_method method_name do |node|
|
|
62
|
-
visit_IN node
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
%w( visit_INTNOTIN visit_STRNOTIN ).each do |method_name|
|
|
67
|
-
define_method method_name do |node|
|
|
68
|
-
visit_NOTIN node
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
%w( visit_INTBETWEEN visit_DATBETWEEN ).each do |method_name|
|
|
73
|
-
define_method method_name do |node|
|
|
74
|
-
visit_BETWEEN node
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
terminal_methods = %w(
|
|
79
|
-
visit_TRUE visit_FALSE
|
|
80
|
-
visit_DATE visit_DURATION
|
|
81
|
-
visit_INTEGER visit_STRING visit_VARIABLE
|
|
82
|
-
visit_BLANK visit_PRESENT
|
|
83
|
-
)
|
|
84
|
-
terminal_methods.each do |method_name|
|
|
85
|
-
define_method method_name do |node|
|
|
86
|
-
terminal node
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
array_methods = %w(
|
|
91
|
-
visit_INTARRAY visit_STRARRAY
|
|
92
|
-
)
|
|
93
|
-
array_methods.each do |method_name|
|
|
94
|
-
define_method method_name do |node|
|
|
95
|
-
visit_ARRAY node
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|
data/lib/predicator/visitors.rb
DELETED
data/predicator.gemspec
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
|
-
lib = File.expand_path "../lib", __FILE__
|
|
3
|
-
$LOAD_PATH.unshift lib unless $LOAD_PATH.include? lib
|
|
4
|
-
require "predicator/version"
|
|
5
|
-
|
|
6
|
-
Gem::Specification.new do |spec|
|
|
7
|
-
spec.name = "predicator"
|
|
8
|
-
spec.version = Predicator::VERSION
|
|
9
|
-
spec.authors = ["JohnnyT"]
|
|
10
|
-
spec.email = ["ubergeek3141@gmail.com"]
|
|
11
|
-
|
|
12
|
-
spec.summary = %q{A secure, non-evaling condition (boolean predicate) engine for end users}
|
|
13
|
-
spec.homepage = "https://github.com/riddler/predicator/tree/master/impl/rb"
|
|
14
|
-
spec.license = "MIT"
|
|
15
|
-
|
|
16
|
-
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(bin|test|spec|features)/}) }
|
|
17
|
-
spec.bindir = "exe"
|
|
18
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename f }
|
|
19
|
-
spec.require_paths = ["lib"]
|
|
20
|
-
|
|
21
|
-
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
22
|
-
spec.metadata["changelog_uri"] = "https://github.com/riddler/predicator/blob/master/impl/rb/HISTORY.md"
|
|
23
|
-
spec.metadata["source_code_uri"] = "https://github.com/riddler/predicator/tree/master/impl/rb"
|
|
24
|
-
spec.metadata["bug_tracker_uri"] = "https://github.com/riddler/predicator/issues"
|
|
25
|
-
|
|
26
|
-
spec.add_development_dependency "bundler"
|
|
27
|
-
spec.add_development_dependency "coveralls"
|
|
28
|
-
spec.add_development_dependency "minitest", "= 5.4.2"
|
|
29
|
-
spec.add_development_dependency "minitest-focus"
|
|
30
|
-
spec.add_development_dependency "oedipus_lex"
|
|
31
|
-
spec.add_development_dependency "pry-nav"
|
|
32
|
-
spec.add_development_dependency "racc"
|
|
33
|
-
spec.add_development_dependency "rake"
|
|
34
|
-
end
|