keisan 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +92 -0
- data/lib/keisan.rb +12 -0
- data/lib/keisan/ast/bitwise_and.rb +1 -5
- data/lib/keisan/ast/bitwise_or.rb +1 -5
- data/lib/keisan/ast/bitwise_xor.rb +1 -5
- data/lib/keisan/ast/builder.rb +57 -22
- data/lib/keisan/ast/exponent.rb +1 -5
- data/lib/keisan/ast/function.rb +50 -1
- data/lib/keisan/ast/logical_and.rb +1 -5
- data/lib/keisan/ast/logical_equal.rb +18 -0
- data/lib/keisan/ast/logical_greater_than.rb +4 -4
- data/lib/keisan/ast/logical_greater_than_or_equal_to.rb +4 -4
- data/lib/keisan/ast/logical_less_than.rb +4 -4
- data/lib/keisan/ast/logical_less_than_or_equal_to.rb +4 -4
- data/lib/keisan/ast/logical_not_equal.rb +18 -0
- data/lib/keisan/ast/logical_or.rb +1 -5
- data/lib/keisan/ast/modulo.rb +18 -0
- data/lib/keisan/ast/node.rb +26 -0
- data/lib/keisan/ast/operator.rb +9 -2
- data/lib/keisan/ast/plus.rb +1 -5
- data/lib/keisan/ast/priorities.rb +27 -0
- data/lib/keisan/ast/times.rb +1 -5
- data/lib/keisan/ast/variable.rb +5 -0
- data/lib/keisan/calculator.rb +1 -12
- data/lib/keisan/context.rb +20 -5
- data/lib/keisan/evaluator.rb +79 -0
- data/lib/keisan/exceptions.rb +1 -0
- data/lib/keisan/functions/default_registry.rb +0 -5
- data/lib/keisan/functions/registry.rb +7 -0
- data/lib/keisan/parser.rb +42 -29
- data/lib/keisan/parsing/dot.rb +6 -0
- data/lib/keisan/parsing/dot_operator.rb +12 -0
- data/lib/keisan/parsing/dot_word.rb +14 -0
- data/lib/keisan/parsing/logical_equal.rb +9 -0
- data/lib/keisan/parsing/logical_not_equal.rb +9 -0
- data/lib/keisan/parsing/modulo.rb +9 -0
- data/lib/keisan/tokenizer.rb +2 -1
- data/lib/keisan/tokens/arithmetic_operator.rb +4 -1
- data/lib/keisan/tokens/dot.rb +11 -0
- data/lib/keisan/tokens/logical_operator.rb +7 -1
- data/lib/keisan/variables/registry.rb +7 -0
- data/lib/keisan/version.rb +1 -1
- metadata +14 -2
@@ -14,7 +14,6 @@ module Keisan
|
|
14
14
|
|
15
15
|
def self.register_defaults!(registry)
|
16
16
|
register_builtin_math!(registry)
|
17
|
-
register_branch_methods!(registry)
|
18
17
|
register_array_methods!(registry)
|
19
18
|
register_random_methods!(registry)
|
20
19
|
end
|
@@ -30,10 +29,6 @@ module Keisan
|
|
30
29
|
end
|
31
30
|
end
|
32
31
|
|
33
|
-
def self.register_branch_methods!(registry)
|
34
|
-
registry.register!(:if, Proc.new {|bool, a, b=nil| bool ? a : b })
|
35
|
-
end
|
36
|
-
|
37
32
|
def self.register_array_methods!(registry)
|
38
33
|
%i(min max size).each do |method|
|
39
34
|
registry.register!(method, Proc.new {|a| a.send(method)})
|
@@ -18,6 +18,13 @@ module Keisan
|
|
18
18
|
raise Keisan::Exceptions::UndefinedFunctionError.new name
|
19
19
|
end
|
20
20
|
|
21
|
+
def has?(name)
|
22
|
+
!!self[name]
|
23
|
+
rescue Keisan::Exceptions::UndefinedFunctionError
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
27
|
+
# For checking if locally defined
|
21
28
|
def has_name?(name)
|
22
29
|
@hash.has_key?(name)
|
23
30
|
end
|
data/lib/keisan/parser.rb
CHANGED
@@ -73,12 +73,35 @@ module Keisan
|
|
73
73
|
# Here it is a postfix Indexing (access elements by index)
|
74
74
|
elsif token.type == :group && token.group_type == :square
|
75
75
|
add_indexing_to_components!(token)
|
76
|
+
elsif token.type == :dot
|
77
|
+
@components << Keisan::Parsing::Dot.new
|
76
78
|
else
|
77
79
|
# Expect an operator
|
78
80
|
raise Keisan::Exceptions::ParseError.new("Expected an operator, received #{token.string}") unless token.type == :operator
|
79
81
|
add_operator_to_components!(token)
|
80
82
|
end
|
81
83
|
|
84
|
+
elsif @components[-1].is_a?(Parsing::Dot)
|
85
|
+
# Expect a word
|
86
|
+
case token.type
|
87
|
+
when :word
|
88
|
+
@components[-1] = Parsing::DotWord.new(token.string)
|
89
|
+
else
|
90
|
+
raise Keisan::Exceptions::ParseError.new("A word must follow a dot, received #{token.string}")
|
91
|
+
end
|
92
|
+
|
93
|
+
elsif @components[-1].is_a?(Parsing::DotWord)
|
94
|
+
# Expect a round group
|
95
|
+
if token.type == :group && token.group_type == :round
|
96
|
+
name = @components[-1].name
|
97
|
+
@components[-1] = Parsing::DotOperator.new(name, arguments_from_group(token))
|
98
|
+
elsif token.type == :dot
|
99
|
+
@components << Keisan::Parsing::Dot.new
|
100
|
+
elsif token.type == :group && token.group_type == :square
|
101
|
+
add_indexing_to_components!(token)
|
102
|
+
else
|
103
|
+
raise Keisan::Exceptions::ParseError.new("Expected arguments to dot operator, received #{token.string}")
|
104
|
+
end
|
82
105
|
else
|
83
106
|
raise Keisan::Exceptions::ParseError.new("Token cannot be parsed, #{token.string}")
|
84
107
|
end
|
@@ -120,15 +143,7 @@ module Keisan
|
|
120
143
|
when :round
|
121
144
|
@components << Keisan::Parsing::RoundGroup.new(token.sub_tokens)
|
122
145
|
when :square
|
123
|
-
@components <<
|
124
|
-
Parsing::List.new([])
|
125
|
-
else
|
126
|
-
Parsing::List.new(
|
127
|
-
token.sub_tokens.split {|sub_token| sub_token.is_a?(Keisan::Tokens::Comma)}.map do |sub_tokens|
|
128
|
-
Parsing::Argument.new(sub_tokens)
|
129
|
-
end
|
130
|
-
)
|
131
|
-
end
|
146
|
+
@components << Parsing::List.new(arguments_from_group(token))
|
132
147
|
else
|
133
148
|
raise Keisan::Exceptions::ParseError.new("Unhandled group type #{token.group_type}")
|
134
149
|
end
|
@@ -150,6 +165,8 @@ module Keisan
|
|
150
165
|
@components << Keisan::Parsing::Divide.new
|
151
166
|
when :**
|
152
167
|
@components << Keisan::Parsing::Exponent.new
|
168
|
+
when :%
|
169
|
+
@components << Keisan::Parsing::Modulo.new
|
153
170
|
# Bitwise
|
154
171
|
when :"&"
|
155
172
|
@components << Keisan::Parsing::BitwiseAnd.new
|
@@ -162,6 +179,10 @@ module Keisan
|
|
162
179
|
when :"~~"
|
163
180
|
@components << Keisan::Parsing::BitwiseNotNot.new
|
164
181
|
# Logical
|
182
|
+
when :"=="
|
183
|
+
@components << Keisan::Parsing::LogicalEqual.new
|
184
|
+
when :"!="
|
185
|
+
@components << Keisan::Parsing::LogicalNotEqual.new
|
165
186
|
when :"&&"
|
166
187
|
@components << Keisan::Parsing::LogicalAnd.new
|
167
188
|
when :"||"
|
@@ -184,30 +205,22 @@ module Keisan
|
|
184
205
|
end
|
185
206
|
|
186
207
|
def add_function_to_components!(token)
|
187
|
-
|
188
|
-
if token.sub_tokens.empty?
|
189
|
-
@components[-1] = Parsing::Function.new(@components[-1].name, [])
|
190
|
-
else
|
191
|
-
@components[-1] = Parsing::Function.new(
|
192
|
-
@components[-1].name,
|
193
|
-
token.sub_tokens.split {|sub_token| sub_token.is_a?(Keisan::Tokens::Comma)}.map do |sub_tokens|
|
194
|
-
Parsing::Argument.new(sub_tokens)
|
195
|
-
end
|
196
|
-
)
|
197
|
-
end
|
208
|
+
@components[-1] = Parsing::Function.new(@components[-1].name, arguments_from_group(token))
|
198
209
|
end
|
199
210
|
|
200
211
|
def add_indexing_to_components!(token)
|
201
212
|
# Have an indexing
|
202
|
-
@components <<
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
213
|
+
@components << Parsing::Indexing.new(arguments_from_group(token))
|
214
|
+
end
|
215
|
+
|
216
|
+
def arguments_from_group(token)
|
217
|
+
if token.sub_tokens.empty?
|
218
|
+
[]
|
219
|
+
else
|
220
|
+
token.sub_tokens.split {|sub_token| sub_token.is_a?(Keisan::Tokens::Comma)}.map do |sub_tokens|
|
221
|
+
Parsing::Argument.new(sub_tokens)
|
222
|
+
end
|
223
|
+
end
|
211
224
|
end
|
212
225
|
end
|
213
226
|
end
|
data/lib/keisan/tokenizer.rb
CHANGED
@@ -4,8 +4,9 @@ module Keisan
|
|
4
4
|
EXPONENT = /(?:\*\*)/
|
5
5
|
TIMES = /(?:\*)/
|
6
6
|
DIVIDE = /(?:\/)/
|
7
|
+
MODULO = /(?:\%)/
|
7
8
|
PLUS_OR_MINUS = /(?:[\+\-]+)/
|
8
|
-
REGEX = /(#{EXPONENT}|#{TIMES}|#{DIVIDE}|#{PLUS_OR_MINUS})/
|
9
|
+
REGEX = /(#{EXPONENT}|#{TIMES}|#{DIVIDE}|#{MODULO}|#{PLUS_OR_MINUS})/
|
9
10
|
|
10
11
|
def self.regex
|
11
12
|
REGEX
|
@@ -20,6 +21,8 @@ module Keisan
|
|
20
21
|
:*
|
21
22
|
when DIVIDE
|
22
23
|
:/
|
24
|
+
when MODULO
|
25
|
+
:%
|
23
26
|
when PLUS_OR_MINUS
|
24
27
|
string.count("-").even? ? :+ : :-
|
25
28
|
end
|
@@ -7,9 +7,11 @@ module Keisan
|
|
7
7
|
GREATER_THAN = /(?:\>)/
|
8
8
|
AND = /(?:\&\&)/
|
9
9
|
OR = /(?:\|\|)/
|
10
|
+
EQUAL = /(?:\=\=)/
|
11
|
+
NOT_EQUAL = /(?:\!\=)/
|
10
12
|
NOT = /(?:\!+)/
|
11
13
|
|
12
|
-
REGEX = /(#{LESS_THAN_OR_EQUAL_TO}|#{GREATER_THAN_OR_EQUAL_TO}|#{LESS_THAN}|#{GREATER_THAN}|#{AND}|#{OR}|#{NOT})/
|
14
|
+
REGEX = /(#{LESS_THAN_OR_EQUAL_TO}|#{GREATER_THAN_OR_EQUAL_TO}|#{LESS_THAN}|#{GREATER_THAN}|#{AND}|#{OR}|#{EQUAL}|#{NOT_EQUAL}|#{NOT})/
|
13
15
|
|
14
16
|
def self.regex
|
15
17
|
REGEX
|
@@ -29,6 +31,10 @@ module Keisan
|
|
29
31
|
:"&&"
|
30
32
|
when OR
|
31
33
|
:"||"
|
34
|
+
when EQUAL
|
35
|
+
:"=="
|
36
|
+
when NOT_EQUAL
|
37
|
+
:"!="
|
32
38
|
when NOT
|
33
39
|
string.count("!").even? ? :"!!" : :"!"
|
34
40
|
end
|
@@ -18,6 +18,13 @@ module Keisan
|
|
18
18
|
raise Keisan::Exceptions::UndefinedVariableError.new name
|
19
19
|
end
|
20
20
|
|
21
|
+
def has?(name)
|
22
|
+
!!self[name]
|
23
|
+
rescue Keisan::Exceptions::UndefinedVariableError
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
27
|
+
# For checking if locally defined
|
21
28
|
def has_name?(name)
|
22
29
|
@hash.has_key?(name)
|
23
30
|
end
|
data/lib/keisan/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: keisan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christopher Locke
|
@@ -125,18 +125,22 @@ files:
|
|
125
125
|
- lib/keisan/ast/list.rb
|
126
126
|
- lib/keisan/ast/literal.rb
|
127
127
|
- lib/keisan/ast/logical_and.rb
|
128
|
+
- lib/keisan/ast/logical_equal.rb
|
128
129
|
- lib/keisan/ast/logical_greater_than.rb
|
129
130
|
- lib/keisan/ast/logical_greater_than_or_equal_to.rb
|
130
131
|
- lib/keisan/ast/logical_less_than.rb
|
131
132
|
- lib/keisan/ast/logical_less_than_or_equal_to.rb
|
133
|
+
- lib/keisan/ast/logical_not_equal.rb
|
132
134
|
- lib/keisan/ast/logical_operator.rb
|
133
135
|
- lib/keisan/ast/logical_or.rb
|
136
|
+
- lib/keisan/ast/modulo.rb
|
134
137
|
- lib/keisan/ast/node.rb
|
135
138
|
- lib/keisan/ast/null.rb
|
136
139
|
- lib/keisan/ast/number.rb
|
137
140
|
- lib/keisan/ast/operator.rb
|
138
141
|
- lib/keisan/ast/parent.rb
|
139
142
|
- lib/keisan/ast/plus.rb
|
143
|
+
- lib/keisan/ast/priorities.rb
|
140
144
|
- lib/keisan/ast/string.rb
|
141
145
|
- lib/keisan/ast/times.rb
|
142
146
|
- lib/keisan/ast/unary_bitwise_not.rb
|
@@ -149,6 +153,7 @@ files:
|
|
149
153
|
- lib/keisan/ast/variable.rb
|
150
154
|
- lib/keisan/calculator.rb
|
151
155
|
- lib/keisan/context.rb
|
156
|
+
- lib/keisan/evaluator.rb
|
152
157
|
- lib/keisan/exceptions.rb
|
153
158
|
- lib/keisan/function.rb
|
154
159
|
- lib/keisan/functions/default_registry.rb
|
@@ -167,6 +172,9 @@ files:
|
|
167
172
|
- lib/keisan/parsing/boolean.rb
|
168
173
|
- lib/keisan/parsing/component.rb
|
169
174
|
- lib/keisan/parsing/divide.rb
|
175
|
+
- lib/keisan/parsing/dot.rb
|
176
|
+
- lib/keisan/parsing/dot_operator.rb
|
177
|
+
- lib/keisan/parsing/dot_word.rb
|
170
178
|
- lib/keisan/parsing/element.rb
|
171
179
|
- lib/keisan/parsing/exponent.rb
|
172
180
|
- lib/keisan/parsing/function.rb
|
@@ -174,15 +182,18 @@ files:
|
|
174
182
|
- lib/keisan/parsing/indexing.rb
|
175
183
|
- lib/keisan/parsing/list.rb
|
176
184
|
- lib/keisan/parsing/logical_and.rb
|
185
|
+
- lib/keisan/parsing/logical_equal.rb
|
177
186
|
- lib/keisan/parsing/logical_greater_than.rb
|
178
187
|
- lib/keisan/parsing/logical_greater_than_or_equal_to.rb
|
179
188
|
- lib/keisan/parsing/logical_less_than.rb
|
180
189
|
- lib/keisan/parsing/logical_less_than_or_equal_to.rb
|
181
190
|
- lib/keisan/parsing/logical_not.rb
|
191
|
+
- lib/keisan/parsing/logical_not_equal.rb
|
182
192
|
- lib/keisan/parsing/logical_not_not.rb
|
183
193
|
- lib/keisan/parsing/logical_operator.rb
|
184
194
|
- lib/keisan/parsing/logical_or.rb
|
185
195
|
- lib/keisan/parsing/minus.rb
|
196
|
+
- lib/keisan/parsing/modulo.rb
|
186
197
|
- lib/keisan/parsing/null.rb
|
187
198
|
- lib/keisan/parsing/number.rb
|
188
199
|
- lib/keisan/parsing/operator.rb
|
@@ -201,6 +212,7 @@ files:
|
|
201
212
|
- lib/keisan/tokens/bitwise_operator.rb
|
202
213
|
- lib/keisan/tokens/boolean.rb
|
203
214
|
- lib/keisan/tokens/comma.rb
|
215
|
+
- lib/keisan/tokens/dot.rb
|
204
216
|
- lib/keisan/tokens/group.rb
|
205
217
|
- lib/keisan/tokens/logical_operator.rb
|
206
218
|
- lib/keisan/tokens/null.rb
|
@@ -231,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
231
243
|
version: '0'
|
232
244
|
requirements: []
|
233
245
|
rubyforge_project:
|
234
|
-
rubygems_version: 2.6.
|
246
|
+
rubygems_version: 2.6.11
|
235
247
|
signing_key:
|
236
248
|
specification_version: 4
|
237
249
|
summary: An equation parser and evaluator
|