rley 0.3.04 → 0.3.05

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.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -3
  3. data/CHANGELOG.md +3 -0
  4. data/Rakefile +30 -30
  5. data/examples/parsers/parsing_L0.rb +1 -1
  6. data/examples/parsers/parsing_L1.rb +1 -1
  7. data/examples/parsers/parsing_abc.rb +1 -1
  8. data/examples/parsers/parsing_ambig.rb +1 -1
  9. data/examples/parsers/parsing_another.rb +1 -1
  10. data/examples/parsers/parsing_b_expr.rb +1 -1
  11. data/examples/parsers/parsing_err_expr.rb +1 -1
  12. data/examples/parsers/parsing_groucho.rb +1 -1
  13. data/examples/parsers/parsing_right_recursive.rb +1 -1
  14. data/examples/parsers/parsing_tricky.rb +1 -1
  15. data/lib/rley/constants.rb +2 -2
  16. data/lib/rley/formatter/base_formatter.rb +0 -2
  17. data/lib/rley/formatter/debug.rb +0 -2
  18. data/lib/rley/formatter/json.rb +1 -3
  19. data/lib/rley/gfg/call_edge.rb +31 -30
  20. data/lib/rley/gfg/edge.rb +22 -23
  21. data/lib/rley/gfg/end_vertex.rb +22 -24
  22. data/lib/rley/gfg/epsilon_edge.rb +20 -21
  23. data/lib/rley/gfg/grm_flow_graph.rb +39 -39
  24. data/lib/rley/gfg/item_vertex.rb +16 -17
  25. data/lib/rley/gfg/non_terminal_vertex.rb +3 -4
  26. data/lib/rley/gfg/return_edge.rb +32 -31
  27. data/lib/rley/gfg/scan_edge.rb +25 -26
  28. data/lib/rley/gfg/shortcut_edge.rb +25 -26
  29. data/lib/rley/gfg/start_vertex.rb +0 -2
  30. data/lib/rley/gfg/vertex.rb +8 -8
  31. data/lib/rley/parse_forest_visitor.rb +113 -115
  32. data/lib/rley/parse_tree_visitor.rb +0 -2
  33. data/lib/rley/parser/base_parser.rb +27 -27
  34. data/lib/rley/parser/chart.rb +14 -14
  35. data/lib/rley/parser/dotted_item.rb +33 -33
  36. data/lib/rley/parser/earley_parser.rb +6 -6
  37. data/lib/rley/parser/gfg_chart.rb +8 -15
  38. data/lib/rley/parser/gfg_earley_parser.rb +15 -13
  39. data/lib/rley/parser/gfg_parsing.rb +26 -22
  40. data/lib/rley/parser/grm_items_builder.rb +3 -2
  41. data/lib/rley/parser/parse_entry.rb +3 -9
  42. data/lib/rley/parser/parse_entry_set.rb +14 -19
  43. data/lib/rley/parser/parse_entry_tracker.rb +56 -56
  44. data/lib/rley/parser/parse_forest_builder.rb +215 -214
  45. data/lib/rley/parser/parse_forest_factory.rb +57 -56
  46. data/lib/rley/parser/parse_state.rb +8 -11
  47. data/lib/rley/parser/parse_state_tracker.rb +56 -56
  48. data/lib/rley/parser/parse_tracer.rb +3 -3
  49. data/lib/rley/parser/parse_tree_builder.rb +10 -10
  50. data/lib/rley/parser/parse_walker_factory.rb +30 -33
  51. data/lib/rley/parser/parsing.rb +8 -8
  52. data/lib/rley/parser/state_set.rb +23 -26
  53. data/lib/rley/ptree/non_terminal_node.rb +1 -1
  54. data/lib/rley/ptree/token_range.rb +2 -2
  55. data/lib/rley/sppf/alternative_node.rb +32 -34
  56. data/lib/rley/sppf/composite_node.rb +27 -27
  57. data/lib/rley/sppf/epsilon_node.rb +26 -27
  58. data/lib/rley/sppf/leaf_node.rb +11 -12
  59. data/lib/rley/sppf/non_terminal_node.rb +37 -38
  60. data/lib/rley/sppf/sppf_node.rb +1 -1
  61. data/lib/rley/sppf/token_node.rb +29 -29
  62. data/lib/rley/syntax/grammar.rb +1 -3
  63. data/lib/rley/syntax/grammar_builder.rb +8 -8
  64. data/lib/rley/syntax/non_terminal.rb +2 -4
  65. data/lib/rley/syntax/production.rb +3 -3
  66. data/lib/rley/syntax/symbol_seq.rb +1 -1
  67. data/spec/rley/gfg/call_edge_spec.rb +50 -51
  68. data/spec/rley/gfg/edge_spec.rb +33 -33
  69. data/spec/rley/gfg/end_vertex_spec.rb +26 -27
  70. data/spec/rley/gfg/epsilon_edge_spec.rb +25 -25
  71. data/spec/rley/gfg/grm_flow_graph_spec.rb +1 -1
  72. data/spec/rley/gfg/item_vertex_spec.rb +3 -4
  73. data/spec/rley/gfg/return_edge_spec.rb +51 -51
  74. data/spec/rley/gfg/scan_edge_spec.rb +32 -30
  75. data/spec/rley/gfg/shortcut_edge_spec.rb +1 -1
  76. data/spec/rley/gfg/vertex_spec.rb +3 -3
  77. data/spec/rley/parse_forest_visitor_spec.rb +239 -238
  78. data/spec/rley/parser/dotted_item_spec.rb +1 -1
  79. data/spec/rley/parser/earley_parser_spec.rb +16 -16
  80. data/spec/rley/parser/gfg_earley_parser_spec.rb +30 -31
  81. data/spec/rley/parser/gfg_parsing_spec.rb +11 -10
  82. data/spec/rley/parser/grm_items_builder_spec.rb +2 -2
  83. data/spec/rley/parser/parse_entry_set_spec.rb +4 -4
  84. data/spec/rley/parser/parse_entry_spec.rb +0 -2
  85. data/spec/rley/parser/parse_forest_builder_spec.rb +82 -57
  86. data/spec/rley/parser/parse_forest_factory_spec.rb +84 -82
  87. data/spec/rley/parser/parse_walker_factory_spec.rb +10 -9
  88. data/spec/rley/parser/parsing_spec.rb +0 -1
  89. data/spec/rley/sppf/alternative_node_spec.rb +2 -2
  90. data/spec/rley/sppf/non_terminal_node_spec.rb +0 -1
  91. data/spec/rley/support/ambiguous_grammar_helper.rb +1 -1
  92. data/spec/rley/support/expectation_helper.rb +37 -36
  93. data/spec/rley/support/grammar_abc_helper.rb +17 -17
  94. data/spec/rley/support/grammar_b_expr_helper.rb +40 -39
  95. data/spec/rley/support/grammar_helper.rb +2 -1
  96. data/spec/rley/support/{grammar_L0_helper.rb → grammar_l0_helper.rb} +82 -81
  97. data/spec/rley/support/grammar_sppf_helper.rb +24 -25
  98. data/spec/rley/syntax/grammar_spec.rb +1 -1
  99. metadata +2 -2
