keisan 0.6.0 → 0.7.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 +90 -132
- data/bin/keisan +13 -2
- data/lib/keisan.rb +5 -0
- data/lib/keisan/ast.rb +11 -0
- data/lib/keisan/ast/assignment.rb +20 -55
- data/lib/keisan/ast/boolean.rb +16 -12
- data/lib/keisan/ast/cell.rb +17 -0
- data/lib/keisan/ast/cell_assignment.rb +70 -0
- data/lib/keisan/ast/function_assignment.rb +52 -0
- data/lib/keisan/ast/hash.rb +82 -0
- data/lib/keisan/ast/indexing.rb +26 -15
- data/lib/keisan/ast/line_builder.rb +22 -4
- data/lib/keisan/ast/list.rb +14 -7
- data/lib/keisan/ast/node.rb +13 -0
- data/lib/keisan/ast/null.rb +14 -0
- data/lib/keisan/ast/parent.rb +8 -3
- data/lib/keisan/ast/string.rb +10 -0
- data/lib/keisan/ast/variable.rb +4 -0
- data/lib/keisan/ast/variable_assignment.rb +62 -0
- data/lib/keisan/context.rb +16 -2
- data/lib/keisan/functions/default_registry.rb +4 -0
- data/lib/keisan/functions/enumerable_function.rb +56 -0
- data/lib/keisan/functions/filter.rb +34 -32
- data/lib/keisan/functions/map.rb +25 -31
- data/lib/keisan/functions/puts.rb +23 -0
- data/lib/keisan/functions/reduce.rb +29 -29
- data/lib/keisan/functions/registry.rb +4 -4
- data/lib/keisan/functions/sample.rb +5 -3
- data/lib/keisan/functions/to_h.rb +34 -0
- data/lib/keisan/interpreter.rb +42 -0
- data/lib/keisan/parser.rb +59 -50
- data/lib/keisan/parsing/compound_assignment.rb +15 -0
- data/lib/keisan/parsing/hash.rb +36 -0
- data/lib/keisan/repl.rb +1 -1
- data/lib/keisan/token.rb +1 -0
- data/lib/keisan/tokenizer.rb +23 -19
- data/lib/keisan/tokens/assignment.rb +21 -1
- data/lib/keisan/tokens/colon.rb +11 -0
- data/lib/keisan/tokens/unknown.rb +11 -0
- data/lib/keisan/variables/registry.rb +11 -6
- data/lib/keisan/version.rb +1 -1
- metadata +14 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 900d86c9daad1cab75e6140a21785f6de67ead1c
|
4
|
+
data.tar.gz: f2c5f2abc85d46ce71aa651f0cc860363a8790bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f5e7ea1fd844e7927af6eb5b66edacc53dac30541cb670d6208e43d0a9edb4611417943be232ba8188c275fa8890ee3c3e7f43a874ae32085f80b05092ecef6
|
7
|
+
data.tar.gz: 588daa93a53120d0456f38e66f5fa27d50b5e517516c3e0747519e51aeb5ca49dc317187e85ec420e5eec5bc722732138499e16188bf7271afbc4481ba1980bd
|
data/README.md
CHANGED
@@ -7,7 +7,9 @@
|
|
7
7
|
[![Maintainability](https://api.codeclimate.com/v1/badges/760e213d5ea81bca4480/maintainability)](https://codeclimate.com/github/project-eutopia/keisan/maintainability)
|
8
8
|
[![Coverage Status](https://coveralls.io/repos/github/project-eutopia/keisan/badge.svg?branch=master)](https://coveralls.io/github/project-eutopia/keisan?branch=master)
|
9
9
|
|
10
|
-
Keisan ([計算, to calculate](https://en.wiktionary.org/wiki/%E8%A8%88%E7%AE%97#Japanese)) is a Ruby library for parsing equations into an abstract syntax tree.
|
10
|
+
Keisan ([計算, to calculate](https://en.wiktionary.org/wiki/%E8%A8%88%E7%AE%97#Japanese)) is a Ruby library for parsing equations into an abstract syntax tree.
|
11
|
+
This allows for safe evaluation of string representations of mathematical/logical expressions.
|
12
|
+
It has support for variables, functions, conditionals, and loops, making it a Turing complete programming language.
|
11
13
|
|
12
14
|
## Installation
|
13
15
|
|
@@ -29,13 +31,17 @@ Or install it yourself as:
|
|
29
31
|
|
30
32
|
### REPL
|
31
33
|
|
32
|
-
|
34
|
+
To try `keisan` out locally, clone this repository and run the executable `bin/keisan` to open up an interactive REPL.
|
35
|
+
The commands you type in to this REPL are relayed to an internal `Keisan::Calculator` class and displayed back to you.
|
33
36
|
|
34
37
|
![alt text](screenshots/repl.png "Keisan built-in REPL")
|
35
38
|
|
39
|
+
|
36
40
|
### Calculator class
|
37
41
|
|
38
|
-
|
42
|
+
This library is interacted with primarily through the `Keisan::Calculator` class.
|
43
|
+
The `evaluate` method evaluates an expression by parsing it into an abstract syntax tree (AST), and evaluating it.
|
44
|
+
There is also a `simplify` method that allows undefined variables and functions to exist, and will just return the simplified AST.
|
39
45
|
|
40
46
|
```ruby
|
41
47
|
calculator = Keisan::Calculator.new
|
@@ -50,29 +56,17 @@ For users who want access to the parsed abstract syntax tree, you can use the `a
|
|
50
56
|
```ruby
|
51
57
|
calculator = Keisan::Calculator.new
|
52
58
|
ast = calculator.ast("x**2+1")
|
53
|
-
ast.to_s
|
54
|
-
#=> "(x**2)+1"
|
55
59
|
ast.class
|
56
60
|
#=> Keisan::AST::Plus
|
57
|
-
ast.
|
58
|
-
#=>
|
59
|
-
ast.children
|
60
|
-
#=>
|
61
|
-
ast.children[0].children[0].name
|
62
|
-
#=> "x"
|
63
|
-
ast.children[0].children[1].class
|
64
|
-
#=> Keisan::AST::Number
|
65
|
-
ast.children[0].children[1].value
|
66
|
-
#=> 2
|
67
|
-
ast.children[1].class
|
68
|
-
#=> Keisan::AST::Number
|
69
|
-
ast.children[1].value
|
70
|
-
#=> 1
|
61
|
+
ast.to_s
|
62
|
+
#=> "(x**2)+1"
|
63
|
+
ast.children.map(&:to_s)
|
64
|
+
#=> ["x**2", "1"]
|
71
65
|
```
|
72
66
|
|
73
67
|
##### Specifying variables
|
74
68
|
|
75
|
-
Passing in a hash of variable (`name`, `value`) pairs to the `evaluate` method
|
69
|
+
Passing in a hash of variable (`name`, `value`) pairs to the `evaluate` method is one way of defining variables
|
76
70
|
|
77
71
|
```ruby
|
78
72
|
calculator = Keisan::Calculator.new
|
@@ -80,15 +74,7 @@ calculator.evaluate("3*x + y**2", x: -2.5, y: 3)
|
|
80
74
|
#=> 1.5
|
81
75
|
```
|
82
76
|
|
83
|
-
It
|
84
|
-
|
85
|
-
```ruby
|
86
|
-
calculator = Keisan::Calculator.new
|
87
|
-
calculator.evaluate("x + 1")
|
88
|
-
#=> Keisan::Exceptions::UndefinedVariableError: x
|
89
|
-
```
|
90
|
-
|
91
|
-
It is also possible to define variables in the string expression itself
|
77
|
+
It is also possible to define variables in the string expression itself using the assignment `=` operator
|
92
78
|
|
93
79
|
```ruby
|
94
80
|
calculator = Keisan::Calculator.new
|
@@ -97,6 +83,7 @@ calculator.evaluate("3*x + 1")
|
|
97
83
|
#=> 61
|
98
84
|
```
|
99
85
|
|
86
|
+
|
100
87
|
##### Specifying functions
|
101
88
|
|
102
89
|
Just like variables, functions can be defined by passing a `Proc` object as follows
|
@@ -107,42 +94,21 @@ calculator.evaluate("2*f(1+2) + 4", f: Proc.new {|x| x**2})
|
|
107
94
|
#=> 22
|
108
95
|
```
|
109
96
|
|
110
|
-
|
97
|
+
Note that functions work in both regular (`f(x)`) and postfix (`x.f()`) notation, where for example `a.f(b,c)` is translated internally to `f(a,b,c)`.
|
98
|
+
The postfix notation requires the function to take at least one argument, and if there is only one argument to the function then the braces can be left off: `x.f`.
|
111
99
|
|
112
100
|
```ruby
|
113
101
|
calculator = Keisan::Calculator.new
|
114
|
-
calculator.evaluate("f(2) + 1")
|
115
|
-
#=> Keisan::Exceptions::UndefinedFunctionError: f
|
116
|
-
```
|
117
|
-
|
118
|
-
Note that functions work in both regular (`f(x)`) and postfix (`x.f()`) notation. The postfix notation requires the function to take at least one argument. In the case of `a.f(b,c)`, this is translated internally to `f(a,b,c)`. If there is only a single argument to the function, the braces can be left off: `x.f`.
|
119
|
-
|
120
|
-
```ruby
|
121
|
-
calculator = Keisan::Calculator.new
|
122
|
-
calculator.evaluate("[1,3,5,7].size()")
|
123
|
-
#=> 4
|
124
102
|
calculator.evaluate("[1,3,5,7].size")
|
125
103
|
#=> 4
|
126
|
-
```
|
127
|
-
|
128
|
-
It is even possible to do more complicated things like follows
|
129
|
-
|
130
|
-
```ruby
|
131
|
-
calculator = Keisan::Calculator.new
|
132
104
|
calculator.define_function!("f", Proc.new {|x| [[x-1,x+1], [x-2,x,x+2]]})
|
133
|
-
calculator.evaluate("4.f")
|
134
|
-
#=> [[3,5], [2,4,6]]
|
135
105
|
calculator.evaluate("4.f[0]")
|
136
106
|
#=> [3,5]
|
137
|
-
calculator.evaluate("4.f[0].size")
|
138
|
-
#=> 2
|
139
|
-
calculator.evaluate("4.f[1]")
|
140
|
-
#=> [2,4,6]
|
141
107
|
calculator.evaluate("4.f[1].size")
|
142
108
|
#=> 3
|
143
109
|
```
|
144
110
|
|
145
|
-
Like variables, it is also possible to define functions in the string expression itself
|
111
|
+
Like variables, it is also possible to define functions in the string expression itself using the assignment operator `=`
|
146
112
|
|
147
113
|
```ruby
|
148
114
|
calculator = Keisan::Calculator.new
|
@@ -165,19 +131,17 @@ calculator.evaluate("my_fact(n) = if (n > 1, n*my_fact(n-1), 1)")
|
|
165
131
|
|
166
132
|
calculator = Keisan::Calculator.new(allow_recursive: true)
|
167
133
|
calculator.evaluate("my_fact(n) = if (n > 1, n*my_fact(n-1), 1)")
|
168
|
-
calculator.evaluate("my_fact(
|
169
|
-
#=>
|
170
|
-
calculator.evaluate("my_fact(1)")
|
171
|
-
#=> 1
|
172
|
-
calculator.evaluate("my_fact(2)")
|
173
|
-
#=> 2
|
134
|
+
calculator.evaluate("my_fact(4)")
|
135
|
+
#=> 24
|
174
136
|
calculator.evaluate("my_fact(5)")
|
175
137
|
#=> 120
|
176
138
|
```
|
177
139
|
|
178
140
|
##### Multiple lines and blocks
|
179
141
|
|
180
|
-
Keisan understands strings which contain multiple lines.
|
142
|
+
Keisan understands strings which contain multiple lines.
|
143
|
+
It will evaluate each line separately, and the last line will be the the result of the total evaluation.
|
144
|
+
Lines can be separated by newlines or semi-colons.
|
181
145
|
|
182
146
|
```ruby
|
183
147
|
calculator = Keisan::Calculator.new
|
@@ -185,7 +149,8 @@ calculator.evaluate("x = 2; y = 5\n x+y")
|
|
185
149
|
#=> 7
|
186
150
|
```
|
187
151
|
|
188
|
-
The use of curly braces `{}` can be used to create block which has a new closure where variable definitions are local to the block itself.
|
152
|
+
The use of curly braces `{}` can be used to create block which has a new closure where variable definitions are local to the block itself.
|
153
|
+
Inside a block, external variables are still visible and re-assignable, but new variable definitions remain local.
|
189
154
|
|
190
155
|
```ruby
|
191
156
|
calculator = Keisan::Calculator.new
|
@@ -198,7 +163,9 @@ calculator.evaluate("a")
|
|
198
163
|
#=> Keisan::Exceptions::UndefinedVariableError: a
|
199
164
|
```
|
200
165
|
|
201
|
-
By default assigning to a variable or function will bubble up to the first definition available in the parent scopes.
|
166
|
+
By default assigning to a variable or function will bubble up to the first definition available in the parent scopes.
|
167
|
+
To assign to a local variable instead of modifying an existing variable out of the closure, you can use the `let` keyword.
|
168
|
+
The difference is illustrated below.
|
202
169
|
|
203
170
|
```ruby
|
204
171
|
calculator = Keisan::Calculator.new
|
@@ -219,9 +186,9 @@ calculator.evaluate("[2, 3, 5, 8]")
|
|
219
186
|
calculator.evaluate("[[1,2,3],[4,5,6],[7,8,9]][1][2]")
|
220
187
|
#=> 6
|
221
188
|
calculator.evaluate("a = [1,2,3]")
|
222
|
-
calculator.evaluate("a[1]
|
189
|
+
calculator.evaluate("a[1] += 10*a[2]")
|
223
190
|
calculator.evaluate("a")
|
224
|
-
#=> [1,
|
191
|
+
#=> [1, 32, 3]
|
225
192
|
```
|
226
193
|
|
227
194
|
They can also be concatenated using the `+` operator
|
@@ -254,20 +221,53 @@ calculator.evaluate("range(0,10,2)")
|
|
254
221
|
#=> [0,2,4,6,8]
|
255
222
|
```
|
256
223
|
|
224
|
+
##### Hashes
|
225
|
+
|
226
|
+
Keisan also supports associative arrays (hashes), which maps keys to values.
|
227
|
+
|
228
|
+
```ruby
|
229
|
+
calculator = Keisan::Calculator.new
|
230
|
+
calculator.evaluate("my_hash = {777: 3*4, \"bar\": \"hello world\"}")
|
231
|
+
calculator.evaluate("my_hash[777]")
|
232
|
+
#=> 12
|
233
|
+
calculator.evaluate("s = 'ba'")
|
234
|
+
calculator.evaluate("my_hash[s + 'r']")
|
235
|
+
#=> "hello world"
|
236
|
+
calculator.evaluate("my_hash['baz']")
|
237
|
+
#=> nil
|
238
|
+
calculator.evaluate("my_hash['baz'] = 999")
|
239
|
+
calculator.evaluate("my_hash['baz']")
|
240
|
+
#=> 999
|
241
|
+
```
|
242
|
+
|
243
|
+
There is also a `to_h` method which converts a list of key value pairs into a hash.
|
244
|
+
|
245
|
+
```ruby
|
246
|
+
calculator = Keisan::Calculator.new
|
247
|
+
calculator.evaluate("range(1, 6).map(x, [x, x**2]).to_h")
|
248
|
+
#=> {1 => 1, 2 => 4, 3 => 9, 4 => 16, 5 => 25}
|
249
|
+
```
|
250
|
+
|
251
|
+
##### Functional programming methods
|
252
|
+
|
257
253
|
Keisan also supports the basic functional programming operators `map` (or `collect`), `filter` (or `select`), and `reduce` (or `inject`).
|
258
254
|
|
259
255
|
```ruby
|
260
256
|
calculator = Keisan::Calculator.new
|
261
257
|
calculator.evaluate("map([1,3,5], x, 2*x)")
|
262
258
|
#=> [2,6,10]
|
263
|
-
calculator.simplify("
|
259
|
+
calculator.simplify("{'a': 1, 'b': 3, 'c': 5}.collect(k, v, y*v**2)").to_s
|
264
260
|
#=> "[y,9*y,25*y]"
|
265
|
-
|
261
|
+
|
262
|
+
calculator.evaluate("[1,2,3,4].select(x, x % 2 == 0)")
|
266
263
|
#=> [2,4]
|
267
|
-
calculator.evaluate("
|
268
|
-
#=>
|
264
|
+
calculator.evaluate("filter({'a': 1, 'bb': 4, 'ccc': 9}, k, v, k.size == 2)")
|
265
|
+
#=> {"bb" => 4}
|
266
|
+
|
269
267
|
calculator.evaluate("[1,2,3,4,5].inject(1, total, x, total*x)")
|
270
268
|
#=> 120
|
269
|
+
calculator.evaluate("{'foo': 'hello', 'bar': ' world'}.reduce('', res, k, v, res + v)")
|
270
|
+
#=> "hello world"
|
271
271
|
```
|
272
272
|
|
273
273
|
##### Logical operations
|
@@ -292,11 +292,11 @@ calculator.evaluate("2 + if(1 > 0, 10, 29)")
|
|
292
292
|
#=> 12
|
293
293
|
```
|
294
294
|
|
295
|
-
For looping, you can use the basic `while` loop, which has an expression that evaluates to a boolean as the first argument, and any expression in the second argument.
|
295
|
+
For looping, you can use the basic `while` loop, which has an expression that evaluates to a boolean as the first argument, and any expression in the second argument.
|
296
296
|
|
297
297
|
```ruby
|
298
298
|
calculator = Keisan::Calculator.new
|
299
|
-
calculator.evaluate("my_sum(a) = {let i = 0; let total = 0; while(i < a.size, {total
|
299
|
+
calculator.evaluate("my_sum(a) = {let i = 0; let total = 0; while(i < a.size, {total += a[i]; i += 1}); total}")
|
300
300
|
calculator.evaluate("my_sum([1,3,5,7,9])")
|
301
301
|
#=> 25
|
302
302
|
```
|
@@ -307,8 +307,8 @@ The basic bitwise operations, NOT `~`, OR `|`, XOR `^`, and AND `&` are also ava
|
|
307
307
|
|
308
308
|
```ruby
|
309
309
|
calculator = Keisan::Calculator.new
|
310
|
-
calculator.evaluate("
|
311
|
-
#=>
|
310
|
+
calculator.evaluate("0b00001111 & 0b10101010")
|
311
|
+
#=> 10
|
312
312
|
```
|
313
313
|
|
314
314
|
##### String
|
@@ -368,19 +368,7 @@ calculator.evaluate("log10(1000)")
|
|
368
368
|
#=> 3.0
|
369
369
|
```
|
370
370
|
|
371
|
-
Furthermore, the
|
372
|
-
|
373
|
-
```ruby
|
374
|
-
calculator = Keisan::Calculator.new
|
375
|
-
calculator.evaluate("PI")
|
376
|
-
#=> 3.141592653589793
|
377
|
-
calculator.evaluate("E")
|
378
|
-
#=> 2.718281828459045
|
379
|
-
calculator.evaluate("I")
|
380
|
-
#=> (0+1i)
|
381
|
-
```
|
382
|
-
|
383
|
-
This allows for simple calculations like
|
371
|
+
Furthermore, the constants `PI`, `E`, and `I` are included.
|
384
372
|
|
385
373
|
```ruby
|
386
374
|
calculator = Keisan::Calculator.new
|
@@ -425,63 +413,26 @@ calculator.evaluate("replace(diff(f(2*t, t+1), t), t, 3)")
|
|
425
413
|
#=> 1+8*3
|
426
414
|
```
|
427
415
|
|
428
|
-
|
429
|
-
|
430
|
-
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
|
416
|
+
There is also a `puts` function that can be used to output the result of an expression to STDOUT.
|
431
417
|
|
432
418
|
```ruby
|
433
419
|
calculator = Keisan::Calculator.new
|
434
|
-
calculator.
|
435
|
-
calculator.evaluate("x
|
436
|
-
#=> 6
|
437
|
-
calculator.evaluate("x + 1", x: 10)
|
438
|
-
#=> 11
|
439
|
-
calculator.evaluate("x + 1")
|
440
|
-
#=> 6
|
441
|
-
|
442
|
-
calculator.evaluate("x = y = 10")
|
443
|
-
#=> 10
|
444
|
-
calculator.evaluate("x + y")
|
445
|
-
#=> 20
|
446
|
-
calculator.evaluate("x + y", y: 100)
|
447
|
-
#=> 110
|
448
|
-
calculator.evaluate("x + y")
|
449
|
-
#=> 20
|
420
|
+
calculator.evaluate("x = 5")
|
421
|
+
calculator.evaluate("puts x**2") # prints "25\n" to STDOUT
|
450
422
|
```
|
451
423
|
|
452
|
-
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
|
453
|
-
|
454
|
-
```ruby
|
455
|
-
calculator = Keisan::Calculator.new
|
456
|
-
calculator.define_function!("f", Proc.new {|x| 3*x})
|
457
|
-
#=> #<Keisan::Function:0x005570f935ecc8 @function_proc=#<Proc:0x005570f935ecf0@(pry):6>, @name="f">
|
458
|
-
calculator.evaluate("f(2)")
|
459
|
-
#=> 6
|
460
|
-
calculator.evaluate("f(2)", f: Proc.new {|x| 10*x})
|
461
|
-
#=> 20
|
462
|
-
calculator.evaluate("f(2)")
|
463
|
-
#=> 6
|
464
|
-
|
465
|
-
calculator.evaluate("f(x) = x + x**2")
|
466
|
-
#=> nil
|
467
|
-
calculator.evaluate("f(3)")
|
468
|
-
#=> 12
|
469
|
-
calculator.evaluate("f(3)", f: Proc.new {|x| 10*x})
|
470
|
-
#=> 30
|
471
|
-
calculator.evaluate("f(3)")
|
472
|
-
#=> 12
|
473
|
-
```
|
474
424
|
|
475
425
|
## Supported elements/operators
|
476
426
|
|
477
427
|
`keisan` supports the following operators and elements.
|
478
428
|
|
479
|
-
#### Numbers, variables, functions, lists
|
429
|
+
#### Numbers, variables, brackets, functions, lists, hashes
|
480
430
|
- `150`, `-5.67`, `6e-5`: regular numbers
|
481
431
|
- `x`, `_myvar1`: variables
|
482
432
|
- `(` and `)`: round brackets for grouping parts to evaluate first
|
483
|
-
- `[0, 3, 6, 9]`: square brackets with comma separated values to denote lists
|
484
433
|
- `f(x,y,z)`, `my_function(max([2.5, 5.5]))`, `[2,4,6,8].size`: functions using `(` `)` brackets (optional if using postfix notation and only takes a single argument)
|
434
|
+
- `[0, 3, 6, 9]`: square brackets with comma separated values to denote lists
|
435
|
+
- `{'foo': 11, 'bar': 22}`: curly brackets containing key/value pairs creates a hash
|
485
436
|
|
486
437
|
#### Arithmetic operators
|
487
438
|
- `+`, `-`, `*`, `/`: regular arithmetic operators
|
@@ -499,18 +450,25 @@ calculator.evaluate("f(3)")
|
|
499
450
|
- `&`, `|`, `^`: bitwise **and**, **or**, **xor** operators
|
500
451
|
- `~`: unary bitwise not
|
501
452
|
|
502
|
-
#### Indexing of arrays
|
453
|
+
#### Indexing of arrays/hashes
|
503
454
|
- `list[i]`: for accessing elements in an array
|
455
|
+
- `hash[k]`: for accessing elements in a hash
|
504
456
|
|
505
457
|
#### Assignment
|
506
458
|
- `=`: can be used to define variables and functions
|
459
|
+
- `+=`: can be used in combination with operators above
|
460
|
+
|
507
461
|
|
508
462
|
## Development
|
509
463
|
|
510
|
-
After checking out the repository, run `bin/setup` to install dependencies.
|
464
|
+
After checking out the repository, run `bin/setup` to install dependencies.
|
465
|
+
Then, run `rake spec` to run the tests.
|
466
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment with the library pre-loaded.
|
511
467
|
|
512
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
468
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
469
|
+
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
513
470
|
|
514
471
|
## Contributing
|
515
472
|
|
516
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/project-eutopia/keisan.
|
473
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/project-eutopia/keisan.
|
474
|
+
If there is any functionality you would like (e.g. new functions), feel free to open a [new issue](https://github.com/project-eutopia/keisan/issues/new).
|
data/bin/keisan
CHANGED
@@ -2,6 +2,17 @@
|
|
2
2
|
|
3
3
|
require "bundler/setup"
|
4
4
|
require "keisan"
|
5
|
-
require "keisan/
|
5
|
+
require "keisan/interpreter"
|
6
6
|
|
7
|
-
|
7
|
+
file_name = nil
|
8
|
+
allow_recursive = false
|
9
|
+
|
10
|
+
ARGV.each do |arg|
|
11
|
+
if arg == "--allow_recursive"
|
12
|
+
allow_recursive = true
|
13
|
+
else
|
14
|
+
file_name = arg
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Keisan::Interpreter.new(allow_recursive: allow_recursive).run(file_name)
|
data/lib/keisan.rb
CHANGED
@@ -48,6 +48,7 @@ require "keisan/ast/logical_less_than_or_equal_to"
|
|
48
48
|
require "keisan/ast/logical_greater_than_or_equal_to"
|
49
49
|
require "keisan/ast/function"
|
50
50
|
require "keisan/ast/list"
|
51
|
+
require "keisan/ast/hash"
|
51
52
|
require "keisan/ast/indexing"
|
52
53
|
|
53
54
|
require "keisan/ast/line_builder"
|
@@ -65,6 +66,7 @@ require "keisan/context"
|
|
65
66
|
|
66
67
|
require "keisan/token"
|
67
68
|
require "keisan/tokens/comma"
|
69
|
+
require "keisan/tokens/colon"
|
68
70
|
require "keisan/tokens/dot"
|
69
71
|
require "keisan/tokens/group"
|
70
72
|
require "keisan/tokens/number"
|
@@ -78,6 +80,7 @@ require "keisan/tokens/logical_operator"
|
|
78
80
|
require "keisan/tokens/bitwise_operator"
|
79
81
|
require "keisan/tokens/word"
|
80
82
|
require "keisan/tokens/line_separator"
|
83
|
+
require "keisan/tokens/unknown"
|
81
84
|
|
82
85
|
require "keisan/tokenizer"
|
83
86
|
|
@@ -98,6 +101,7 @@ require "keisan/parsing/round_group"
|
|
98
101
|
require "keisan/parsing/square_group"
|
99
102
|
require "keisan/parsing/curly_group"
|
100
103
|
require "keisan/parsing/list"
|
104
|
+
require "keisan/parsing/hash"
|
101
105
|
require "keisan/parsing/indexing"
|
102
106
|
require "keisan/parsing/argument"
|
103
107
|
require "keisan/parsing/line_separator"
|
@@ -105,6 +109,7 @@ require "keisan/parsing/line_separator"
|
|
105
109
|
require "keisan/parsing/operator"
|
106
110
|
|
107
111
|
require "keisan/parsing/assignment"
|
112
|
+
require "keisan/parsing/compound_assignment"
|
108
113
|
|
109
114
|
require "keisan/parsing/unary_operator"
|
110
115
|
require "keisan/parsing/unary_plus"
|