sexpr 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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