@@ -1,115 +1,113 @@
1
- module Rley # This module is used as a namespace
2
- # A visitor class dedicated in the visit of a parse forest.
3
- # It combines the Visitor and Observer patterns.
4
- class ParseForestVisitor
5
- # Link to the parse forest to visit
6
- attr_reader(:pforest)
7
-
8
- # List of objects that subscribed to the visit event notification.
9
- attr_reader(:subscribers)
10
-
11
- # A Hash with pairs of the form: Node => node visit data
12
- attr_reader(:agenda)
13
-
14
- # Indicates the kind of forest traversal to perform: :post_order, :pre-order
15
- attr_reader(:traversal)
16
-
17
- # Build a visitor for the given pforest.
18
- # @param aParseForest [ParseForest] the parse tree to visit.
19
- def initialize(aParseForest, aTraversalStrategy = :post_order)
20
- @pforest = aParseForest
21
- @subscribers = []
22
- @traversal = aTraversalStrategy
23
- end
24
-
25
- public
26
-
27
- # Add a subscriber for the visit event notifications.
28
- # @param aSubscriber [Object]
29
- def subscribe(aSubscriber)
30
- subscribers << aSubscriber
31
- end
32
-
33
- # Remove the given object from the subscription list.
34
- # The object won't be notified of visit events.
35
- # @param aSubscriber [Object]
36
- def unsubscribe(aSubscriber)
37
- subscribers.delete_if { |entry| entry == aSubscriber }
38
- end
39
-
40
- # The signal to begin the visit of the parse forest.
41
- def start()
42
- pforest.accept(self)
43
- end
44
-
45
-
46
- # Visit event. The visitor is about to visit the pforest.
47
- # @param aParseForest [ParseForest] the pforest to visit.
48
- def start_visit_pforest(aParseForest)
49
- broadcast(:before_pforest, aParseForest)
50
- end
51
-
52
-
53
- # Visit event. The visitor is about to visit the given non terminal node.
54
- # @param aNonTerminalNode [NonTerminalNode] the node to visit.
55
- def visit_nonterminal(aNonTerminalNode)
56
- if @traversal == :post_order
57
- broadcast(:before_non_terminal, aNonTerminalNode)
58
- traverse_children(aNonTerminalNode)
59
- else
60
- traverse_children(aNonTerminalNode)
61
- broadcast(:before_non_terminal, aNonTerminalNode)
62
- end
63
- broadcast(:after_non_terminal, aNonTerminalNode)
64
- end
65
-
66
- # Visit event. The visitor is visiting the
67
- # given terminal node.
68
- # @param aTerminalNode [TerminalNode] the terminal to visit.
69
- def visit_terminal(aTerminalNode)
70
- broadcast(:before_terminal, aTerminalNode)
71
- broadcast(:after_terminal, aTerminalNode)
72
- end
73
-
74
-
75
- # Visit event. The visitor has completed its visit of the given
76
- # non-terminal node.
77
- # @param aNonTerminalNode [NonTerminalNode] the node to visit.
78
- def end_visit_nonterminal(aNonTerminalNode)
79
- broadcast(:after_non_terminal, aNonTerminalNode)
80
- end
81
-
82
- # Visit event. The visitor has completed the visit of the pforest.
83
- # @param aParseForest [ParseForest] the pforest to visit.
84
- def end_visit_pforest(aParseForest)
85
- broadcast(:after_pforest, aParseForest)
86
- end
87
-
88
- private
89
-
90
- # Visit event. The visitor is about to visit the children of a non
91
- # terminal node.
92
- # @param aParentNode [NonTeminalNode] the (non-terminal) parent node.
93
- def traverse_children(aParentNode)
94
- children = aParentNode.children
95
- broadcast(:before_children, aParentNode, children)
96
-
97
- # Let's proceed with the visit of children
98
- children.each { |a_node| a_node.accept(self) }
99
-
100
- broadcast(:after_children, aParentNode, children)
101
- end
102
-
103
- # Send a notification to all subscribers.
104
- # @param msg [Symbol] event to notify
105
- # @param args [Array] arguments of the notification.
106
- def broadcast(msg, *args)
107
- subscribers.each do |a_subscriber|
108
- next unless a_subscriber.respond_to?(msg)
109
- a_subscriber.send(msg, *args)
110
- end
111
- end
112
- end # class
113
- end # module
114
-
115
- # End of file
1
+ module Rley # This module is used as a namespace
2
+ # A visitor class dedicated in the visit of a parse forest.
3
+ # It combines the Visitor and Observer patterns.
4
+ class ParseForestVisitor
5
+ # Link to the parse forest to visit
6
+ attr_reader(:pforest)
7
+
8
+ # List of objects that subscribed to the visit event notification.
9
+ attr_reader(:subscribers)
10
+
11
+ # A Hash with pairs of the form: Node => node visit data
12
+ attr_reader(:agenda)
13
+
14
+ # Indicates the kind of forest traversal to perform: :post_order, :pre-order
15
+ attr_reader(:traversal)
16
+
17
+ # Build a visitor for the given pforest.
18
+ # @param aParseForest [ParseForest] the parse tree to visit.
19
+ def initialize(aParseForest, aTraversalStrategy = :post_order)
20
+ @pforest = aParseForest
21
+ @subscribers = []
22
+ @traversal = aTraversalStrategy
23
+ end
24
+
25
+ # Add a subscriber for the visit event notifications.
26
+ # @param aSubscriber [Object]
27
+ def subscribe(aSubscriber)
28
+ subscribers << aSubscriber
29
+ end
30
+
31
+ # Remove the given object from the subscription list.
32
+ # The object won't be notified of visit events.
33
+ # @param aSubscriber [Object]
34
+ def unsubscribe(aSubscriber)
35
+ subscribers.delete_if { |entry| entry == aSubscriber }
36
+ end
37
+
38
+ # The signal to begin the visit of the parse forest.
39
+ def start()
40
+ pforest.accept(self)
41
+ end
42
+
43
+
44
+ # Visit event. The visitor is about to visit the pforest.
45
+ # @param aParseForest [ParseForest] the pforest to visit.
46
+ def start_visit_pforest(aParseForest)
47
+ broadcast(:before_pforest, aParseForest)
48
+ end
49
+
50
+
51
+ # Visit event. The visitor is about to visit the given non terminal node.
52
+ # @param aNonTerminalNode [NonTerminalNode] the node to visit.
53
+ def visit_nonterminal(aNonTerminalNode)
54
+ if @traversal == :post_order
55
+ broadcast(:before_non_terminal, aNonTerminalNode)
56
+ traverse_children(aNonTerminalNode)
57
+ else
58
+ traverse_children(aNonTerminalNode)
59
+ broadcast(:before_non_terminal, aNonTerminalNode)
60
+ end
61
+ broadcast(:after_non_terminal, aNonTerminalNode)
62
+ end
63
+
64
+ # Visit event. The visitor is visiting the
65
+ # given terminal node.
66
+ # @param aTerminalNode [TerminalNode] the terminal to visit.
67
+ def visit_terminal(aTerminalNode)
68
+ broadcast(:before_terminal, aTerminalNode)
69
+ broadcast(:after_terminal, aTerminalNode)
70
+ end
71
+
72
+
73
+ # Visit event. The visitor has completed its visit of the given
74
+ # non-terminal node.
75
+ # @param aNonTerminalNode [NonTerminalNode] the node to visit.
76
+ def end_visit_nonterminal(aNonTerminalNode)
77
+ broadcast(:after_non_terminal, aNonTerminalNode)
78
+ end
79
+
80
+ # Visit event. The visitor has completed the visit of the pforest.
81
+ # @param aParseForest [ParseForest] the pforest to visit.
82
+ def end_visit_pforest(aParseForest)
83
+ broadcast(:after_pforest, aParseForest)
84
+ end
85
+
86
+ private
87
+
88
+ # Visit event. The visitor is about to visit the children of a non
89
+ # terminal node.
90
+ # @param aParentNode [NonTeminalNode] the (non-terminal) parent node.
91
+ def traverse_children(aParentNode)
92
+ children = aParentNode.children
93
+ broadcast(:before_children, aParentNode, children)
94
+
95
+ # Let's proceed with the visit of children
96
+ children.each { |a_node| a_node.accept(self) }
97
+
98
+ broadcast(:after_children, aParentNode, children)
99
+ end
100
+
101
+ # Send a notification to all subscribers.
102
+ # @param msg [Symbol] event to notify
103
+ # @param args [Array] arguments of the notification.
104
+ def broadcast(msg, *args)
105
+ subscribers.each do |a_subscriber|
106
+ next unless a_subscriber.respond_to?(msg)
107
+ a_subscriber.send(msg, *args)
108
+ end
109
+ end
110
+ end # class
111
+ end # module
112
+
113
+ # End of file
@@ -19,8 +19,6 @@ module Rley # This module is used as a namespace
19
19
  @traversal = aTraversalStrategy
