rley 0.0.13 → 0.0.14
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 +8 -8
- data/CHANGELOG.md +5 -0
- data/lib/rley/constants.rb +1 -1
- data/lib/rley/parser/dotted_item.rb +58 -56
- data/lib/rley/parser/earley_parser.rb +1 -1
- data/lib/rley/syntax/grammar_builder.rb +2 -0
- data/spec/rley/parser/earley_parser_spec.rb +148 -1
- data/spec/rley/syntax/grammar_builder_spec.rb +39 -11
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ODY2NWVkNGUzYzNlZDM0MmNhYWIyNGFkYjA2ZGU1NGYyZmNmZTkxMA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
N2RlYjRlNDc5OWIxZWU1YmIwMzA4MWY0MDBhYmFjYzJlZWIyZTVlNg==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NTBkMTExZWZiZGYxMWZjYTQ0MmUwMDA1ZDE4ZTBlNzYxMDhmZmRkOTdiMWNk
|
10
|
+
MzkwNWE0MmMzYjQzZGM5MjBiYjA3NTc3MmVkZDNmNmMzNTkxZGJiYjgxNDVl
|
11
|
+
ZGY1N2QwYTY3NzgxNDJjYzc4ZjU1YWRkMmYwNmVmN2JkZGE0OGY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
Zjc0YzVlNGU1N2YzNmQ3ZDRlM2VmYmYyNTJhZTQxNDdkZDBkZWYyYWVlZjcy
|
14
|
+
NGQwODhmZTcwYzQ1YmY2Y2EzOWEyMmRlMDFlMGUyZjM3NjA4MmU0OGU1YWJj
|
15
|
+
MjUwYmNjOWQ3NTAxYmY4ZjNiNWVlNWQ4ZmNjOThkMmQ0NGFkZDA=
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
### 0.0.14 / 2014-11-20
|
2
|
+
* [NEW] `EarleyParser` now supports grammar with empty productions (i.e. nullable nonterminals).
|
3
|
+
* [CHANGE] (private) method `EarleyParser#prediction` updated with Ayock-Horspool improvement.
|
4
|
+
* [CHANGE] Moved class `DottedItem` under the `Parser` module.
|
5
|
+
|
1
6
|
### 0.0.13 / 2014-11-19
|
2
7
|
* [NEW] (private) method `Grammar#compute_nullable` added.
|
3
8
|
* [CHANGE] `Grammar#initialize` constructor calls the method `Grammar#compute_nullable`
|
data/lib/rley/constants.rb
CHANGED
@@ -13,71 +13,73 @@ module Rley # This module is used as a namespace
|
|
13
13
|
# An item with the dot at the end (i.e. after all rhs symbols)
|
14
14
|
# is called a reduce item.
|
15
15
|
# An item with a dot in front of a terminal is called a shift item.
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
module Parser # This module is used as a namespace
|
17
|
+
class DottedItem
|
18
|
+
# Production rule
|
19
|
+
attr_reader(:production)
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
# Index of the next symbol (from the rhs) after the 'dot'.
|
22
|
+
# If the dot is at the end of the rhs (i.e.) there is no next
|
23
|
+
# symbol, then the position takes the value -1.
|
24
|
+
# It the rhs is empty, then the postion is -2
|
25
|
+
attr_reader(:position)
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
# @param aProduction
|
28
|
+
def initialize(aProduction, aPosition)
|
29
|
+
@production = aProduction
|
30
|
+
@position = valid_position(aPosition)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Return true if the dot position is at the start of the rhs.
|
34
|
+
def at_start?()
|
35
|
+
return position == 0 || position == -2
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
# An item with the dot at the beginning is called
|
39
|
+
# predicted item
|
40
|
+
alias_method :predicted_item?, :at_start?
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
42
|
+
# A dotted item is called a reduce item if the dot is at the end.
|
43
|
+
def reduce_item?()
|
44
|
+
return position < 0 # Either -1 or -2
|
45
|
+
end
|
46
|
+
|
47
|
+
# The non-terminal symbol that is on the left-side of the production
|
48
|
+
def lhs()
|
49
|
+
return production.lhs
|
50
|
+
end
|
51
|
+
|
52
|
+
# Return the symbol after the dot.
|
53
|
+
# nil is returned if the dot is at the end
|
54
|
+
def next_symbol()
|
55
|
+
return (position < 0) ? nil : production.rhs[position]
|
56
|
+
end
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
58
|
+
# An item with the dot in front of a terminal is called a shift item
|
59
|
+
def shift_item?()
|
60
|
+
end
|
60
61
|
|
61
|
-
|
62
|
+
private
|
62
63
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
64
|
+
# Return the given after its validation.
|
65
|
+
def valid_position(aPosition)
|
66
|
+
rhs_size = production.rhs.size
|
67
|
+
if aPosition < 0 || aPosition > rhs_size
|
68
|
+
fail StandardError, 'Out of bound index'
|
69
|
+
end
|
69
70
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
71
|
+
if rhs_size == 0
|
72
|
+
index = -2 # Minus 2 at start/end of empty production
|
73
|
+
elsif aPosition == rhs_size
|
74
|
+
index = -1 # Minus 1 at end of non-empty production
|
75
|
+
else
|
76
|
+
index = aPosition
|
77
|
+
end
|
77
78
|
|
78
|
-
|
79
|
-
|
80
|
-
|
79
|
+
return index
|
80
|
+
end
|
81
|
+
end # class
|
82
|
+
end # module
|
81
83
|
end # module
|
82
84
|
|
83
85
|
# End of file
|
@@ -63,7 +63,7 @@ module Rley # This module is used as a namespace
|
|
63
63
|
aGrammar.rules.each do |prod|
|
64
64
|
rhs_size = prod.rhs.size
|
65
65
|
if rhs_size == 0
|
66
|
-
items <<
|
66
|
+
items << DottedItem.new(prod, 0)
|
67
67
|
else
|
68
68
|
items += (0..rhs_size).map { |i| DottedItem.new(prod, i) }
|
69
69
|
end
|
@@ -48,6 +48,8 @@ module Rley # This module is used as a namespace
|
|
48
48
|
rhs_constituents = rhs_repr.map { |name| get_nonterminal(name) }
|
49
49
|
when String
|
50
50
|
rhs_constituents = [ get_nonterminal(rhs_repr) ]
|
51
|
+
when Terminal
|
52
|
+
rhs_constituents = [ rhs_repr ]
|
51
53
|
end
|
52
54
|
new_prod = Production.new(lhs, rhs_constituents)
|
53
55
|
productions << new_prod
|
@@ -5,6 +5,7 @@ require_relative '../../../lib/rley/syntax/non_terminal'
|
|
5
5
|
require_relative '../../../lib/rley/syntax/production'
|
6
6
|
require_relative '../../../lib/rley/syntax/grammar_builder'
|
7
7
|
require_relative '../../../lib/rley/parser/token'
|
8
|
+
require_relative '../../../lib/rley/parser/dotted_item'
|
8
9
|
# Load the class under test
|
9
10
|
require_relative '../../../lib/rley/parser/earley_parser'
|
10
11
|
|
@@ -373,7 +374,10 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
373
374
|
Token.new('*', t_star),
|
374
375
|
Token.new('4', t_int)
|
375
376
|
]
|
376
|
-
|
377
|
+
instance = EarleyParser.new(builder.grammar)
|
378
|
+
expect { instance.parse(tokens) }.not_to raise_error
|
379
|
+
parse_result = instance.parse(tokens)
|
380
|
+
expect(parse_result.success?).to eq(true)
|
377
381
|
end
|
378
382
|
|
379
383
|
|
@@ -432,6 +436,149 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
432
436
|
state_set_3 = parse_result.chart[3]
|
433
437
|
expect(state_set_3.states).to be_empty # This is an error symptom
|
434
438
|
end
|
439
|
+
|
440
|
+
it 'should parse a grammar with nullable nonterminals' do
|
441
|
+
# Grammar 4: A grammar with nullable nonterminal
|
442
|
+
# based on example in "Parsing Techniques" book (D. Grune, C. Jabobs)
|
443
|
+
# Z ::= E.
|
444
|
+
# E ::= E Q F.
|
445
|
+
# E ::= F.
|
446
|
+
# F ::= a.
|
447
|
+
# Q ::= *.
|
448
|
+
# Q ::= /.
|
449
|
+
# Q ::=.
|
450
|
+
t_a = Syntax::VerbatimSymbol.new('a')
|
451
|
+
t_star = Syntax::VerbatimSymbol.new('*')
|
452
|
+
t_slash = Syntax::VerbatimSymbol.new('/')
|
453
|
+
|
454
|
+
builder = Syntax::GrammarBuilder.new
|
455
|
+
builder.add_terminals(t_a, t_star, t_slash)
|
456
|
+
builder.add_production('Z' => 'E')
|
457
|
+
builder.add_production('E' => %w(E Q F))
|
458
|
+
builder.add_production('E' => 'F')
|
459
|
+
builder.add_production('F' => t_a)
|
460
|
+
builder.add_production('Q' => t_star)
|
461
|
+
builder.add_production('Q' => t_slash)
|
462
|
+
builder.add_production('Q' => []) # Empty production
|
463
|
+
tokens = [
|
464
|
+
Token.new('a', t_a),
|
465
|
+
Token.new('a', t_a),
|
466
|
+
Token.new('/', t_slash),
|
467
|
+
Token.new('a', t_a)
|
468
|
+
]
|
469
|
+
prod_Z = builder.productions[0]
|
470
|
+
prod_E1 = builder.productions[1]
|
471
|
+
prod_E2 = builder.productions[2]
|
472
|
+
prod_F = builder.productions[3]
|
473
|
+
prod_Q1 = builder.productions[4]
|
474
|
+
prod_Q2 = builder.productions[5]
|
475
|
+
prod_Q3 = builder.productions[6]
|
476
|
+
|
477
|
+
instance = EarleyParser.new(builder.grammar)
|
478
|
+
expect { instance.parse(tokens) }.not_to raise_error
|
479
|
+
parse_result = instance.parse(tokens)
|
480
|
+
expect(parse_result.success?).to eq(true)
|
481
|
+
|
482
|
+
###################### S(0) == . a a / a
|
483
|
+
# Expectation chart[0]:
|
484
|
+
# (1) S -> . E, 0 # start rule
|
485
|
+
# (2) E -> . E Q F, 0 # predict from (1)
|
486
|
+
# (3) E -> . F, 0 # predict from (1)
|
487
|
+
# (4) F -> . a # predict from (3)
|
488
|
+
expectations = [
|
489
|
+
{ origin: 0, production: prod_Z, dot: 0 },
|
490
|
+
{ origin: 0, production: prod_E1, dot: 0 },
|
491
|
+
{ origin: 0, production: prod_E2, dot: 0 },
|
492
|
+
{ origin: 0, production: prod_F, dot: 0 }
|
493
|
+
]
|
494
|
+
compare_state_set(parse_result.chart[0], expectations)
|
495
|
+
|
496
|
+
###################### S(1) == a . a / a
|
497
|
+
# Expectation chart[1]:
|
498
|
+
# (1) F -> a ., 0 # scan from S(0) 4
|
499
|
+
# (2) E -> F ., 0 # complete from (1) and S(0) 3
|
500
|
+
# (3) S -> E ., 0 # complete from (2) and S(0) 1
|
501
|
+
# (4) E -> E . Q F, 0 # complete from (2) and S(0) 2
|
502
|
+
# (5) Q -> . *, 1 # Predict from (4)
|
503
|
+
# (6) Q -> . /, 1 # Predict from (4)
|
504
|
+
# (7) Q -> ., 1 # Predict from (4)
|
505
|
+
# (8) E -> E Q . F, 0 # Modified predict from (4)
|
506
|
+
# (9) F -> . a, 1 # Predict from (8)
|
507
|
+
expectations = [
|
508
|
+
{ origin: 0, production: prod_F, dot: -1 },
|
509
|
+
{ origin: 0, production: prod_E2, dot: -1 },
|
510
|
+
{ origin: 0, production: prod_Z, dot: -1 },
|
511
|
+
{ origin: 0, production: prod_E1, dot: 1 },
|
512
|
+
{ origin: 1, production: prod_Q1, dot: 0 },
|
513
|
+
{ origin: 1, production: prod_Q2, dot: 0 },
|
514
|
+
{ origin: 1, production: prod_Q3, dot: -2 },
|
515
|
+
{ origin: 0, production: prod_E1, dot: 2 },
|
516
|
+
{ origin: 1, production: prod_F, dot: 0 }
|
517
|
+
]
|
518
|
+
compare_state_set(parse_result.chart[1], expectations)
|
519
|
+
|
520
|
+
###################### S(2) == a a . / a
|
521
|
+
# Expectation chart[2]:
|
522
|
+
# (1) F -> a ., 1 # scan from S(1) 9
|
523
|
+
# (2) E -> E Q F ., 0 # complete from (1) and S(1) 8
|
524
|
+
# (3) S -> E ., 0 # complete from (1) and S(0) 1
|
525
|
+
# (4) E -> E . Q F, 0 # complete from (1) and S(0) 2
|
526
|
+
# (5) Q -> . *, 2 # Predict from (4)
|
527
|
+
# (6) Q -> . /, 2 # Predict from (4)
|
528
|
+
# (7) Q -> ., 2 # Predict from (4)
|
529
|
+
# (8) E -> E Q . F, 0 # Complete from (5) and S(1) 4
|
530
|
+
# (9) F -> . a, 1 # Predict from (8)
|
531
|
+
expectations = [
|
532
|
+
{ origin: 1, production: prod_F, dot: -1 },
|
533
|
+
{ origin: 0, production: prod_E1, dot: -1 },
|
534
|
+
{ origin: 0, production: prod_Z, dot: -1 },
|
535
|
+
{ origin: 0, production: prod_E1, dot: 1 },
|
536
|
+
{ origin: 2, production: prod_Q1, dot: 0 },
|
537
|
+
{ origin: 2, production: prod_Q2, dot: 0 },
|
538
|
+
{ origin: 2, production: prod_Q3, dot: -2 },
|
539
|
+
{ origin: 0, production: prod_E1, dot: 2 },
|
540
|
+
{ origin: 2, production: prod_F, dot: 0 },
|
541
|
+
]
|
542
|
+
compare_state_set(parse_result.chart[2], expectations)
|
543
|
+
|
544
|
+
###################### S(3) == a a / . a
|
545
|
+
# Expectation chart[3]:
|
546
|
+
# (1) Q -> / ., 2 # scan from S(2) 6
|
547
|
+
# (2) E -> E Q . F, 0 # complete from (1) and S(1) 4
|
548
|
+
# (3) F -> . a, 3 # Predict from (2)
|
549
|
+
expectations = [
|
550
|
+
{ origin: 2, production: prod_Q2, dot: -1 },
|
551
|
+
{ origin: 0, production: prod_E1, dot: 2 },
|
552
|
+
{ origin: 3, production: prod_F, dot: 0 }
|
553
|
+
]
|
554
|
+
compare_state_set(parse_result.chart[3], expectations)
|
555
|
+
|
556
|
+
|
557
|
+
###################### S(4) == a a / a .
|
558
|
+
# Expectation chart[4]:
|
559
|
+
# (1) F -> a ., 3 # scan from S(3) 3
|
560
|
+
# (2) E -> E Q F ., 0 # complete from (1) and S(3) 2
|
561
|
+
# (3) S -> E ., 0 # complete from (2) and S(0) 1
|
562
|
+
# (4) E -> E . Q F, 0 # complete from (2) and S(0) 2
|
563
|
+
# (5) Q -> . *, 3 # Predict from (4)
|
564
|
+
# (6) Q -> . /, 3 # Predict from (4)
|
565
|
+
# (7) Q -> ., 3 # Predict from (4)
|
566
|
+
# (8) E -> E Q . F, 0 # Modified predict from (4)
|
567
|
+
# (9) F -> . a, 4 # Predict from (8)
|
568
|
+
expectations = [
|
569
|
+
{ origin: 3, production: prod_F, dot: -1 },
|
570
|
+
{ origin: 0, production: prod_E1, dot: -1 },
|
571
|
+
{ origin: 0, production: prod_Z, dot: -1 },
|
572
|
+
{ origin: 0, production: prod_E1, dot: 1 },
|
573
|
+
{ origin: 4, production: prod_Q1, dot: 0 },
|
574
|
+
{ origin: 4, production: prod_Q2, dot: 0 },
|
575
|
+
{ origin: 4, production: prod_Q3, dot: -2 },
|
576
|
+
{ origin: 0, production: prod_E1, dot: 2 },
|
577
|
+
{ origin: 4, production: prod_F, dot: 0 },
|
578
|
+
]
|
579
|
+
compare_state_set(parse_result.chart[4], expectations)
|
580
|
+
|
581
|
+
end
|
435
582
|
end # context
|
436
583
|
|
437
584
|
end # describe
|
@@ -11,7 +11,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
11
11
|
it 'should be created without argument' do
|
12
12
|
expect { GrammarBuilder.new }.not_to raise_error
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
it 'should have no grammar symbols at start' do
|
16
16
|
expect(subject.symbols).to be_empty
|
17
17
|
end
|
@@ -58,14 +58,14 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
58
58
|
expect(subject.symbols['c']).to eq(c)
|
59
59
|
end
|
60
60
|
end # context
|
61
|
-
|
61
|
+
|
62
62
|
context 'Adding productions:' do
|
63
63
|
subject do
|
64
64
|
instance = GrammarBuilder.new
|
65
65
|
instance.add_terminals('a', 'b', 'c')
|
66
66
|
instance
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
it 'should add a valid production' do
|
70
70
|
# case of a rhs representation that consists of one name
|
71
71
|
expect { subject.add_production('S' => 'A') }.not_to raise_error
|
@@ -73,22 +73,22 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
73
73
|
new_prod = subject.productions[0]
|
74
74
|
expect(new_prod.lhs).to eq(subject['S'])
|
75
75
|
expect(new_prod.rhs[0]).to eq(subject['A'])
|
76
|
-
|
76
|
+
|
77
77
|
subject.add_production('A' => %w(a A c))
|
78
78
|
expect(subject.productions.size).to eq(2)
|
79
79
|
new_prod = subject.productions.last
|
80
80
|
expect(new_prod.lhs).to eq(subject['A'])
|
81
81
|
expect_rhs = [ subject['a'], subject['A'], subject['c'] ]
|
82
82
|
expect(new_prod.rhs.members).to eq(expect_rhs)
|
83
|
-
|
83
|
+
|
84
84
|
subject.add_production('A' => ['b'])
|
85
85
|
expect(subject.productions.size).to eq(3)
|
86
86
|
new_prod = subject.productions.last
|
87
87
|
expect(new_prod.lhs).to eq(subject['A'])
|
88
88
|
expect(new_prod.rhs[0]).to eq(subject['b'])
|
89
|
-
end
|
89
|
+
end
|
90
90
|
end # context
|
91
|
-
|
91
|
+
|
92
92
|
context 'Building grammar:' do
|
93
93
|
subject do
|
94
94
|
instance = GrammarBuilder.new
|
@@ -98,20 +98,20 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
98
98
|
instance.add_production('A' => ['b'])
|
99
99
|
instance
|
100
100
|
end
|
101
|
-
|
101
|
+
|
102
102
|
it 'should build a grammar' do
|
103
103
|
expect(subject.grammar).to be_kind_of(Grammar)
|
104
104
|
grm = subject.grammar
|
105
105
|
expect(grm.rules).to eq(subject.productions)
|
106
106
|
end
|
107
|
-
|
107
|
+
|
108
108
|
it 'should complain in absence of symbols' do
|
109
109
|
instance = GrammarBuilder.new
|
110
110
|
err = StandardError
|
111
111
|
msg = 'No symbol found for grammar'
|
112
112
|
expect { instance.grammar }.to raise_error(err, msg)
|
113
113
|
end
|
114
|
-
|
114
|
+
|
115
115
|
it 'should complain in absence of productions' do
|
116
116
|
instance = GrammarBuilder.new
|
117
117
|
instance.add_terminals('a', 'b', 'c')
|
@@ -119,7 +119,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
119
119
|
msg = 'No production found for grammar'
|
120
120
|
expect { instance.grammar }.to raise_error(err, msg)
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
it 'should complain when non-terminal has no production' do
|
124
124
|
instance = GrammarBuilder.new
|
125
125
|
instance.add_terminals('a', 'b', 'c')
|
@@ -128,6 +128,34 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
128
128
|
msg = 'Nonterminal A not rewritten'
|
129
129
|
expect { instance.grammar }.to raise_error(err, msg)
|
130
130
|
end
|
131
|
+
|
132
|
+
it 'should build a grammar with nullable nonterminals' do
|
133
|
+
# Grammar 4: A grammar with nullable nonterminal
|
134
|
+
# based on example in "Parsing Techniques" book (D. Grune, C. Jabobs)
|
135
|
+
# S ::= E.
|
136
|
+
# E ::= E Q F.
|
137
|
+
# E ::= F.
|
138
|
+
# F ::= a.
|
139
|
+
# Q ::= *.
|
140
|
+
# Q ::= /.
|
141
|
+
# Q ::=.
|
142
|
+
t_a = VerbatimSymbol.new('a')
|
143
|
+
t_star = VerbatimSymbol.new('*')
|
144
|
+
t_slash = VerbatimSymbol.new('/')
|
145
|
+
|
146
|
+
builder = GrammarBuilder.new
|
147
|
+
builder.add_terminals(t_a, t_star, t_slash)
|
148
|
+
builder.add_production('S' => 'E')
|
149
|
+
builder.add_production('E' => %w(E Q F))
|
150
|
+
builder.add_production('E' => 'F')
|
151
|
+
builder.add_production('F' => t_a)
|
152
|
+
builder.add_production('Q' => t_star)
|
153
|
+
builder.add_production('Q' => t_slash)
|
154
|
+
builder.add_production('Q' => []) # Empty production
|
155
|
+
|
156
|
+
expect { builder.grammar }.not_to raise_error
|
157
|
+
expect(builder.productions.last).to be_empty
|
158
|
+
end
|
131
159
|
end
|
132
160
|
|
133
161
|
end # describe
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rley
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|