sexpr 0.2.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 (53) hide show
  1. data/CHANGELOG.md +13 -0
  2. data/Gemfile +8 -0
  3. data/Gemfile.lock +25 -0
  4. data/LICENCE.md +22 -0
  5. data/Manifest.txt +15 -0
  6. data/README.md +46 -0
  7. data/Rakefile +23 -0
  8. data/lib/sexpr.rb +31 -0
  9. data/lib/sexpr/alternative.rb +28 -0
  10. data/lib/sexpr/element.rb +9 -0
  11. data/lib/sexpr/grammar.rb +82 -0
  12. data/lib/sexpr/loader.rb +1 -0
  13. data/lib/sexpr/many.rb +52 -0
  14. data/lib/sexpr/reference.rb +30 -0
  15. data/lib/sexpr/rule.rb +29 -0
  16. data/lib/sexpr/sequence.rb +28 -0
  17. data/lib/sexpr/terminal.rb +35 -0
  18. data/lib/sexpr/version.rb +14 -0
  19. data/sexpr.gemspec +188 -0
  20. data/sexpr.noespec +25 -0
  21. data/spec/alternative/test_eat.rb +20 -0
  22. data/spec/alternative/test_match_q.rb +20 -0
  23. data/spec/bool_expr.yml +19 -0
  24. data/spec/grammar.yml +24 -0
  25. data/spec/grammar/test_compile_rule.rb +25 -0
  26. data/spec/grammar/test_compile_rule_defn.rb +98 -0
  27. data/spec/grammar/test_fetch.rb +18 -0
  28. data/spec/grammar/test_parse.rb +32 -0
  29. data/spec/grammar/test_root.rb +20 -0
  30. data/spec/many/test_eat.rb +59 -0
  31. data/spec/many/test_initialize.rb +36 -0
  32. data/spec/many/test_match_q.rb +24 -0
  33. data/spec/reference/test_eat.rb +13 -0
  34. data/spec/reference/test_match_q.rb +20 -0
  35. data/spec/rule/test_eat.rb +21 -0
  36. data/spec/rule/test_match_q.rb +24 -0
  37. data/spec/sequence/test_eat.rb +20 -0
  38. data/spec/sequence/test_match_q.rb +25 -0
  39. data/spec/spec_helper.rb +3 -0
  40. data/spec/terminal/test_eat.rb +20 -0
  41. data/spec/terminal/test_match_q.rb +56 -0
  42. data/spec/terminal/test_terminal_match.rb +89 -0
  43. data/spec/test_bool_expr.rb +27 -0
  44. data/spec/test_load.rb +35 -0
  45. data/spec/test_readme_examples.rb +44 -0
  46. data/spec/test_sexpr.rb +8 -0
  47. data/tasks/debug_mail.rake +75 -0
  48. data/tasks/debug_mail.txt +13 -0
  49. data/tasks/gem.rake +68 -0
  50. data/tasks/spec_test.rake +71 -0
  51. data/tasks/unit_test.rake +76 -0
  52. data/tasks/yard.rake +51 -0
  53. metadata +173 -0