20
20
  end
21
21
 
22
- public
23
-
24
22
  # Add a subscriber for the visit event notifications.
25
23
  # @param aSubscriber [Object]
26
24
  def subscribe(aSubscriber)
@@ -1,27 +1,27 @@
1
- require_relative '../syntax/grammar'
2
- require_relative 'grm_items_builder' # Use mix-in module
3
- require_relative 'parse_tracer'
4
- require_relative 'parsing'
5
-
6
- module Rley # This module is used as a namespace
7
- module Parser # This module is used as a namespace
8
- # Abstract class for Earley parser.
9
- class BaseParser
10
- include GrmItemsBuilder # Mix-in module for created dotted items of given grammar
11
-
12
- # The grammar of the language.
13
- attr_reader(:grammar)
14
-
15
- # The dotted items/rules for the productions of the grammar
16
- attr_reader(:dotted_items)
17
-
18
-
19
- def initialize(aGrammar)
20
- @grammar = aGrammar
21
- @dotted_items = build_dotted_items(grammar) # Method from mixin
22
- end
23
- end # class
24
- end # module
25
- end # module
26
-
27
- # End of file
1
+ require_relative '../syntax/grammar'
2
+ require_relative 'grm_items_builder' # Use mix-in module
3
+ require_relative 'parse_tracer'
4
+ require_relative 'parsing'
5
+
6
+ module Rley # This module is used as a namespace
7
+ module Parser # This module is used as a namespace
8
+ # Abstract class for Earley parser.
9
+ class BaseParser
10
+ include GrmItemsBuilder # Mix-in for creating dotted items of grammar
11
+
12
+ # The grammar of the language.
13
+ attr_reader(:grammar)
14
+
15
+ # The dotted items/rules for the productions of the grammar
16
+ attr_reader(:dotted_items)
17
+
18
+
19
+ def initialize(aGrammar)
20
+ @grammar = aGrammar
21
+ @dotted_items = build_dotted_items(grammar) # Method from mixin
22
+ end
23
+ end # class
24
+ end # module
25
+ end # module
26
+
27
+ # End of file
@@ -8,7 +8,7 @@ module Rley # This module is used as a namespace
8
8
  class Chart
