Commits

Kaspar Schiess committed 76fad6d

Allowing for alternation

Comments (0)

Files changed (3)

examples/alternation.rb

+$:.unshift File.dirname(__FILE__) + "/../lib"
+
+require 'par'
+include Par
+
+def integer source
+  source.pattern(/\+|-/).maybe >>
+    source.pattern(/\d+/)
+end
+def float s
+  s.cr {
+    s.pattern(/\+|-/).maybe >>
+      s.pattern(/\d+/) >> 
+      s.string('.') >> s.pattern(/\d+/)
+  }
+end
+def element s
+  p(float(s)) | p(integer(s))
+end
+
+%w(
+  1.23
+  232
+).each do |example|
+  s = source(example)
+  r = element(s)
+
+  puts "Parsing #{example.inspect} yields #{r.inspect}."
+end
+
       def | other
         self
       end
+      def maybe
+        self
+      end
     end
   end
   class Source
       Par.result(head(n)).tap { @pos += n }
     end
 
+    def conditional_rewind
+      old_pos = @pos
+      r = yield
+      old_pos = @pos if r != Par.bot
+
+      return r
+    ensure
+      @pos = old_pos
+    end
+    alias :cr :conditional_rewind
+
     def head n=nil
       n && str[@pos, n] || str[@pos..-1]
     end

spec/lib/par/source_spec.rb

       r == 'foo'
     end
   end
+  describe "#cr" do
+    let(:s) { source 'foobar' }
+    it 'rewinds the source if the block exits with Par.bot' do
+      s.cr { 
+        s.string 'foo'
+        Par.bot
+      }
+
+      s.head.should == 'foobar'
+    end
+    it "doesn't rewind if the block has other return values" do
+      s.cr {
+        s.string 'foo'
+      }
+      s.head.should == 'bar'
+    end
+  end
 end