@@ -0,0 +1,35 @@
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
@@ -0,0 +1,14 @@
1
+ module Sexpr
2
+ module Version
3
+
4
+ MAJOR = 0
5
+ MINOR = 2
6
+ TINY = 0
7
+
8
+ def self.to_s
9
+ [ MAJOR, MINOR, TINY ].join('.')
10
+ end
11
+
12
+ end
13
+ VERSION = Version.to_s
14
+ end
@@ -0,0 +1,188 @@
1
+ # We require your library, mainly to have access to the VERSION number.
2
+ # Feel free to set $version manually.
3
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
4
+ require "sexpr/version"
5
+ $version = Sexpr::Version.to_s
6
+
7
+ #
8
+ # This is your Gem specification. Default values are provided so that your library
9
+ # should be correctly packaged given what you have described in the .noespec file.
10
+ #
11
+ Gem::Specification.new do |s|
12
+
13
+ ################################################################### ABOUT YOUR GEM
14
+
15
+ # Gem name (required)
16
+ s.name = "sexpr"
17
+
18
+ # Gem version (required)
19
+ s.version = $version
20
+
21
+ # A short summary of this gem
22
+ #
23
+ # This is displayed in `gem list -d`.
24
+ s.summary = "A compilation framework around s-expressions"
25
+
26
+ # A long description of this gem (required)
27
+ #
28
+ # The description should be more detailed than the summary. For example,
29
+ # you might wish to copy the entire README into the description.
30
+ s.description = "Sexpr helps manipulating s-expressions in ruby."
31
+
32
+ # The URL of this gem home page (optional)
33
+ s.homepage = "https://github.com/blambeau/sexp"
34
+
35
+ # Gem publication date (required but auto)
36
+ #
37
+ # Today is automatically used by default, uncomment only if
38
+ # you know what you do!
39
+ #
40
+ # s.date = Time.now.strftime('%Y-%m-%d')
41
+
42
+ # The license(s) for the library. Each license must be a short name, no
43
+ # more than 64 characters.
44
+ #
45
+ # s.licences = %w{}
46
+
47
+ # The rubyforge project this gem lives under (optional)
48
+ #
49
+ # s.rubyforge_project = nil
50
+
51
+ ################################################################### ABOUT THE AUTHORS
52
+
53
+ # The list of author names who wrote this gem.
54
+ #
55
+ # If you are providing multiple authors and multiple emails they should be
56
+ # in the same order.
57
+ #
58
+ s.authors = ["Bernard Lambeau"]
59
+
60
+ # Contact emails for this gem
61
+ #
62
+ # If you are providing multiple authors and multiple emails they should be
63
+ # in the same order.
64
+ #
65
+ # NOTE: Somewhat strangly this attribute is always singular!
66
+ # Don't replace by s.emails = ...
67
+ s.email = ["blambeau@gmail.com"]
68
+
69
+ ################################################################### PATHS, FILES, BINARIES
70
+
71
+ # Paths in the gem to add to $LOAD_PATH when this gem is
72
+ # activated (required).
73
+ #
74
+ # The default 'lib' is typically sufficient.
75
+ s.require_paths = ["lib"]
76
+
77
+ # Files included in this gem.
78
+ #
79
+ # By default, we take all files included in the Manifest.txt file on root
80
+ # of the project. Entries of the manifest are interpreted as Dir[...]
81
+ # patterns so that lazy people may use wilcards like lib/**/*
82
+ #
83
+ here = File.expand_path(File.dirname(__FILE__))
84
+ s.files = File.readlines(File.join(here, 'Manifest.txt')).
85
+ inject([]){|files, pattern| files + Dir[File.join(here, pattern.strip)]}.
86
+ collect{|x| x[(1+here.size)..-1]}
87
+
88
+ # Test files included in this gem.
89
+ #
90
+ s.test_files = Dir["test/**/*"] + Dir["spec/**/*"]
91
+
92
+ # The path in the gem for executable scripts (optional)
93
+ #
94
+ s.bindir = "bin"
95
+
96
+ # Executables included in the gem.
97
+ #
98
+ s.executables = (Dir["bin/*"]).collect{|f| File.basename(f)}
99
+
100
+ ################################################################### REQUIREMENTS & INSTALL
101
+ # Remember the gem version requirements operators and schemes:
102
+ # = Equals version
103
+ # != Not equal to version
104
+ # > Greater than version
105
+ # < Less than version
106
+ # >= Greater than or equal to
107
+ # <= Less than or equal to
108
+ # ~> Approximately greater than
109
+ #
110
+ # Don't forget to have a look at http://lmgtfy.com/?q=Ruby+Versioning+Policies
111
+ # for setting your gem version.
112
+ #
113
+ # For your requirements to other gems, remember that
114
+ # ">= 2.2.0" (optimistic: specify minimal version)
115
+ # ">= 2.2.0", "< 3.0" (pessimistic: not greater than the next major)
116
+ # "~> 2.2" (shortcut for ">= 2.2.0", "< 3.0")
117
+ # "~> 2.2.0" (shortcut for ">= 2.2.0", "< 2.3.0")
118
+ #
119
+
120
+ #
121
+ # One call to add_dependency('gem_name', 'gem version requirement') for each
122
+ # runtime dependency. These gems will be installed with your gem.
123
+ # One call to add_development_dependency('gem_name', 'gem version requirement')
124
+ # for each development dependency. These gems are required for developers
125
+ #
126
+ s.add_development_dependency("epath", "~> 0.0.1")
127
+ s.add_development_dependency("rake", "~> 0.9.2")
128
+ s.add_development_dependency("rspec", "~> 2.8.0")
129
+ s.add_development_dependency("wlang", "~> 0.10.2")
130
+
131
+
132
+ # The version of ruby required by this gem
133
+ #
134
+ # Uncomment and set this if your gem requires specific ruby versions.
135
+ #
136
+ # s.required_ruby_version = ">= 0"
137
+
138
+ # The RubyGems version required by this gem
139
+ #
140
+ # s.required_rubygems_version = ">= 0"
141
+
142
+ # The platform this gem runs on. See Gem::Platform for details.
143
+ #
144
+ # s.platform = nil
145
+
146
+ # Extensions to build when installing the gem.
147
+ #
148
+ # Valid types of extensions are extconf.rb files, configure scripts
149
+ # and rakefiles or mkrf_conf files.
150
+ #
151
+ s.extensions = []
152
+
153
+ # External (to RubyGems) requirements that must be met for this gem to work.
154
+ # It’s simply information for the user.
155
+ #
156
+ s.requirements = nil
157
+
158
+ # A message that gets displayed after the gem is installed
159
+ #
160
+ # Uncomment and set this if you want to say something to the user
161
+ # after gem installation
162
+ #
163
+ s.post_install_message = nil
164
+
165
+ ################################################################### SECURITY
166
+
167
+ # The key used to sign this gem. See Gem::Security for details.
168
+ #
169
+ # s.signing_key = nil
170
+
171
+ # The certificate chain used to sign this gem. See Gem::Security for
172
+ # details.
173
+ #
174
+ # s.cert_chain = []
175
+
176
+ ################################################################### RDOC
177
+
178
+ # An ARGV style array of options to RDoc
179
+ #
180
+ # See 'rdoc --help' about this
181
+ #
182
+ s.rdoc_options = []
183
+
184
+ # Extra files to add to RDoc such as README
185
+ #
186
+ s.extra_rdoc_files = Dir["README.md"] + Dir["CHANGELOG.md"] + Dir["LICENCE.md"]
187
+
188
+ end
@@ -0,0 +1,25 @@
1
+ template-info:
2
+ name: "ruby"
3
+ version: 1.7.0
4
+ links:
5
+ source: https://github.com/blambeau/noe
6
+ variables:
7
+ lower:
8
+ sexpr
9
+ upper:
10
+ Sexpr
11
+ version:
12
+ 0.2.0
13
+ summary: |-
14
+ A compilation framework around s-expressions
15
+ description: |-
16
+ Sexpr helps manipulating s-expressions in ruby.
17
+ authors:
18
+ - {name: Bernard Lambeau, email: blambeau@gmail.com}
19
+ links:
20
+ - https://github.com/blambeau/sexp
21
+ dependencies:
22
+ - {name: epath, version: "~> 0.0.1", groups: [development]}
23
+ - {name: rake, version: "~> 0.9.2", groups: [development]}
24
+ - {name: rspec, version: "~> 2.8.0", groups: [development]}
25
+ - {name: wlang, version: "~> 0.10.2", groups: [development]}
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Alternative, "eat" do
4
+
5
+ let(:alt1){ Terminal.new(nil) }
6
+ let(:alt2){ Terminal.new(/^[a-z]+$/) }
7
+ let(:rule){ Alternative.new [alt1, alt2] }
8
+
9
+ it 'returns the subarray when match' do
10
+ rule.eat(["hello", "world"]).should eq(["world"])
11
+ rule.eat([nil, "world"]).should eq(["world"])
12
+ end
13
+
14
+ it 'returns nil when no match' do
15
+ rule.eat([]).should be_nil
16
+ rule.eat(["12"]).should be_nil
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ module Sexpr
3
+ describe Alternative, "match?" do
4
+
5
+ let(:alt1){ Terminal.new(nil) }
6
+ let(:alt2){ Terminal.new(/^[a-z]+$/) }
7
+ let(:rule){ Alternative.new [alt1, alt2] }
8
+
9
+ it 'returns true if one matches' do
10
+ rule.should be_match("hello")
11
+ rule.should be_match(nil)
12
+ end
13
+
14
+ it 'returns false on no match' do
15
+ rule.should_not be_match("12")
16
+ rule.should_not be_match([])
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,19 @@
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
@@ -0,0 +1,24 @@
1
+ rule:
2
+ - non_terminal
3
+ - terminal
4
+ non_terminal:
5
+ - [ a_rule ]
6
+ - [ a_rule+ ]
7
+ - [ a_rule* ]
8
+ - [ "a_rule?" ]
9
+ - [ a_rule, a_rule, a_rule ]
10
+ a_rule:
11
+ - [ terminal, non_terminal ]
12
+ terminal:
13
+ - regexp_nt
14
+ - true_nt
15
+ - false_nt
16
+ - nil_nt
17
+ regexp_nt:
18
+ !ruby/regexp /^[a-z]+$/
19
+ true_nt:
20
+ true
21
+ false_nt:
22
+ false
23
+ nil_nt:
24
+ ~
@@ -0,0 +1,25 @@
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
@@ -0,0 +1,98 @@
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