keisan 0.9.0 → 0.9.1
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/README.md +8 -0
- data/lib/keisan/ast/indexing.rb +13 -0
- data/lib/keisan/calculator.rb +8 -0
- data/lib/keisan/evaluator.rb +10 -2
- data/lib/keisan/functions/default_registry.rb +4 -1
- data/lib/keisan/functions/enumerable_function.rb +1 -1
- data/lib/keisan/functions/expression_function.rb +7 -1
- data/lib/keisan/functions/registry.rb +3 -0
- data/lib/keisan/parser.rb +2 -1
- data/lib/keisan/parsing/hash.rb +14 -4
- data/lib/keisan/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11f1a2644fbb02817db69dd289564d6fdb9bfd09d294cda62b07156723aebc0e
|
4
|
+
data.tar.gz: 4b9787c0d558af15d466759e40fe4cfac35131d254d227416144588256e5ea9f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8149fee69d598164334b96f8be59b9763168af97e3803c9abea7285da5ed1d90bb9f87710a3de94498461baec65db335168f8e721fe73c4a837c684a30bc4114
|
7
|
+
data.tar.gz: 8a4e301fb14461b164bf0331684fe7ebe3cd660d4abd38f3c44aba5f50fbed58b6b945082accdf13f9da55bcb76579890fd63db75e8b17e5c098c52d0e2d80ae
|
data/README.md
CHANGED
@@ -280,6 +280,14 @@ calculator.evaluate("range(5,10)")
|
|
280
280
|
#=> [5,6,7,8,9]
|
281
281
|
calculator.evaluate("range(0,10,2)")
|
282
282
|
#=> [0,2,4,6,8]
|
283
|
+
calculator.evaluate("[1, 2, 2, 3].uniq")
|
284
|
+
#=> [1,2,3]
|
285
|
+
calculator.evaluate("[1, 2, 3].difference([2, 3, 4])")
|
286
|
+
#=> [1]
|
287
|
+
calculator.evaluate("[1, 2, 3].intersection([2, 3, 4])")
|
288
|
+
#=> [2, 3]
|
289
|
+
calculator.evaluate("[1, 2, 3].union([2, 3, 4])")
|
290
|
+
#=> [1, 2, 3, 4]
|
283
291
|
```
|
284
292
|
|
285
293
|
##### Hashes
|
data/lib/keisan/ast/indexing.rb
CHANGED
@@ -8,6 +8,19 @@ module Keisan
|
|
8
8
|
@indexes = indexes
|
9
9
|
end
|
10
10
|
|
11
|
+
def deep_dup
|
12
|
+
dupped = super
|
13
|
+
dupped.instance_variable_set(
|
14
|
+
:@indexes, indexes.map(&:deep_dup)
|
15
|
+
)
|
16
|
+
dupped
|
17
|
+
end
|
18
|
+
|
19
|
+
def freeze
|
20
|
+
indexes.each(&:freeze)
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
11
24
|
def value(context = nil)
|
12
25
|
return child.value(context).send(:[], *indexes.map {|index| index.value(context)})
|
13
26
|
end
|
data/lib/keisan/calculator.rb
CHANGED
@@ -47,10 +47,18 @@ module Keisan
|
|
47
47
|
Evaluator.new(self, cache: @cache).evaluate(expression, definitions)
|
48
48
|
end
|
49
49
|
|
50
|
+
def evaluate_ast(ast, definitions = {})
|
51
|
+
Evaluator.new(self, cache: @cache).evaluate_ast(ast, definitions: definitions)
|
52
|
+
end
|
53
|
+
|
50
54
|
def simplify(expression, definitions = {})
|
51
55
|
Evaluator.new(self, cache: @cache).simplify(expression, definitions)
|
52
56
|
end
|
53
57
|
|
58
|
+
def simplify_ast(ast, definitions = {})
|
59
|
+
Evaluator.new(self, cache: @cache).simplify_ast(ast, definitions: definitions)
|
60
|
+
end
|
61
|
+
|
54
62
|
def ast(expression)
|
55
63
|
Evaluator.new(self, cache: @cache).parse_ast(expression)
|
56
64
|
end
|
data/lib/keisan/evaluator.rb
CHANGED
@@ -9,7 +9,11 @@ module Keisan
|
|
9
9
|
|
10
10
|
def evaluate(expression, definitions = {})
|
11
11
|
context = calculator.context.spawn_child(definitions: definitions, transient: true)
|
12
|
-
|
12
|
+
evaluate_ast(parse_ast(expression), context: context)
|
13
|
+
end
|
14
|
+
|
15
|
+
def evaluate_ast(ast, definitions: {}, context: nil)
|
16
|
+
context ||= calculator.context.spawn_child(definitions: definitions, transient: true)
|
13
17
|
last_line = last_line(ast)
|
14
18
|
|
15
19
|
evaluation = ast.evaluated(context)
|
@@ -25,7 +29,11 @@ module Keisan
|
|
25
29
|
|
26
30
|
def simplify(expression, definitions = {})
|
27
31
|
context = calculator.context.spawn_child(definitions: definitions, transient: true)
|
28
|
-
|
32
|
+
simplify_ast(parse_ast(expression), context: context)
|
33
|
+
end
|
34
|
+
|
35
|
+
def simplify_ast(ast, definitions: {}, context: nil)
|
36
|
+
context ||= calculator.context.spawn_child(definitions: definitions, transient: true)
|
29
37
|
ast.simplified(context)
|
30
38
|
end
|
31
39
|
|
@@ -118,10 +118,13 @@ module Keisan
|
|
118
118
|
end
|
119
119
|
|
120
120
|
def self.register_array_methods!(registry)
|
121
|
-
%i(min max size flatten reverse).each do |method|
|
121
|
+
%i(min max size flatten reverse uniq).each do |method|
|
122
122
|
registry.register!(method, Proc.new {|a| a.send(method)}, force: true)
|
123
123
|
end
|
124
124
|
|
125
|
+
registry.register!(:difference, Proc.new {|a, b| a - b}, force: true)
|
126
|
+
registry.register!(:intersection, Proc.new {|a, b| a & b}, force: true)
|
127
|
+
registry.register!(:union, Proc.new {|a, b| a | b}, force: true)
|
125
128
|
registry.register!("range", Functions::Range.new, force: true)
|
126
129
|
end
|
127
130
|
|
@@ -54,7 +54,7 @@ module Keisan
|
|
54
54
|
private
|
55
55
|
|
56
56
|
def operand_arguments_expression_for(ast_function, context)
|
57
|
-
operand = ast_function.children[0].
|
57
|
+
operand = ast_function.children[0].evaluate(context)
|
58
58
|
arguments = ast_function.children[1...-1]
|
59
59
|
expression = ast_function.children[-1]
|
60
60
|
|
@@ -14,6 +14,12 @@ module Keisan
|
|
14
14
|
@transient_definitions = transient_definitions
|
15
15
|
end
|
16
16
|
|
17
|
+
def freeze
|
18
|
+
@arguments.freeze
|
19
|
+
@expression.freeze
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
17
23
|
def call(context, *args)
|
18
24
|
validate_arguments!(args.count)
|
19
25
|
|
@@ -96,7 +102,7 @@ module Keisan
|
|
96
102
|
private
|
97
103
|
|
98
104
|
def argument_variables
|
99
|
-
|
105
|
+
arguments.map {|argument| AST::Variable.new(argument)}
|
100
106
|
end
|
101
107
|
|
102
108
|
def calculate_partial_derivatives(context)
|
@@ -44,6 +44,9 @@ module Keisan
|
|
44
44
|
when Proc
|
45
45
|
self[name] = ProcFunction.new(name, function)
|
46
46
|
when Function
|
47
|
+
# The expression AST which represents the function should be constant,
|
48
|
+
# so we freeze it so it will always have the same behavior.
|
49
|
+
function.freeze if function.is_a?(ExpressionFunction)
|
47
50
|
self[name] = function
|
48
51
|
else
|
49
52
|
raise Exceptions::InvalidFunctionError.new
|
data/lib/keisan/parser.rb
CHANGED
@@ -211,7 +211,8 @@ module Keisan
|
|
211
211
|
when :square
|
212
212
|
@components << Parsing::List.new(arguments_from_group(token))
|
213
213
|
when :curly
|
214
|
-
|
214
|
+
# A hash either has a colon, or is empty
|
215
|
+
if token.sub_tokens.any? {|token| token.is_a?(Tokens::Colon)} || token.sub_tokens.empty?
|
215
216
|
@components << Parsing::Hash.new(Util.array_split(token.sub_tokens) {|token| token.is_a?(Tokens::Comma)})
|
216
217
|
else
|
217
218
|
@components << Parsing::CurlyGroup.new(token.sub_tokens)
|
data/lib/keisan/parsing/hash.rb
CHANGED
@@ -4,15 +4,25 @@ module Keisan
|
|
4
4
|
attr_reader :key_value_pairs
|
5
5
|
|
6
6
|
def initialize(key_value_pairs)
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
key_value_pairs = Array(key_value_pairs)
|
8
|
+
if key_value_pairs.size == 1 && key_value_pairs.first.empty?
|
9
|
+
@key_value_pairs = []
|
10
|
+
else
|
11
|
+
@key_value_pairs = key_value_pairs.map {|key_value_pair|
|
12
|
+
validate_and_extract_key_value_pair(key_value_pair)
|
13
|
+
}
|
14
|
+
end
|
10
15
|
end
|
11
16
|
|
12
17
|
private
|
13
18
|
|
14
19
|
def validate_and_extract_key_value_pair(key_value_pair)
|
15
|
-
|
20
|
+
filtered_key_value_pair = key_value_pair.select {|token|
|
21
|
+
!token.is_a?(Tokens::LineSeparator)
|
22
|
+
}
|
23
|
+
key, value = Util.array_split(filtered_key_value_pair) {|token|
|
24
|
+
token.is_a?(Tokens::Colon)
|
25
|
+
}
|
16
26
|
raise Exceptions::ParseError.new("Invalid hash") unless key.size == 1 && value.size >= 1
|
17
27
|
|
18
28
|
key = key.first
|
data/lib/keisan/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: keisan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christopher Locke
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cmath
|