rley 0.8.01 → 0.8.02

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.
@@ -51,7 +51,7 @@ module Rley # This module is used as a namespace
51
51
  result.chart[index].each do |entry|
52
52
  # Is entry of the form? [A => alpha . B beta, k]...
53
53
  next_symbol = entry.next_symbol
54
- if next_symbol&.kind_of?(Syntax::NonTerminal)
54
+ if next_symbol.kind_of?(Syntax::NonTerminal)
55
55
  # ...apply the Call rule
56
56
  call_rule(result, entry, index)
57
57
  end
@@ -55,14 +55,14 @@ module Rley # This module is used as a namespace
55
55
  new_symbs = build_symbols(Terminal, terminalSymbols)
56
56
  symbols.merge!(new_symbs)
57
57
  end
58
-
58
+
59
59
  # Add the given marker symbol to the grammar of the language
60
60
  # @param aMarkerSymbol [Syntax::Marker] A mazker symbol
61
- # @return [void]
61
+ # @return [void]
62
62
  def add_marker(aMarkerSymbol)
63
63
  new_symb = build_symbol(Marker, aMarkerSymbol)
64
64
  symbols[aMarkerSymbol.name] = new_symb
65
- end
65
+ end
66
66
 
67
67
  # Add a production rule in the grammar given one
68
68
  # key-value pair of the form: String => Array.
@@ -7,13 +7,13 @@ module Rley # This module is used as a namespace
7
7
  class MatchClosest
8
8
  # @return [Integer] index of constrained symbol to match
9
9
  attr_reader(:idx_symbol)
10
-
10
+
11
11
  # @return [String] name of closest preceding symbol to pair
12
12
  attr_reader(:closest_symb)
13
13
 
14
14
  # @return [NilClass, Array<Parser::ParseEntry>] set of entries with closest symbol
15
15
  attr_accessor(:entries)
16
-
16
+
17
17
  # @param aSymbolSeq [Rley::Syntax::SymbolSeq] a sequence of grammar symbols
18
18
  # @param idxSymbol [Integer] index of symbol
19
19
  # @param nameClosest [String] Terminal symbol name
@@ -21,18 +21,18 @@ module Rley # This module is used as a namespace
21
21
  @idx_symbol = valid_idx_symbol(idxSymbol, aSymbolSeq)
22
22
  @closest_symb = valid_name_closest(nameClosest)
23
23
  end
24
-
24
+
25
25
  private
26
-
26
+
27
27
  # Check that the provided index is within plausible bounds
28
28
  def valid_idx_symbol(idxSymbol, aSymbolSeq)
29
- bounds = 0 .. aSymbolSeq.size - 1
29
+ bounds = 0..aSymbolSeq.size - 1
30
30
  err_msg_outbound = 'Index of symbol out of bound'
31
31
  raise StandardError, err_msg_outbound unless bounds.include? idxSymbol
32
-
32
+
33
33
  idxSymbol
34
34
  end
35
-
35
+
36
36
  def valid_name_closest(nameClosest)
37
37
  nameClosest
38
38
  end
@@ -170,7 +170,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
170
170
  expect(val_prod.rhs.members[0].name).to eq('digit_plus')
171
171
  end
172
172
 
173
- it "should support optional grouping" do
173
+ it 'should support optional grouping' do
174
174
  instance = GrammarBuilder.new
175
175
  instance.add_terminals('EQUAL', 'IDENTIFIER', 'VAR')
176
176
 
@@ -199,7 +199,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
199
199
  expect(p2.name).to eq('_qmark_none')
200
200
  end
201
201
 
202
- it "should support grouping with star modifier" do
202
+ it 'should support grouping with star modifier' do
203
203
  instance = GrammarBuilder.new
204
204
  instance.add_terminals('OR')
205
205
 
@@ -230,7 +230,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
230
230
  expect(p2.name).to eq('_star_none')
231
231
  end
232
232
 
233
- it "should support grouping with plus modifier" do
233
+ it 'should support grouping with plus modifier' do
234
234
  instance = GrammarBuilder.new
