keisan 0.8.7 → 0.8.12
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 +12 -0
- data/lib/keisan/ast/assignment.rb +11 -0
- data/lib/keisan/ast/block.rb +2 -2
- data/lib/keisan/ast/cell.rb +2 -2
- data/lib/keisan/ast/cell_assignment.rb +5 -1
- data/lib/keisan/ast/constant_literal.rb +164 -0
- data/lib/keisan/ast/function.rb +7 -0
- data/lib/keisan/ast/hash.rb +15 -2
- data/lib/keisan/ast/list.rb +1 -0
- data/lib/keisan/ast/list_assignment.rb +38 -0
- data/lib/keisan/ast/node.rb +20 -2
- data/lib/keisan/ast/number.rb +5 -0
- data/lib/keisan/ast/parent.rb +12 -2
- data/lib/keisan/calculator.rb +7 -2
- data/lib/keisan/context.rb +6 -1
- data/lib/keisan/functions/enumerable_function.rb +1 -1
- data/lib/keisan/variables/registry.rb +3 -1
- data/lib/keisan/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 39ac1f6356b788327b43e6819d18b136da5bbada5f410b64c3f6995b2877973b
|
|
4
|
+
data.tar.gz: 60522376948b4806c0e45cb4f8e09e5187d37448fae0831630fea1f07608485c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 964905af3a5734456ea5e3f81ddb5183a7512e9cf81567c72586dbab813123160d4aaa085467f2626bd0e29df861f87e44425e216b8ccf174cb9f1251d578122
|
|
7
|
+
data.tar.gz: be653ccfd93f2fa6ce3a33e26be4e14db33e9ccea8d2273d491e8df0aaa16b400291b08e90d66cd48020efc691742bf49667b3547fcae57e8adeaab52bf18d5d
|
data/README.md
CHANGED
|
@@ -83,6 +83,18 @@ calculator.evaluate("3*x + 1")
|
|
|
83
83
|
#=> 61
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
+
To perform multiple assignments, lists can be used
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
calculator = Keisan::Calculator.new
|
|
90
|
+
calculator.evaluate("x = [1, 2]")
|
|
91
|
+
calculator.evaluate("[x[1], y] = [11, 22]")
|
|
92
|
+
calculator.evaluate("x")
|
|
93
|
+
#=> [1, 11]
|
|
94
|
+
calculator.evaluate("y")
|
|
95
|
+
#=> 22
|
|
96
|
+
```
|
|
97
|
+
|
|
86
98
|
|
|
87
99
|
##### Specifying functions
|
|
88
100
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require_relative "variable_assignment"
|
|
2
2
|
require_relative "function_assignment"
|
|
3
|
+
require_relative "list_assignment"
|
|
3
4
|
require_relative "cell_assignment"
|
|
4
5
|
|
|
5
6
|
module Keisan
|
|
@@ -31,6 +32,8 @@ module Keisan
|
|
|
31
32
|
evaluate_variable_assignment(context, lhs, rhs)
|
|
32
33
|
elsif is_function_definition?
|
|
33
34
|
evaluate_function_assignment(context, lhs, rhs)
|
|
35
|
+
elsif is_list_assignment?
|
|
36
|
+
evaluate_list_assignment(context, lhs, rhs)
|
|
34
37
|
else
|
|
35
38
|
# Try cell assignment
|
|
36
39
|
evaluate_cell_assignment(context, lhs, rhs)
|
|
@@ -71,6 +74,10 @@ module Keisan
|
|
|
71
74
|
children.first.is_a?(Function)
|
|
72
75
|
end
|
|
73
76
|
|
|
77
|
+
def is_list_assignment?
|
|
78
|
+
children.first.is_a?(List)
|
|
79
|
+
end
|
|
80
|
+
|
|
74
81
|
private
|
|
75
82
|
|
|
76
83
|
def evaluate_variable_assignment(context, lhs, rhs)
|
|
@@ -82,6 +89,10 @@ module Keisan
|
|
|
82
89
|
FunctionAssignment.new(context, lhs, rhs, local).evaluate
|
|
83
90
|
end
|
|
84
91
|
|
|
92
|
+
def evaluate_list_assignment(context, lhs, rhs)
|
|
93
|
+
ListAssignment.new(self, context, lhs, rhs).evaluate
|
|
94
|
+
end
|
|
95
|
+
|
|
85
96
|
def evaluate_cell_assignment(context, lhs, rhs)
|
|
86
97
|
CellAssignment.new(self, context, lhs, rhs).evaluate
|
|
87
98
|
end
|
data/lib/keisan/ast/block.rb
CHANGED
data/lib/keisan/ast/cell.rb
CHANGED
|
@@ -30,7 +30,11 @@ module Keisan
|
|
|
30
30
|
private
|
|
31
31
|
|
|
32
32
|
def lhs_evaluate_and_check_modifiable
|
|
33
|
-
lhs.evaluate(context)
|
|
33
|
+
res = lhs.evaluate(context)
|
|
34
|
+
if res.frozen?
|
|
35
|
+
raise Exceptions::UnmodifiableError.new("Cannot modify frozen variables")
|
|
36
|
+
end
|
|
37
|
+
res
|
|
34
38
|
rescue RuntimeError => e
|
|
35
39
|
raise Exceptions::UnmodifiableError.new("Cannot modify frozen variables") if e.message =~ /can't modify frozen/
|
|
36
40
|
raise
|
|
@@ -22,6 +22,170 @@ module Keisan
|
|
|
22
22
|
value.to_s
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
|
+
|
|
26
|
+
def is_constant?
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def +(other)
|
|
31
|
+
if other.is_constant?
|
|
32
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot add #{self.class} to #{other.class}")
|
|
33
|
+
else
|
|
34
|
+
super
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def -(other)
|
|
39
|
+
if other.is_constant?
|
|
40
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot subtract #{self.class} from #{other.class}")
|
|
41
|
+
else
|
|
42
|
+
super
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def *(other)
|
|
47
|
+
if other.is_constant?
|
|
48
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot multiply #{self.class} and #{other.class}")
|
|
49
|
+
else
|
|
50
|
+
super
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def /(other)
|
|
55
|
+
if other.is_constant?
|
|
56
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot divide #{self.class} and #{other.class}")
|
|
57
|
+
else
|
|
58
|
+
super
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def %(other)
|
|
63
|
+
if other.is_constant?
|
|
64
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot modulo #{self.class} and #{other.class}")
|
|
65
|
+
else
|
|
66
|
+
super
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def !
|
|
71
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot take logical not of #{self.class}")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def ~
|
|
75
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot take bitwise not of #{self.class}")
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def +@
|
|
79
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot take unary plus of #{self.class}")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def -@
|
|
83
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot take unary minus of #{self.class}")
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def **(other)
|
|
87
|
+
if other.is_constant?
|
|
88
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot exponentiate #{self.class} and #{other.class}")
|
|
89
|
+
else
|
|
90
|
+
super
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def &(other)
|
|
95
|
+
if other.is_constant?
|
|
96
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot bitwise and #{self.class} and #{other.class}")
|
|
97
|
+
else
|
|
98
|
+
super
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def ^(other)
|
|
103
|
+
if other.is_constant?
|
|
104
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot bitwise xor #{self.class} and #{other.class}")
|
|
105
|
+
else
|
|
106
|
+
super
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def |(other)
|
|
111
|
+
if other.is_constant?
|
|
112
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot bitwise or #{self.class} and #{other.class}")
|
|
113
|
+
else
|
|
114
|
+
super
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def <<(other)
|
|
119
|
+
if other.is_constant?
|
|
120
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot bitwise left shift #{self.class} and #{other.class}")
|
|
121
|
+
else
|
|
122
|
+
super
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def >>(other)
|
|
127
|
+
if other.is_constant?
|
|
128
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot bitwise right shift #{self.class} and #{other.class}")
|
|
129
|
+
else
|
|
130
|
+
super
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def >(other)
|
|
135
|
+
if other.is_constant?
|
|
136
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot compute #{self.class} > #{other.class}")
|
|
137
|
+
else
|
|
138
|
+
super
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def >=(other)
|
|
143
|
+
if other.is_constant?
|
|
144
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot compute #{self.class} >= #{other.class}")
|
|
145
|
+
else
|
|
146
|
+
super
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def <(other)
|
|
151
|
+
if other.is_constant?
|
|
152
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot compute #{self.class} < #{other.class}")
|
|
153
|
+
else
|
|
154
|
+
super
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def <=(other)
|
|
159
|
+
if other.is_constant?
|
|
160
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot compute #{self.class} <= #{other.class}")
|
|
161
|
+
else
|
|
162
|
+
super
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def equal(other)
|
|
167
|
+
other.is_constant? ? Boolean.new(false) : super
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def not_equal(other)
|
|
171
|
+
other.is_constant? ? Boolean.new(true) : super
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def and(other)
|
|
175
|
+
if other.is_constant?
|
|
176
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot logical and #{self.class} and #{other.class}")
|
|
177
|
+
else
|
|
178
|
+
super
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def or(other)
|
|
183
|
+
if other.is_constant?
|
|
184
|
+
raise Keisan::Exceptions::InvalidExpression.new("Cannot logical or #{self.class} and #{other.class}")
|
|
185
|
+
else
|
|
186
|
+
super
|
|
187
|
+
end
|
|
188
|
+
end
|
|
25
189
|
end
|
|
26
190
|
end
|
|
27
191
|
end
|
data/lib/keisan/ast/function.rb
CHANGED
|
@@ -91,6 +91,13 @@ module Keisan
|
|
|
91
91
|
|
|
92
92
|
self.class.new([self, variable], "diff")
|
|
93
93
|
end
|
|
94
|
+
|
|
95
|
+
# Functions cannot be guaranteed to be constant even if the arguments
|
|
96
|
+
# are constants, because there might be randomness involved in the
|
|
97
|
+
# outputs.
|
|
98
|
+
def is_constant?
|
|
99
|
+
false
|
|
100
|
+
end
|
|
94
101
|
end
|
|
95
102
|
end
|
|
96
103
|
end
|
data/lib/keisan/ast/hash.rb
CHANGED
|
@@ -21,11 +21,20 @@ module Keisan
|
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
def
|
|
25
|
-
|
|
24
|
+
def traverse(&block)
|
|
25
|
+
value = super(&block)
|
|
26
|
+
return value if value
|
|
27
|
+
@hash.each do |k, v|
|
|
28
|
+
value = k.to_node.traverse(&block)
|
|
29
|
+
return value if value
|
|
30
|
+
value = v.traverse(&block)
|
|
31
|
+
return value if value
|
|
32
|
+
end
|
|
33
|
+
false
|
|
26
34
|
end
|
|
27
35
|
|
|
28
36
|
def evaluate(context = nil)
|
|
37
|
+
return self if frozen?
|
|
29
38
|
context ||= Context.new
|
|
30
39
|
|
|
31
40
|
@hash = ::Hash[
|
|
@@ -81,6 +90,10 @@ module Keisan
|
|
|
81
90
|
])
|
|
82
91
|
AST::Cell.new(h)
|
|
83
92
|
end
|
|
93
|
+
|
|
94
|
+
def is_constant?
|
|
95
|
+
@hash.all? {|k,v| v.is_constant?}
|
|
96
|
+
end
|
|
84
97
|
end
|
|
85
98
|
end
|
|
86
99
|
end
|
data/lib/keisan/ast/list.rb
CHANGED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Keisan
|
|
2
|
+
module AST
|
|
3
|
+
class ListAssignment
|
|
4
|
+
attr_reader :assignment, :context, :lhs, :rhs
|
|
5
|
+
|
|
6
|
+
def initialize(assignment, context, lhs, rhs)
|
|
7
|
+
@assignment = assignment
|
|
8
|
+
@context = context
|
|
9
|
+
@lhs = lhs
|
|
10
|
+
@rhs = rhs
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def evaluate
|
|
14
|
+
rhs = @rhs.evaluate(context)
|
|
15
|
+
|
|
16
|
+
if !rhs.is_a?(List)
|
|
17
|
+
raise Exceptions::InvalidExpression.new("To do multiple assignment, RHS must be a list")
|
|
18
|
+
end
|
|
19
|
+
if lhs.children.size != rhs.children.size
|
|
20
|
+
raise Exceptions::InvalidExpression.new("To do multiple assignment, RHS list must have same length as LHS list")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
i = 0
|
|
24
|
+
while i < lhs.children.size
|
|
25
|
+
lhs_variable = lhs.children[i]
|
|
26
|
+
rhs_assignment = rhs.children[i]
|
|
27
|
+
individual_assignment = Assignment.new(
|
|
28
|
+
children = [lhs_variable, rhs_assignment],
|
|
29
|
+
local: assignment.local,
|
|
30
|
+
compound_operator: assignment.compound_operator
|
|
31
|
+
)
|
|
32
|
+
individual_assignment.evaluate(context)
|
|
33
|
+
i += 1
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/keisan/ast/node.rb
CHANGED
|
@@ -37,12 +37,26 @@ module Keisan
|
|
|
37
37
|
value(context)
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
# Takes a block, and does a DFS down the AST, evaluating the received block
|
|
41
|
+
# at each node, passing in the node as the single argument. If the block
|
|
42
|
+
# returns a truthy value at any point, the DFS ends and the return value is
|
|
43
|
+
# percolated up the tree.
|
|
44
|
+
def traverse(&block)
|
|
45
|
+
block.call(self)
|
|
46
|
+
end
|
|
47
|
+
|
|
40
48
|
def contains_a?(klass)
|
|
41
49
|
case klass
|
|
42
50
|
when Array
|
|
43
|
-
klass.any?
|
|
51
|
+
klass.any? do |k|
|
|
52
|
+
traverse do |node|
|
|
53
|
+
node.is_a?(k)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
44
56
|
else
|
|
45
|
-
|
|
57
|
+
traverse do |node|
|
|
58
|
+
node.is_a?(klass)
|
|
59
|
+
end
|
|
46
60
|
end
|
|
47
61
|
end
|
|
48
62
|
|
|
@@ -188,6 +202,10 @@ module Keisan
|
|
|
188
202
|
def or(other)
|
|
189
203
|
LogicalOr.new([self, other.to_node])
|
|
190
204
|
end
|
|
205
|
+
|
|
206
|
+
def is_constant?
|
|
207
|
+
false
|
|
208
|
+
end
|
|
191
209
|
end
|
|
192
210
|
end
|
|
193
211
|
end
|
data/lib/keisan/ast/number.rb
CHANGED
data/lib/keisan/ast/parent.rb
CHANGED
|
@@ -25,8 +25,14 @@ module Keisan
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
def
|
|
29
|
-
|
|
28
|
+
def traverse(&block)
|
|
29
|
+
value = super(&block)
|
|
30
|
+
return value if value
|
|
31
|
+
children.each do |child|
|
|
32
|
+
value = child.traverse(&block)
|
|
33
|
+
return value if value
|
|
34
|
+
end
|
|
35
|
+
false
|
|
30
36
|
end
|
|
31
37
|
|
|
32
38
|
def freeze
|
|
@@ -69,6 +75,10 @@ module Keisan
|
|
|
69
75
|
@children = children.map {|child| child.replace(variable, replacement)}
|
|
70
76
|
self
|
|
71
77
|
end
|
|
78
|
+
|
|
79
|
+
def is_constant?
|
|
80
|
+
@children.all?(&:is_constant?)
|
|
81
|
+
end
|
|
72
82
|
end
|
|
73
83
|
end
|
|
74
84
|
end
|
data/lib/keisan/calculator.rb
CHANGED
|
@@ -4,11 +4,12 @@ module Keisan
|
|
|
4
4
|
|
|
5
5
|
# Note, allow_recursive would be more appropriately named:
|
|
6
6
|
# allow_unbound_functions_in_function_definitions, but it is too late for that.
|
|
7
|
-
def initialize(context: nil, allow_recursive: false, allow_blocks: true, allow_multiline: true)
|
|
7
|
+
def initialize(context: nil, allow_recursive: false, allow_blocks: true, allow_multiline: true, allow_random: true)
|
|
8
8
|
@context = context || Context.new(
|
|
9
9
|
allow_recursive: allow_recursive,
|
|
10
10
|
allow_blocks: allow_blocks,
|
|
11
|
-
allow_multiline: allow_multiline
|
|
11
|
+
allow_multiline: allow_multiline,
|
|
12
|
+
allow_random: allow_random
|
|
12
13
|
)
|
|
13
14
|
end
|
|
14
15
|
|
|
@@ -28,6 +29,10 @@ module Keisan
|
|
|
28
29
|
context.allow_multiline
|
|
29
30
|
end
|
|
30
31
|
|
|
32
|
+
def allow_random
|
|
33
|
+
context.allow_random
|
|
34
|
+
end
|
|
35
|
+
|
|
31
36
|
def evaluate(expression, definitions = {})
|
|
32
37
|
Evaluator.new(self).evaluate(expression, definitions)
|
|
33
38
|
end
|
data/lib/keisan/context.rb
CHANGED
|
@@ -4,13 +4,15 @@ module Keisan
|
|
|
4
4
|
:variable_registry,
|
|
5
5
|
:allow_recursive,
|
|
6
6
|
:allow_multiline,
|
|
7
|
-
:allow_blocks
|
|
7
|
+
:allow_blocks,
|
|
8
|
+
:allow_random
|
|
8
9
|
|
|
9
10
|
def initialize(parent: nil,
|
|
10
11
|
random: nil,
|
|
11
12
|
allow_recursive: false,
|
|
12
13
|
allow_multiline: true,
|
|
13
14
|
allow_blocks: true,
|
|
15
|
+
allow_random: true,
|
|
14
16
|
shadowed: [])
|
|
15
17
|
@parent = parent
|
|
16
18
|
@function_registry = Functions::Registry.new(parent: @parent&.function_registry)
|
|
@@ -19,6 +21,7 @@ module Keisan
|
|
|
19
21
|
@allow_recursive = allow_recursive
|
|
20
22
|
@allow_multiline = allow_multiline
|
|
21
23
|
@allow_blocks = allow_blocks
|
|
24
|
+
@allow_random = allow_random
|
|
22
25
|
end
|
|
23
26
|
|
|
24
27
|
def allow_recursive!
|
|
@@ -111,10 +114,12 @@ module Keisan
|
|
|
111
114
|
end
|
|
112
115
|
|
|
113
116
|
def random
|
|
117
|
+
raise Keisan::Exceptions::InvalidExpression.new("Context does not permit expressions with randomness") unless allow_random
|
|
114
118
|
@random ||= @parent&.random || Random.new
|
|
115
119
|
end
|
|
116
120
|
|
|
117
121
|
def set_random(random)
|
|
122
|
+
raise Keisan::Exceptions::InvalidExpression.new("Context does not permit expressions with randomness") unless allow_random
|
|
118
123
|
@random = random
|
|
119
124
|
end
|
|
120
125
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require "set"
|
|
2
|
+
|
|
1
3
|
module Keisan
|
|
2
4
|
module Variables
|
|
3
5
|
class Registry
|
|
@@ -5,7 +7,7 @@ module Keisan
|
|
|
5
7
|
|
|
6
8
|
def initialize(variables: {}, shadowed: [], parent: nil, use_defaults: true, force: false)
|
|
7
9
|
@hash = {}
|
|
8
|
-
@shadowed = Set.new(shadowed.map(&:to_s))
|
|
10
|
+
@shadowed = ::Set.new(shadowed.map(&:to_s))
|
|
9
11
|
@parent = parent
|
|
10
12
|
@use_defaults = use_defaults
|
|
11
13
|
|
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.8.
|
|
4
|
+
version: 0.8.12
|
|
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-05-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: cmath
|
|
@@ -151,6 +151,7 @@ files:
|
|
|
151
151
|
- lib/keisan/ast/indexing.rb
|
|
152
152
|
- lib/keisan/ast/line_builder.rb
|
|
153
153
|
- lib/keisan/ast/list.rb
|
|
154
|
+
- lib/keisan/ast/list_assignment.rb
|
|
154
155
|
- lib/keisan/ast/literal.rb
|
|
155
156
|
- lib/keisan/ast/logical_and.rb
|
|
156
157
|
- lib/keisan/ast/logical_equal.rb
|