rley 0.7.03 → 0.7.08

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 (174) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +362 -62
  3. data/.travis.yml +6 -7
  4. data/CHANGELOG.md +20 -1
  5. data/LICENSE.txt +1 -1
  6. data/README.md +6 -7
  7. data/Rakefile +2 -0
  8. data/appveyor.yml +2 -4
  9. data/examples/NLP/benchmark_pico_en.rb +2 -0
  10. data/examples/NLP/engtagger.rb +193 -188
  11. data/examples/NLP/nano_eng/nano_en_demo.rb +2 -0
  12. data/examples/NLP/nano_eng/nano_grammar.rb +7 -5
  13. data/examples/NLP/pico_en_demo.rb +2 -0
  14. data/examples/data_formats/JSON/cli_options.rb +3 -1
  15. data/examples/data_formats/JSON/json_ast_builder.rb +14 -9
  16. data/examples/data_formats/JSON/json_ast_nodes.rb +14 -21
  17. data/examples/data_formats/JSON/json_demo.rb +2 -0
  18. data/examples/data_formats/JSON/json_grammar.rb +4 -2
  19. data/examples/data_formats/JSON/json_lexer.rb +10 -8
  20. data/examples/data_formats/JSON/json_minifier.rb +3 -1
  21. data/examples/general/calc_iter1/calc_ast_builder.rb +15 -10
  22. data/examples/general/calc_iter1/calc_ast_nodes.rb +25 -37
  23. data/examples/general/calc_iter1/calc_demo.rb +2 -0
  24. data/examples/general/calc_iter1/calc_grammar.rb +4 -2
  25. data/examples/general/calc_iter1/calc_lexer.rb +8 -4
  26. data/examples/general/calc_iter1/spec/calculator_spec.rb +7 -5
  27. data/examples/general/calc_iter2/calc_ast_builder.rb +7 -3
  28. data/examples/general/calc_iter2/calc_ast_nodes.rb +29 -43
  29. data/examples/general/calc_iter2/calc_demo.rb +2 -0
  30. data/examples/general/calc_iter2/calc_grammar.rb +5 -3
  31. data/examples/general/calc_iter2/calc_lexer.rb +13 -10
  32. data/examples/general/calc_iter2/spec/calculator_spec.rb +28 -26
  33. data/examples/general/left.rb +4 -2
  34. data/examples/general/right.rb +4 -2
  35. data/lib/rley.rb +2 -0
  36. data/lib/rley/base/base_parser.rb +2 -0
  37. data/lib/rley/base/dotted_item.rb +38 -41
  38. data/lib/rley/base/grm_items_builder.rb +2 -0
  39. data/lib/rley/constants.rb +5 -3
  40. data/lib/rley/engine.rb +22 -24
  41. data/lib/rley/formatter/asciitree.rb +6 -4
  42. data/lib/rley/formatter/base_formatter.rb +2 -0
  43. data/lib/rley/formatter/bracket_notation.rb +3 -8
  44. data/lib/rley/formatter/debug.rb +8 -6
  45. data/lib/rley/formatter/json.rb +4 -2
  46. data/lib/rley/gfg/call_edge.rb +3 -1
  47. data/lib/rley/gfg/edge.rb +7 -5
  48. data/lib/rley/gfg/end_vertex.rb +4 -6
  49. data/lib/rley/gfg/epsilon_edge.rb +3 -5
  50. data/lib/rley/gfg/grm_flow_graph.rb +31 -25
  51. data/lib/rley/gfg/item_vertex.rb +12 -22
  52. data/lib/rley/gfg/non_terminal_vertex.rb +6 -4
  53. data/lib/rley/gfg/return_edge.rb +2 -0
  54. data/lib/rley/gfg/scan_edge.rb +3 -1
  55. data/lib/rley/gfg/shortcut_edge.rb +4 -2
  56. data/lib/rley/gfg/start_vertex.rb +6 -8
  57. data/lib/rley/gfg/vertex.rb +47 -41
  58. data/lib/rley/lexical/token.rb +3 -1
  59. data/lib/rley/lexical/token_range.rb +8 -6
  60. data/lib/rley/parse_forest_visitor.rb +7 -5
  61. data/lib/rley/parse_rep/ast_base_builder.rb +11 -11
  62. data/lib/rley/parse_rep/cst_builder.rb +7 -4
  63. data/lib/rley/parse_rep/parse_forest_builder.rb +36 -25
  64. data/lib/rley/parse_rep/parse_forest_factory.rb +5 -3
  65. data/lib/rley/parse_rep/parse_rep_creator.rb +18 -13
  66. data/lib/rley/parse_rep/parse_tree_builder.rb +15 -15
  67. data/lib/rley/parse_rep/parse_tree_factory.rb +27 -25
  68. data/lib/rley/parse_tree_visitor.rb +3 -1
  69. data/lib/rley/parser/error_reason.rb +9 -8
  70. data/lib/rley/parser/gfg_chart.rb +54 -22
  71. data/lib/rley/parser/gfg_earley_parser.rb +3 -1
  72. data/lib/rley/parser/gfg_parsing.rb +51 -31
  73. data/lib/rley/parser/parse_entry.rb +29 -33
  74. data/lib/rley/parser/parse_entry_set.rb +32 -27
  75. data/lib/rley/parser/parse_entry_tracker.rb +6 -4
  76. data/lib/rley/parser/parse_state.rb +18 -21
  77. data/lib/rley/parser/parse_state_tracker.rb +6 -4
  78. data/lib/rley/parser/parse_tracer.rb +15 -13
  79. data/lib/rley/parser/parse_walker_factory.rb +28 -29
  80. data/lib/rley/parser/state_set.rb +11 -10
  81. data/lib/rley/ptree/non_terminal_node.rb +10 -6
  82. data/lib/rley/ptree/parse_tree.rb +6 -4
  83. data/lib/rley/ptree/parse_tree_node.rb +7 -5
  84. data/lib/rley/ptree/terminal_node.rb +9 -7
  85. data/lib/rley/rley_error.rb +12 -10
  86. data/lib/rley/sppf/alternative_node.rb +8 -6
  87. data/lib/rley/sppf/composite_node.rb +9 -7
  88. data/lib/rley/sppf/epsilon_node.rb +5 -3
  89. data/lib/rley/sppf/leaf_node.rb +5 -3
  90. data/lib/rley/sppf/non_terminal_node.rb +2 -0
  91. data/lib/rley/sppf/parse_forest.rb +19 -17
  92. data/lib/rley/sppf/sppf_node.rb +9 -8
  93. data/lib/rley/sppf/token_node.rb +5 -3
  94. data/lib/rley/syntax/grammar.rb +7 -5
  95. data/lib/rley/syntax/grammar_builder.rb +11 -9
  96. data/lib/rley/syntax/grm_symbol.rb +8 -6
  97. data/lib/rley/syntax/literal.rb +2 -0
  98. data/lib/rley/syntax/non_terminal.rb +11 -15
  99. data/lib/rley/syntax/production.rb +13 -11
  100. data/lib/rley/syntax/symbol_seq.rb +10 -10
  101. data/lib/rley/syntax/terminal.rb +6 -5
  102. data/lib/rley/syntax/verbatim_symbol.rb +5 -3
  103. data/lib/support/base_tokenizer.rb +23 -20
  104. data/spec/rley/base/dotted_item_spec.rb +4 -2
  105. data/spec/rley/base/grm_items_builder_spec.rb +2 -0
  106. data/spec/rley/engine_spec.rb +47 -9
  107. data/spec/rley/formatter/asciitree_spec.rb +11 -9
  108. data/spec/rley/formatter/bracket_notation_spec.rb +16 -14
  109. data/spec/rley/formatter/debug_spec.rb +4 -2
  110. data/spec/rley/formatter/json_spec.rb +5 -3
  111. data/spec/rley/gfg/call_edge_spec.rb +2 -0
  112. data/spec/rley/gfg/edge_spec.rb +2 -0
  113. data/spec/rley/gfg/end_vertex_spec.rb +7 -5
  114. data/spec/rley/gfg/epsilon_edge_spec.rb +2 -0
  115. data/spec/rley/gfg/grm_flow_graph_spec.rb +2 -0
  116. data/spec/rley/gfg/item_vertex_spec.rb +12 -10
  117. data/spec/rley/gfg/non_terminal_vertex_spec.rb +5 -3
  118. data/spec/rley/gfg/return_edge_spec.rb +2 -0
  119. data/spec/rley/gfg/scan_edge_spec.rb +2 -0
  120. data/spec/rley/gfg/shortcut_edge_spec.rb +3 -1
  121. data/spec/rley/gfg/start_vertex_spec.rb +7 -5
  122. data/spec/rley/gfg/vertex_spec.rb +5 -3
  123. data/spec/rley/lexical/token_range_spec.rb +18 -16
  124. data/spec/rley/lexical/token_spec.rb +4 -2
  125. data/spec/rley/parse_forest_visitor_spec.rb +167 -163
  126. data/spec/rley/parse_rep/ambiguous_parse_spec.rb +46 -44
  127. data/spec/rley/parse_rep/ast_builder_spec.rb +8 -6
  128. data/spec/rley/parse_rep/cst_builder_spec.rb +7 -5
  129. data/spec/rley/parse_rep/groucho_spec.rb +25 -25
  130. data/spec/rley/parse_rep/parse_forest_builder_spec.rb +28 -26
  131. data/spec/rley/parse_rep/parse_forest_factory_spec.rb +8 -6
  132. data/spec/rley/parse_rep/parse_tree_factory_spec.rb +4 -2
  133. data/spec/rley/parse_tree_visitor_spec.rb +12 -8
  134. data/spec/rley/parser/error_reason_spec.rb +8 -6
  135. data/spec/rley/parser/gfg_chart_spec.rb +17 -4
  136. data/spec/rley/parser/gfg_earley_parser_spec.rb +16 -11
  137. data/spec/rley/parser/gfg_parsing_spec.rb +41 -252
  138. data/spec/rley/parser/parse_entry_set_spec.rb +2 -0
  139. data/spec/rley/parser/parse_entry_spec.rb +21 -19
  140. data/spec/rley/parser/parse_state_spec.rb +7 -5
  141. data/spec/rley/parser/parse_tracer_spec.rb +16 -14
  142. data/spec/rley/parser/parse_walker_factory_spec.rb +10 -8
  143. data/spec/rley/parser/state_set_spec.rb +24 -22
  144. data/spec/rley/ptree/non_terminal_node_spec.rb +7 -3
  145. data/spec/rley/ptree/parse_tree_node_spec.rb +6 -4
  146. data/spec/rley/ptree/parse_tree_spec.rb +2 -0
  147. data/spec/rley/ptree/terminal_node_spec.rb +8 -6
  148. data/spec/rley/sppf/alternative_node_spec.rb +8 -6
  149. data/spec/rley/sppf/non_terminal_node_spec.rb +5 -3
  150. data/spec/rley/sppf/token_node_spec.rb +6 -4
  151. data/spec/rley/support/ambiguous_grammar_helper.rb +5 -4
  152. data/spec/rley/support/expectation_helper.rb +2 -0
  153. data/spec/rley/support/grammar_abc_helper.rb +4 -4
  154. data/spec/rley/support/grammar_ambig01_helper.rb +6 -5
  155. data/spec/rley/support/grammar_arr_int_helper.rb +6 -5
  156. data/spec/rley/support/grammar_b_expr_helper.rb +6 -5
  157. data/spec/rley/support/grammar_helper.rb +2 -0
  158. data/spec/rley/support/grammar_l0_helper.rb +15 -16
  159. data/spec/rley/support/grammar_pb_helper.rb +8 -5
  160. data/spec/rley/support/grammar_sppf_helper.rb +3 -1
  161. data/spec/rley/syntax/grammar_builder_spec.rb +7 -5
  162. data/spec/rley/syntax/grammar_spec.rb +8 -6
  163. data/spec/rley/syntax/grm_symbol_spec.rb +3 -1
  164. data/spec/rley/syntax/literal_spec.rb +2 -0
  165. data/spec/rley/syntax/non_terminal_spec.rb +10 -8
  166. data/spec/rley/syntax/production_spec.rb +15 -13
  167. data/spec/rley/syntax/symbol_seq_spec.rb +4 -2
  168. data/spec/rley/syntax/terminal_spec.rb +7 -5
  169. data/spec/rley/syntax/verbatim_symbol_spec.rb +3 -1
  170. data/spec/spec_helper.rb +2 -12
  171. data/spec/support/base_tokenizer_spec.rb +9 -2
  172. metadata +21 -63
  173. data/.simplecov +0 -7
  174. data/Gemfile +0 -8
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'calc_lexer'
2
4
  require_relative 'calc_ast_builder'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Grammar for simple arithmetical expressions
