keisan 0.3.0 → 0.4.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 +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
|