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
         
     |