2
4
  require 'rley' # Load the gem
3
5
 
@@ -16,9 +18,9 @@ builder = Rley::Syntax::GrammarBuilder.new do
16
18
  rule 'factor' => 'NUMBER'
17
19
  rule 'factor' => %w[LPAREN expression RPAREN]
18
20
  rule 'add_operator' => 'PLUS'
19
- rule 'add_operator' => 'MINUS'
21
+ rule 'add_operator' => 'MINUS'
20
22
  rule 'mul_operator' => 'STAR'
21
- rule 'mul_operator' => 'DIVIDE'
23
+ rule 'mul_operator' => 'DIVIDE'
22
24
  end
23
25
 
24
26
  # And now build the grammar...
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # File: calc_lexer.rb
2
4
  # Lexer for a basic arithmetical expression parser
3
5
  require 'strscan'
@@ -26,7 +28,7 @@ class CalcLexer
26
28
  @lineno = 1
27
29
  end
28
30
 
29
- def tokens()
31
+ def tokens
30
32
  tok_sequence = []
31
33
  until @scanner.eos?
32
34
  token = _next_token
@@ -38,7 +40,8 @@ class CalcLexer
38
40
 
39
41
  private
40
42
 
41
- def _next_token()
43
+ # rubocop: disable Lint/DuplicateBranch
44
+ def _next_token
42
45
  skip_whitespaces
