sexpr 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +16 -0
- data/Gemfile +3 -3
- data/Gemfile.lock +14 -14
- data/Rakefile +0 -4
- data/examples/bool_expr/bool_expr.rb +1 -95
- data/lib/sexpr/grammar/matching.rb +3 -3
- data/lib/sexpr/grammar/parsing.rb +1 -1
- data/lib/sexpr/grammar/tagging.rb +16 -13
- data/lib/sexpr/loader.rb +1 -0
- data/lib/sexpr/matcher.rb +3 -2
- data/lib/sexpr/matcher/many.rb +16 -1
- data/lib/sexpr/matcher/non_terminal.rb +31 -0
- data/lib/sexpr/matcher/rule.rb +3 -6
- data/lib/sexpr/node.rb +1 -1
- data/lib/sexpr/parser.rb +1 -1
- data/lib/sexpr/processor.rb +11 -1
- data/lib/sexpr/processor/helper.rb +1 -1
- data/lib/sexpr/processor/sexpr_coercions.rb +6 -14
- data/lib/sexpr/rewriter.rb +0 -8
- data/lib/sexpr/version.rb +3 -3
- data/sexpr.gemspec +3 -3
- data/sexpr.noespec +13 -6
- data/spec/integration/bool_expr/test_not_push.rb +38 -0
- data/spec/integration/bool_expr/test_parsing.rb +15 -0
- data/spec/integration/bool_expr/test_tagging.rb +25 -0
- data/spec/integration/bool_expr/test_validation.rb +15 -0
- data/spec/{test_readme_examples.rb → integration/test_readme_examples.rb} +0 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/grammar/matching/test_compile_rule.rb +55 -0
- data/spec/{grammar → unit/grammar}/matching/test_compile_rule_defn.rb +0 -0
- data/spec/unit/grammar/matching/test_compile_rules.rb +45 -0
- data/spec/{grammar → unit/grammar}/options/test_install_parser.rb +0 -0
- data/spec/{grammar → unit/grammar}/options/test_install_path.rb +0 -0
- data/spec/{grammar → unit/grammar}/options/test_install_root.rb +0 -0
- data/spec/{grammar → unit/grammar}/tagging/test_looks_a_sexpr.rb +0 -0
- data/spec/{grammar → unit/grammar}/tagging/test_mod2rulename.rb +0 -0
- data/spec/{grammar → unit/grammar}/tagging/test_rule2modname.rb +0 -0
- data/spec/{grammar → unit/grammar}/tagging/test_tag_sexpr.rb +0 -0
- data/spec/unit/grammar/tagging/test_tagging_module_for.rb +72 -0
- data/spec/{grammar → unit/grammar}/test_new.rb +0 -0
- data/spec/{grammar → unit/grammar}/test_parse.rb +0 -0
- data/spec/{grammar → unit/grammar}/test_sexpr.rb +0 -0
- data/spec/{matcher → unit/matcher}/alternative/test_eat.rb +1 -1
- data/spec/{matcher → unit/matcher}/alternative/test_match_q.rb +0 -0
- data/spec/{matcher → unit/matcher}/many/test_eat.rb +0 -0
- data/spec/{matcher → unit/matcher}/many/test_initialize.rb +0 -0
- data/spec/{matcher → unit/matcher}/many/test_match_q.rb +0 -0
- data/spec/unit/matcher/non_terminal/test_eat.rb +31 -0
- data/spec/unit/matcher/non_terminal/test_match_q.rb +32 -0
- data/spec/{matcher → unit/matcher}/reference/test_eat.rb +0 -0
- data/spec/{matcher → unit/matcher}/reference/test_match_q.rb +0 -0
- data/spec/unit/matcher/rule/test_eat.rb +17 -0
- data/spec/unit/matcher/rule/test_match_q.rb +17 -0
- data/spec/{matcher → unit/matcher}/sequence/test_eat.rb +0 -0
- data/spec/{matcher → unit/matcher}/sequence/test_match_q.rb +0 -0
- data/spec/{matcher → unit/matcher}/terminal/test_eat.rb +1 -1
- data/spec/{matcher → unit/matcher}/terminal/test_match_q.rb +0 -0
- data/spec/{matcher → unit/matcher}/terminal/test_terminal_match.rb +0 -0
- data/spec/{node → unit/node}/test_sexpr_body.rb +0 -0
- data/spec/{node → unit/node}/test_sexpr_copy.rb +0 -0
- data/spec/{node → unit/node}/test_sexpr_type.rb +0 -0
- data/spec/{node → unit/node}/test_tracking_markers.rb +0 -0
- data/spec/{parser → unit/parser}/citrus/test_new.rb +0 -0
- data/spec/{parser → unit/parser}/citrus/test_parse.rb +0 -0
- data/spec/{parser → unit/parser}/citrus/test_recognize.rb +0 -0
- data/spec/{parser → unit/parser}/citrus/test_registration.rb +0 -0
- data/spec/{parser → unit/parser}/citrus/test_to_sexpr.rb +0 -0
- data/spec/{parser → unit/parser}/test_factor.rb +0 -0
- data/spec/{parser → unit/parser}/test_input_text.rb +0 -0
- data/spec/{processor → unit/processor}/helper/test_call.rb +0 -0
- data/spec/{processor → unit/processor}/test_apply.rb +0 -0
- data/spec/{processor → unit/processor}/test_build_helper_chain.rb +0 -0
- data/spec/{processor → unit/processor}/test_call.rb +0 -0
- data/spec/unit/processor/test_grammar.rb +56 -0
- data/spec/{processor → unit/processor}/test_helper.rb +0 -0
- data/spec/{processor → unit/processor}/test_sexpr_coercions.rb +6 -2
- data/spec/{processor → unit/processor}/test_use.rb +0 -0
- data/spec/{rewriter → unit/rewriter}/test_copy_and_apply.rb +0 -0
- data/spec/{test_load.rb → unit/test_load.rb} +3 -2
- data/spec/{test_rewriter.rb → unit/test_rewriter.rb} +0 -0
- data/spec/{test_sexpr.rb → unit/test_sexpr.rb} +1 -1
- data/tasks/gem.rake +9 -4
- data/tasks/test.rake +26 -0
- metadata +163 -117
- data/spec/grammar/matching/test_compile_rule.rb +0 -23
- data/spec/matcher/rule/test_eat.rb +0 -21
- data/spec/matcher/rule/test_match_q.rb +0 -24
- data/tasks/spec_test.rake +0 -71
- data/tasks/unit_test.rake +0 -76
data/lib/sexpr/rewriter.rb
CHANGED
@@ -2,14 +2,6 @@ module Sexpr
|
|
2
2
|
class Rewriter < Processor
|
3
3
|
helper SexprCoercions
|
4
4
|
|
5
|
-
def self.grammar(sexpr_grammar)
|
6
|
-
@sexpr_grammar = sexpr_grammar
|
7
|
-
end
|
8
|
-
|
9
|
-
def sexpr_grammar
|
10
|
-
(self.class.instance_variable_get(:"@sexpr_grammar") || super) rescue Sexpr
|
11
|
-
end
|
12
|
-
|
13
5
|
def copy_and_apply(sexpr)
|
14
6
|
sexpr.sexpr_copy do |copy, child|
|
15
7
|
copy << (Sexpr===child ? apply(child) : child)
|
data/lib/sexpr/version.rb
CHANGED
data/sexpr.gemspec
CHANGED
@@ -123,10 +123,10 @@ Gem::Specification.new do |s|
|
|
123
123
|
# One call to add_development_dependency('gem_name', 'gem version requirement')
|
124
124
|
# for each development dependency. These gems are required for developers
|
125
125
|
#
|
126
|
-
s.add_development_dependency("
|
126
|
+
s.add_development_dependency("path", "~> 1.3")
|
127
127
|
s.add_development_dependency("citrus", "~> 2.4")
|
128
|
-
s.add_development_dependency("rake", "~> 0
|
129
|
-
s.add_development_dependency("rspec", "~> 2.
|
128
|
+
s.add_development_dependency("rake", "~> 10.0")
|
129
|
+
s.add_development_dependency("rspec", "~> 2.10")
|
130
130
|
s.add_development_dependency("wlang", "~> 0.10.2")
|
131
131
|
|
132
132
|
|
data/sexpr.noespec
CHANGED
@@ -1,15 +1,22 @@
|
|
1
1
|
template-info:
|
2
|
-
name: "
|
3
|
-
version:
|
2
|
+
name: "rubygem.noe"
|
3
|
+
version: 2.0.1
|
4
4
|
links:
|
5
5
|
source: https://github.com/blambeau/noe
|
6
|
+
manifest:
|
7
|
+
tasks/unit_test.rake:
|
8
|
+
ignore: true
|
9
|
+
safe_override: false
|
10
|
+
tasks/spec_test.rake:
|
11
|
+
ignore: true
|
12
|
+
safe_override: false
|
6
13
|
variables:
|
7
14
|
lower:
|
8
15
|
sexpr
|
9
16
|
upper:
|
10
17
|
Sexpr
|
11
18
|
version:
|
12
|
-
0.
|
19
|
+
0.6.0
|
13
20
|
summary: |-
|
14
21
|
A compilation framework around s-expressions
|
15
22
|
description: |-
|
@@ -19,8 +26,8 @@ variables:
|
|
19
26
|
links:
|
20
27
|
- https://github.com/blambeau/sexp
|
21
28
|
dependencies:
|
22
|
-
- {name:
|
29
|
+
- {name: path, version: "~> 1.3", groups: [development]}
|
23
30
|
- {name: citrus, version: "~> 2.4", groups: [development]}
|
24
|
-
- {name: rake, version: "~> 0
|
25
|
-
- {name: rspec, version: "~> 2.
|
31
|
+
- {name: rake, version: "~> 10.0", groups: [development]}
|
32
|
+
- {name: rspec, version: "~> 2.10", groups: [development]}
|
26
33
|
- {name: wlang, version: "~> 0.10.2", groups: [development]}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe BoolExpr::NotPushProcessor do
|
3
|
+
subject{ BoolExpr }
|
4
|
+
|
5
|
+
def _(expr)
|
6
|
+
BoolExpr.sexpr(expr)
|
7
|
+
end
|
8
|
+
|
9
|
+
def rw(expr)
|
10
|
+
BoolExpr::NotPushProcessor.new.call(expr)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'does nothing on variable references' do
|
14
|
+
rw("not x").should eq([:bool_not, [:var_ref, "x"]])
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'rewrites literals through negating them' do
|
18
|
+
rw("not true").should eq(_ "false")
|
19
|
+
rw("not false").should eq(_ "true")
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'rewrites not through removing them' do
|
23
|
+
rw("not not true").should eq(_ "true")
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'rewrites or through and of negated terms' do
|
27
|
+
rw("not(x or y)").should eq(_ "not(x) and not(y)")
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'rewrites and through or of negated terms' do
|
31
|
+
rw("not(x and y)").should eq(_ "not(x) or not(y)")
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'rewrites recursively' do
|
35
|
+
rw("not(x and not(y))").should eq(_ "not(x) or y")
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe BoolExpr, "the parsing feature" do
|
3
|
+
subject{ BoolExpr }
|
4
|
+
|
5
|
+
it 'parses boolean expressions without error' do
|
6
|
+
subject.parse("x and y").should be_a(Citrus::Match)
|
7
|
+
subject.parse("not(y)").should be_a(Citrus::Match)
|
8
|
+
subject.parse("not(true)").should be_a(Citrus::Match)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'provides a shortcut to get s-expressions directly' do
|
12
|
+
subject.sexpr("x and y").should eq([:bool_and, [:var_ref, "x"], [:var_ref, "y"]])
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe BoolExpr, "the tagging feature" do
|
3
|
+
subject{ BoolExpr }
|
4
|
+
|
5
|
+
it 'tags parsing results with the Sexpr module' do
|
6
|
+
sexpr = subject.sexpr("x and y")
|
7
|
+
sexpr.should be_a(Sexpr)
|
8
|
+
sexpr.sexpr_type.should eq(:bool_and)
|
9
|
+
sexpr.sexpr_body.should eq([[:var_ref, "x"], [:var_ref, "y"]])
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'tags parsing results with user modules' do
|
13
|
+
subject.sexpr("x and y").should be_a(BoolExpr::And)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'allows tagging manually' do
|
17
|
+
subject.sexpr([:bool_lit, true]).should be_a(BoolExpr::Lit)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'applies tagging recursively' do
|
21
|
+
sexpr = subject.sexpr([:bool_not, [:bool_lit, true]])
|
22
|
+
sexpr.last.should be_a(BoolExpr::Lit)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe BoolExpr, 'the validation feature' do
|
3
|
+
subject{ BoolExpr }
|
4
|
+
|
5
|
+
it 'validates s-expressions' do
|
6
|
+
subject.match?([:bool_lit, true]).should be_true
|
7
|
+
subject.match?([:bool_lit, "x"]).should be_false
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'validates s-expressions against specific rules' do
|
11
|
+
subject[:bool_lit].match?([:bool_lit, true]).should be_true
|
12
|
+
subject[:bool_and].match?([:bool_lit, true]).should be_false
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
File without changes
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Sexpr
|
3
|
+
module Grammar
|
4
|
+
describe Matching, "compile_rule" do
|
5
|
+
include Matching
|
6
|
+
|
7
|
+
subject{ compile_rule(:hello, defn) }
|
8
|
+
|
9
|
+
shared_examples_for 'a terminal rule' do
|
10
|
+
it{ should be_a(Matcher::Rule) }
|
11
|
+
|
12
|
+
it 'should have the expected defn' do
|
13
|
+
subject.defn.should be(defn)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should have the correct name' do
|
17
|
+
subject.name.should eq(:hello)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
shared_examples_for 'a non-terminal rule' do
|
22
|
+
it{ should be_a(Matcher::Rule) }
|
23
|
+
|
24
|
+
it 'should have the expected non-terminal' do
|
25
|
+
subject.defn.should be_a(Matcher::NonTerminal)
|
26
|
+
subject.defn.name.should eq(:hello)
|
27
|
+
subject.defn.defn.should be(defn)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should have the correct name' do
|
31
|
+
subject.name.should eq(:hello)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'on Alternative' do
|
36
|
+
let(:defn){ Matcher::Alternative.new([]) }
|
37
|
+
|
38
|
+
it_should_behave_like "a terminal rule"
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'on Terminal' do
|
42
|
+
let(:defn){ Matcher::Terminal.new(true) }
|
43
|
+
|
44
|
+
it_should_behave_like "a terminal rule"
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'on Sequence' do
|
48
|
+
let(:defn){ Matcher::Sequence.new([]) }
|
49
|
+
|
50
|
+
it_should_behave_like "a non-terminal rule"
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
File without changes
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Sexpr
|
3
|
+
module Grammar
|
4
|
+
describe Matching, "compile_rules" do
|
5
|
+
include Matching
|
6
|
+
|
7
|
+
let(:yaml){
|
8
|
+
<<-YAML
|
9
|
+
bool_and:
|
10
|
+
- [ bool_lit, bool_lit ]
|
11
|
+
bool_lit:
|
12
|
+
- true
|
13
|
+
- false
|
14
|
+
var_name:
|
15
|
+
!ruby/regexp /^[a-z]+$/
|
16
|
+
YAML
|
17
|
+
}
|
18
|
+
|
19
|
+
let(:rules){
|
20
|
+
YAML.load(yaml)
|
21
|
+
}
|
22
|
+
|
23
|
+
subject{ compile_rules(rules) }
|
24
|
+
|
25
|
+
it{ should be_a(Hash) }
|
26
|
+
|
27
|
+
it 'has expected keys' do
|
28
|
+
subject.keys.should eq([:bool_and, :bool_lit, :var_name])
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'has expected values' do
|
32
|
+
subject.values.each do |val|
|
33
|
+
val.should be_a(Matcher::Rule)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'has expected defn' do
|
38
|
+
subject[:bool_and].defn.should be_a(Matcher::NonTerminal)
|
39
|
+
subject[:bool_lit].defn.should be_a(Matcher::Alternative)
|
40
|
+
subject[:var_name].defn.should be_a(Matcher::Terminal)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Sexpr::Grammar
|
3
|
+
describe Tagging, "tagging_module_for" do
|
4
|
+
include Tagging
|
5
|
+
|
6
|
+
module TaggingReference
|
7
|
+
module Node; end
|
8
|
+
module Not; end
|
9
|
+
module Lit; end
|
10
|
+
end
|
11
|
+
|
12
|
+
subject{ tagging_module_for(rulename) }
|
13
|
+
|
14
|
+
context 'when there is a tagging reference and a default tagging module' do
|
15
|
+
|
16
|
+
def tagging_reference
|
17
|
+
TaggingReference
|
18
|
+
end
|
19
|
+
|
20
|
+
def default_tagging_module
|
21
|
+
TaggingReference::Node
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when the module exists' do
|
25
|
+
let(:rulename){ :not }
|
26
|
+
|
27
|
+
it{ should be(TaggingReference::Not) }
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when the module does not exists' do
|
31
|
+
let(:rulename){ :blah }
|
32
|
+
|
33
|
+
it{ should be(TaggingReference::Node) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when there is a no tagging reference but default tagging module' do
|
38
|
+
|
39
|
+
def default_tagging_module
|
40
|
+
TaggingReference::Node
|
41
|
+
end
|
42
|
+
|
43
|
+
let(:rulename){ :not }
|
44
|
+
|
45
|
+
it{ should be(TaggingReference::Node) }
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when there is a a tagging reference and no default tagging module' do
|
49
|
+
|
50
|
+
def tagging_reference
|
51
|
+
TaggingReference
|
52
|
+
end
|
53
|
+
|
54
|
+
def default_tagging_module
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when the module exists' do
|
59
|
+
let(:rulename){ :not }
|
60
|
+
|
61
|
+
it{ should be(TaggingReference::Not) }
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'when the module does not exists' do
|
65
|
+
let(:rulename){ :blah }
|
66
|
+
|
67
|
+
it{ should be_nil }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Sexpr::Matcher
|
3
|
+
describe NonTerminal, "eat" do
|
4
|
+
|
5
|
+
let(:defn){ Sequence.new [Terminal.new(/^[a-z]+$/)] }
|
6
|
+
let(:rule){ NonTerminal.new :hello, defn }
|
7
|
+
|
8
|
+
subject{ rule.eat(sexpr) }
|
9
|
+
|
10
|
+
context 'when match' do
|
11
|
+
let(:sexpr){ [[:hello, "world"], "!"] }
|
12
|
+
|
13
|
+
it{ should eq(["!"]) }
|
14
|
+
end
|
15
|
+
|
16
|
+
[
|
17
|
+
[:hello, "world"],
|
18
|
+
[:hello],
|
19
|
+
[],
|
20
|
+
[[]],
|
21
|
+
[nil],
|
22
|
+
].each do |example|
|
23
|
+
context "when no match, e.g. #{example.inspect}" do
|
24
|
+
let(:sexpr){ example }
|
25
|
+
|
26
|
+
it{ should be_nil }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Sexpr::Matcher
|
3
|
+
describe NonTerminal, "match?" do
|
4
|
+
|
5
|
+
let(:defn){ Sequence.new [Terminal.new(/^[a-z]+$/)] }
|
6
|
+
let(:rule){ NonTerminal.new :hello, defn }
|
7
|
+
|
8
|
+
subject{ rule.match?(sexpr) }
|
9
|
+
|
10
|
+
context 'when match' do
|
11
|
+
let(:sexpr){ [:hello, "world"] }
|
12
|
+
|
13
|
+
it{ should be_true }
|
14
|
+
end
|
15
|
+
|
16
|
+
[
|
17
|
+
[[:hello, "world"]],
|
18
|
+
[:hello],
|
19
|
+
[],
|
20
|
+
[[]],
|
21
|
+
[nil],
|
22
|
+
nil
|
23
|
+
].each do |example|
|
24
|
+
context "when no match, e.g. #{example.inspect}" do
|
25
|
+
let(:sexpr){ example }
|
26
|
+
|
27
|
+
it{ should be_false }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|