sexpr 0.2.0 → 0.3.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 (83) hide show
  1. data/CHANGELOG.md +24 -1
  2. data/Gemfile +1 -0
  3. data/Gemfile.lock +2 -0
  4. data/LICENCE.md +1 -1
  5. data/Manifest.txt +1 -0
  6. data/README.md +46 -31
  7. data/examples/bool_expr/bool_expr.citrus +72 -0
  8. data/examples/bool_expr/bool_expr.rb +86 -0
  9. data/examples/bool_expr/bool_expr.sexp.yml +23 -0
  10. data/lib/sexpr.rb +27 -20
  11. data/lib/sexpr/errors.rb +15 -0
  12. data/lib/sexpr/grammar.rb +21 -77
  13. data/lib/sexpr/grammar/matching.rb +56 -0
  14. data/lib/sexpr/grammar/options.rb +53 -0
  15. data/lib/sexpr/grammar/parsing.rb +20 -0
  16. data/lib/sexpr/grammar/tagging.rb +49 -0
  17. data/lib/sexpr/loader.rb +0 -1
  18. data/lib/sexpr/matcher.rb +15 -0
  19. data/lib/sexpr/matcher/alternative.rb +30 -0
  20. data/lib/sexpr/matcher/many.rb +54 -0
  21. data/lib/sexpr/matcher/reference.rb +32 -0
  22. data/lib/sexpr/matcher/rule.rb +31 -0
  23. data/lib/sexpr/matcher/sequence.rb +30 -0
  24. data/lib/sexpr/matcher/terminal.rb +37 -0
  25. data/lib/sexpr/node.rb +16 -0
  26. data/lib/sexpr/parser.rb +48 -0
  27. data/lib/sexpr/parser/citrus.rb +67 -0
  28. data/lib/sexpr/version.rb +2 -2
  29. data/sexpr.gemspec +1 -0
  30. data/sexpr.noespec +2 -1
  31. data/spec/grammar/matching/test_compile_rule.rb +23 -0
  32. data/spec/grammar/matching/test_compile_rule_defn.rb +103 -0
  33. data/spec/grammar/options/test_install_parser.rb +36 -0
  34. data/spec/grammar/options/test_install_path.rb +19 -0
  35. data/spec/grammar/options/test_install_root.rb +27 -0
  36. data/spec/grammar/tagging/test_looks_a_sexpr.rb +20 -0
  37. data/spec/grammar/tagging/test_mod2rulename.rb +19 -0
  38. data/spec/grammar/tagging/test_rule2modname.rb +19 -0
  39. data/spec/grammar/tagging/test_tag_sexpr.rb +28 -0
  40. data/spec/grammar/test_new.rb +15 -0
  41. data/spec/grammar/test_parse.rb +27 -18
  42. data/spec/grammar/test_sexpr.rb +53 -0
  43. data/spec/{alternative → matcher/alternative}/test_eat.rb +1 -1
  44. data/spec/{alternative → matcher/alternative}/test_match_q.rb +1 -1
  45. data/spec/{many → matcher/many}/test_eat.rb +1 -1
  46. data/spec/{many → matcher/many}/test_initialize.rb +1 -1
  47. data/spec/{many → matcher/many}/test_match_q.rb +1 -1
  48. data/spec/{reference → matcher/reference}/test_eat.rb +1 -1
  49. data/spec/{reference → matcher/reference}/test_match_q.rb +1 -1
  50. data/spec/{rule → matcher/rule}/test_eat.rb +1 -1
  51. data/spec/{rule → matcher/rule}/test_match_q.rb +1 -1
  52. data/spec/{sequence → matcher/sequence}/test_eat.rb +1 -1
  53. data/spec/{sequence → matcher/sequence}/test_match_q.rb +1 -1
  54. data/spec/{terminal → matcher/terminal}/test_eat.rb +1 -1
  55. data/spec/{terminal → matcher/terminal}/test_match_q.rb +1 -1
  56. data/spec/{terminal → matcher/terminal}/test_terminal_match.rb +1 -1
  57. data/spec/node/test_sexpr_body.rb +18 -0
  58. data/spec/node/test_sexpr_type.rb +14 -0
  59. data/spec/parser/citrus/test_new.rb +28 -0
  60. data/spec/parser/citrus/test_parse.rb +40 -0
  61. data/spec/parser/citrus/test_recognize.rb +18 -0
  62. data/spec/parser/citrus/test_registration.rb +20 -0
  63. data/spec/parser/citrus/test_to_sexpr.rb +16 -0
  64. data/spec/parser/test_factor.rb +17 -0
  65. data/spec/parser/test_input_text.rb +27 -0
  66. data/spec/spec_helper.rb +18 -1
  67. data/spec/test_load.rb +40 -13
  68. data/spec/test_readme_examples.rb +40 -30
  69. data/spec/test_sexpr.rb +1 -1
  70. metadata +118 -68
  71. data/lib/sexpr/alternative.rb +0 -28
  72. data/lib/sexpr/element.rb +0 -9
  73. data/lib/sexpr/many.rb +0 -52
  74. data/lib/sexpr/reference.rb +0 -30
  75. data/lib/sexpr/rule.rb +0 -29
  76. data/lib/sexpr/sequence.rb +0 -28
  77. data/lib/sexpr/terminal.rb +0 -35
  78. data/spec/bool_expr.yml +0 -19
  79. data/spec/grammar/test_compile_rule.rb +0 -25
  80. data/spec/grammar/test_compile_rule_defn.rb +0 -98
  81. data/spec/grammar/test_fetch.rb +0 -18
  82. data/spec/grammar/test_root.rb +0 -20
  83. data/spec/test_bool_expr.rb +0 -27