43
46
  curr_ch = scanner.peek(1)
44
47
  return nil if curr_ch.nil?
@@ -61,18 +64,19 @@ class CalcLexer
61
64
  erroneous = curr_ch.nil? ? '' : curr_ch
62
65
  sequel = scanner.scan(/.{1,20}/)
63
66
  erroneous += sequel unless sequel.nil?
64
- raise ScanError.new("Unknown token #{erroneous}")
67
+ raise ScanError, "Unknown token #{erroneous}"
65
68
  end
66
69
 
67
70
  return token
68
71
  end
72
+ # rubocop: enable Lint/DuplicateBranch
69
73
 
70
74
  def build_token(aSymbolName, aLexeme)
71
75
  pos = Rley::Lexical::Position.new(1, scanner.pos)
72
76
  return Rley::Lexical::Token.new(aLexeme, aSymbolName, pos)
73
77
  end
74
78
 
75
- def skip_whitespaces()
79
+ def skip_whitespaces
76
80
  scanner.scan(/[ \t\f\n\r]+/)
77
81
  end
78
82
  end # class
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rspec' # Use the RSpec framework
2
4
  require_relative '../calc_lexer'
3
5
  require_relative '../calc_grammar'
@@ -10,13 +12,13 @@ describe 'Calculator' do
10
12
  engine = Rley::Engine.new do |cfg|