235
235
  instance.add_terminals('POINT TO SEMI_COLON')
236
236
 
@@ -261,7 +261,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
261
261
  expect(p2.name).to eq('_plus_one')
262
262
  end
263
263
 
264
- it "should support grouping with nested annotation" do
264
+ it 'should support grouping with nested annotation' do
265
265
  instance = GrammarBuilder.new
266
266
  instance.add_terminals('IF ELSE LPAREN RPAREN')
267
267
  st = "IF LPAREN expr RPAREN stmt (ELSE { match_closest: 'IF' } stmt)?"
@@ -281,7 +281,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
281
281
  expect(p0.rhs[0].name).to eq('ELSE')
282
282
  expect(p0.rhs[1].name).to eq('stmt')
283
283
  expect(p0.name).to eq('return_children')
284
- expect(p0.constraints.size). to eq(1)
284
+ expect(p0.constraints.size).to eq(1)
285
285
  expect(p0.constraints[0]).to be_kind_of(Syntax::MatchClosest)
286
286
  expect(p0.constraints[0].idx_symbol).to eq(0) # ELSE is on position 0
287
287
  expect(p0.constraints[0].closest_symb).to eq('IF')
@@ -299,4 +299,4 @@ module Rley # Open this namespace to avoid module qualifier prefixes
299
299
  end # module
300
300
  end # module
301
301
 