@@ -1,30 +0,0 @@
1
- module Sexpr
2
- class Reference
3
- include Element
4
-
5
- attr_reader :rule_name
6
- attr_reader :grammar
7
-
8
- def initialize(rule_name, grammar)
9
- @rule_name = rule_name
10
- @grammar = grammar
11
- end
12
-
13
- def rule
14
- @rule ||= @grammar[@rule_name]
15
- end
16
-
17
- def match?(sexp)
18
- rule && rule.match?(sexp)
19
- end
20
-
21
- def eat(sexp)
22
- rule && rule.eat(sexp)
23
- end
24
-
25
- def inspect
26
- "(ref #{rule_name}, #{rule.inspect})"
27
- end
28
-
29
- end # class Reference
30
- end # module Sexpr
@@ -1,29 +0,0 @@
1
- module Sexpr
2
- class Rule
3
- include Element
4
-
5
- attr_reader :name
6
- attr_reader :defn
7
-
8
- def initialize(name, defn)
9
- @name = name
10
- @defn = defn
11
- end
12
-
13
- def match?(sexp)
14
- return nil unless sexp.is_a?(Array)
15
- return false unless sexp.first && (sexp.first == name)
16
- defn.match?(sexp[1..-1])
17
- end
18
-
19
- def eat(sexp)
20
- return nil unless match?(sexp.first)
21
- sexp[1..-1]
22
- end
23
-
24
- def inspect
25
- "(rule #{name}, #{defn.inspect})"
26
- end
27
-
28
- end # class Rule
29
- end # module Sexpr
@@ -1,28 +0,0 @@
1
- module Sexpr
2
- class Sequence
3
- include Element
4
-
5
- attr_reader :terms
6
-
7
- def initialize(terms)
8
- @terms = terms
9
- end
10
-
11
- def match?(sexp)
12
- return nil unless sexp.is_a?(Array)
13
- eat = eat(sexp)
14
- eat && eat.empty?
15
- end
16
-
17
- def eat(sexp)
18
- @terms.inject sexp do |rest,rule|
19
- rest && rule.eat(rest)
20
- end
21
- end
22
-
23
- def inspect
24
- "(seq #{terms.inspect})"
25
- end
26
-
27
- end # class Sequence
28
- end # module Sexpr
@@ -1,35 +0,0 @@
1
- module Sexpr
2
- class Terminal
3
- include Element
4
-
5
- attr_reader :value
6
-
7
- def initialize(value)
8
- @value = value
9
- end
10
-
11
- def inspect
12
- "(terminal #{value.inspect})"
13
- end
14
-
15
- def match?(sexp)
16
- terminal_match?(sexp)
17
- end
18
-
19
- def eat(sexp)
20
- match?(sexp.first) ? sexp[1..-1] : nil
21
- end
22
-
23
- private
24
-
25
- def terminal_match?(term)
26
- case @value
27
- when Regexp
28
- @value === term rescue false
29
- when TrueClass, FalseClass, NilClass
30
- @value == term
31
- end
32
- end
33
-
34
- end # class Terminal
35
- end # module Sexpr
@@ -1,19 +0,0 @@
1
- bool_expr:
2
- - bool_and
3
- - bool_or
4
- - bool_not
5
- - var_ref
6
- - bool_lit
7
- bool_and:
8
- - [ bool_expr+ ]
9
- bool_or:
10
- - [ bool_expr+ ]
11
- bool_not:
12
- - [ bool_expr ]
13
- var_ref:
14
- - [ var_name ]
15
- var_name:
16
- !ruby/regexp /^[a-z]+$/
17
- bool_lit:
18
- - true
19
- - false
@@ -1,25 +0,0 @@
1
- require 'spec_helper'
2
- module Sexpr
3
- class Grammar; public :compile_rule; end
4
- describe Grammar, "compile_rule" do
5
-
6
- def compile(name, arg)
7
- Grammar.new.compile_rule(name, arg)
8
- end
9
-
10
- it 'keep alternatives unchanged' do
11
- compile(:hello, Alternative.new([]) ).should be_a(Alternative)
12
- end
13
-
14
- it 'keep terminals unchanged' do
15
- compile(:hello, Terminal.new(true) ).should be_a(Terminal)
16
- end
17
-
18
- it 'keep creates a Rule englobing sequences' do
19
- compiled = compile(:hello, Sequence.new([]) )
20
- compiled.should be_a(Rule)
21
- compiled.name.should eq(:hello)
22
- end
23
-
24
- end
25
- end
@@ -1,98 +0,0 @@
1
- require 'spec_helper'
2
- module Sexpr
3
- class Grammar; public :compile_rule_defn; end
4
- describe Grammar, "compile_rule_defn" do
5
-
6
- let(:grammar){ Grammar.new }
7
- subject{ grammar.compile_rule_defn(arg) }
8
-
9
- context 'with an Element' do
10
- let(:arg){ Terminal.new(//) }
11
- it 'returns arg itself' do
12
- subject.should eq(arg)
13
- end
14
- end
15
-
16
- context "with true" do
17
- let(:arg){ true }
18
- it 'gives it true' do
19
- subject.should be_a(Terminal)
20
- subject.value.should eq(true)
21
- end
22
- end
23
-
24
- context "with false" do
25
- let(:arg){ false }
26
- it 'gives it false' do
27
- subject.should be_a(Terminal)
28
- subject.value.should eq(false)
29
- end
30
- end
31
-
32
- context "with nil" do
33
- let(:arg){ nil }
34
- it 'gives it nil' do
35
- subject.should be_a(Terminal)
36
- subject.value.should eq(nil)
37
- end
38
- end
39
-
40
- context 'with an alternative array' do
41
- let(:arg){ [true, false, nil] }
42
- it 'factors an Alternative' do
43
- subject.should be_a(Alternative)
44
- end
45
- it 'compiles its elements' do
46
- subject.terms.size.should eq(3)
47
- subject.terms.all?{|x| x.is_a?(Terminal)}.should be_true
48
- end
49
- end
50
-
51
- context 'with a sequence array' do
52
- let(:arg){ [[true, false, nil]] }
53
- it 'factors a Sequence' do
54
- subject.should be_a(Sequence)
55
- end
56
- it 'compiles its elements' do
57
- subject.terms.size.should eq(3)
58
- subject.terms.all?{|x| x.is_a?(Terminal)}.should be_true
59
- end
60
- end
61
-
62
- context 'with subalternatives' do
63
- let(:arg){ [ ["a_rule", [false, true, nil] ]] }
64
- it 'compiles the last as an Alternative' do
65
- subject.terms.last.should be_a(Alternative)
66
- end
67
- end
68
-
69
- context 'with a reference to a non-terminal' do
70
- let(:arg){ "a_rule" }
71
- it 'factors a Reference' do
72
- subject.should be_a(Reference)
73
- end
74
- it 'refers to the appropriate rule name' do
75
- subject.rule_name.should eq(:a_rule)
76
- end
77
- it 'refers to the appropriate grammar' do
78
- subject.grammar.should eq(grammar)
79
- end
80
- end
81
-
82
- context 'with a stared non-terminal' do
83
- let(:arg){ "a_rule+" }
84
- it 'factors a Many' do
85
- subject.should be_a(Many)
86
- end
87
- it 'refers to the appropriate rule' do
88
- subject.term.should be_a(Reference)
89
- subject.term.rule_name.should eq(:a_rule)
90
- end
91
- it 'refers to the appropriate multiplicities' do
92
- subject.min.should eq(1)
93
- subject.max.should be_nil
94
- end
95
- end
96
-
97
- end
98
- end
@@ -1,18 +0,0 @@
1
- require 'spec_helper'
2
- module Sexpr
3
- describe Grammar, "fetch" do
4
-
5
- let(:grammar){
6
- Sexpr.load(:terminal => /[a-z]+/)
7
- }
8
-
9
- it 'returns the rule when it exists' do
10
- grammar[:terminal].should be_a(Terminal)
11
- end
12
-
13
- it 'returns nil otherwise' do
14
- grammar[:nosuchone].should be_nil
15
- end
16
-
17
- end
18
- end # module Sexpr
@@ -1,20 +0,0 @@
1
- require 'spec_helper'
2
- module Sexpr
3
- describe Grammar, "root" do
4
-
5
- let(:rules){ {:t => /[a-z]+/, :nt => true} }
6
-
7
- def grammar(options = {})
8
- Sexpr.load(rules, options)
9
- end
10
-
11
- it 'is the first key by default' do
12
- grammar.root.value.should eq(/[a-z]+/)
13
- end
14
-
15
- it 'is the specified rule when specified' do
16
- grammar(:root => :nt).root.value.should eq(true)
17
- end
18
-
19
- end
20
- end
@@ -1,27 +0,0 @@
1
- require 'spec_helper'
2
- module Sexpr
3
- describe "the bool_expr grammar" do
4
-
5
- let(:g){ Sexpr.load(Path.dir/"bool_expr.yml") }
6
-
7
- it "allows checking validy of specific nodes" do
8
- (g[:bool_lit] === true).should be_true
9
- (g[:var_ref] === [:var_ref, "x"]).should be_true
10
- (g[:bool_and] === [:bool_and, true, false]).should be_true
11
- (g[:bool_and] === [:bool_or, true, false]).should be_false
12
- end
13
-
14
- it 'allows checking the validity against the root rule' do
15
- (g === true).should be_true
16
- (g === false).should be_true
17
- (g === [:bool_not, true]).should be_true
18
- (g === [:var_ref, "x"]).should be_true
19
- (g === [:bool_not, [:var_ref, "x"]]).should be_true
20
- end
21
-
22
- it 'detects wrong matches' do
23
- (g === [:bool_not, [:something_else, "x"]]).should be_false
24
- end
25
-
26
- end
27
- end