11
13
  cfg.repr_builder = CalcASTBuilder
12
14
  end
13
-
15
+
14
16
  engine.use_grammar(CalcGrammar)
15
17
  raw_result = parse_expression(engine, anExpression)
16
18
  ast = engine.to_ptree(raw_result)
17
19
  return expect(ast.root.interpret)
18
20
  end
19
-
21
+
20
22
  def parse_expression(anEngine, anExpression)
21
23
  lexer = CalcLexer.new(anExpression)
22
24
  result = anEngine.parse(lexer.tokens)
@@ -29,7 +31,7 @@ describe 'Calculator' do
29
31
  end
30
32
 
31
33
  return result
32
- end
34
+ end
33
35
 
34
36
  it 'should evaluate simple number literals' do
35
37
  expect_expr('2').to eq(2)
@@ -54,7 +56,7 @@ describe 'Calculator' do
54
56
  it 'should evaluate parentheses' do
55
57
  expect_expr('2 * (2.1 + 1)').to eq(6.2)
56
58
  end
57
-
59
+
58
60
  it 'should evaluate regardless of whitespace' do
59
61
  expect_expr("2*(1+\t1)").to eq(4)
60
62
  end
@@ -65,6 +67,6 @@ describe 'Calculator' do
65
67
 
66
68
  it 'should evaluate multiple levels of parentheses' do
67
69
  expect_expr('2*(1/(1+3))').to eq(0.5)
68
- end
70
+ end
69
71
  end # describe
70
72
  # End of file
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'calc_ast_nodes'
2
4
 
3
5
  # The purpose of a CalcASTBuilder is to build piece by piece an AST
@@ -13,8 +15,7 @@ class CalcASTBuilder < Rley::ParseRep::ASTBaseBuilder
13
15
  # The unary negation operator on one hand, the binary substraction operator
14
16
  'MINUS' => { 'add_operator_1' => Rley::PTree::TerminalNode,
15
17
  'simple_factor_2' => CalcNegateNode,
16
- 'sign_1' => CalcNegateNode
17
- },
18
+ 'sign_1' => CalcNegateNode },
18
19
  'NUMBER' => CalcNumberNode,
