rubic 0.2.0 → 0.3.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/Rakefile +4 -8
- data/bin/rubic +24 -6
- data/lib/rubic/builtin/number.rb +349 -37
- data/lib/rubic/environment.rb +10 -0
- data/lib/rubic/interpreter.rb +10 -1
- data/lib/rubic/lexer.rb +117 -0
- data/lib/rubic/parser.rb +1224 -212
- data/lib/rubic/parser.y +131 -41
- data/lib/rubic/util.rb +42 -0
- data/lib/rubic/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fb42d61b5b7dfc4252cf900a2f9b11e891e65d7
|
4
|
+
data.tar.gz: 6eeb54706788bc451103169445cc0e1c7f1e765d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a2430c6a05165a448a2176461f7c498dcb24fc55233f5a5a12ac2d6dfd9ff87d9840513fecc74744bead16510678258c4cdcac7971121926730be5f1db9702a2
|
7
|
+
data.tar.gz: 47f74178b95c7fd6184762ccee1413c73383efa85ee8ba80afdbf198c2855a2d0f0f94c60743bb196cef33b866d87f4164fdab995c51c3ac6350838cf3e1bfc1
|
data/Rakefile
CHANGED
@@ -3,16 +3,12 @@ require 'rake/testtask'
|
|
3
3
|
|
4
4
|
Rake::TestTask.new do |t|
|
5
5
|
t.libs << 'test'
|
6
|
+
t.pattern = 'test/**/test_*.rb'
|
6
7
|
end
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
task :compile do
|
11
|
-
src = 'lib/rubic/parser.y'
|
12
|
-
dst = 'lib/rubic/parser.rb'
|
13
|
-
sh "bundle exec racc -o #{dst} #{src}"
|
14
|
-
end
|
9
|
+
file 'lib/rubic/parser.rb' => 'lib/rubic/parser.y' do |t|
|
10
|
+
sh "bundle exec racc -o #{t.name} #{t.prerequisites.first}"
|
15
11
|
end
|
16
12
|
|
17
|
-
task :test => '
|
13
|
+
task :test => 'lib/rubic/parser.rb'
|
18
14
|
task :default => :test
|
data/bin/rubic
CHANGED
@@ -3,18 +3,38 @@
|
|
3
3
|
require 'rubic'
|
4
4
|
require 'rubic/inspector'
|
5
5
|
require 'readline'
|
6
|
+
require 'optparse'
|
6
7
|
|
7
8
|
using Rubic::Inspector
|
8
9
|
|
10
|
+
def error(str)
|
11
|
+
$stderr.puts "\e[31m#{str}\e[0m"
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
rubic = Rubic::Interpreter.new
|
16
|
+
|
17
|
+
opts = OptionParser.new
|
18
|
+
opts.version = Rubic::VERSION
|
19
|
+
opts.on('-r FILE', 'load FILE at startup') do |file|
|
20
|
+
File.open(file) do |f|
|
21
|
+
begin
|
22
|
+
rubic.evaluate(f.read)
|
23
|
+
rescue Rubic::RubicError => e
|
24
|
+
error "Error: #{e.message}"
|
25
|
+
exit false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
opts.parse!(ARGV)
|
30
|
+
|
9
31
|
if ARGV.size == 1
|
10
32
|
file = ARGV.shift
|
11
33
|
File.open(file) do |f|
|
12
|
-
rubic = Rubic::Interpreter.new
|
13
|
-
|
14
34
|
begin
|
15
35
|
rubic.evaluate(f.read)
|
16
36
|
rescue Rubic::RubicError => e
|
17
|
-
|
37
|
+
error "Error: #{e.message}"
|
18
38
|
exit false
|
19
39
|
end
|
20
40
|
end
|
@@ -24,8 +44,6 @@ else
|
|
24
44
|
puts "Welcome to interactive Rubic (v#{Rubic::VERSION})"
|
25
45
|
puts 'Hit ^D to exit'
|
26
46
|
|
27
|
-
rubic = Rubic::Interpreter.new
|
28
|
-
|
29
47
|
while input = Readline.readline(">> ", true)
|
30
48
|
next if input.empty?
|
31
49
|
while input.count('(') > input.count(')')
|
@@ -35,7 +53,7 @@ else
|
|
35
53
|
begin
|
36
54
|
puts '=> ' + rubic.evaluate(input).inspect
|
37
55
|
rescue Rubic::RubicError => e
|
38
|
-
|
56
|
+
error "Error: #{e.message}"
|
39
57
|
end
|
40
58
|
end
|
41
59
|
end
|
data/lib/rubic/builtin/number.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
+
require 'cmath'
|
2
|
+
require 'rubic/util'
|
3
|
+
|
1
4
|
module Rubic
|
2
5
|
module Builtin
|
3
6
|
class Number
|
7
|
+
include Rubic::Util
|
8
|
+
|
4
9
|
def +(*args)
|
5
|
-
|
6
|
-
unless number? i
|
7
|
-
raise Rubic::TypeError, "operation `+' is not defined between `#{res}' and `#{i}'"
|
8
|
-
end
|
9
|
-
res + i
|
10
|
-
end
|
10
|
+
transitive_operation('+', 0, args) {|a, b| a + b }
|
11
11
|
end
|
12
12
|
|
13
13
|
def -(*args)
|
@@ -17,22 +17,12 @@ module Rubic
|
|
17
17
|
when 1
|
18
18
|
-args.first
|
19
19
|
else
|
20
|
-
args
|
21
|
-
unless number? i
|
22
|
-
raise Rubic::TypeError, "operation `-' is not defined between `#{res}' and `#{i}'"
|
23
|
-
end
|
24
|
-
res - i
|
25
|
-
end
|
20
|
+
transitive_operation('-', args) {|a, b| a - b }
|
26
21
|
end
|
27
22
|
end
|
28
23
|
|
29
24
|
def *(*args)
|
30
|
-
|
31
|
-
unless number? i
|
32
|
-
raise Rubic::TypeError, "operation `*' is not defined between `#{res}' and `#{i}'"
|
33
|
-
end
|
34
|
-
res * i
|
35
|
-
end
|
25
|
+
transitive_operation('*', 1, args) {|a, b| a * b }
|
36
26
|
end
|
37
27
|
|
38
28
|
def /(*args)
|
@@ -40,41 +30,363 @@ module Rubic
|
|
40
30
|
when 0
|
41
31
|
raise Rubic::ArgumentError, "wrong number of arguments (0 for 1+)"
|
42
32
|
when 1
|
43
|
-
1
|
33
|
+
1.quo(args.first)
|
34
|
+
else
|
35
|
+
transitive_operation('/', args) {|a, b| a.quo(b) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
define_method '=' do |*args|
|
40
|
+
if args.size < 2
|
41
|
+
raise Rubic::ArgumentError, "wrong number of arguments (#{args.size} for 2+)"
|
44
42
|
else
|
45
|
-
args
|
46
|
-
|
47
|
-
raise Rubic::TypeError, "operation `/' is not defined between `#{res}' and `#{i}'"
|
48
|
-
end
|
49
|
-
res / i
|
43
|
+
transitive_operation('=', args) do |a, b|
|
44
|
+
(a == b) ? b : (return false)
|
50
45
|
end
|
46
|
+
true
|
51
47
|
end
|
52
48
|
end
|
53
49
|
|
54
|
-
def
|
55
|
-
|
56
|
-
raise Rubic::
|
50
|
+
def >(*args)
|
51
|
+
if args.size < 2
|
52
|
+
raise Rubic::ArgumentError, "wrong number of arguments (#{args.size} for 2+)"
|
53
|
+
else
|
54
|
+
transitive_operation('>', args) do |a, b|
|
55
|
+
(a > b) ? b : (return false)
|
56
|
+
end
|
57
|
+
true
|
57
58
|
end
|
58
|
-
a < b
|
59
59
|
end
|
60
60
|
|
61
|
-
def
|
62
|
-
|
63
|
-
raise Rubic::
|
61
|
+
def <(*args)
|
62
|
+
if args.size < 2
|
63
|
+
raise Rubic::ArgumentError, "wrong number of arguments (#{args.size} for 2+)"
|
64
|
+
else
|
65
|
+
transitive_operation('<', args) do |a, b|
|
66
|
+
(a < b) ? b : (return false)
|
67
|
+
end
|
68
|
+
true
|
64
69
|
end
|
65
|
-
a > b
|
66
70
|
end
|
67
71
|
|
68
|
-
|
69
|
-
|
70
|
-
raise Rubic::
|
72
|
+
def >=(*args)
|
73
|
+
if args.size < 2
|
74
|
+
raise Rubic::ArgumentError, "wrong number of arguments (#{args.size} for 2+)"
|
75
|
+
else
|
76
|
+
transitive_operation('>=', args) do |a, b|
|
77
|
+
(a >= b) ? b : (return false)
|
78
|
+
end
|
79
|
+
true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def <=(*args)
|
84
|
+
if args.size < 2
|
85
|
+
raise Rubic::ArgumentError, "wrong number of arguments (#{args.size} for 2+)"
|
86
|
+
else
|
87
|
+
transitive_operation('<=', args) do |a, b|
|
88
|
+
(a <= b) ? b : (return false)
|
89
|
+
end
|
90
|
+
true
|
71
91
|
end
|
72
|
-
a == b
|
73
92
|
end
|
74
93
|
|
75
94
|
def number?(suspect)
|
76
|
-
suspect.is_a?(
|
95
|
+
suspect.is_a?(Numeric) || complex?(suspect)
|
77
96
|
end
|
97
|
+
|
98
|
+
def complex?(suspect)
|
99
|
+
suspect.is_a?(Complex) || real?(suspect)
|
100
|
+
end
|
101
|
+
|
102
|
+
def real?(suspect)
|
103
|
+
suspect.is_a?(Float) || rational?(suspect)
|
104
|
+
end
|
105
|
+
|
106
|
+
def rational?(suspect)
|
107
|
+
suspect.is_a?(Rational) || integer?(suspect)
|
108
|
+
end
|
109
|
+
|
110
|
+
def integer?(suspect)
|
111
|
+
if suspect.is_a?(Float)
|
112
|
+
suspect == suspect.truncate # X.0
|
113
|
+
else
|
114
|
+
suspect.is_a?(Integer)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def exact?(suspect)
|
119
|
+
case suspect
|
120
|
+
when Complex
|
121
|
+
exact?(suspect.real) && exact?(suspect.imag)
|
122
|
+
when Float
|
123
|
+
false
|
124
|
+
when Rational
|
125
|
+
true
|
126
|
+
when Integer
|
127
|
+
true
|
128
|
+
else
|
129
|
+
false
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def inexact?(suspect)
|
134
|
+
number?(suspect) && !exact?(suspect)
|
135
|
+
end
|
136
|
+
|
137
|
+
def zero?(suspect)
|
138
|
+
ensure_number suspect
|
139
|
+
suspect.zero?
|
140
|
+
end
|
141
|
+
|
142
|
+
def positive?(suspect)
|
143
|
+
ensure_real suspect
|
144
|
+
suspect > 0.0
|
145
|
+
end
|
146
|
+
|
147
|
+
def negative?(suspect)
|
148
|
+
ensure_real suspect
|
149
|
+
suspect < 0.0
|
150
|
+
end
|
151
|
+
|
152
|
+
def odd?(suspect)
|
153
|
+
ensure_integer suspect
|
154
|
+
suspect.to_i.odd?
|
155
|
+
end
|
156
|
+
|
157
|
+
def even?(suspect)
|
158
|
+
ensure_integer suspect
|
159
|
+
suspect.to_i.even?
|
160
|
+
end
|
161
|
+
|
162
|
+
def max(a, *args)
|
163
|
+
args.unshift(a)
|
164
|
+
exact = args.all? do |e|
|
165
|
+
ensure_real e
|
166
|
+
exact?(e)
|
167
|
+
end
|
168
|
+
exact ? args.max : exact_to_inexact(args.max)
|
169
|
+
end
|
170
|
+
|
171
|
+
def min(a, *args)
|
172
|
+
args.unshift(a)
|
173
|
+
exact = args.all? do |e|
|
174
|
+
ensure_real e
|
175
|
+
exact?(e)
|
176
|
+
end
|
177
|
+
exact ? args.min : exact_to_inexact(args.min)
|
178
|
+
end
|
179
|
+
|
180
|
+
def abs(num)
|
181
|
+
ensure_number num
|
182
|
+
num.abs
|
183
|
+
end
|
184
|
+
|
185
|
+
def quotient(a, b)
|
186
|
+
ensure_integer a, b
|
187
|
+
ret = a.quo(b).round
|
188
|
+
exact?(a) && exact?(b) ? ret : exact_to_inexact(ret)
|
189
|
+
end
|
190
|
+
|
191
|
+
def modulo(a, b)
|
192
|
+
ensure_integer a, b
|
193
|
+
ret = a.modulo(b)
|
194
|
+
exact?(a) && exact?(b) ? ret : exact_to_inexact(ret)
|
195
|
+
end
|
196
|
+
|
197
|
+
def remainder(a, b)
|
198
|
+
ensure_integer a, b
|
199
|
+
ret = a.remainder(b)
|
200
|
+
exact?(a) && exact?(b) ? ret : exact_to_inexact(ret)
|
201
|
+
end
|
202
|
+
|
203
|
+
def gcd(*args)
|
204
|
+
exact = true
|
205
|
+
ret = args.reduce(0) do |res, num|
|
206
|
+
ensure_integer num
|
207
|
+
exact &&= exact?(num)
|
208
|
+
res.gcd(num.to_i)
|
209
|
+
end
|
210
|
+
exact ? ret : exact_to_inexact(ret)
|
211
|
+
end
|
212
|
+
|
213
|
+
def lcm(*args)
|
214
|
+
exact = true
|
215
|
+
ret = args.reduce(1) do |res, num|
|
216
|
+
ensure_integer num
|
217
|
+
exact &&= exact?(num)
|
218
|
+
res.lcm(num.to_i)
|
219
|
+
end
|
220
|
+
exact ? ret : exact_to_inexact(ret)
|
221
|
+
end
|
222
|
+
|
223
|
+
def numerator(num)
|
224
|
+
ensure_real num
|
225
|
+
ret = num.to_r.numerator
|
226
|
+
exact?(num) ? ret : exact_to_inexact(ret)
|
227
|
+
end
|
228
|
+
|
229
|
+
def denominator(num)
|
230
|
+
ensure_real num
|
231
|
+
ret = num.to_r.denominator
|
232
|
+
exact?(num) ? ret : exact_to_inexact(ret)
|
233
|
+
end
|
234
|
+
|
235
|
+
def floor(num)
|
236
|
+
ensure_real num
|
237
|
+
num.floor
|
238
|
+
end
|
239
|
+
|
240
|
+
def ceiling(num)
|
241
|
+
ensure_real num
|
242
|
+
num.ceil
|
243
|
+
end
|
244
|
+
|
245
|
+
def truncate(num)
|
246
|
+
ensure_real num
|
247
|
+
num.truncate
|
248
|
+
end
|
249
|
+
|
250
|
+
def round(num)
|
251
|
+
ensure_real num
|
252
|
+
num.round
|
253
|
+
end
|
254
|
+
|
255
|
+
def rationalize(num, eps)
|
256
|
+
ensure_real num
|
257
|
+
normalize_number num.rationalize(eps)
|
258
|
+
end
|
259
|
+
|
260
|
+
def exp(num)
|
261
|
+
ensure_number num
|
262
|
+
CMath.exp(num)
|
263
|
+
end
|
264
|
+
|
265
|
+
def log(num)
|
266
|
+
ensure_number num
|
267
|
+
CMath.log(num)
|
268
|
+
end
|
269
|
+
|
270
|
+
def sin(num)
|
271
|
+
ensure_number num
|
272
|
+
CMath.sin(num)
|
273
|
+
end
|
274
|
+
|
275
|
+
def cos(num)
|
276
|
+
ensure_number num
|
277
|
+
CMath.cos(num)
|
278
|
+
end
|
279
|
+
|
280
|
+
def tan(num)
|
281
|
+
ensure_number num
|
282
|
+
CMath.tan(num)
|
283
|
+
end
|
284
|
+
|
285
|
+
def asin(num)
|
286
|
+
ensure_number num
|
287
|
+
CMath.asin(num)
|
288
|
+
end
|
289
|
+
|
290
|
+
def acos(num)
|
291
|
+
ensure_number num
|
292
|
+
CMath.acos(num)
|
293
|
+
end
|
294
|
+
|
295
|
+
def atan(*args)
|
296
|
+
case args.size
|
297
|
+
when 1
|
298
|
+
ensure_number args[0]
|
299
|
+
CMath.atan(args[0])
|
300
|
+
when 2
|
301
|
+
ensure_number args[0], args[1]
|
302
|
+
Complex(args[1], args[0]).angle
|
303
|
+
else
|
304
|
+
raise Rubic::ArgumentError, "wrong number of arguments (#{args.size} for 1..2)"
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
def sqrt(num)
|
309
|
+
ensure_number num
|
310
|
+
CMath.sqrt(num)
|
311
|
+
end
|
312
|
+
|
313
|
+
def expt(x, y)
|
314
|
+
ensure_number x, y
|
315
|
+
x ** y
|
316
|
+
end
|
317
|
+
|
318
|
+
define_method 'make-rectangular' do |x, y|
|
319
|
+
ensure_real x, y
|
320
|
+
normalize_number Complex(x, y)
|
321
|
+
end
|
322
|
+
|
323
|
+
define_method 'make-polar' do |x, y|
|
324
|
+
ensure_real x, y
|
325
|
+
normalize_number Complex.polar(x, y)
|
326
|
+
end
|
327
|
+
|
328
|
+
define_method 'real-part' do |num|
|
329
|
+
ensure_number num
|
330
|
+
num.real
|
331
|
+
end
|
332
|
+
|
333
|
+
define_method 'imag-part' do |num|
|
334
|
+
ensure_number num
|
335
|
+
num.imag
|
336
|
+
end
|
337
|
+
|
338
|
+
def magnitude(num)
|
339
|
+
ensure_number num
|
340
|
+
num.magnitude
|
341
|
+
end
|
342
|
+
|
343
|
+
def angle(num)
|
344
|
+
ensure_number num
|
345
|
+
num.angle
|
346
|
+
end
|
347
|
+
|
348
|
+
define_method 'inexact->exact' do |num|
|
349
|
+
ensure_number num
|
350
|
+
return num if exact?(num)
|
351
|
+
inexact_to_exact(num)
|
352
|
+
end
|
353
|
+
|
354
|
+
define_method 'exact->inexact' do |num|
|
355
|
+
ensure_number num
|
356
|
+
return num unless exact?(num)
|
357
|
+
exact_to_inexact(num)
|
358
|
+
end
|
359
|
+
|
360
|
+
private
|
361
|
+
|
362
|
+
def transitive_operation(opname, initial=nil, args)
|
363
|
+
initial = args.shift if initial.nil?
|
364
|
+
args.reduce(initial) do |res, num|
|
365
|
+
unless number?(num)
|
366
|
+
raise Rubic::TypeError, "operation `#{opname}' is not defined between `#{res}' and `#{num}'"
|
367
|
+
end
|
368
|
+
yield res, num
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
def ensure_number(*args)
|
373
|
+
args.each do |e|
|
374
|
+
raise Rubic::TypeError, "`#{e}' is not a number" unless number?(e)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
def ensure_real(*args)
|
379
|
+
args.each do |e|
|
380
|
+
raise Rubic::TypeError, "`#{e}' is not a real number" unless real?(e)
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
def ensure_integer(*args)
|
385
|
+
args.each do |e|
|
386
|
+
raise Rubic::TypeError, "`#{e}' is not an integer" unless integer?(e)
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
78
390
|
end
|
79
391
|
end
|
80
392
|
end
|