302
- # End of file
302
+ # End of file
@@ -1,184 +1,183 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../../spec_helper' # Use the RSpec framework
4
-
5
- require_relative '../../../lib/rley/notation/ast_builder'
6
- # Load the class under test
7
- require_relative '../../../lib/rley/notation/parser'
8
-
9
- module Rley
10
- module Notation
11
- describe Parser do
12
- subject { Parser.new }
13
-
14
- # Utility method to walk towards deeply nested node
15
- # @param aNTNode [Rley::PTree::NonTerminalNode]
16
- # @param subnodePath[Array<Integer>] An Array of subnode indices
17
- def walk_subnodes(aNTNode, subnodePath)
18
- curr_node = aNTNode
19
- subnodePath.each do |index|
20
- curr_node = curr_node.subnodes[index]
21
- end
22
-
23
- curr_node
24
- end
25
-
26
- context 'Initialization:' do
27
- it 'should be initialized without argument' do
28
- expect { Parser.new }.not_to raise_error
29
- end
30
-
31
- it 'should have its parse engine initialized' do
32
- expect(subject.engine).to be_kind_of(Rley::Engine)
33
- end
34
- end # context
35
-
36
- context 'Parsing into CST:' do
37
- subject do
38
- instance = Parser.new
39
- instance.engine.configuration.repr_builder = Rley::ParseRep::CSTBuilder
40
-
41
- instance
42
- end
43
-
44
- it 'should parse single symbol names' do
45
- samples = %w[IF ifCondition statement]
46
-
47
- # One drawback od CSTs: they have a deeply nested structure
48
- samples.each do |source|
49
- ptree = subject.parse(source)
50
- expect(ptree.root).to be_kind_of(Rley::PTree::NonTerminalNode)
51
- expect(ptree.root.symbol.name).to eq('notation')
52
- expect(ptree.root.subnodes[0]).to be_kind_of(Rley::PTree::NonTerminalNode)
53
- expect(ptree.root.subnodes[0].symbol.name).to eq('rhs')
54
- expect(ptree.root.subnodes[0].subnodes[0]).to be_kind_of(Rley::PTree::NonTerminalNode)
55
- member_seq = ptree.root.subnodes[0].subnodes[0]
56
- expect(member_seq.symbol.name).to eq('member_seq')
57
- expect(member_seq.subnodes[0]).to be_kind_of(Rley::PTree::NonTerminalNode)
58
- expect(member_seq.subnodes[0].symbol.name).to eq('member')
59
- expect(member_seq.subnodes[0].subnodes[0]).to be_kind_of(Rley::PTree::NonTerminalNode)
60
- expect(member_seq.subnodes[0].subnodes[0].symbol.name).to eq('strait_member')
61
- strait_member = member_seq.subnodes[0].subnodes[0]
62
- expect(strait_member.subnodes[0]).to be_kind_of(Rley::PTree::NonTerminalNode)
63
- expect(strait_member.subnodes[0].symbol.name).to eq('base_member')
64
- expect(strait_member.subnodes[0].subnodes[0]).to be_kind_of(Rley::PTree::TerminalNode)
65
- expect(strait_member.subnodes[0].subnodes[0].token.lexeme).to eq(source)
66
- end
67
- end
68
-
69
- end # context
70
-
71
- context 'Parsing into AST:' do
72
- subject do
73
- instance = Parser.new
74
- instance.engine.configuration.repr_builder = ASTBuilder
75
-
76
- instance
77
- end
78
-
79
- it 'should parse single symbol names' do
80
- samples = %w[IF ifCondition statement]
81
-
82
- samples.each do |source|
83
- ptree = subject.parse(source)
84
- expect(ptree.root).to be_kind_of(SymbolNode)
85
- expect(ptree.root.name).to eq(source)
86
- expect(ptree.root.repetition).to eq(:exactly_one)
87
- end
88
- end
89
-
90
- it 'should parse a sequence of symbols' do
91
- sequence = 'INT_LIT ELLIPSIS INT_LIT'
92
-
93
- ptree = subject.parse(sequence)
94
- expect(ptree.root).to be_kind_of(SequenceNode)
95
- expect(ptree.root.subnodes[0]).to be_kind_of(SymbolNode)
96
- expect(ptree.root.subnodes[0].name).to eq('INT_LIT')
97
- expect(ptree.root.subnodes[1]).to be_kind_of(SymbolNode)
98
- expect(ptree.root.subnodes[1].name).to eq('ELLIPSIS')
99
- expect(ptree.root.subnodes[2]).to be_kind_of(SymbolNode)
100
- expect(ptree.root.subnodes[2].name).to eq('INT_LIT')
101
- end
102
-
103
- it 'should parse an optional symbol' do
104
- optional = 'member_seq?'
105
-
106
- ptree = subject.parse(optional)
107
- expect(ptree.root).to be_kind_of(SymbolNode)
108
- expect(ptree.root.name).to eq('member_seq')
109
- expect(ptree.root.repetition).to eq(:zero_or_one)
110
- end
111
-
112
- it 'should parse a symbol with a + modifier' do
113
- one_or_more = 'member+'
114
-
115
- ptree = subject.parse(one_or_more)
116
- expect(ptree.root).to be_kind_of(SymbolNode)
117
- expect(ptree.root.name).to eq('member')
118
- expect(ptree.root.repetition).to eq(:one_or_more)
119
- end
120
-
121
- it 'should parse a symbol with a * modifier' do
122
- zero_or_more = 'declaration* EOF'
123
-
124
- ptree = subject.parse(zero_or_more)
125
- expect(ptree.root).to be_kind_of(SequenceNode)
126
- expect(ptree.root.subnodes[0]).to be_kind_of(SymbolNode)
127
- expect(ptree.root.subnodes[0].name).to eq('declaration')
128
- expect(ptree.root.subnodes[0].repetition).to eq(:zero_or_more)
129
- expect(ptree.root.subnodes[1]).to be_kind_of(SymbolNode)
130
- expect(ptree.root.subnodes[1].name).to eq('EOF')
131
- expect(ptree.root.subnodes[1].repetition).to eq(:exactly_one)
132
- end
133
-
134
- it 'should parse a grouping with a modifier' do
135
- input = "IF ifCondition statement (ELSE statement)?"
136
-
137
- ptree = subject.parse(input)
138
- expect(ptree.root).to be_kind_of(SequenceNode)
139
- expect(ptree.root.subnodes[0]).to be_kind_of(SymbolNode)
140
- expect(ptree.root.subnodes[0].name).to eq('IF')
141
- expect(ptree.root.subnodes[1]).to be_kind_of(SymbolNode)
142
- expect(ptree.root.subnodes[1].name).to eq('ifCondition')
143
- expect(ptree.root.subnodes[2]).to be_kind_of(SymbolNode)
144
- expect(ptree.root.subnodes[2].name).to eq('statement')
145
- expect(ptree.root.subnodes[3]).to be_kind_of(SequenceNode)
146
- expect(ptree.root.subnodes[3].repetition).to eq(:zero_or_one)
147
- expect(ptree.root.subnodes[3].subnodes[0]).to be_kind_of(SymbolNode)
148
- expect(ptree.root.subnodes[3].subnodes[0].name).to eq('ELSE')
149
- expect(ptree.root.subnodes[3].subnodes[1]).to be_kind_of(SymbolNode)
150
- expect(ptree.root.subnodes[3].subnodes[1].name).to eq('statement')
151
- end
152
-
153
- it 'should parse an annotated symbol' do
154
- optional = 'member_seq{repeat: 0..1}'
155
-
156
- ptree = subject.parse(optional)
157
- expect(ptree.root).to be_kind_of(SymbolNode)
158
- expect(ptree.root.name).to eq('member_seq')
159
- expect(ptree.root.repetition).to eq(:zero_or_one)
160
- end
161
-
162
- it 'should parse a grouping with embedded annotation' do
163
- if_stmt = "IF ifCondition statement ( ELSE { match_closest: 'IF' } statement )?"
164
-
165
- ptree = subject.parse(if_stmt)
166
- expect(ptree.root).to be_kind_of(SequenceNode)
167
- expect(ptree.root.subnodes[0]).to be_kind_of(SymbolNode)
168
- expect(ptree.root.subnodes[0].name).to eq('IF')
169
- expect(ptree.root.subnodes[1]).to be_kind_of(SymbolNode)
170
- expect(ptree.root.subnodes[1].name).to eq('ifCondition')
171
- expect(ptree.root.subnodes[2]).to be_kind_of(SymbolNode)
172
- expect(ptree.root.subnodes[2].name).to eq('statement')
173
- optional = ptree.root.subnodes[3]
174
- expect(optional).to be_kind_of(SequenceNode)
175
- expect(optional.repetition).to eq(:zero_or_one)
176
- expect(optional.subnodes[0]).to be_kind_of(SymbolNode)
177
- expect(optional.subnodes[0].name).to eq('ELSE')
178
- expect(optional.subnodes[0].annotation).to eq({'match_closest' => 'IF'})
179
- expect(optional.subnodes[1].name).to eq('statement')
180
- end
181
- end # context
182
- end # describe
183
- end # module
184
- end # module
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../spec_helper' # Use the RSpec framework
4
+
5
+ require_relative '../../../lib/rley/notation/ast_builder'
6
+ # Load the class under test
7
+ require_relative '../../../lib/rley/notation/parser'
8
+
9
+ module Rley
10
+ module Notation
11
+ describe Parser do
12
+ subject { Parser.new }
13
+
14
+ # Utility method to walk towards deeply nested node
15
+ # @param aNTNode [Rley::PTree::NonTerminalNode]
16
+ # @param subnodePath[Array<Integer>] An Array of subnode indices
17
+ def walk_subnodes(aNTNode, subnodePath)
18
+ curr_node = aNTNode
19
+ subnodePath.each do |index|
20
+ curr_node = curr_node.subnodes[index]
21
+ end
22
+
23
+ curr_node
24
+ end
25
+
26
+ context 'Initialization:' do
27
+ it 'should be initialized without argument' do
28
+ expect { Parser.new }.not_to raise_error
29
+ end
30
+
31
+ it 'should have its parse engine initialized' do
32
+ expect(subject.engine).to be_kind_of(Rley::Engine)
33
+ end
34
+ end # context
35
+
36
+ context 'Parsing into CST:' do
37
+ subject do
38
+ instance = Parser.new
39
+ instance.engine.configuration.repr_builder = Rley::ParseRep::CSTBuilder
40
+
41
+ instance
42
+ end
43
+
44
+ it 'should parse single symbol names' do
45
+ samples = %w[IF ifCondition statement]
46
+
47
+ # One drawback od CSTs: they have a deeply nested structure
48
+ samples.each do |source|
49
+ ptree = subject.parse(source)
50
+ expect(ptree.root).to be_kind_of(Rley::PTree::NonTerminalNode)
51
+ expect(ptree.root.symbol.name).to eq('notation')
52
+ expect(ptree.root.subnodes[0]).to be_kind_of(Rley::PTree::NonTerminalNode)
53
+ expect(ptree.root.subnodes[0].symbol.name).to eq('rhs')
54
+ expect(ptree.root.subnodes[0].subnodes[0]).to be_kind_of(Rley::PTree::NonTerminalNode)
55
+ member_seq = ptree.root.subnodes[0].subnodes[0]
56
+ expect(member_seq.symbol.name).to eq('member_seq')
57
+ expect(member_seq.subnodes[0]).to be_kind_of(Rley::PTree::NonTerminalNode)
58
+ expect(member_seq.subnodes[0].symbol.name).to eq('member')
59
+ expect(member_seq.subnodes[0].subnodes[0]).to be_kind_of(Rley::PTree::NonTerminalNode)
60
+ expect(member_seq.subnodes[0].subnodes[0].symbol.name).to eq('strait_member')
61
+ strait_member = member_seq.subnodes[0].subnodes[0]
62
+ expect(strait_member.subnodes[0]).to be_kind_of(Rley::PTree::NonTerminalNode)
63
+ expect(strait_member.subnodes[0].symbol.name).to eq('base_member')
64
+ expect(strait_member.subnodes[0].subnodes[0]).to be_kind_of(Rley::PTree::TerminalNode)
65
+ expect(strait_member.subnodes[0].subnodes[0].token.lexeme).to eq(source)
66
+ end
67
+ end
68
+ end # context
69
+
70
+ context 'Parsing into AST:' do
71
+ subject do
72
+ instance = Parser.new
73
+ instance.engine.configuration.repr_builder = ASTBuilder
74
+
75
+ instance
76
+ end
77
+
78
+ it 'should parse single symbol names' do
79
+ samples = %w[IF ifCondition statement]
80
+
81
+ samples.each do |source|
82
+ ptree = subject.parse(source)
83
+ expect(ptree.root).to be_kind_of(SymbolNode)
84
+ expect(ptree.root.name).to eq(source)
85
+ expect(ptree.root.repetition).to eq(:exactly_one)
86
+ end
87
+ end
88
+
89
+ it 'should parse a sequence of symbols' do
90
+ sequence = 'INT_LIT ELLIPSIS INT_LIT'
91
+
92
+ ptree = subject.parse(sequence)
93
+ expect(ptree.root).to be_kind_of(SequenceNode)
94
+ expect(ptree.root.subnodes[0]).to be_kind_of(SymbolNode)
95
+ expect(ptree.root.subnodes[0].name).to eq('INT_LIT')
96
+ expect(ptree.root.subnodes[1]).to be_kind_of(SymbolNode)
97
+ expect(ptree.root.subnodes[1].name).to eq('ELLIPSIS')
98
+ expect(ptree.root.subnodes[2]).to be_kind_of(SymbolNode)
99
+ expect(ptree.root.subnodes[2].name).to eq('INT_LIT')
100
+ end
101
+
102
+ it 'should parse an optional symbol' do
103
+ optional = 'member_seq?'
104
+
105
+ ptree = subject.parse(optional)
106
+ expect(ptree.root).to be_kind_of(SymbolNode)
107
+ expect(ptree.root.name).to eq('member_seq')
108
+ expect(ptree.root.repetition).to eq(:zero_or_one)
109
+ end
110
+
111
+ it 'should parse a symbol with a + modifier' do
112
+ one_or_more = 'member+'
113
+
114
+ ptree = subject.parse(one_or_more)
115
+ expect(ptree.root).to be_kind_of(SymbolNode)
116
+ expect(ptree.root.name).to eq('member')
117
+ expect(ptree.root.repetition).to eq(:one_or_more)
118
+ end
119
+
120
+ it 'should parse a symbol with a * modifier' do
121
+ zero_or_more = 'declaration* EOF'
122
+
123
+ ptree = subject.parse(zero_or_more)
124
+ expect(ptree.root).to be_kind_of(SequenceNode)
125
+ expect(ptree.root.subnodes[0]).to be_kind_of(SymbolNode)
126
+ expect(ptree.root.subnodes[0].name).to eq('declaration')
127
+ expect(ptree.root.subnodes[0].repetition).to eq(:zero_or_more)
128
+ expect(ptree.root.subnodes[1]).to be_kind_of(SymbolNode)
129
+ expect(ptree.root.subnodes[1].name).to eq('EOF')
130
+ expect(ptree.root.subnodes[1].repetition).to eq(:exactly_one)
131
+ end
132
+
133
+ it 'should parse a grouping with a modifier' do
134
+ input = 'IF ifCondition statement (ELSE statement)?'
135
+
136
+ ptree = subject.parse(input)
137
+ expect(ptree.root).to be_kind_of(SequenceNode)
138
+ expect(ptree.root.subnodes[0]).to be_kind_of(SymbolNode)
139
+ expect(ptree.root.subnodes[0].name).to eq('IF')
140
+ expect(ptree.root.subnodes[1]).to be_kind_of(SymbolNode)
141
+ expect(ptree.root.subnodes[1].name).to eq('ifCondition')
142
+ expect(ptree.root.subnodes[2]).to be_kind_of(SymbolNode)
143
+ expect(ptree.root.subnodes[2].name).to eq('statement')
144
+ expect(ptree.root.subnodes[3]).to be_kind_of(SequenceNode)
145
+ expect(ptree.root.subnodes[3].repetition).to eq(:zero_or_one)
146
+ expect(ptree.root.subnodes[3].subnodes[0]).to be_kind_of(SymbolNode)
147
+ expect(ptree.root.subnodes[3].subnodes[0].name).to eq('ELSE')
148
+ expect(ptree.root.subnodes[3].subnodes[1]).to be_kind_of(SymbolNode)
149
+ expect(ptree.root.subnodes[3].subnodes[1].name).to eq('statement')
150
+ end
151
+
152
+ it 'should parse an annotated symbol' do
153
+ optional = 'member_seq{repeat: 0..1}'
154
+
155
+ ptree = subject.parse(optional)
156
+ expect(ptree.root).to be_kind_of(SymbolNode)
157
+ expect(ptree.root.name).to eq('member_seq')
158
+ expect(ptree.root.repetition).to eq(:zero_or_one)
159
+ end
160
+
161
+ it 'should parse a grouping with embedded annotation' do
162
+ if_stmt = "IF ifCondition statement ( ELSE { match_closest: 'IF' } statement )?"
163
+
164
+ ptree = subject.parse(if_stmt)
165
+ expect(ptree.root).to be_kind_of(SequenceNode)
166
+ expect(ptree.root.subnodes[0]).to be_kind_of(SymbolNode)
167
+ expect(ptree.root.subnodes[0].name).to eq('IF')
168
+ expect(ptree.root.subnodes[1]).to be_kind_of(SymbolNode)
169
+ expect(ptree.root.subnodes[1].name).to eq('ifCondition')
170
+ expect(ptree.root.subnodes[2]).to be_kind_of(SymbolNode)
171
+ expect(ptree.root.subnodes[2].name).to eq('statement')
172
+ optional = ptree.root.subnodes[3]
173
+ expect(optional).to be_kind_of(SequenceNode)
174
+ expect(optional.repetition).to eq(:zero_or_one)
175
+ expect(optional.subnodes[0]).to be_kind_of(SymbolNode)
176
+ expect(optional.subnodes[0].name).to eq('ELSE')
177
+ expect(optional.subnodes[0].annotation).to eq({ 'match_closest' => 'IF' })
178
+ expect(optional.subnodes[1].name).to eq('statement')
179
+ end
180
+ end # context
181
+ end # describe
182
+ end # module
183
+ end # module