19
20
  'PI' => CalcConstantNode,
20
21
  'E' => CalcConstantNode,
@@ -23,7 +24,7 @@ class CalcASTBuilder < Rley::ParseRep::ASTBaseBuilder
23
24
 
24
25
  protected
25
26
 
26
- def terminal2node()
27
+ def terminal2node
27
28
  Terminal2NodeClass
28
29
  end
29
30
 
@@ -34,6 +35,8 @@ class CalcASTBuilder < Rley::ParseRep::ASTBaseBuilder
34
35
  return operator_node
35
36
  end
36
37
 
38
+ # rubocop: disable Naming/VariableNumber
39
+
37
40
  # rule 'simple_expression' => %w[simple_expression add_operator term]
38
41
  def reduce_simple_expression_1(_production, _range, _tokens, theChildren)
39
42
  reduce_binary_operator(theChildren)
@@ -104,5 +107,6 @@ class CalcASTBuilder < Rley::ParseRep::ASTBaseBuilder
104
107
  def reduce_mul_operator_1(_production, aRange, _tokens, theChildren)
105
108
  return CalcDivideNode.new(theChildren[0].symbol, aRange)
106
109
  end
110
+ # rubocop: enable Naming/VariableNumber
107
111
  end # class
108
112
  # End of file
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Classes that implement nodes of Abstract Syntax Trees (AST) representing
2
4
  # calculator parse results.
3
5
 
4
-
5
6
  CalcTerminalNode = Struct.new(:token, :value, :position) do
6
7
  def initialize(aToken, aPosition)
7
8
  self.token = aToken
@@ -14,15 +15,15 @@ CalcTerminalNode = Struct.new(:token, :value, :position) do
14
15
  self.value = aLiteral.dup
15
16
  end
16
17
 
17
- def symbol()
18
+ def symbol
18
19
  token.terminal
19
20
  end
20
21
 
21
- def interpret()
22
- return value
22
+ def interpret
23
+ value
23
24
  end
24
-
25
- def done!()
25
+
26
+ def done!
26
27
  # Do nothing
27
28
  end
28
29
 
@@ -43,9 +44,9 @@ class CalcNumberNode < CalcTerminalNode
43
44
  self.value = aLiteral.to_f
44
45
  end
45
46
  end
46
-
47
+
47
48
  # Overriding the unary minus operator
48
- def -@()
49
+ def -@
49
50
  self.value = - value
50
51
  return self
51
52
  end
@@ -81,8 +82,8 @@ class CalcCompositeNode
81
82
  def accept(aVisitor)
82
83
  aVisitor.visit_nonterminal(self)
83
84
  end
84
-
85
- def done!()
85
+
86
+ def done!
86
87
  # Do nothing
87
88
  end
88
89
 
@@ -90,44 +91,36 @@ class CalcCompositeNode
90
91
  end # class
91
92
 
92
93
  class CalcUnaryOpNode < CalcCompositeNode
93
- def initialize(aSymbol, aPosition)
94
- super(aSymbol, aPosition)
95
- end
96
-
97
94
  alias members children
98
95
  end # class
99
96
 
100
- class CalcNegateNode < CalcUnaryOpNode
101
- def interpret()
97
+ class CalcNegateNode < CalcUnaryOpNode
98
+ def interpret
102
99
  return -children[0].interpret
103
100
  end
104
101
  end # class
105
102
 
106
103
  class CalcUnaryFunction < CalcCompositeNode
107
- @@name_mapping = begin
104
+ @@name_mapping = begin
108
105
  map = Hash.new { |me, key| me[key] = key }
109
106
  map['ln'] = 'log'
110
107
  map['log'] = 'log10'
111
108
  map
112
109
  end
113
110
  attr_accessor(:func_name)
114
-
115
-
116
- def interpret()
111
+
112
+
113
+ def interpret
117
114
  argument = children[0].interpret
118
115
  internal_name = @@name_mapping[@func_name]
119
116
  return Math.send(internal_name.to_sym, argument)
120
- end
117
+ end
121
118
  end
122
119
 
123
120
  class CalcBinaryOpNode < CalcCompositeNode
124
- def initialize(aSymbol, aRange)
125
- super(aSymbol, aRange)
126
- end
127
-
128
121
  protected
129
122
 
130
- def retrieve_operands()
123
+ def retrieve_operands
131
124
  operands = []
132
125
  children.each do |child|
133
126
  oper = child.respond_to?(:interpret) ? child.interpret : child
