rubic 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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