Commits

Kaspar Schiess committed d6a44f3

Nice repetition, some cleanup of object handling

Comments (0)

Files changed (6)

+# A sample Guardfile
+# More info at https://github.com/guard/guard#readme
+
+guard 'rspec' do
+  watch(%r{^spec/.+_spec\.rb$})
+  watch(%r{^lib/(.+)\.rb$})     { |m| "spec/lib/#{m[1]}_spec.rb" }
+  watch('spec/spec_helper.rb')  { "spec" }
+end

examples/repetition.rb

+$:.unshift File.dirname(__FILE__) + "/../lib"
+
+require 'par'
+include Par
+
+def greedy
+  result = []
+  loop do
+    r = yield
+    break if !r || r.bottom?
+
+    result << r
+  end
+
+  result
+end
+def ab_lang s
+  s.string('a') >>
+    greedy { s.string('b') } >>
+    s.string('a')
+end
+
+%w(
+  abbba
+  abbbbbba
+  abbb
+).each do |example|
+  s = source(example)
+  r = ab_lang(s)
+
+  puts "Parsing #{example.inspect} yields #{r.inspect}."
+end
+
+
     end
 
     def >> other
+      # Concatenation with another Result
       if other.respond_to? :obj
-        return new(
-          concat(obj, other.obj))
+        return concat(obj, other.obj)
       end
 
-      other == bot ? bot : self
+      # Concatenation with bottom
+      return bottom if other == bottom
+      return self if other == top
+
+      # Wild concatenation with any other object
+      return concat(obj, other)
     end
     def | other
       self
     def new obj
       self.class.new obj
     end
-    def bot
-      self.class.bot
+    def bottom
+      self.class.bottom
     end
     def top
       self.class.top
     end
+
+    def bottom?
+      false
+    end
     
     def concat obj1, obj2
-      obj1 + obj2
+      new(obj1 + obj2)
     end
 
     def to_s
     end
     include Comparable
 
-    def self.bot
-      @bot ||= Bot.new
+    def self.bottom
+      @bottom ||= Bottom.new
     end
     def self.top
       @top ||= Top.new
     end
 
-    class Bot
+    class Bottom
       def >> other
         self
       end
       def maybe
         Par.top
       end
+      def bottom?
+        true
+      end
     end
 
     class Top
       def maybe
         self
       end
+      def bottom?
+        false
+      end
     end
   end
   class Source
         return self.n(str.size)
       end
 
-      Par.bot
+      Par.bottom
     end
     def pattern pat
       idx = head.index(pat)
-      return bot unless idx == 0
+      return bottom unless idx == 0
       md =head.match(pat)
       n(md[0].size)
     end
     def conditional_rewind
       old_pos = @pos
       r = yield
-      old_pos = @pos if r != Par.bot
+      old_pos = @pos if r != Par.bottom
 
       return r
     ensure
   def source str
     Source.new str
   end
-  def bot 
-    Result.bot
+  def bottom
+    Result.bottom
   end
   def top
     Result.top

spec/lib/par/result_spec.rb

 describe Par::Result do
   include Par
 
+  context 'a simple result' do
+    let(:r) { result 'r' }
+
+    it 'should not be bottom' do 
+      r.should_not be_bottom
+    end
+    it 'should allow concatenation with any object, using #+ to form a composite' do
+      o = 's'
+      c = r >> o
+
+      c.obj.should == 'rs'
+    end
+  end
   context 'given 2 results' do
     let(:a) { result 'foo' }
     let(:b) { result 'bar' }
       a.maybe.should == a
     end
   end
-  context '.bot' do
+  context '.bottom' do
     let(:any) { result 'any' }
 
     it "cannot be concatenated left" do
-      (bot >> any).should == bot
+      (bottom >> any).should == bottom
     end
     it "cannot be concatenated right" do
-      (any >> bot).should == bot 
+      (any >> bottom).should == bottom 
     end
     it "can be alternated left" do
-      (bot | any).should == any
+      (bottom | any).should == any
     end
     it "can be alternated right" do
-      (any | bot).should == any
+      (any | bottom).should == any
+    end
+    it "can be tested for bottom?" do 
+      bottom.should be_bottom
     end
   end
   context '.top' do
     it 'can be maybeed' do
       top.maybe.should == top
     end
+    it 'should not be bottom' do 
+      top.should_not be_bottom
+    end
   end
 end

spec/lib/par/source_spec.rb

     it 'rewinds the source if the block exits with Par.bot' do
       s.cr { 
         s.string 'foo'
-        Par.bot
+        Par.bottom
       }
 
       s.head.should == 'foobar'

spec/lib/par_spec.rb

 
   describe "sequences" do
     it "parse" do
-      (s.string('foo') >> s.string('bar')).should_not == bot
+      (s.string('foo') >> s.string('bar')).should_not == bottom
     end
     it "or not" do
-      (s.string('bar') >> s.string('bar')).should == bot
+      (s.string('bar') >> s.string('bar')).should == bottom
     end
   end
   describe 'maybe' do