summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormokha <mokha@cisco.com>2019-05-14 21:12:37 -0600
committermokha <mokha@cisco.com>2019-05-14 21:12:37 -0600
commite31832068a8cb77cd346d9001a215b574070b761 (patch)
tree2b0e7fb453f0cd1300a246caf9d8d4db666dafb7
parent7f7bdb2be416cb111c5d2d635343c42e5e0d4caa (diff)
start to implement a small transaction
-rw-r--r--lib/mpeg.rb1
-rw-r--r--lib/mpeg/base.rb5
-rw-r--r--lib/mpeg/input.rb16
-rw-r--r--lib/mpeg/lookahead.rb7
-rw-r--r--lib/mpeg/sequence.rb6
-rw-r--r--lib/mpeg/transaction.rb19
-rw-r--r--spec/lookahead_spec.rb14
-rw-r--r--spec/sequence_spec.rb19
8 files changed, 82 insertions, 5 deletions
diff --git a/lib/mpeg.rb b/lib/mpeg.rb
index c53cf89..a785c98 100644
--- a/lib/mpeg.rb
+++ b/lib/mpeg.rb
@@ -11,6 +11,7 @@ require "mpeg/repitition"
require "mpeg/sequence"
require "mpeg/slice"
require "mpeg/str"
+require "mpeg/transaction"
module Mpeg
class Error < StandardError; end
diff --git a/lib/mpeg/base.rb b/lib/mpeg/base.rb
index f8f97c5..e2e8563 100644
--- a/lib/mpeg/base.rb
+++ b/lib/mpeg/base.rb
@@ -1,8 +1,7 @@
module Mpeg
class Base
- def parse(string)
- input = Input.new(string)
- call(input) && input.end?
+ def parse(string, input: Input.new(string))
+ call(input) && input.end_of_string?
end
def repeat(min = 0, max = nil)
diff --git a/lib/mpeg/input.rb b/lib/mpeg/input.rb
index 1a36fe6..7fd185b 100644
--- a/lib/mpeg/input.rb
+++ b/lib/mpeg/input.rb
@@ -14,8 +14,22 @@ module Mpeg
Slice.new(position, slice)
end
- def end?
+ def rewind
+ transaction do |_|
+ yield
+ end
+ end
+
+ def transaction(&block)
+ Transaction.new(@scanner).run(&block)
+ end
+
+ def end_of_string?
@scanner.eos?
end
+
+ def position
+ @scanner.pos
+ end
end
end
diff --git a/lib/mpeg/lookahead.rb b/lib/mpeg/lookahead.rb
index 7fcbf3d..19e1876 100644
--- a/lib/mpeg/lookahead.rb
+++ b/lib/mpeg/lookahead.rb
@@ -4,5 +4,12 @@ module Mpeg
@parser = parser
@positive = positive
end
+
+ def call(input)
+ input.rewind do
+ result = @parser.call(input)
+ @positive ? result : (result ? false : true)
+ end
+ end
end
end
diff --git a/lib/mpeg/sequence.rb b/lib/mpeg/sequence.rb
index e3823de..9172370 100644
--- a/lib/mpeg/sequence.rb
+++ b/lib/mpeg/sequence.rb
@@ -6,7 +6,11 @@ module Mpeg
end
def call(input)
- @left.call(input) && @right.call(input)
+ input.transaction do |x|
+ result = @left.call(input) && @right.call(input)
+ x.commit! if result
+ result
+ end
end
end
end
diff --git a/lib/mpeg/transaction.rb b/lib/mpeg/transaction.rb
new file mode 100644
index 0000000..718352c
--- /dev/null
+++ b/lib/mpeg/transaction.rb
@@ -0,0 +1,19 @@
+module Mpeg
+ class Transaction
+ def initialize(scanner)
+ @scanner = scanner
+ @rewind_position = @scanner.pos
+ @commit = false
+ end
+
+ def commit!
+ @commit = true
+ end
+
+ def run(&block)
+ block.call(self)
+ ensure
+ @scanner.pos = @rewind_position unless @commit
+ end
+ end
+end
diff --git a/spec/lookahead_spec.rb b/spec/lookahead_spec.rb
new file mode 100644
index 0000000..391df07
--- /dev/null
+++ b/spec/lookahead_spec.rb
@@ -0,0 +1,14 @@
+RSpec.describe Mpeg::Lookahead do
+ def str(string)
+ Mpeg::Str.new(string)
+ end
+
+ def any
+ Mpeg::Re.new('.')
+ end
+
+ subject { str('"').absent? >> any.repeat }
+
+ specify { expect(subject.parse('"Hello')).to be_falsey }
+ specify { expect(subject.parse('Hello')).to be_truthy }
+end
diff --git a/spec/sequence_spec.rb b/spec/sequence_spec.rb
new file mode 100644
index 0000000..31041db
--- /dev/null
+++ b/spec/sequence_spec.rb
@@ -0,0 +1,19 @@
+RSpec.describe Mpeg::Sequence do
+ subject { Mpeg::Str.new('h') >> Mpeg::Str.new('i') }
+
+ context "when the sequence does match" do
+ let(:input) { Mpeg::Input.new('hi') }
+ let!(:result) { subject.parse('hi', input: input) }
+
+ specify { expect(result).to be_truthy }
+ specify { expect(input).to be_end_of_string }
+ end
+
+ context "when the sequence does not match" do
+ let(:input) { Mpeg::Input.new('hello') }
+ let!(:result) { subject.parse('hello', input: input) }
+
+ specify { expect(result).to be_falsey }
+ specify { expect(input.position).to be_zero }
+ end
+end