whittle 0.0.1

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.
@@ -0,0 +1,4 @@
1
+ require "whittle"
2
+
3
+ RSpec.configure do |config|
4
+ end
@@ -0,0 +1,21 @@
1
+ require "spec_helper"
2
+
3
+ describe "a parser with an empty rule" do
4
+ let(:parser) do
5
+ Class.new(Whittle::Parser) do
6
+ rule(:expr) do |r|
7
+ r[].as { "test" }
8
+ r["(", :expr, ")"].as { |_, expr, _| expr }
9
+ end
10
+
11
+ rule("(")
12
+ rule(")")
13
+
14
+ start(:expr)
15
+ end
16
+ end
17
+
18
+ it "injects the empty rule to allow matching the input" do
19
+ parser.new.parse("((()))").should == "test"
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ require "spec_helper"
2
+
3
+ describe "a parser matching the empty string" do
4
+ let(:parser) do
5
+ Class.new(Whittle::Parser) do
6
+ rule(:empty) do |r|
7
+ r[].as { "bob" }
8
+ end
9
+
10
+ start(:empty)
11
+ end
12
+ end
13
+
14
+ it "always matches the empty string" do
15
+ parser.new.parse("").should == "bob"
16
+ end
17
+ end
@@ -0,0 +1,55 @@
1
+ require "spec_helper"
2
+
3
+ describe "a parser encountering unexpected input" do
4
+ let(:parser) do
5
+ Class.new(Whittle::Parser) do
6
+ rule(:wsp) do |r|
7
+ r[/\s+/]
8
+ end
9
+
10
+ rule(:id) do |r|
11
+ r[/[a-z]+/].as(:value)
12
+ end
13
+
14
+ rule(",")
15
+ rule("-")
16
+
17
+ rule(:list) do |r|
18
+ r[:list, ",", :id].as { |list, _, id| list << id }
19
+ r[:id].as { |id| Array(id) }
20
+ end
21
+
22
+ start(:list)
23
+ end
24
+ end
25
+
26
+ it "raises an exception of type ParseError" do
27
+ expect {
28
+ parser.new.parse("a, b - c")
29
+ }.to raise_error(Whittle::ParseError)
30
+ end
31
+
32
+ it "provides access to the line number" do
33
+ begin
34
+ parser.new.parse("a, \nb, \nc- \nd")
35
+ rescue Whittle::ParseError => e
36
+ e.line.should == 3
37
+ end
38
+ end
39
+
40
+ it "provides access to the expected tokens" do
41
+ begin
42
+ parser.new.parse("a, \nb, \nc- \nd")
43
+ rescue Whittle::ParseError => e
44
+ e.expected.should == [","]
45
+ end
46
+ end
47
+
48
+ it "provides access to the received token" do
49
+ begin
50
+ parser.new.parse("a, \nb, \nc- \nd")
51
+ rescue Whittle::ParseError => e
52
+ e.received.should == "-"
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+
3
+ describe "a parser with logical grouping" do
4
+ let(:parser) do
5
+ Class.new(Whittle::Parser) do
6
+ rule(:expr) do |r|
7
+ r["(", :expr, ")"].as { |_, expr, _| expr }
8
+ r[:expr, "-", :expr].as { |a, _, b| a - b }
9
+ r[:int].as(:value)
10
+ end
11
+
12
+ rule(:int) do |r|
13
+ r[/[0-9]+/].as { |int| Integer(int) }
14
+ end
15
+
16
+ rule("(")
17
+ rule(")")
18
+ rule("-") % :left ^ 1
19
+
20
+ start(:expr)
21
+ end
22
+ end
23
+
24
+ it "parses the grouping first" do
25
+ parser.new.parse("2-(3-1)-1").should == -1
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ require "spec_helper"
2
+
3
+ describe "a parser with multiple precedence levels" do
4
+ let(:parser) do
5
+ Class.new(Whittle::Parser) do
6
+ rule(:expr) do |r|
7
+ r["(", :expr, ")"].as { |_, expr, _| expr }
8
+ r[:expr, "+", :expr].as { |a, _, b| a + b }
9
+ r[:expr, "-", :expr].as { |a, _, b| a - b }
10
+ r[:expr, "*", :expr].as { |a, _, b| a * b }
11
+ r[:expr, "/", :expr].as { |a, _, b| a / b }
12
+ r[:int].as(:value)
13
+ end
14
+
15
+ rule(:int) do |r|
16
+ r[/[0-9]+/].as { |int| Integer(int) }
17
+ end
18
+
19
+ rule("(")
20
+ rule(")")
21
+ rule("+") % :left ^ 1
22
+ rule("-") % :left ^ 1
23
+ rule("*") % :left ^ 2
24
+ rule("/") % :left ^ 2
25
+
26
+ start(:expr)
27
+ end
28
+ end
29
+
30
+ it "evaluates each precedence as it is encountered" do
31
+ parser.new.parse("4-2*3-(6/3)/2+1").should == -2
32
+ end
33
+ end
@@ -0,0 +1,23 @@
1
+ require "spec_helper"
2
+
3
+ describe "a noop parser" do
4
+ let(:parser) do
5
+ Class.new(Whittle::Parser) do
6
+ rule(:char) do |r|
7
+ r[/./].as(:value)
8
+ end
9
+
10
+ rule(:prog) do |r|
11
+ r[:char]
12
+ end
13
+
14
+ start(:prog)
15
+ end
16
+ end
17
+
18
+ it "returns nil for all inputs" do
19
+ ["a", "b"].each do |input|
20
+ parser.new.parse(input).should be_nil
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ require "spec_helper"
2
+
3
+ describe "a pass-through parser" do
4
+ let(:parser) do
5
+ Class.new(Whittle::Parser) do
6
+ rule(:foo) do |r|
7
+ r["FOO"].as(:value)
8
+ end
9
+
10
+ start(:foo)
11
+ end
12
+ end
13
+
14
+ it "returns the input" do
15
+ parser.new.parse("FOO").should == "FOO"
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+
3
+ describe "a parser depending on operator precedences" do
4
+ let(:parser) do
5
+ Class.new(Whittle::Parser) do
6
+ rule("+") % :left ^ 1
7
+ rule("*") % :left ^ 2
8
+
9
+ rule(:int) do |r|
10
+ r[/[0-9]+/].as { |i| Integer(i) }
11
+ end
12
+
13
+ rule(:expr) do |r|
14
+ r[:expr, "+", :expr].as { |a, _, b| a + b }
15
+ r[:expr, "*", :expr].as { |a, _, b| a * b }
16
+ r[:int].as(:value)
17
+ end
18
+
19
+ start(:expr)
20
+ end
21
+ end
22
+
23
+ it "resolves shift-reduce conflicts by precedence" do
24
+ parser.new.parse("1+2*3").should == 7
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+
3
+ describe "a parser with a self-referential rule" do
4
+ let(:parser) do
5
+ Class.new(Whittle::Parser) do
6
+ rule("(")
7
+ rule(")")
8
+ rule("+")
9
+
10
+ rule(:int) do |r|
11
+ r[/[0-9]+/].as { |int| Integer(int) }
12
+ end
13
+
14
+ rule(:expr) do |r|
15
+ r[:expr, "+", :expr].as { |a, _, b| a + b }
16
+ r[:int].as(:value)
17
+ end
18
+
19
+ start(:expr)
20
+ end
21
+ end
22
+
23
+ it "handles the recursion gracefully" do
24
+ parser.new.parse("2+3+1").should == 6
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ require "spec_helper"
2
+
3
+ describe "a parser that skips tokens" do
4
+ let(:parser) do
5
+ Class.new(Whittle::Parser) do
6
+ rule(:wsp) do |r|
7
+ r[/\s+/]
8
+ end
9
+
10
+ rule("-") % :left
11
+
12
+ rule(:int) do |r|
13
+ r[/[0-9]+/].as { |int| Integer(int) }
14
+ end
15
+
16
+ rule(:expr) do |r|
17
+ r[:expr, "-", :expr].as { |a, _, b| a - b }
18
+ r[:int].as(:value)
19
+ end
20
+
21
+ start(:expr)
22
+ end
23
+ end
24
+
25
+ it "reads the input excluding the skipped tokens" do
26
+ parser.new.parse("6 - 3 - 1").should == 2
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ require "spec_helper"
2
+
3
+ describe "a parser returning the sum of two integers" do
4
+ let(:parser) do
5
+ Class.new(Whittle::Parser) do
6
+ rule("+")
7
+
8
+ rule(:int) do |r|
9
+ r[/[0-9]+/].as { |int| Integer(int) }
10
+ end
11
+
12
+ rule(:sum) do |r|
13
+ r[:int, "+", :int].as { |a, _, b| a + b }
14
+ end
15
+
16
+ start(:sum)
17
+ end
18
+ end
19
+
20
+ it "returns the sum of the operands" do
21
+ parser.new.parse("10+20").should == 30
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ require "spec_helper"
2
+
3
+ describe "a type-casting parser" do
4
+ let(:parser) do
5
+ Class.new(Whittle::Parser) do
6
+ rule(:int) do |r|
7
+ r[/[0-9]+/].as { |int| Integer(int) }
8
+ end
9
+
10
+ start(:int)
11
+ end
12
+ end
13
+
14
+ it "returns the input passed through the callback" do
15
+ parser.new.parse("123").should == 123
16
+ end
17
+ end
data/whittle.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "whittle/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "whittle"
7
+ s.version = Whittle::VERSION
8
+ s.authors = ["d11wtq"]
9
+ s.email = ["chris@w3style.co.uk"]
10
+ s.homepage = "https://github.com/d11wtq/whittle"
11
+ s.summary = %q{An efficient, easy to use, LALR parser for Ruby}
12
+ s.description = %q{Write powerful parsers by defining a series of very simple rules
13
+ and operations to perform as those rules are matched. Whittle
14
+ parsers are written in pure ruby and as such are extremely flexible.
15
+ Anybody familiar with parsers like yacc should find Whittle intuitive.
16
+ Those unfamiliar with parsers shouldn't find it difficult to
17
+ understand.}
18
+
19
+ s.rubyforge_project = "whittle"
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
+ s.require_paths = ["lib"]
25
+
26
+ s.add_development_dependency "rspec", "~> 2.6"
27
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: whittle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - d11wtq
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70265816010420 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.6'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70265816010420
25
+ description: ! "Write powerful parsers by defining a series of very simple rules\n
26
+ \ and operations to perform as those rules are matched. Whittle\n
27
+ \ parsers are written in pure ruby and as such are extremely
28
+ flexible.\n Anybody familiar with parsers like yacc should find
29
+ Whittle intuitive.\n Those unfamiliar with parsers shouldn't
30
+ find it difficult to\n understand."
31
+ email:
32
+ - chris@w3style.co.uk
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - .rspec
39
+ - Gemfile
40
+ - LICENSE
41
+ - README.md
42
+ - Rakefile
43
+ - lib/whittle.rb
44
+ - lib/whittle/error.rb
45
+ - lib/whittle/errors/grammar_error.rb
46
+ - lib/whittle/errors/parse_error.rb
47
+ - lib/whittle/errors/unconsumed_input_error.rb
48
+ - lib/whittle/parser.rb
49
+ - lib/whittle/rule.rb
50
+ - lib/whittle/rule_set.rb
51
+ - lib/whittle/version.rb
52
+ - spec/spec_helper.rb
53
+ - spec/unit/parser/empty_rule_spec.rb
54
+ - spec/unit/parser/empty_string_spec.rb
55
+ - spec/unit/parser/error_reporting_spec.rb
56
+ - spec/unit/parser/grouped_expr_spec.rb
57
+ - spec/unit/parser/multiple_precedence_spec.rb
58
+ - spec/unit/parser/noop_spec.rb
59
+ - spec/unit/parser/pass_through_parser_spec.rb
60
+ - spec/unit/parser/precedence_spec.rb
61
+ - spec/unit/parser/self_referential_expr_spec.rb
62
+ - spec/unit/parser/skipped_tokens_spec.rb
63
+ - spec/unit/parser/sum_parser_spec.rb
64
+ - spec/unit/parser/typecast_parser_spec.rb
65
+ - whittle.gemspec
66
+ homepage: https://github.com/d11wtq/whittle
67
+ licenses: []
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project: whittle
86
+ rubygems_version: 1.8.11
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: An efficient, easy to use, LALR parser for Ruby
90
+ test_files:
91
+ - spec/spec_helper.rb
92
+ - spec/unit/parser/empty_rule_spec.rb
93
+ - spec/unit/parser/empty_string_spec.rb
94
+ - spec/unit/parser/error_reporting_spec.rb
95
+ - spec/unit/parser/grouped_expr_spec.rb
96
+ - spec/unit/parser/multiple_precedence_spec.rb
97
+ - spec/unit/parser/noop_spec.rb
98
+ - spec/unit/parser/pass_through_parser_spec.rb
99
+ - spec/unit/parser/precedence_spec.rb
100
+ - spec/unit/parser/self_referential_expr_spec.rb
101
+ - spec/unit/parser/skipped_tokens_spec.rb
102
+ - spec/unit/parser/sum_parser_spec.rb
103
+ - spec/unit/parser/typecast_parser_spec.rb
104
+ has_rdoc: