d-parse 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.
- checksums.yaml +7 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +104 -0
- data/Guardfile +3 -0
- data/LICENSE +19 -0
- data/NEWS.md +0 -0
- data/README.md +137 -0
- data/Rakefile +14 -0
- data/d-parse.gemspec +26 -0
- data/lib/d-parse.rb +10 -0
- data/lib/d-parse/dsl.rb +71 -0
- data/lib/d-parse/failure.rb +46 -0
- data/lib/d-parse/parser.rb +102 -0
- data/lib/d-parse/parsers.rb +26 -0
- data/lib/d-parse/parsers/combinators/alt.rb +32 -0
- data/lib/d-parse/parsers/combinators/repeat.rb +42 -0
- data/lib/d-parse/parsers/combinators/seq.rb +49 -0
- data/lib/d-parse/parsers/highlevel/char_in.rb +13 -0
- data/lib/d-parse/parsers/highlevel/intersperse.rb +18 -0
- data/lib/d-parse/parsers/highlevel/json.rb +237 -0
- data/lib/d-parse/parsers/highlevel/opt.rb +16 -0
- data/lib/d-parse/parsers/highlevel/string.rb +13 -0
- data/lib/d-parse/parsers/highlevel/whitespace_char.rb +15 -0
- data/lib/d-parse/parsers/modifiers/capturing.rb +13 -0
- data/lib/d-parse/parsers/modifiers/describe.rb +28 -0
- data/lib/d-parse/parsers/modifiers/ignore.rb +17 -0
- data/lib/d-parse/parsers/modifiers/lazy.rb +18 -0
- data/lib/d-parse/parsers/modifiers/map.rb +24 -0
- data/lib/d-parse/parsers/primitives/any.rb +22 -0
- data/lib/d-parse/parsers/primitives/bind.rb +25 -0
- data/lib/d-parse/parsers/primitives/char.rb +27 -0
- data/lib/d-parse/parsers/primitives/char_not.rb +27 -0
- data/lib/d-parse/parsers/primitives/char_not_in.rb +30 -0
- data/lib/d-parse/parsers/primitives/eof.rb +21 -0
- data/lib/d-parse/parsers/primitives/except.rb +33 -0
- data/lib/d-parse/parsers/primitives/fail.rb +17 -0
- data/lib/d-parse/parsers/primitives/succeed.rb +13 -0
- data/lib/d-parse/position.rb +31 -0
- data/lib/d-parse/success.rb +35 -0
- data/lib/d-parse/version.rb +3 -0
- data/samples/parse-bind +25 -0
- data/samples/parse-csv +19 -0
- data/samples/parse-errortest +45 -0
- data/samples/parse-fun +61 -0
- data/samples/parse-json +18 -0
- data/samples/parse-readme +27 -0
- data/spec/d-parse/failure_spec.rb +36 -0
- data/spec/d-parse/parser_spec.rb +77 -0
- data/spec/d-parse/parsers/alt_spec.rb +48 -0
- data/spec/d-parse/parsers/any_spec.rb +15 -0
- data/spec/d-parse/parsers/bind_spec.rb +31 -0
- data/spec/d-parse/parsers/capture_spec.rb +11 -0
- data/spec/d-parse/parsers/char_in_spec.rb +22 -0
- data/spec/d-parse/parsers/char_not_in_spec.rb +23 -0
- data/spec/d-parse/parsers/char_not_spec.rb +16 -0
- data/spec/d-parse/parsers/char_spec.rb +22 -0
- data/spec/d-parse/parsers/describe_spec.rb +22 -0
- data/spec/d-parse/parsers/end_of_input_spec.rb +20 -0
- data/spec/d-parse/parsers/except_spec.rb +20 -0
- data/spec/d-parse/parsers/fail_spec.rb +12 -0
- data/spec/d-parse/parsers/intersperse_spec.rb +18 -0
- data/spec/d-parse/parsers/json_spec.rb +69 -0
- data/spec/d-parse/parsers/lazy_spec.rb +16 -0
- data/spec/d-parse/parsers/map_spec.rb +54 -0
- data/spec/d-parse/parsers/optional_spec.rb +16 -0
- data/spec/d-parse/parsers/or_spec.rb +26 -0
- data/spec/d-parse/parsers/repeat_spec.rb +40 -0
- data/spec/d-parse/parsers/sequence_spec.rb +52 -0
- data/spec/d-parse/parsers/string_spec.rb +19 -0
- data/spec/d-parse/parsers/succeed_spec.rb +12 -0
- data/spec/d-parse/parsers/whitespace_char_spec.rb +14 -0
- data/spec/spec_helper.rb +97 -0
- metadata +140 -0
data/samples/parse-bind
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'd-parse'
|
4
|
+
|
5
|
+
include DParse::DSL
|
6
|
+
|
7
|
+
digit = chars(*('0'..'9')).capture
|
8
|
+
letter = chars(*('a'..'z')).capture
|
9
|
+
|
10
|
+
init = alt(char('d'), char('l')).capture
|
11
|
+
|
12
|
+
parser_map = {
|
13
|
+
'd' => digit,
|
14
|
+
'l' => letter,
|
15
|
+
}
|
16
|
+
|
17
|
+
pair =
|
18
|
+
init.bind do |data|
|
19
|
+
new_parser = parser_map[data]
|
20
|
+
new_parser.map { |d| [data, d] }
|
21
|
+
end
|
22
|
+
|
23
|
+
parser = repeat(pair)
|
24
|
+
|
25
|
+
p parser.apply('lad1d2d3lblc')
|
data/samples/parse-csv
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'd-parse'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
data = <<EOS
|
7
|
+
first_name,last_name,age
|
8
|
+
Denis,Defreyne,29
|
9
|
+
EOS
|
10
|
+
|
11
|
+
module Grammar
|
12
|
+
extend DParse::DSL
|
13
|
+
|
14
|
+
FIELD = repeat(char_not_in([',', "\n"])).capture
|
15
|
+
LINE = intersperse(FIELD, char(',')).select_even
|
16
|
+
FILE = seq(intersperse(LINE, char("\n")).select_even, eof).first
|
17
|
+
end
|
18
|
+
|
19
|
+
pp Grammar::FILE.apply(data)
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'd-parse'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
module MyGrammar
|
7
|
+
extend DParse::DSL
|
8
|
+
|
9
|
+
LETTER =
|
10
|
+
describe(alt(*('a'..'z').map { |c| char(c) }), 'letter')
|
11
|
+
|
12
|
+
IDENTIFIER =
|
13
|
+
describe(
|
14
|
+
repeat(LETTER).capture,
|
15
|
+
'identifier',
|
16
|
+
)
|
17
|
+
|
18
|
+
FUNDEF =
|
19
|
+
seq(
|
20
|
+
describe(IDENTIFIER, 'identifier'),
|
21
|
+
eof,
|
22
|
+
)
|
23
|
+
|
24
|
+
PARSER =
|
25
|
+
alt(
|
26
|
+
string('Hello!'),
|
27
|
+
string('Hello, world!'),
|
28
|
+
string('Hello… ?'),
|
29
|
+
)
|
30
|
+
|
31
|
+
TESTB =
|
32
|
+
seq(
|
33
|
+
alt(
|
34
|
+
seq(string('a+a').capture),
|
35
|
+
seq(string('a').capture),
|
36
|
+
),
|
37
|
+
eof,
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
puts MyGrammar::PARSER.apply('Hello, what?').pretty_message
|
42
|
+
puts
|
43
|
+
puts MyGrammar::FUNDEF.apply('foo3a').pretty_message
|
44
|
+
puts
|
45
|
+
puts MyGrammar::TESTB.apply('a+').pretty_message
|
data/samples/parse-fun
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'd-parse'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
data = <<EOS
|
7
|
+
add(1, mul(2, 3))
|
8
|
+
mul(2,3)
|
9
|
+
EOS
|
10
|
+
|
11
|
+
include DParse::DSL
|
12
|
+
|
13
|
+
# primitives
|
14
|
+
digit = describe(alt(*('0'..'9').map { |c| char(c) }), 'digit')
|
15
|
+
letter = describe(alt(*('a'..'z').map { |c| char(c) }), 'letter')
|
16
|
+
lparen = char('(')
|
17
|
+
rparen = char(')')
|
18
|
+
comma = char(',')
|
19
|
+
|
20
|
+
# basic
|
21
|
+
identifier = describe(seq(letter, repeat(letter)).capture, 'identifier')
|
22
|
+
lit = seq(digit, repeat(digit)).capture.map { |d| d.to_i(10) }
|
23
|
+
eof_with_opt_nl = seq(opt(char("\n")), eof)
|
24
|
+
whitespace = repeat(whitespace_char)
|
25
|
+
|
26
|
+
# complex
|
27
|
+
funcall = nil
|
28
|
+
expression = alt(lazy { funcall }, lit)
|
29
|
+
arglist_tail = repeat(seq(comma, whitespace, expression).map { |d| d[2] })
|
30
|
+
arglist = seq(expression, arglist_tail).map { |d| [d[0]] + d[1] }
|
31
|
+
funcall = seq(identifier, lparen, arglist, rparen).map { |d| [d[0]] + d[2] }
|
32
|
+
program = seq(intersperse(expression, char("\n")).select_even, eof_with_opt_nl).first
|
33
|
+
|
34
|
+
def eval_expr(expr)
|
35
|
+
case expr
|
36
|
+
when Array
|
37
|
+
case expr[0]
|
38
|
+
when 'add'
|
39
|
+
eval_expr(expr[1]) + eval_expr(expr[2])
|
40
|
+
when 'mul'
|
41
|
+
eval_expr(expr[1]) * eval_expr(expr[2])
|
42
|
+
else
|
43
|
+
raise '???'
|
44
|
+
end
|
45
|
+
when Integer
|
46
|
+
expr
|
47
|
+
else
|
48
|
+
raise '???'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
res = program.apply(data)
|
53
|
+
case res
|
54
|
+
when DParse::Success
|
55
|
+
exprs = res.data
|
56
|
+
pp exprs
|
57
|
+
exprs.each { |e| p eval_expr(e) }
|
58
|
+
when DParse::Failure
|
59
|
+
$stderr.puts res.pretty_message
|
60
|
+
exit 1
|
61
|
+
end
|
data/samples/parse-json
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'd-parse'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
json = DParse::Parsers::JSON.new
|
7
|
+
|
8
|
+
puts "[#{Time.now}] start"
|
9
|
+
res = json.apply($stdin.read)
|
10
|
+
puts "[#{Time.now}] stop"
|
11
|
+
puts
|
12
|
+
|
13
|
+
case res
|
14
|
+
when DParse::Success
|
15
|
+
pp res.data
|
16
|
+
when DParse::Failure
|
17
|
+
puts res.pretty_message
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'd-parse'
|
4
|
+
|
5
|
+
module Grammar
|
6
|
+
extend DParse::DSL
|
7
|
+
|
8
|
+
DIGIT = char_in('0'..'9')
|
9
|
+
|
10
|
+
ROOT =
|
11
|
+
seq(
|
12
|
+
intersperse(
|
13
|
+
repeat(DIGIT).capture.map { |d| d.to_i(10) },
|
14
|
+
char(',').ignore,
|
15
|
+
).compact,
|
16
|
+
eof,
|
17
|
+
).first
|
18
|
+
end
|
19
|
+
|
20
|
+
res = Grammar::ROOT.apply('1,2,100,582048,07,09')
|
21
|
+
case res
|
22
|
+
when DParse::Success
|
23
|
+
p res.data
|
24
|
+
when DParse::Failure
|
25
|
+
$stderr.puts res.pretty_message
|
26
|
+
exit 1
|
27
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
describe DParse::Failure do
|
2
|
+
let(:failure) { described_class.new("one\ntwo\nthree\nfour\nfive", position, origin: origin) }
|
3
|
+
|
4
|
+
let(:position) { DParse::Position.new(index: 13, line: 2, column: 3) }
|
5
|
+
let(:origin) { double(:origin, expectation_message: expectation_message) }
|
6
|
+
let(:expectation_message) { 'lols' }
|
7
|
+
|
8
|
+
describe '#full_message' do
|
9
|
+
subject { failure.full_message }
|
10
|
+
it { is_expected.to eql('expected lols at line 3, column 4') }
|
11
|
+
|
12
|
+
context 'no origin' do
|
13
|
+
let(:origin) { nil }
|
14
|
+
it { is_expected.to eql('expected ? at line 3, column 4') }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#pretty_message' do
|
19
|
+
subject { failure.pretty_message }
|
20
|
+
|
21
|
+
context 'column 3' do
|
22
|
+
let(:position) { DParse::Position.new(index: 13, line: 2, column: 3) }
|
23
|
+
it { is_expected.to eql("expected lols at line 3, column 4\n\nthr\e[31me\e[0me\n\e[31m ↑\e[0m") }
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'column 4' do
|
27
|
+
let(:position) { DParse::Position.new(index: 14, line: 2, column: 4) }
|
28
|
+
it { is_expected.to eql("expected lols at line 3, column 5\n\nthre\e[31me\e[0m\n\e[31m ↑\e[0m") }
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'column 5' do
|
32
|
+
let(:position) { DParse::Position.new(index: 15, line: 2, column: 5) }
|
33
|
+
it { is_expected.to eql("expected lols at line 3, column 6\n\nthree\n\e[31m ↑\e[0m") }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
describe DParse::Parser do
|
2
|
+
context 'bare parser' do
|
3
|
+
let(:klass) do
|
4
|
+
Class.new(described_class) do
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:parser) { klass.new }
|
9
|
+
|
10
|
+
it 'errors on #read' do
|
11
|
+
expect { parser.read('foo', :some_pos) }.to raise_error(NotImplementedError)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'errors on #inspect' do
|
15
|
+
expect { parser.inspect }.to raise_error(NotImplementedError)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'parser returning an array' do
|
20
|
+
let(:klass) do
|
21
|
+
Class.new(described_class) do
|
22
|
+
def initialize(result)
|
23
|
+
@result = result
|
24
|
+
end
|
25
|
+
|
26
|
+
def read(_input, _pos)
|
27
|
+
@result
|
28
|
+
end
|
29
|
+
|
30
|
+
def inspect
|
31
|
+
'sample()'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:result) { DParse::Success.new('…', pos, data: [:a, :b, :c, :d, :e]) }
|
37
|
+
let(:pos) { DParse::Position.new(index: 0, line: 0, column: 0) }
|
38
|
+
|
39
|
+
let(:parser) { klass.new(result) }
|
40
|
+
|
41
|
+
describe '#first' do
|
42
|
+
subject { parser.first }
|
43
|
+
example { expect(subject).to parse('…').and_capture(:a) }
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#second' do
|
47
|
+
subject { parser.second }
|
48
|
+
example { expect(subject).to parse('…').and_capture(:b) }
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#select_even' do
|
52
|
+
subject { parser.select_even }
|
53
|
+
example { expect(subject).to parse('…').and_capture([:a, :c, :e]) }
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#select_odd' do
|
57
|
+
subject { parser.select_odd }
|
58
|
+
example { expect(subject).to parse('…').and_capture([:b, :d]) }
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#match?' do
|
62
|
+
subject { parser.match?('…') }
|
63
|
+
|
64
|
+
let(:pos) { DParse::Position.new(index: 0, line: 0, column: 0) }
|
65
|
+
|
66
|
+
context 'failure' do
|
67
|
+
let(:result) { DParse::Failure.new('…', pos) }
|
68
|
+
it { is_expected.to equal(false) }
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'success' do
|
72
|
+
let(:result) { DParse::Success.new('…', pos) }
|
73
|
+
it { is_expected.to equal(true) }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
describe DParse::Parsers::Alt do
|
2
|
+
let(:a) { DParse::Parsers::String.new('Hello') }
|
3
|
+
let(:b) { DParse::Parsers::String.new('Goodbye') }
|
4
|
+
let(:parser) { described_class.new(a, b) }
|
5
|
+
|
6
|
+
example { expect(parser).to parse('Hello').up_to(5).line(0).column(5) }
|
7
|
+
example { expect(parser).to parse('Goodbye').up_to(7).line(0).column(7) }
|
8
|
+
|
9
|
+
example { expect(parser).not_to parse('').and_fail_at(0).line(0).column(0).with_failure('expected \'H\'') }
|
10
|
+
example { expect(parser).not_to parse('Wilkommen').and_fail_at(0).line(0).column(0).with_failure('expected \'H\'') }
|
11
|
+
example { expect(parser).not_to parse('Hallo').and_fail_at(1).line(0).column(1).with_failure('expected \'e\'') }
|
12
|
+
example { expect(parser).not_to parse('Hellenistic period').and_fail_at(4).line(0).column(4).with_failure('expected \'o\'') }
|
13
|
+
|
14
|
+
describe '#inspect' do
|
15
|
+
subject { parser.inspect }
|
16
|
+
|
17
|
+
let(:a) { DParse::Parsers::Char.new('a') }
|
18
|
+
let(:b) { DParse::Parsers::Char.new('b') }
|
19
|
+
|
20
|
+
it { is_expected.to eql('alt(char("a"),char("b"))') }
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'ambiguous parsers' do
|
24
|
+
let(:a) { double('parser') }
|
25
|
+
let(:b) { double('parser') }
|
26
|
+
|
27
|
+
before do
|
28
|
+
expect(a).to receive(:read).and_return(DParse::Failure.new('…', DParse::Position.new(index: 10, line: 0, column: 10)))
|
29
|
+
expect(b).to receive(:read).and_return(DParse::Failure.new('…', DParse::Position.new(index: 20, line: 0, column: 20)))
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'shortest first' do
|
33
|
+
let(:parser) { described_class.new(a, b) }
|
34
|
+
|
35
|
+
it 'picks the most specific failure' do
|
36
|
+
expect(parser).not_to parse('…').and_fail_at(20).line(0).column(20)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'longest first' do
|
41
|
+
let(:parser) { described_class.new(b, a) }
|
42
|
+
|
43
|
+
it 'picks the most specific failure' do
|
44
|
+
expect(parser).not_to parse('…').and_fail_at(20).line(0).column(20)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
describe DParse::Parsers::Any do
|
2
|
+
let(:parser) { described_class.new }
|
3
|
+
|
4
|
+
example { expect(parser).to parse('a').up_to(1).line(0).column(1) }
|
5
|
+
example { expect(parser).to parse('b').up_to(1).line(0).column(1) }
|
6
|
+
example { expect(parser).to parse('ab').up_to(1).line(0).column(1) }
|
7
|
+
|
8
|
+
example { expect(parser).not_to parse('').and_fail_at(0).line(0).column(0).with_failure('expected any character except end of file') }
|
9
|
+
|
10
|
+
describe '#inspect' do
|
11
|
+
subject { parser.inspect }
|
12
|
+
|
13
|
+
it { is_expected.to eql('any()') }
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
describe DParse::Parsers::Bind do
|
2
|
+
let(:a) { DParse::Parsers::Char.new('a') }
|
3
|
+
let(:b) { DParse::Parsers::Char.new('b') }
|
4
|
+
|
5
|
+
let(:init) { DParse::Parsers::Alt.new(a, b).capture }
|
6
|
+
|
7
|
+
let(:parser) do
|
8
|
+
parser_map = {
|
9
|
+
'a' => DParse::Parsers::Char.new('0'),
|
10
|
+
'b' => DParse::Parsers::Char.new('1'),
|
11
|
+
}
|
12
|
+
|
13
|
+
init.bind do |data|
|
14
|
+
new_parser = parser_map[data]
|
15
|
+
new_parser.map { |d| [data, d] }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
example { expect(parser).to parse('a0').up_to(2).line(0).column(2) }
|
20
|
+
example { expect(parser).to parse('b1').up_to(2).line(0).column(2) }
|
21
|
+
|
22
|
+
example { expect(parser).not_to parse('').and_fail_at(0).line(0).column(0) }
|
23
|
+
example { expect(parser).not_to parse('a').and_fail_at(1).line(0).column(1) }
|
24
|
+
example { expect(parser).not_to parse('aa').and_fail_at(1).line(0).column(1) }
|
25
|
+
example { expect(parser).not_to parse('ab').and_fail_at(1).line(0).column(1) }
|
26
|
+
example { expect(parser).not_to parse('a1').and_fail_at(1).line(0).column(1) }
|
27
|
+
example { expect(parser).not_to parse('b').and_fail_at(1).line(0).column(1) }
|
28
|
+
example { expect(parser).not_to parse('ba').and_fail_at(1).line(0).column(1) }
|
29
|
+
example { expect(parser).not_to parse('bb').and_fail_at(1).line(0).column(1) }
|
30
|
+
example { expect(parser).not_to parse('b0').and_fail_at(1).line(0).column(1) }
|
31
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
describe DParse::Parsers::Capturing do
|
2
|
+
let(:any) { DParse::Parsers::Any.new }
|
3
|
+
let(:parser) { described_class.new(any) }
|
4
|
+
|
5
|
+
example { expect(parser).to parse('a').up_to(1).line(0).column(1).and_capture('a') }
|
6
|
+
example { expect(parser).to parse('aa').up_to(1).line(0).column(1).and_capture('a') }
|
7
|
+
example { expect(parser).to parse('ab').up_to(1).line(0).column(1).and_capture('a') }
|
8
|
+
example { expect(parser).to parse('ba').up_to(1).line(0).column(1).and_capture('b') }
|
9
|
+
|
10
|
+
example { expect(parser).not_to parse('').and_fail_at(0).line(0).column(0) }
|
11
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
describe DParse::Parsers::CharIn do
|
2
|
+
let(:parser) { described_class.new(%w(a b)) }
|
3
|
+
|
4
|
+
example { expect(parser).to parse('a').up_to(1) }
|
5
|
+
example { expect(parser).to parse('b').up_to(1) }
|
6
|
+
example { expect(parser).to parse('ab').up_to(1) }
|
7
|
+
example { expect(parser).to parse('ac').up_to(1) }
|
8
|
+
example { expect(parser).to parse('ba').up_to(1) }
|
9
|
+
example { expect(parser).to parse('bc').up_to(1) }
|
10
|
+
|
11
|
+
example { expect(parser).not_to parse('').and_fail_at(0).line(0).column(0) }
|
12
|
+
example { expect(parser).not_to parse('c').and_fail_at(0).line(0).column(0) }
|
13
|
+
example { expect(parser).not_to parse('d').and_fail_at(0).line(0).column(0) }
|
14
|
+
example { expect(parser).not_to parse('ca').and_fail_at(0).line(0).column(0) }
|
15
|
+
example { expect(parser).not_to parse('db').and_fail_at(0).line(0).column(0) }
|
16
|
+
|
17
|
+
describe '#inspect' do
|
18
|
+
subject { parser.inspect }
|
19
|
+
|
20
|
+
it { is_expected.to eql('alt(char("a"),char("b"))') }
|
21
|
+
end
|
22
|
+
end
|