9
9
  # An array of state sets (one per input token + 1)
10
10
  attr_reader(:state_sets)
11
-
11
+
12
12
  # The level of trace details reported on stdout during the parse.
13
13
  # The possible values are:
14
14
  # 0: No trace output (default case)
@@ -16,10 +16,10 @@ module Rley # This module is used as a namespace
16
16
  # 2: Same as of 1 with the addition of the prediction rules
17
17
  attr_reader(:tracer)
18
18
 
19
- # @param startItems [Array] A non-empty Array of dotted items for
19
+ # @param startItems [Array] A non-empty Array of dotted items for
20
20
  # the start symbol.
21
21
  # @param tokenCount [Fixnum] The number of lexemes in the input to parse.
22
- # @param aTracer [ParseTracer] A tracer object.
22
+ # @param aTracer [ParseTracer] A tracer object.
23
23
  def initialize(startItems, tokenCount, aTracer)
24
24
  @tracer = aTracer
25
25
  @state_sets = Array.new(tokenCount + 1) { |_| StateSet.new }
@@ -34,7 +34,7 @@ module Rley # This module is used as a namespace
34
34
  def start_dotted_rule()
35
35
  return self[0].states.first.dotted_rule
36
36
  end
37
-
37
+
38
38
  # Return the start (non-terminal) symbol of the grammar.
