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