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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9ce7e32bbc4068cda59ee86d64f3210c2b6272ae
4
- data.tar.gz: d823d0e4f0c57f89681e0f14bb650ae700effef6
3
+ metadata.gz: 3fb42d61b5b7dfc4252cf900a2f9b11e891e65d7
4
+ data.tar.gz: 6eeb54706788bc451103169445cc0e1c7f1e765d
5
5
  SHA512:
6
- metadata.gz: 80788b219b735f2c54aeaa57b5957e8018e8a5c34fbd074ed4fa6a85d43bed4f955eaa547f5f782ba9e482eb19233dafdf197ac77ece18d284c13f47dce0c12c
7
- data.tar.gz: a1682bcb6a83ebff28c20da879a9bc73aa69cde0b8e86e06d2f6dbae37e74007fa5664ad8c66e115050b17af8fb683ded60c1179e1ea8b9a07471362033ea732
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
- namespace :racc do
9
- desc 'Compile syntax file'
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 => 'racc:compile'
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
- puts "\e[31mError: #{e.message}\e[0m"
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
- puts "\e[31mError: #{e.message}\e[0m"
56
+ error "Error: #{e.message}"
39
57
  end
40
58
  end
41
59
  end
@@ -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
- args.reduce(0) do |res, i|
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.reduce do |res, i|
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
- args.reduce(1) do |res, i|
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 / args.first
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.reduce do |res, i|
46
- unless number? i
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 <(a, b)
55
- unless number?(a) && number?(b)
56
- raise Rubic::TypeError, "operation `<' is not defined between `#{a}' and `#{b}'"
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 >(a, b)
62
- unless number?(a) && number?(b)
63
- raise Rubic::TypeError, "operation `>' is not defined between `#{a}' and `#{b}'"
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
- define_method '=' do |a, b|
69
- unless number?(a) && number?(b)
70
- raise Rubic::TypeError, "operation `=' is not defined between `#{a}' and `#{b}'"
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?(Integer) || suspect.is_a?(Float)
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