39
39
  def start_symbol()
40
40
  return state_sets.first.states[0].dotted_rule.lhs
@@ -44,16 +44,16 @@ module Rley # This module is used as a namespace
44
44
  def [](index)
45
45
  return state_sets[index]
46
46
  end
47
-
47
+
48
48
  # Return the index value of the last non-empty state set.
49
49
  def last_index()
50
50
  first_empty = state_sets.find_index(&:empty?)
51
- if first_empty.nil?
52
- index = state_sets.size - 1
53
- else
54
- index = first_empty == 0 ? 0 : first_empty - 1
55
- end
56
-
51
+ index = if first_empty.nil?
52
+ state_sets.size - 1
53
+ else
54
+ first_empty.zero? ? 0 : first_empty - 1
55
+ end
56
+
57
57
  return index
58
58
  end
59
59
 
@@ -65,14 +65,14 @@ module Rley # This module is used as a namespace
65
65
  case aReason
66
66
  when :start_rule, :prediction
67
67
  tracer.trace_prediction(anIndex, new_state)
68
-
68
+
69
69
  when :scanning
70
70
  tracer.trace_scanning(anIndex, new_state)
71
-
71
+
72
72
  when :completion
73
73
  tracer.trace_completion(anIndex, new_state)
74
74
  else
75
- fail NotImplementedError, "Unknown push_state mode #{aReason}"
75
+ raise NotImplementedError, "Unknown push_state mode #{aReason}"
76
76
  end
77
77
  end
78
78
  end # class
@@ -6,7 +6,7 @@ module Rley # This module is used as a namespace
6
6
  # The right part consists of symbols that are predicted to match the
7
7
  # input tokens.
8
8
  # The terminology stems from the traditional way to visualize the partition
9
- # by using a fat dot character as a separator between the left and right
9
+ # by using a fat dot character as a separator between the left and right
10
10
  # parts
