keisan 0.5.0 → 0.6.0
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 +49 -1
- data/keisan.gemspec +1 -0
- data/lib/keisan.rb +30 -0
- data/lib/keisan/ast/assignment.rb +44 -17
- data/lib/keisan/ast/block.rb +60 -0
- data/lib/keisan/ast/boolean.rb +5 -5
- data/lib/keisan/ast/builder.rb +10 -207
- data/lib/keisan/ast/cell.rb +60 -0
- data/lib/keisan/ast/constant_literal.rb +9 -0
- data/lib/keisan/ast/exponent.rb +6 -6
- data/lib/keisan/ast/function.rb +12 -8
- data/lib/keisan/ast/indexing.rb +25 -15
- data/lib/keisan/ast/line_builder.rb +230 -0
- data/lib/keisan/ast/list.rb +28 -1
- data/lib/keisan/ast/literal.rb +0 -8
- data/lib/keisan/ast/logical_and.rb +1 -1
- data/lib/keisan/ast/logical_or.rb +1 -1
- data/lib/keisan/ast/multi_line.rb +28 -0
- data/lib/keisan/ast/node.rb +32 -24
- data/lib/keisan/ast/number.rb +31 -31
- data/lib/keisan/ast/operator.rb +12 -4
- data/lib/keisan/ast/parent.rb +4 -4
- data/lib/keisan/ast/plus.rb +10 -10
- data/lib/keisan/ast/string.rb +3 -3
- data/lib/keisan/ast/times.rb +8 -8
- data/lib/keisan/ast/unary_identity.rb +1 -1
- data/lib/keisan/ast/unary_inverse.rb +7 -7
- data/lib/keisan/ast/unary_minus.rb +5 -5
- data/lib/keisan/ast/unary_operator.rb +2 -2
- data/lib/keisan/ast/unary_plus.rb +2 -2
- data/lib/keisan/ast/variable.rb +26 -10
- data/lib/keisan/context.rb +5 -5
- data/lib/keisan/evaluator.rb +15 -8
- data/lib/keisan/function.rb +24 -6
- data/lib/keisan/functions/cbrt.rb +1 -1
- data/lib/keisan/functions/cos.rb +1 -1
- data/lib/keisan/functions/cosh.rb +1 -1
- data/lib/keisan/functions/cot.rb +1 -1
- data/lib/keisan/functions/coth.rb +1 -1
- data/lib/keisan/functions/csc.rb +1 -1
- data/lib/keisan/functions/csch.rb +1 -1
- data/lib/keisan/functions/default_registry.rb +53 -74
- data/lib/keisan/functions/diff.rb +18 -14
- data/lib/keisan/functions/erf.rb +15 -0
- data/lib/keisan/functions/exp.rb +1 -1
- data/lib/keisan/functions/expression_function.rb +15 -21
- data/lib/keisan/functions/filter.rb +13 -15
- data/lib/keisan/functions/if.rb +14 -20
- data/lib/keisan/functions/let.rb +36 -0
- data/lib/keisan/functions/map.rb +11 -13
- data/lib/keisan/functions/math_function.rb +2 -2
- data/lib/keisan/functions/proc_function.rb +10 -6
- data/lib/keisan/functions/rand.rb +2 -1
- data/lib/keisan/functions/range.rb +74 -0
- data/lib/keisan/functions/reduce.rb +12 -14
- data/lib/keisan/functions/registry.rb +7 -7
- data/lib/keisan/functions/replace.rb +8 -8
- data/lib/keisan/functions/sample.rb +2 -1
- data/lib/keisan/functions/sec.rb +1 -1
- data/lib/keisan/functions/sech.rb +1 -1
- data/lib/keisan/functions/sin.rb +1 -1
- data/lib/keisan/functions/sinh.rb +1 -1
- data/lib/keisan/functions/sqrt.rb +1 -1
- data/lib/keisan/functions/tan.rb +1 -1
- data/lib/keisan/functions/tanh.rb +1 -1
- data/lib/keisan/functions/while.rb +46 -0
- data/lib/keisan/parser.rb +121 -79
- data/lib/keisan/parsing/assignment.rb +1 -1
- data/lib/keisan/parsing/bitwise_and.rb +1 -1
- data/lib/keisan/parsing/bitwise_not.rb +1 -1
- data/lib/keisan/parsing/bitwise_not_not.rb +1 -1
- data/lib/keisan/parsing/bitwise_or.rb +1 -1
- data/lib/keisan/parsing/bitwise_xor.rb +1 -1
- data/lib/keisan/parsing/curly_group.rb +6 -0
- data/lib/keisan/parsing/divide.rb +1 -1
- data/lib/keisan/parsing/exponent.rb +1 -1
- data/lib/keisan/parsing/function.rb +1 -1
- data/lib/keisan/parsing/group.rb +1 -1
- data/lib/keisan/parsing/indexing.rb +1 -1
- data/lib/keisan/parsing/line_separator.rb +6 -0
- data/lib/keisan/parsing/logical_and.rb +1 -1
- data/lib/keisan/parsing/logical_equal.rb +1 -1
- data/lib/keisan/parsing/logical_greater_than.rb +1 -1
- data/lib/keisan/parsing/logical_greater_than_or_equal_to.rb +1 -1
- data/lib/keisan/parsing/logical_less_than.rb +1 -1
- data/lib/keisan/parsing/logical_less_than_or_equal_to.rb +1 -1
- data/lib/keisan/parsing/logical_not.rb +1 -1
- data/lib/keisan/parsing/logical_not_equal.rb +1 -1
- data/lib/keisan/parsing/logical_not_not.rb +1 -1
- data/lib/keisan/parsing/logical_or.rb +1 -1
- data/lib/keisan/parsing/minus.rb +1 -1
- data/lib/keisan/parsing/modulo.rb +1 -1
- data/lib/keisan/parsing/operator.rb +1 -1
- data/lib/keisan/parsing/plus.rb +1 -1
- data/lib/keisan/parsing/times.rb +1 -1
- data/lib/keisan/parsing/unary_minus.rb +1 -1
- data/lib/keisan/parsing/unary_operator.rb +1 -1
- data/lib/keisan/parsing/unary_plus.rb +1 -1
- data/lib/keisan/repl.rb +1 -1
- data/lib/keisan/tokenizer.rb +4 -9
- data/lib/keisan/tokens/group.rb +3 -1
- data/lib/keisan/tokens/line_separator.rb +11 -0
- data/lib/keisan/variables/default_registry.rb +0 -5
- data/lib/keisan/variables/registry.rb +7 -7
- data/lib/keisan/version.rb +1 -1
- metadata +27 -2
data/lib/keisan/ast/list.rb
CHANGED
@@ -1,14 +1,41 @@
|
|
1
1
|
module Keisan
|
2
2
|
module AST
|
3
3
|
class List < Parent
|
4
|
+
def initialize(children = [])
|
5
|
+
super(children)
|
6
|
+
cellify!
|
7
|
+
end
|
8
|
+
|
9
|
+
def evaluate(context = nil)
|
10
|
+
context ||= Context.new
|
11
|
+
super(context)
|
12
|
+
cellify!
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def simplify(context = nil)
|
17
|
+
context ||= Context.new
|
18
|
+
super(context)
|
19
|
+
cellify!
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
4
23
|
def value(context = nil)
|
5
|
-
context ||=
|
24
|
+
context ||= Context.new
|
6
25
|
children.map {|child| child.value(context)}
|
7
26
|
end
|
8
27
|
|
9
28
|
def to_s
|
10
29
|
"[#{children.map(&:to_s).join(',')}]"
|
11
30
|
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def cellify!
|
35
|
+
@children = @children.map do |child|
|
36
|
+
child.is_a?(Cell) ? child : Cell.new(child)
|
37
|
+
end
|
38
|
+
end
|
12
39
|
end
|
13
40
|
end
|
14
41
|
end
|
data/lib/keisan/ast/literal.rb
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Keisan
|
2
|
+
module AST
|
3
|
+
class MultiLine < Parent
|
4
|
+
def value(context = nil)
|
5
|
+
context ||= Context.new
|
6
|
+
evaluate(context).value(context)
|
7
|
+
end
|
8
|
+
|
9
|
+
def evaluate_assignments(context = nil)
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def evaluate(context = nil)
|
14
|
+
context ||= Context.new
|
15
|
+
@children = children.map {|child| child.evaluate(context)}
|
16
|
+
@children.last
|
17
|
+
end
|
18
|
+
|
19
|
+
def simplify(context = nil)
|
20
|
+
evaluate(context)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
children.map(&:to_s).join(";")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/keisan/ast/node.rb
CHANGED
@@ -2,7 +2,7 @@ module Keisan
|
|
2
2
|
module AST
|
3
3
|
class Node
|
4
4
|
def value(context = nil)
|
5
|
-
raise
|
5
|
+
raise Exceptions::NotImplementedError.new
|
6
6
|
end
|
7
7
|
|
8
8
|
def unbound_variables(context = nil)
|
@@ -29,12 +29,20 @@ module Keisan
|
|
29
29
|
self
|
30
30
|
end
|
31
31
|
|
32
|
+
def evaluated(context = nil)
|
33
|
+
deep_dup.evaluate(context)
|
34
|
+
end
|
35
|
+
|
32
36
|
def evaluate(context = nil)
|
37
|
+
value(context)
|
38
|
+
end
|
39
|
+
|
40
|
+
def evaluate_assignments(context = nil)
|
33
41
|
self
|
34
42
|
end
|
35
43
|
|
36
44
|
def differentiate(variable, context = nil)
|
37
|
-
raise
|
45
|
+
raise Exceptions::NonDifferentiableError.new
|
38
46
|
end
|
39
47
|
|
40
48
|
def replace(variable, replacement)
|
@@ -50,41 +58,41 @@ module Keisan
|
|
50
58
|
end
|
51
59
|
|
52
60
|
def +(other)
|
53
|
-
|
61
|
+
Plus.new(
|
54
62
|
[self, other.to_node]
|
55
63
|
)
|
56
64
|
end
|
57
65
|
|
58
66
|
def -(other)
|
59
|
-
|
60
|
-
[self,
|
67
|
+
Plus.new(
|
68
|
+
[self, UnaryMinus.new(other.to_node)]
|
61
69
|
)
|
62
70
|
end
|
63
71
|
|
64
72
|
def *(other)
|
65
|
-
|
73
|
+
Times.new(
|
66
74
|
[self, other.to_node]
|
67
75
|
)
|
68
76
|
end
|
69
77
|
|
70
78
|
def /(other)
|
71
|
-
|
72
|
-
[self,
|
79
|
+
Times.new(
|
80
|
+
[self, UnaryInverse.new(other.to_node)]
|
73
81
|
)
|
74
82
|
end
|
75
83
|
|
76
84
|
def %(other)
|
77
|
-
|
85
|
+
Modulo.new(
|
78
86
|
[self, other.to_node]
|
79
87
|
)
|
80
88
|
end
|
81
89
|
|
82
90
|
def !
|
83
|
-
|
91
|
+
UnaryLogicalNot.new(self)
|
84
92
|
end
|
85
93
|
|
86
94
|
def ~
|
87
|
-
|
95
|
+
UnaryBitwiseNot.new(self)
|
88
96
|
end
|
89
97
|
|
90
98
|
def +@
|
@@ -92,55 +100,55 @@ module Keisan
|
|
92
100
|
end
|
93
101
|
|
94
102
|
def -@
|
95
|
-
|
103
|
+
UnaryMinus.new(self)
|
96
104
|
end
|
97
105
|
|
98
106
|
def **(other)
|
99
|
-
|
107
|
+
Exponent.new([self, other.to_node])
|
100
108
|
end
|
101
109
|
|
102
110
|
def &(other)
|
103
|
-
|
111
|
+
BitwiseAnd.new([self, other.to_node])
|
104
112
|
end
|
105
113
|
|
106
114
|
def ^(other)
|
107
|
-
|
115
|
+
BitwiseXor.new([self, other.to_node])
|
108
116
|
end
|
109
117
|
|
110
118
|
def |(other)
|
111
|
-
|
119
|
+
BitwiseOr.new([self, other.to_node])
|
112
120
|
end
|
113
121
|
|
114
122
|
def >(other)
|
115
|
-
|
123
|
+
LogicalGreaterThan.new([self, other.to_node])
|
116
124
|
end
|
117
125
|
|
118
126
|
def >=(other)
|
119
|
-
|
127
|
+
LogicalGreaterThanOrEqualTo.new([self, other.to_node])
|
120
128
|
end
|
121
129
|
|
122
130
|
def <(other)
|
123
|
-
|
131
|
+
LogicalLessThan.new([self, other.to_node])
|
124
132
|
end
|
125
133
|
|
126
134
|
def <=(other)
|
127
|
-
|
135
|
+
LogicalLessThanOrEqualTo.new([self, other.to_node])
|
128
136
|
end
|
129
137
|
|
130
138
|
def equal(other)
|
131
|
-
|
139
|
+
LogicalEqual.new([self, other.to_node])
|
132
140
|
end
|
133
141
|
|
134
142
|
def not_equal(other)
|
135
|
-
|
143
|
+
LogicalNotEqual.new([self, other.to_node])
|
136
144
|
end
|
137
145
|
|
138
146
|
def and(other)
|
139
|
-
|
147
|
+
LogicalAnd.new([self, other.to_node])
|
140
148
|
end
|
141
149
|
|
142
150
|
def or(other)
|
143
|
-
|
151
|
+
LogicalOr.new([self, other.to_node])
|
144
152
|
end
|
145
153
|
end
|
146
154
|
end
|
data/lib/keisan/ast/number.rb
CHANGED
@@ -12,18 +12,18 @@ module Keisan
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def -@
|
15
|
-
|
15
|
+
Number.new(-value)
|
16
16
|
end
|
17
17
|
|
18
18
|
def +@
|
19
|
-
|
19
|
+
Number.new(value)
|
20
20
|
end
|
21
21
|
|
22
22
|
def +(other)
|
23
23
|
other = other.to_node
|
24
24
|
case other
|
25
|
-
when
|
26
|
-
|
25
|
+
when Number
|
26
|
+
Number.new(value + other.value)
|
27
27
|
else
|
28
28
|
super
|
29
29
|
end
|
@@ -36,8 +36,8 @@ module Keisan
|
|
36
36
|
def *(other)
|
37
37
|
other = other.to_node
|
38
38
|
case other
|
39
|
-
when
|
40
|
-
|
39
|
+
when Number
|
40
|
+
Number.new(value * other.value)
|
41
41
|
else
|
42
42
|
super
|
43
43
|
end
|
@@ -46,8 +46,8 @@ module Keisan
|
|
46
46
|
def /(other)
|
47
47
|
other = other.to_node
|
48
48
|
case other
|
49
|
-
when
|
50
|
-
|
49
|
+
when Number
|
50
|
+
Number.new(Rational(value, other.value))
|
51
51
|
else
|
52
52
|
super
|
53
53
|
end
|
@@ -56,8 +56,8 @@ module Keisan
|
|
56
56
|
def **(other)
|
57
57
|
other = other.to_node
|
58
58
|
case other
|
59
|
-
when
|
60
|
-
|
59
|
+
when Number
|
60
|
+
Number.new(value ** other.value)
|
61
61
|
else
|
62
62
|
super
|
63
63
|
end
|
@@ -66,8 +66,8 @@ module Keisan
|
|
66
66
|
def %(other)
|
67
67
|
other = other.to_node
|
68
68
|
case other
|
69
|
-
when
|
70
|
-
|
69
|
+
when Number
|
70
|
+
Number.new(value % other.value)
|
71
71
|
else
|
72
72
|
super
|
73
73
|
end
|
@@ -76,22 +76,22 @@ module Keisan
|
|
76
76
|
def &(other)
|
77
77
|
other = other.to_node
|
78
78
|
case other
|
79
|
-
when
|
80
|
-
|
79
|
+
when Number
|
80
|
+
Number.new(value & other.value)
|
81
81
|
else
|
82
82
|
super
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
86
|
def ~
|
87
|
-
|
87
|
+
Number.new(~value)
|
88
88
|
end
|
89
89
|
|
90
90
|
def ^(other)
|
91
91
|
other = other.to_node
|
92
92
|
case other
|
93
|
-
when
|
94
|
-
|
93
|
+
when Number
|
94
|
+
Number.new(value ^ other.value)
|
95
95
|
else
|
96
96
|
super
|
97
97
|
end
|
@@ -100,8 +100,8 @@ module Keisan
|
|
100
100
|
def |(other)
|
101
101
|
other = other.to_node
|
102
102
|
case other
|
103
|
-
when
|
104
|
-
|
103
|
+
when Number
|
104
|
+
Number.new(value | other.value)
|
105
105
|
else
|
106
106
|
super
|
107
107
|
end
|
@@ -110,8 +110,8 @@ module Keisan
|
|
110
110
|
def >(other)
|
111
111
|
other = other.to_node
|
112
112
|
case other
|
113
|
-
when
|
114
|
-
|
113
|
+
when Number
|
114
|
+
Boolean.new(value > other.value)
|
115
115
|
else
|
116
116
|
super
|
117
117
|
end
|
@@ -120,8 +120,8 @@ module Keisan
|
|
120
120
|
def >=(other)
|
121
121
|
other = other.to_node
|
122
122
|
case other
|
123
|
-
when
|
124
|
-
|
123
|
+
when Number
|
124
|
+
Boolean.new(value >= other.value)
|
125
125
|
else
|
126
126
|
super
|
127
127
|
end
|
@@ -130,8 +130,8 @@ module Keisan
|
|
130
130
|
def <(other)
|
131
131
|
other = other.to_node
|
132
132
|
case other
|
133
|
-
when
|
134
|
-
|
133
|
+
when Number
|
134
|
+
Boolean.new(value < other.value)
|
135
135
|
else
|
136
136
|
super
|
137
137
|
end
|
@@ -140,8 +140,8 @@ module Keisan
|
|
140
140
|
def <=(other)
|
141
141
|
other = other.to_node
|
142
142
|
case other
|
143
|
-
when
|
144
|
-
|
143
|
+
when Number
|
144
|
+
Boolean.new(value <= other.value)
|
145
145
|
else
|
146
146
|
super
|
147
147
|
end
|
@@ -150,8 +150,8 @@ module Keisan
|
|
150
150
|
def equal(other)
|
151
151
|
other = other.to_node
|
152
152
|
case other
|
153
|
-
when
|
154
|
-
|
153
|
+
when Number
|
154
|
+
Boolean.new(value == other.value)
|
155
155
|
else
|
156
156
|
super
|
157
157
|
end
|
@@ -160,8 +160,8 @@ module Keisan
|
|
160
160
|
def not_equal(other)
|
161
161
|
other = other.to_node
|
162
162
|
case other
|
163
|
-
when
|
164
|
-
|
163
|
+
when Number
|
164
|
+
Boolean.new(value != other.value)
|
165
165
|
else
|
166
166
|
super
|
167
167
|
end
|
data/lib/keisan/ast/operator.rb
CHANGED
@@ -38,7 +38,7 @@ module Keisan
|
|
38
38
|
|
39
39
|
def initialize(children = [], parsing_operators = [])
|
40
40
|
unless parsing_operators.empty? || children.count == parsing_operators.count + 1
|
41
|
-
raise
|
41
|
+
raise Exceptions::ASTError.new("Mismatch of children and operators")
|
42
42
|
end
|
43
43
|
|
44
44
|
children = Array.wrap(children)
|
@@ -47,6 +47,14 @@ module Keisan
|
|
47
47
|
@parsing_operators = parsing_operators
|
48
48
|
end
|
49
49
|
|
50
|
+
def evaluate_assignments(context = nil)
|
51
|
+
context ||= Context.new
|
52
|
+
@children = children.map do |child|
|
53
|
+
child.evaluate_assignments(context)
|
54
|
+
end
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
50
58
|
def self.associativity_of_priority(priority)
|
51
59
|
ASSOCIATIVITY_OF_PRIORITY[priority]
|
52
60
|
end
|
@@ -80,11 +88,11 @@ module Keisan
|
|
80
88
|
end
|
81
89
|
|
82
90
|
def self.symbol
|
83
|
-
raise
|
91
|
+
raise Exceptions::NotImplementedError.new
|
84
92
|
end
|
85
93
|
|
86
94
|
def blank_value
|
87
|
-
raise
|
95
|
+
raise Exceptions::NotImplementedError.new
|
88
96
|
end
|
89
97
|
|
90
98
|
def value(context = nil)
|
@@ -103,7 +111,7 @@ module Keisan
|
|
103
111
|
def to_s
|
104
112
|
children.map do |child|
|
105
113
|
case child
|
106
|
-
when
|
114
|
+
when Operator
|
107
115
|
"(#{child.to_s})"
|
108
116
|
else
|
109
117
|
"#{child.to_s}"
|