@@ -140,52 +133,45 @@ end # class
140
133
 
141
134
  class CalcAddNode < CalcBinaryOpNode
142
135
  # TODO
143
- def interpret()
136
+ def interpret
144
137
  operands = retrieve_operands
145
138
 
146
- sum = operands[0] + operands[1]
147
- return sum
139
+ operands[0] + operands[1]
148
140
  end
149
141
  end # class
150
142
 
151
-
152
143
  class CalcSubtractNode < CalcBinaryOpNode
153
144
  # TODO
154
- def interpret()
145
+ def interpret
155
146
  operands = retrieve_operands
156
147
 
157
- substraction = operands[0] - operands[1]
158
- return substraction
148
+ operands[0] - operands[1]
159
149
  end
160
150
  end # class
161
151
 
162
152
  class CalcMultiplyNode < CalcBinaryOpNode
163
153
  # TODO
164
- def interpret()
154
+ def interpret
165
155
  operands = retrieve_operands
166
- multiplication = operands[0] * operands[1]
167
- return multiplication
156
+ operands[0] * operands[1]
168
157
  end
169
158
  end # class
170
159
 
171
160
  class CalcDivideNode < CalcBinaryOpNode
172
161
  # TODO
173
- def interpret()
162
+ def interpret
174
163
  operands = retrieve_operands
175
164
  numerator = operands[0].to_f
176
165
  denominator = operands[1]
177
- division = numerator / denominator
178
- return division
166
+ numerator / denominator
179
167
  end
180
168
  end # class
181
169
 
182
-
183
170
  class PowerNode < CalcBinaryOpNode
184
171
  # TODO
185
- def interpret()
172
+ def interpret
186
173
  operands = retrieve_operands
187
- exponentiation = operands[0]**operands[1]
188
- return exponentiation
174
+ operands[0]**operands[1]
189
175
  end
190
176
  end # class
191
177
  # End of file
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'calc_lexer'
2
4
  require_relative 'calc_ast_builder'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Grammar for simple arithmetical expressions
2
4
  require 'rley' # Load the gem
3
5
 
@@ -7,7 +9,7 @@ builder = Rley::Syntax::GrammarBuilder.new do
7
9
  add_terminals('NUMBER')
8
10
  add_terminals('PLUS', 'MINUS') # For '+', '-' operators or sign
9
11
  add_terminals('STAR', 'DIVIDE', 'POWER') # For '*', '/', '**' operators
10
- add_terminals('LPAREN', 'RPAREN') # For '(', ')' delimiters
12
+ add_terminals('LPAREN', 'RPAREN') # For '(', ')' delimiters
11
13
  add_terminals('PI', 'E') # For numeric constants
12
14
  add_terminals('RESERVED') # Reserved identifiers
13
15
 
@@ -21,13 +23,13 @@ builder = Rley::Syntax::GrammarBuilder.new do
21
23
  rule 'simple_factor' => %w[sign scalar]
22
24
  rule 'simple_factor' => %w[unary_function in_parenthesis]
23
25
  rule 'simple_factor' => %w[MINUS in_parenthesis]
24
- rule 'simple_factor' => 'in_parenthesis'
26
+ rule 'simple_factor' => 'in_parenthesis'
25
27
  rule 'sign' => 'PLUS'
26
28
  rule 'sign' => 'MINUS'
27
29
  rule 'sign' => []
28
30
  rule 'scalar' => 'NUMBER'
29
31
  rule 'scalar' => 'PI'
30
- rule 'scalar' => 'E'
32
+ rule 'scalar' => 'E'
31
33
  rule 'unary_function' => 'RESERVED'
32
34
  rule 'in_parenthesis' => %w[LPAREN expression RPAREN]
33
35
  rule 'add_operator' => 'PLUS'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # File: calc_lexer.rb
2
4
  # Lexer for a basic arithmetical expression parser
3
5
  require 'strscan'
@@ -8,7 +10,6 @@ class CalcLexer
8
10
  attr_reader(:lineno)
9
11
  attr_reader(:line_start)
10
12
 
11
-
12
13
  @@lexeme2name = {
13
14
  '(' => 'LPAREN',
14
15
  ')' => 'RPAREN',
@@ -20,7 +21,7 @@ class CalcLexer
20
21
  'PI' => 'PI',
21
22
  'E' => 'E'
22
23
  }.freeze