11
11
  # An item with the dot at the beginning (i.e. before any rhs symbol)
12
12
  # is called a predicted item.
@@ -29,7 +29,7 @@ module Rley # This module is used as a namespace
29
29
  @production = aProduction
30
30
  @position = valid_position(aPosition)
31
31
  end
32
-
32
+
33
33
  # Return a String representation of the dotted item.
34
34
  # @return [String]
35
35
  def to_s()
@@ -41,68 +41,68 @@ module Rley # This module is used as a namespace
41
41
  text_values.insert(position, '.')
42
42
  end
43
43
  suffix = text_values.join(' ')
44
-
44
+
45
45
  return prefix + suffix
46
46
  end
47
-
47
+
48
48
  # Return true if the dot position is at the start of the rhs.
49
49
  def at_start?()
50
- return position == 0 || position == -2
50
+ return position.zero? || position == -2
51
51
  end
52
52
 
53
- # An item with the dot at the beginning is called
54
- # predicted item
55
- alias_method :predicted_item?, :at_start?
53
+ # An item with the dot at the beginning is called
54
+ # predicted item
55
+ alias predicted_item? at_start?
56
56
 
57
57
  # A dotted item is called a reduce item if the dot is at the end.
58
58
  def reduce_item?()
59
59
  return position < 0 # Either -1 or -2
60
60
  end
61
-
61
+
62
62
  # The non-terminal symbol that is on the left-side of the production
63
63
  def lhs()
64
64
  return production.lhs
65
65
  end
66
-
66
+
67
67
  # Return the symbol before the dot.
68
68
  # nil is returned if the dot is at the start of the rhs
69
69
  def prev_symbol()
70
70
  before_position = prev_position
71
- if before_position.nil?
72
- result = nil
73
- else
74
- result = production.rhs[before_position]
75
- end
76
-
71
+ result = if before_position.nil?
72
+ nil
73
+ else
74
+ production.rhs[before_position]
75
+ end
76
+
77
77
  return result
78
78
  end
79
-
79
+
80
80
  # Return the symbol after the dot.
81
81
  # nil is returned if the dot is at the end
82
82
  def next_symbol()
83
- return (position < 0) ? nil : production.rhs[position]
83
+ return position < 0 ? nil : production.rhs[position]
84
84
  end
85
-
86
- # Calculate the position of the dot if were moved by
85
+
86
+ # Calculate the position of the dot if were moved by
87
87
  # one step on the left.
88
88
  def prev_position()
89
89
  case position
90
90
  when -2, 0
91
91
  result = nil
92
92
  when -1
93
- result = (production.rhs.size == 1) ? 0 : (production.rhs.size - 1)
93
+ result = production.rhs.size == 1 ? 0 : production.rhs.size - 1
94
94
  else
95
95
  result = position - 1
96
96
  end
97
-
97
+
98
98
  return result
99
99
  end
100
100
 
101
101
  # An item with the dot in front of a terminal is called a shift item
102
102
  def shift_item?()
103
- return position == 0
103
+ return position.zero?
104
104
  end
105
-
105
+
106
106
  # Return true if this dotted item has a dot one place
107
107
  # to the right compared to the dotted item argument.
108
108
  def successor_of?(another)
@@ -111,7 +111,7 @@ module Rley # This module is used as a namespace
111
111
  return false if to_the_left.nil?
112
112
  return to_the_left == another.position
113
113
  end
114
-
114
+
115
115
 
116
116
  private
117
117
 
@@ -119,16 +119,16 @@ module Rley # This module is used as a namespace
119
119
  def valid_position(aPosition)
120
120
  rhs_size = production.rhs.size
121
121
  if aPosition < 0 || aPosition > rhs_size
122
- fail StandardError, 'Out of bound index'
122
+ raise StandardError, 'Out of bound index'
123
123
  end
124
124
 
125
- if rhs_size == 0
126
- index = -2 # Minus 2 at start/end of empty production
127
- elsif aPosition == rhs_size
128
- index = -1 # Minus 1 at end of non-empty production
129
- else
130
- index = aPosition
131
- end
125
+ index = if rhs_size.zero?
126
+ -2 # Minus 2 at start/end of empty production
127
+ elsif aPosition == rhs_size
128
+ -1 # Minus 1 at end of non-empty production
129
+ else
130
+ aPosition
131
+ end
132
132
 
133
133
  return index
134
134
  end