keisan 0.3.0 → 0.4.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 +57 -9
- data/lib/keisan.rb +21 -12
- data/lib/keisan/ast.rb +50 -0
- data/lib/keisan/ast/arithmetic_operator.rb +0 -3
- data/lib/keisan/ast/assignment.rb +72 -0
- data/lib/keisan/ast/bitwise_and.rb +4 -4
- data/lib/keisan/ast/bitwise_operator.rb +0 -3
- data/lib/keisan/ast/bitwise_or.rb +4 -4
- data/lib/keisan/ast/bitwise_xor.rb +4 -4
- data/lib/keisan/ast/boolean.rb +25 -1
- data/lib/keisan/ast/builder.rb +98 -63
- data/lib/keisan/ast/constant_literal.rb +13 -0
- data/lib/keisan/ast/exponent.rb +62 -8
- data/lib/keisan/ast/function.rb +37 -26
- data/lib/keisan/ast/functions/diff.rb +57 -0
- data/lib/keisan/ast/functions/if.rb +47 -0
- data/lib/keisan/ast/indexing.rb +44 -4
- data/lib/keisan/ast/list.rb +4 -0
- data/lib/keisan/ast/literal.rb +8 -0
- data/lib/keisan/ast/logical_and.rb +9 -4
- data/lib/keisan/ast/logical_equal.rb +4 -4
- 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 +4 -4
- data/lib/keisan/ast/logical_operator.rb +0 -3
- data/lib/keisan/ast/logical_or.rb +10 -5
- data/lib/keisan/ast/modulo.rb +4 -4
- data/lib/keisan/ast/node.rb +132 -20
- data/lib/keisan/ast/null.rb +1 -1
- data/lib/keisan/ast/number.rb +172 -1
- data/lib/keisan/ast/operator.rb +66 -8
- data/lib/keisan/ast/parent.rb +50 -0
- data/lib/keisan/ast/plus.rb +38 -4
- data/lib/keisan/ast/string.rb +10 -1
- data/lib/keisan/ast/times.rb +47 -4
- data/lib/keisan/ast/unary_bitwise_not.rb +9 -1
- data/lib/keisan/ast/unary_identity.rb +18 -1
- data/lib/keisan/ast/unary_inverse.rb +35 -1
- data/lib/keisan/ast/unary_logical_not.rb +5 -1
- data/lib/keisan/ast/unary_minus.rb +31 -1
- data/lib/keisan/ast/unary_operator.rb +29 -1
- data/lib/keisan/ast/unary_plus.rb +14 -1
- data/lib/keisan/ast/variable.rb +44 -0
- data/lib/keisan/calculator.rb +2 -2
- data/lib/keisan/context.rb +32 -16
- data/lib/keisan/evaluator.rb +10 -65
- data/lib/keisan/exceptions.rb +2 -0
- data/lib/keisan/function.rb +11 -5
- data/lib/keisan/function_definition_context.rb +34 -0
- data/lib/keisan/functions/default_registry.rb +13 -5
- data/lib/keisan/functions/diff.rb +82 -0
- data/lib/keisan/functions/expression_function.rb +63 -0
- data/lib/keisan/functions/if.rb +62 -0
- data/lib/keisan/functions/proc_function.rb +52 -0
- data/lib/keisan/functions/rand.rb +1 -1
- data/lib/keisan/functions/registry.rb +20 -10
- data/lib/keisan/functions/replace.rb +49 -0
- data/lib/keisan/functions/sample.rb +1 -1
- data/lib/keisan/parser.rb +13 -1
- data/lib/keisan/parsing/assignment.rb +9 -0
- data/lib/keisan/parsing/operator.rb +8 -0
- data/lib/keisan/parsing/unary_operator.rb +1 -1
- data/lib/keisan/tokenizer.rb +1 -0
- data/lib/keisan/tokens/assignment.rb +15 -0
- data/lib/keisan/variables/default_registry.rb +4 -4
- data/lib/keisan/variables/registry.rb +17 -8
- data/lib/keisan/version.rb +1 -1
- metadata +15 -3
- data/lib/keisan/ast/priorities.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 32b53dd19dc29bced6d98d110f7d11c0a7d22ea5
|
4
|
+
data.tar.gz: d55ec179a6f8b1e597cb322e42bab4ed0b959fed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4c87fabd551121df563306488410003e9291b1569330ca3da65d833b9e9e97f925dcbc3d07e23cb9c5e05272b8fe74028766388064e0713ff66d625261a5752
|
7
|
+
data.tar.gz: cdfef6449002d021fe83b10457959e5d1bccf81aa569be908e6ba98026f0adc2df44eeb3a60b6d013126e6d278992cd8a50b4c397c11460656a33574f0234ad7
|
data/README.md
CHANGED
@@ -112,9 +112,14 @@ calculator.evaluate("n") # n only exists in the definition of f(x)
|
|
112
112
|
#=> Keisan::Exceptions::UndefinedVariableError: n
|
113
113
|
```
|
114
114
|
|
115
|
-
This form even supports recursion
|
115
|
+
This form even supports recursion, but you must explicitly allow it.
|
116
116
|
|
117
117
|
```ruby
|
118
|
+
calculator = Keisan::Calculator.new(allow_recursive: false)
|
119
|
+
calculator.evaluate("my_fact(n) = if (n > 1, n*my_fact(n-1), 1)")
|
120
|
+
#=> Keisan::Exceptions::InvalidExpression: Unbound function definitions are not allowed by current context
|
121
|
+
|
122
|
+
calculator = Keisan::Calculator.new(allow_recursive: true)
|
118
123
|
calculator.evaluate("my_fact(n) = if (n > 1, n*my_fact(n-1), 1)")
|
119
124
|
calculator.evaluate("my_fact(0)")
|
120
125
|
#=> 1
|
@@ -190,7 +195,7 @@ Using the prefixes `0b`, `0o`, and `0x` (standard in Ruby) indicates binary, oct
|
|
190
195
|
calculator.evaluate("0b1100")
|
191
196
|
#=> 12
|
192
197
|
calculator.evaluate("0o775")
|
193
|
-
#=>
|
198
|
+
#=> 509
|
194
199
|
calculator.evaluate("0x1f0")
|
195
200
|
#=> 496
|
196
201
|
```
|
@@ -209,8 +214,8 @@ calculator.evaluate("sample([2, 4, 6, 8])")
|
|
209
214
|
If you want reproducibility, you can pass in your own `Random` object to the calculator's context.
|
210
215
|
|
211
216
|
```ruby
|
212
|
-
calculator1 = Keisan::Calculator.new(Keisan::Context.new(random: Random.new(1234)))
|
213
|
-
calculator2 = Keisan::Calculator.new(Keisan::Context.new(random: Random.new(1234)))
|
217
|
+
calculator1 = Keisan::Calculator.new(context: Keisan::Context.new(random: Random.new(1234)))
|
218
|
+
calculator2 = Keisan::Calculator.new(context: Keisan::Context.new(random: Random.new(1234)))
|
214
219
|
5.times.map {calculator1.evaluate("rand(1000)")}
|
215
220
|
#=> [815, 723, 294, 53, 204]
|
216
221
|
5.times.map {calculator2.evaluate("rand(1000)")}
|
@@ -229,24 +234,48 @@ calculator.evaluate("log10(1000)")
|
|
229
234
|
Furthermore, the following builtin constants are defined
|
230
235
|
|
231
236
|
```ruby
|
232
|
-
calculator.evaluate("
|
237
|
+
calculator.evaluate("PI")
|
233
238
|
#=> 3.141592653589793
|
234
|
-
calculator.evaluate("
|
239
|
+
calculator.evaluate("E")
|
235
240
|
#=> 2.718281828459045
|
236
|
-
calculator.evaluate("
|
241
|
+
calculator.evaluate("I")
|
237
242
|
#=> (0+1i)
|
238
243
|
```
|
239
244
|
|
240
245
|
This allows for simple calculations like
|
241
246
|
|
242
247
|
```ruby
|
243
|
-
calculator.evaluate("
|
248
|
+
calculator.evaluate("E**(I*PI)+1")
|
244
249
|
=> (0.0+0.0i)
|
245
250
|
```
|
246
251
|
|
252
|
+
There is a `replace` method that can replace instances of a variable in an expression with another expression. The form is `replace(original_expression, variable_to_replace, replacement_expression)`. Before the replacement is carried out, the `original_expression` and `replacement_expression` are `evaluate`d, then instances in the original expression of the given variable are replaced by the replacement expression.
|
253
|
+
|
254
|
+
```ruby
|
255
|
+
calculator.evaluate("replace(x**2, x, 3)")
|
256
|
+
#=> 9
|
257
|
+
```
|
258
|
+
|
259
|
+
When using `Calculator` class, all variables must be replaced before an expression can be calculated, but the ability to replace any expression is useful when working directly with the AST.
|
260
|
+
|
261
|
+
```ruby
|
262
|
+
ast = Keisan::AST.parse("replace(replace(x**2 + y**2, x, sin(theta)), y, cos(theta))")
|
263
|
+
ast.evaluate.to_s
|
264
|
+
#=> "(sin(theta)**2)+(cos(theta)**2)"
|
265
|
+
```
|
266
|
+
|
267
|
+
The derivative operation is also builtin to Keisan as the `diff` function.
|
268
|
+
|
269
|
+
```ruby
|
270
|
+
calculator = Keisan::Calculator.new
|
271
|
+
calculator.evaluate("diff(4*x, x)")
|
272
|
+
calculator.evaluate("replace(diff(4*x**2, x), x, 3)")
|
273
|
+
#=> 24
|
274
|
+
```
|
275
|
+
|
247
276
|
### Adding custom variables and functions
|
248
277
|
|
249
|
-
The `Keisan::Calculator` class has a single `Keisan::Context` object in its `context` attribute. This class is used to store local variables and functions. As an example of pre-defining some variables and functions, see the following
|
278
|
+
The `Keisan::Calculator` class has a single `Keisan::Context` object in its `context` attribute. This class is used to store local variables and functions. These can be stored using either the `define_variable!` or `define_function!` methods, or by using the assignment operator `=` in an expression that is evaluated. As an example of pre-defining some variables and functions, see the following
|
250
279
|
|
251
280
|
```ruby
|
252
281
|
calculator.define_variable!("x", 5)
|
@@ -257,11 +286,21 @@ calculator.evaluate("x + 1", x: 10)
|
|
257
286
|
#=> 11
|
258
287
|
calculator.evaluate("x + 1")
|
259
288
|
#=> 6
|
289
|
+
|
290
|
+
calculator.evaluate("x = y = 10")
|
291
|
+
#=> 10
|
292
|
+
calculator.evaluate("x + y")
|
293
|
+
#=> 20
|
294
|
+
calculator.evaluate("x + y", y: 100)
|
295
|
+
#=> 110
|
296
|
+
calculator.evaluate("x + y")
|
297
|
+
#=> 20
|
260
298
|
```
|
261
299
|
|
262
300
|
Notice how when passing variable values directly to the `evaluate` method, it only shadows the value of 5 for that specific calculation. The same thing works for functions
|
263
301
|
|
264
302
|
```ruby
|
303
|
+
calculator = Keisan::Calculator.new
|
265
304
|
calculator.define_function!("f", Proc.new {|x| 3*x})
|
266
305
|
#=> #<Keisan::Function:0x005570f935ecc8 @function_proc=#<Proc:0x005570f935ecf0@(pry):6>, @name="f">
|
267
306
|
calculator.evaluate("f(2)")
|
@@ -270,6 +309,15 @@ calculator.evaluate("f(2)", f: Proc.new {|x| 10*x})
|
|
270
309
|
#=> 20
|
271
310
|
calculator.evaluate("f(2)")
|
272
311
|
#=> 6
|
312
|
+
|
313
|
+
calculator.evaluate("f(x) = x + x**2")
|
314
|
+
#=> nil
|
315
|
+
calculator.evaluate("f(3)")
|
316
|
+
#=> 12
|
317
|
+
calculator.evaluate("f(3)", f: Proc.new {|x| 10*x})
|
318
|
+
#=> 30
|
319
|
+
calculator.evaluate("f(3)")
|
320
|
+
#=> 12
|
273
321
|
```
|
274
322
|
|
275
323
|
## Supported elements/operators
|
data/lib/keisan.rb
CHANGED
@@ -4,32 +4,26 @@ require "active_support/core_ext"
|
|
4
4
|
require "keisan/version"
|
5
5
|
require "keisan/exceptions"
|
6
6
|
|
7
|
-
require "keisan/function"
|
8
|
-
require "keisan/functions/registry"
|
9
|
-
require "keisan/functions/default_registry"
|
10
|
-
require "keisan/variables/registry"
|
11
|
-
require "keisan/variables/default_registry"
|
12
|
-
require "keisan/context"
|
13
|
-
|
14
|
-
require "keisan/ast/priorities"
|
15
7
|
require "keisan/ast/node"
|
16
8
|
|
17
9
|
require "keisan/ast/literal"
|
10
|
+
require "keisan/ast/variable"
|
11
|
+
require "keisan/ast/constant_literal"
|
18
12
|
require "keisan/ast/number"
|
19
13
|
require "keisan/ast/string"
|
20
14
|
require "keisan/ast/null"
|
21
15
|
require "keisan/ast/boolean"
|
22
|
-
require "keisan/ast/variable"
|
23
16
|
|
24
17
|
require "keisan/ast/parent"
|
18
|
+
require "keisan/ast/operator"
|
19
|
+
require "keisan/ast/assignment"
|
25
20
|
require "keisan/ast/unary_operator"
|
21
|
+
require "keisan/ast/unary_identity"
|
26
22
|
require "keisan/ast/unary_plus"
|
27
23
|
require "keisan/ast/unary_minus"
|
28
24
|
require "keisan/ast/unary_inverse"
|
29
25
|
require "keisan/ast/unary_bitwise_not"
|
30
26
|
require "keisan/ast/unary_logical_not"
|
31
|
-
require "keisan/ast/unary_identity"
|
32
|
-
require "keisan/ast/operator"
|
33
27
|
require "keisan/ast/arithmetic_operator"
|
34
28
|
require "keisan/ast/plus"
|
35
29
|
require "keisan/ast/times"
|
@@ -54,6 +48,17 @@ require "keisan/ast/list"
|
|
54
48
|
require "keisan/ast/indexing"
|
55
49
|
|
56
50
|
require "keisan/ast/builder"
|
51
|
+
require "keisan/ast"
|
52
|
+
|
53
|
+
require "keisan/function"
|
54
|
+
require "keisan/functions/proc_function"
|
55
|
+
require "keisan/functions/expression_function"
|
56
|
+
require "keisan/functions/registry"
|
57
|
+
require "keisan/functions/default_registry"
|
58
|
+
require "keisan/variables/registry"
|
59
|
+
require "keisan/variables/default_registry"
|
60
|
+
require "keisan/context"
|
61
|
+
require "keisan/function_definition_context"
|
57
62
|
|
58
63
|
require "keisan/token"
|
59
64
|
require "keisan/tokens/comma"
|
@@ -64,6 +69,7 @@ require "keisan/tokens/operator"
|
|
64
69
|
require "keisan/tokens/string"
|
65
70
|
require "keisan/tokens/null"
|
66
71
|
require "keisan/tokens/boolean"
|
72
|
+
require "keisan/tokens/assignment"
|
67
73
|
require "keisan/tokens/arithmetic_operator"
|
68
74
|
require "keisan/tokens/logical_operator"
|
69
75
|
require "keisan/tokens/bitwise_operator"
|
@@ -90,11 +96,14 @@ require "keisan/parsing/list"
|
|
90
96
|
require "keisan/parsing/indexing"
|
91
97
|
require "keisan/parsing/argument"
|
92
98
|
|
99
|
+
require "keisan/parsing/operator"
|
100
|
+
|
101
|
+
require "keisan/parsing/assignment"
|
102
|
+
|
93
103
|
require "keisan/parsing/unary_operator"
|
94
104
|
require "keisan/parsing/unary_plus"
|
95
105
|
require "keisan/parsing/unary_minus"
|
96
106
|
|
97
|
-
require "keisan/parsing/operator"
|
98
107
|
require "keisan/parsing/arithmetic_operator"
|
99
108
|
require "keisan/parsing/plus"
|
100
109
|
require "keisan/parsing/minus"
|
data/lib/keisan/ast.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Keisan
|
2
|
+
module AST
|
3
|
+
def self.parse(expression)
|
4
|
+
AST::Builder.new(string: expression).ast
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module KeisanNumeric
|
10
|
+
def to_node
|
11
|
+
Keisan::AST::Number.new(self)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module KeisanString
|
16
|
+
def to_node
|
17
|
+
Keisan::AST::String.new(self)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module KeisanTrueClass
|
22
|
+
def to_node
|
23
|
+
Keisan::AST::Boolean.new(true)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module KeisanFalseClass
|
28
|
+
def to_node
|
29
|
+
Keisan::AST::Boolean.new(false)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module KeisanNilClass
|
34
|
+
def to_node
|
35
|
+
Keisan::AST::Null.new
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module KeisanArray
|
40
|
+
def to_node
|
41
|
+
Keisan::AST::List.new(map {|n| n.to_node})
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Numeric; prepend KeisanNumeric; end
|
46
|
+
class String; prepend KeisanString; end
|
47
|
+
class TrueClass; prepend KeisanTrueClass; end
|
48
|
+
class FalseClass; prepend KeisanFalseClass; end
|
49
|
+
class NilClass; prepend KeisanNilClass; end
|
50
|
+
class Array; prepend KeisanArray; end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Keisan
|
2
|
+
module AST
|
3
|
+
class Assignment < Operator
|
4
|
+
def self.symbol
|
5
|
+
:"="
|
6
|
+
end
|
7
|
+
|
8
|
+
def evaluate(context = nil)
|
9
|
+
context ||= Keisan::Context.new
|
10
|
+
|
11
|
+
lhs = children.first
|
12
|
+
rhs = children.last
|
13
|
+
|
14
|
+
case lhs
|
15
|
+
when Keisan::AST::Variable
|
16
|
+
evaluate_variable(context, lhs, rhs)
|
17
|
+
when Keisan::AST::Function
|
18
|
+
evaluate_function(context, lhs, rhs)
|
19
|
+
else
|
20
|
+
raise Keisan::Exceptions::InvalidExpression.new("Unhandled left hand side #{lhs} in assignment")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def evaluate_variable(context, lhs, rhs)
|
27
|
+
rhs = rhs.evaluate(context)
|
28
|
+
|
29
|
+
unless rhs.well_defined?
|
30
|
+
raise Keisan::Exceptions::InvalidExpression.new("Right hand side of assignment to variable must be well defined")
|
31
|
+
end
|
32
|
+
|
33
|
+
rhs_value = rhs.value(context)
|
34
|
+
context.register_variable!(lhs.name, rhs_value)
|
35
|
+
rhs
|
36
|
+
end
|
37
|
+
|
38
|
+
def evaluate_function(context, lhs, rhs)
|
39
|
+
unless lhs.children.all? {|arg| arg.is_a?(Keisan::AST::Variable)}
|
40
|
+
raise Keisan::Exceptions::InvalidExpression.new("Left hand side function must have variables as arguments")
|
41
|
+
end
|
42
|
+
|
43
|
+
argument_names = lhs.children.map(&:name)
|
44
|
+
function_definition_context = Keisan::FunctionDefinitionContext.new(
|
45
|
+
parent: context,
|
46
|
+
arguments: argument_names
|
47
|
+
)
|
48
|
+
rhs = rhs.evaluate(function_definition_context)
|
49
|
+
|
50
|
+
unless rhs.unbound_variables(context) <= Set.new(argument_names)
|
51
|
+
raise Keisan::Exceptions::InvalidExpression.new("Unbound variables found in function definition")
|
52
|
+
end
|
53
|
+
|
54
|
+
unless context.allow_recursive || rhs.unbound_functions(context).empty?
|
55
|
+
raise Keisan::Exceptions::InvalidExpression.new("Unbound function definitions are not allowed by current context")
|
56
|
+
end
|
57
|
+
|
58
|
+
context.register_function!(
|
59
|
+
lhs.name,
|
60
|
+
Keisan::Functions::ExpressionFunction.new(
|
61
|
+
lhs.name,
|
62
|
+
argument_names,
|
63
|
+
rhs,
|
64
|
+
function_definition_context
|
65
|
+
)
|
66
|
+
)
|
67
|
+
|
68
|
+
rhs
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -1,10 +1,6 @@
|
|
1
1
|
module Keisan
|
2
2
|
module AST
|
3
3
|
class BitwiseAnd < BitwiseOperator
|
4
|
-
def arity
|
5
|
-
2..Float::INFINITY
|
6
|
-
end
|
7
|
-
|
8
4
|
def self.symbol
|
9
5
|
:"&"
|
10
6
|
end
|
@@ -12,6 +8,10 @@ module Keisan
|
|
12
8
|
def blank_value
|
13
9
|
~0
|
14
10
|
end
|
11
|
+
|
12
|
+
def evaluate(context = nil)
|
13
|
+
children[1..-1].inject(children.first.evaluate(context)) {|total, child| total & child.evaluate(context)}
|
14
|
+
end
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -1,10 +1,6 @@
|
|
1
1
|
module Keisan
|
2
2
|
module AST
|
3
3
|
class BitwiseOr < BitwiseOperator
|
4
|
-
def arity
|
5
|
-
2..Float::INFINITY
|
6
|
-
end
|
7
|
-
|
8
4
|
def self.symbol
|
9
5
|
:"|"
|
10
6
|
end
|
@@ -12,6 +8,10 @@ module Keisan
|
|
12
8
|
def blank_value
|
13
9
|
0
|
14
10
|
end
|
11
|
+
|
12
|
+
def evaluate(context = nil)
|
13
|
+
children[1..-1].inject(children.first.evaluate(context)) {|total, child| total | child.evaluate(context)}
|
14
|
+
end
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -1,10 +1,6 @@
|
|
1
1
|
module Keisan
|
2
2
|
module AST
|
3
3
|
class BitwiseXor < BitwiseOperator
|
4
|
-
def arity
|
5
|
-
2..Float::INFINITY
|
6
|
-
end
|
7
|
-
|
8
4
|
def self.symbol
|
9
5
|
:"^"
|
10
6
|
end
|
@@ -12,6 +8,10 @@ module Keisan
|
|
12
8
|
def blank_value
|
13
9
|
0
|
14
10
|
end
|
11
|
+
|
12
|
+
def evaluate(context = nil)
|
13
|
+
children[1..-1].inject(children.first.evaluate(context)) {|total, child| total ^ child.evaluate(context)}
|
14
|
+
end
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
data/lib/keisan/ast/boolean.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Keisan
|
2
2
|
module AST
|
3
|
-
class Boolean <
|
3
|
+
class Boolean < ConstantLiteral
|
4
4
|
attr_reader :bool
|
5
5
|
|
6
6
|
def initialize(bool)
|
@@ -10,6 +10,30 @@ module Keisan
|
|
10
10
|
def value(context = nil)
|
11
11
|
bool
|
12
12
|
end
|
13
|
+
|
14
|
+
def !
|
15
|
+
AST::Boolean.new(!bool)
|
16
|
+
end
|
17
|
+
|
18
|
+
def and(other)
|
19
|
+
other = other.to_node
|
20
|
+
case other
|
21
|
+
when AST::Boolean
|
22
|
+
AST::Boolean.new(bool && other.bool)
|
23
|
+
else
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def or(other)
|
29
|
+
other = other.to_node
|
30
|
+
case other
|
31
|
+
when AST::Boolean
|
32
|
+
AST::Boolean.new(bool || other.bool)
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
13
37
|
end
|
14
38
|
end
|
15
39
|
end
|