23
-
24
+
24
25
  @@unary_functions = %w[
25
26
  sin cos tan asin acos atan
26
27
  sqrt cbrt exp ln log
@@ -33,7 +34,7 @@ class CalcLexer
33
34
  @lineno = 1
34
35
  end
35
36
 
36
- def tokens()
37
+ def tokens
37
38
  @unary_f_pattern = Regexp.new(@@unary_functions.join('|'))
38
39
  tok_sequence = []
39
40
  until @scanner.eos?
@@ -46,11 +47,12 @@ class CalcLexer
46
47
 
47
48
  private
48
49
 
49
- def _next_token()
50
+ # rubocop: disable Lint/DuplicateBranch
51
+ def _next_token
50
52
  skip_whitespaces
51
53
  curr_ch = scanner.peek(1)
52
54
  return nil if curr_ch.nil?
53
-
55
+
54
56
  token = nil
55
57
 
56
58
  if '()+-/'.include? curr_ch
@@ -61,25 +63,26 @@ class CalcLexer
61
63
  elsif (lexeme = scanner.scan(/\*|PI|E/))
62
64
  token = build_token(@@lexeme2name[lexeme], lexeme)
63
65
  elsif (lexeme = scanner.scan(@unary_f_pattern))
64
- token = build_token('RESERVED', lexeme)
66
+ token = build_token('RESERVED', lexeme)
65
67
  elsif (lexeme = scanner.scan(/[0-9]+(\.[0-9]+)?([eE][-+]?[0-9])?/))
66
68
  token = build_token('NUMBER', lexeme)
67
69
  else # Unknown token
68
70
  erroneous = curr_ch.nil? ? '' : curr_ch
69
71
  sequel = scanner.scan(/.{1,20}/)
70
72
  erroneous += sequel unless sequel.nil?
71
- raise ScanError.new("Unknown token #{erroneous}")
73
+ raise ScanError, "Unknown token #{erroneous}"
72
74
  end
73
75
 
74
76
  return token
75
77
  end
76
-
78
+ # rubocop: enable Lint/DuplicateBranch
79
+
77
80
  def build_token(aSymbolName, aLexeme)
78
81
  pos = Rley::Lexical::Position.new(1, scanner.pos)
79
- return Rley::Lexical::Token.new(aLexeme, aSymbolName, pos)
82
+ return Rley::Lexical::Token.new(aLexeme, aSymbolName, pos)
80
83
  end
81
84
 
82
- def skip_whitespaces()
85
+ def skip_whitespaces
83
86
  scanner.scan(/[ \t\f\n\r]+/)
84
87
  end
85
88
  end # class
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rspec' # Use the RSpec framework
2
4
  require_relative '../calc_lexer'
3
5
  require_relative '../calc_grammar'
@@ -15,13 +17,13 @@ describe 'Calculator' do
15
17
  engine = Rley::Engine.new do |cfg|
16
18
  cfg.repr_builder = CalcASTBuilder
17
19
  end
18
-
20
+
19
21
  engine.use_grammar(CalcGrammar)
20
22
  raw_result = parse_expression(engine, anExpression)
21
23
  ast = engine.to_ptree(raw_result)
22
24
  return expect(ast.root.interpret)
23
25
  end
24
-
26
+
25
27
  def parse_expression(anEngine, anExpression)
26
28
  lexer = CalcLexer.new(anExpression)
27
29
  result = anEngine.parse(lexer.tokens)
@@ -38,7 +40,7 @@ describe 'Calculator' do
38
40
 
39
41
  context 'Parsing valid expressions' do
40
42
  let(:epsilon) { 0.0000000001 }
41
-
43
+
42
44
  it 'should evaluate simple integer literals' do
43
45
  expect_expr('2').to eq(2)
44
46
  end
@@ -70,18 +72,18 @@ describe 'Calculator' do
70
72
  it 'should evaluate the pi constant' do
71
73
  expect_expr('PI').to eq(3.141592653589793)
72
74
  end
73
-
75
+
74
76
  it 'should evaluate the negated pi constant' do
75
77
  expect_expr('-PI').to eq(-3.141592653589793)
76
- end
78
+ end
77
79
 
78
80
  it "should evaluate Neper's e constant" do
79
81
  expect_expr('E').to eq(2.718281828459045)
80
82
  end
81
-
83
+
82
84
  it "should evaluate negated Neper's e constant" do
83
85
  expect_expr('-E').to eq(-2.718281828459045)
84
- end
86
+ end
85
87
 
86
88
  it 'should evaluate integer addition' do
87
89
  expect_expr('2 + 2').to eq(4)
@@ -154,7 +156,7 @@ describe 'Calculator' do
154
156
  it 'should evaluate multiple levels of parentheses' do
155
157
  expect_expr('2*(1/(1+3))').to eq(0.5)
156
158
  end
157
-
159
+
158
160
  # Some special functions
159
161
  it 'should evaluate square root of expressions' do
160
162
  expect_expr('sqrt(0)').to eq(0)
@@ -168,69 +170,69 @@ describe 'Calculator' do
168
170
  expect_expr('cbrt(1)').to eq(1)
169
171
  expect_expr('cbrt(1 + 1)').to eq(Math.cbrt(2))
170
172
  expect_expr('cbrt(5 * 5 * 5)').to eq(5)
171
- end
173
+ end
172
174
 
173
175
  it 'should evaluate exponential of expressions' do
174
- expect_expr('exp(-1)').to eq(1 / Math::E)
176
+ expect_expr('exp(-1)').to eq(1 / Math::E)
175
177
  expect_expr('exp(0)').to eq(1)
176
178
  expect_expr('exp(1)').to eq(Math::E)
177
179
  expect_expr('exp(2)').to be_within(epsilon).of(Math::E * Math::E)
178
180
  end
179
181
 
180
182
  it 'should evaluate natural logarithm of expressions' do
181
- expect_expr('ln(1/E)').to eq(-1)
182
- expect_expr('ln(1)').to eq(0)
183
+ expect_expr('ln(1/E)').to eq(-1)
184
+ expect_expr('ln(1)').to eq(0)
183
185
  expect_expr('ln(E)').to eq(1)
184
186
  expect_expr('ln(E * E)').to eq(2)
185
- end
187
+ end
186
188
 
187
189
  it 'should evaluate the logarithm base 10 of expressions' do
188
- expect_expr('log(1/10)').to eq(-1)
189
- expect_expr('log(1)').to eq(0)
190
+ expect_expr('log(1/10)').to eq(-1)
191
+ expect_expr('log(1)').to eq(0)
190
192
  expect_expr('log(10)').to eq(1)
191
193
  expect_expr('log(10 * 10 * 10)').to eq(3)
192
- end
193
-
194
+ end
195
+
194
196
  # Trigonometric functions
195
-
197
+
196
198
  it 'should compute the sinus of an expression' do
197
199
  expect_expr('sin(0)').to eq(0)
198
200
  expect_expr('sin(PI/6)').to be_within(epsilon).of(0.5)
199
201
  expect_expr('sin(PI/2)').to eq(1)
200
202
  end
201
-
203
+
202
204
  it 'should compute the cosinus of an expression' do
203
205
  expect_expr('cos(0)').to eq(1)
204
206
  expect_expr('cos(PI/3)').to be_within(epsilon).of(0.5)
205
207
  expect_expr('cos(PI/2)').to be_within(epsilon).of(0)
206
- end
208
+ end
207
209
 
208
210
  it 'should compute the tangent of an expression' do
209
211
  expect_expr('tan(0)').to eq(0)
210
212
  expect_expr('tan(PI/4)').to be_within(epsilon).of(1)
211
213
  expect_expr('tan(5*PI/12)').to be_within(epsilon).of(2 + Math.sqrt(3))
212
- end
213
-
214
+ end
215
+
214
216
  # Inverse trigonometric functions
215
-
217
+
216
218
  it 'should compute the arcsinus of an expression' do
217
219
  expect_expr('asin(0)').to eq(0)
218
220
  expect_expr('asin(0.5)').to be_within(epsilon).of(Math::PI / 6)
219
221
  expect_expr('asin(1)').to eq(Math::PI / 2)
220
222
  end
221
-
223
+
222
224
  it 'should compute the arccosinus of an expression' do
223
225
  expect_expr('acos(1)').to eq(0)
224
226
  expect_expr('acos(0.5)').to be_within(epsilon).of(Math::PI / 3)
225
227
  expect_expr('acos(0)').to be_within(epsilon).of(Math::PI / 2)
226
- end
228
+ end
227
229
 
228
230
  it 'should compute the tangent of an expression' do
229
231
  expect_expr('atan(0)').to eq(0)
230
232
  pi = Math::PI
231
233
  expect_expr('atan(1)').to be_within(epsilon).of(pi / 4)
232
234
  expect_expr('atan(2 + sqrt(3))').to be_within(epsilon).of(5 * pi / 12)
233
- end
235
+ end
234
236
  end # context
235
237
  end # describe
236
238
  # End of file