risp 0.0.1

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.
Files changed (6) hide show
  1. data/README +65 -0
  2. data/Rakefile +65 -0
  3. data/bin/risp +79 -0
  4. data/lib/risp.rb +522 -0
  5. data/test/test_risp_reader.rb +25 -0
  6. metadata +82 -0
data/README ADDED
@@ -0,0 +1,65 @@
1
+ = Risp
2
+
3
+ Risp (Ruby lisp) is a quite tiny, toy interpreter of lisp.
4
+
5
+ For almost people, it seems not to be appropriate Lisp --
6
+ it lacks even a macro!!
7
+
8
+ Features: variables are bound to Lisp-1 namespace, there's no
9
+ special-form which is appropriate `defun'. It means a scheme's
10
+ way is invalid. Please use lambda.
11
+
12
+ (define (hoge x) ;; raise type error for list
13
+ (+ x 1))
14
+
15
+ There's no package system, macro and beautiful API.
16
+
17
+
18
+ + Types
19
+ * integer
20
+ * string
21
+ * t
22
+ * nil
23
+ * symbol
24
+ * list
25
+ * function
26
+
27
+ + Builtin functions and special-forms
28
+ * car
29
+ * cdr
30
+ * cons
31
+ * eq
32
+ * atom
33
+ * quote
34
+ * cond
35
+ * define
36
+ * lambda
37
+ * +
38
+
39
+
40
+ = Install
41
+
42
+ $ gem install risp
43
+
44
+
45
+ = Usage
46
+
47
+ $ risp somefile.l
48
+
49
+ $ risp -i
50
+
51
+
52
+ = Dependence
53
+
54
+ Risp is developed on:
55
+ ruby 1.9.1p429 (2010-07-02 revision 28523) [i386-mswin32]
56
+
57
+
58
+ = Lisence
59
+
60
+ Under the modified BSD lisence.
61
+
62
+
63
+ ---
64
+
65
+ arikui <arikui.ruby@gmail.com>
@@ -0,0 +1,65 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/testtask'
5
+ require_relative 'lib/risp'
6
+
7
+ LIBS = FileList["lib/*.rb"]
8
+ TESTS = FileList["test/test_*.rb"]
9
+
10
+ task :default => :test
11
+
12
+ gemspec = Gem::Specification.new do |s|
13
+ s.name = %q{risp}
14
+ s.version = Risp.version
15
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
16
+ s.authors = ["arikui"]
17
+ s.date = %q{2010-11-19}
18
+ s.description = %q{A toy lisp interpreter.}
19
+ s.email = %q{arikui.ruby@gmail.com}
20
+ s.executable = 'risp'
21
+ s.extra_rdoc_files = ["README"]
22
+ s.files = ["README",
23
+ "Rakefile",
24
+ "bin/risp",
25
+ *TESTS, *LIBS]
26
+ s.homepage = %q{http://wiki.github.com/arikui1911/risp}
27
+ s.rdoc_options = ["--title", "risp documentation",
28
+ "--charset", "utf-8",
29
+ "--opname", "index.html",
30
+ "--line-numbers",
31
+ "--main", "README",
32
+ "--inline-source",
33
+ "--exclude", "^(examples|extras)/"]
34
+ s.require_paths = ["lib"]
35
+ s.rubyforge_project = %q{risp}
36
+ s.rubygems_version = %q{1.3.7}
37
+ s.summary = %q{A toy lisp interpreter; provides `pure-lisp' functions and Lisp-1 namespaces. Currently it lacks package system and macro(!!).}
38
+ s.test_files = TESTS.to_a
39
+ if s.respond_to? :specification_version then
40
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
41
+ s.specification_version = 3
42
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
43
+ else
44
+ end
45
+ else
46
+ end
47
+ end
48
+
49
+ gem_task = Rake::GemPackageTask.new(gemspec)
50
+ gem_task.define
51
+
52
+ desc "Upload the gem file #{gem_task.gem_file}"
53
+ task 'cutter' => 'gem' do |t|
54
+ gem "push #{gem_task.package_dir}/#{gem_task.gem_file}"
55
+ end
56
+
57
+ Rake::TestTask.new do |t|
58
+ t.warning = true
59
+ end
60
+
61
+ Rake::RDocTask.new do |t|
62
+ t.rdoc_dir = 'doc'
63
+ t.rdoc_files = LIBS.include("README")
64
+ t.options.push '-S', '-N'
65
+ end
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright (c) 2010, arikui
4
+ # All rights reserved.
5
+
6
+ # Redistribution and use in source and binary forms, with or
7
+ # without modification, are permitted provided that the
8
+ # following conditions are met:
9
+
10
+ # * Redistributions of source code must retain the above
11
+ # copyright notice, this list of conditions and the
12
+ # following disclaimer.
13
+ # * Redistributions in binary form must reproduce the above
14
+ # copyright notice, this list of conditions and the following
15
+ # disclaimer in the documentation and/or other materials
16
+ # provided with the distribution.
17
+ # * Neither the name of the arikui-risp nor the names of its
18
+ # contributors may be used to endorse or promote products
19
+ # derived from this software without specific prior written
20
+ # permission.
21
+
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
23
+ # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
24
+ # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25
+ # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29
+ # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31
+ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33
+ # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
34
+ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
+
36
+ require 'risp'
37
+ require 'optparse'
38
+
39
+ Version = Risp.version
40
+ interactive_p = false
41
+
42
+ ARGV.options do |o|
43
+ o.banner = "Usage: #{o.program_name} [-options] [source-file]"
44
+ o.on '-i', '--interactive', 'turn on interactive mode' do
45
+ interactive_p = true
46
+ end
47
+ end
48
+
49
+ def with_input(file, &block)
50
+ file ? File.open(file, &block) : yield($stdin)
51
+ end
52
+
53
+ ARGV.parse!
54
+
55
+ source = interactive_p ? nil : ARGV.shift
56
+ interpreter = Risp::Interpreter.new
57
+
58
+ with_input(source) do |f|
59
+ reader = Risp::Reader.new(f)
60
+ loop do
61
+ begin
62
+ if interactive_p
63
+ print "Risp> "
64
+ sexp = reader.read
65
+ break if sexp.serialize == 'QUIT' || reader.eof?
66
+ r = sexp.evaluate(interpreter)
67
+ r.print($stdout)
68
+ puts
69
+ else
70
+ break if reader.eof?
71
+ sexp = reader.read
72
+ sexp.evaluate(interpreter)
73
+ end
74
+ rescue Risp::RuntimeError, Risp::ReadError => ex
75
+ $stderr.puts ex.message
76
+ exit 1 unless interactive_p
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,522 @@
1
+ # Copyright (c) 2010, arikui
2
+ # All rights reserved.
3
+
4
+ # Redistribution and use in source and binary forms, with or
5
+ # without modification, are permitted provided that the
6
+ # following conditions are met:
7
+
8
+ # * Redistributions of source code must retain the above
9
+ # copyright notice, this list of conditions and the
10
+ # following disclaimer.
11
+ # * Redistributions in binary form must reproduce the above
12
+ # copyright notice, this list of conditions and the following
13
+ # disclaimer in the documentation and/or other materials
14
+ # provided with the distribution.
15
+ # * Neither the name of the arikui-risp nor the names of its
16
+ # contributors may be used to endorse or promote products
17
+ # derived from this software without specific prior written
18
+ # permission.
19
+
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
21
+ # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
22
+ # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23
+ # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27
+ # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
+ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31
+ # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
32
+ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
+
34
+ require 'singleton'
35
+
36
+ module Risp
37
+ VERSION = '0.0.1'
38
+
39
+ def self.version
40
+ VERSION
41
+ end
42
+
43
+ class ReadError < RuntimeError ; end
44
+
45
+ class Reader
46
+ def initialize(f, filename = '-', lineno = 1)
47
+ @f = f
48
+ @filename = filename
49
+ @lineno = lineno
50
+ @read_table = {}
51
+ DEFAULT_READ_TABLE.each do |char, m|
52
+ @read_table[char] = method(m)
53
+ end
54
+ @read_table.default = method(DEFAULT_READ_TABLE.default)
55
+ end
56
+
57
+ def read
58
+ get_sexp()
59
+ end
60
+
61
+ def eof?
62
+ @f.eof?
63
+ end
64
+
65
+ private
66
+
67
+ def getc
68
+ c = @f.getc
69
+ @lineno += 1 if c == "\n"
70
+ c
71
+ end
72
+
73
+ def error(msg)
74
+ raise ReadError, "#{@filename}:#{@lineno}: #{msg}"
75
+ end
76
+
77
+ DEFAULT_READ_TABLE = {
78
+ '(' => :get_list,
79
+ "'" => :get_quote,
80
+ '"' => :get_string,
81
+ }
82
+ DEFAULT_READ_TABLE.default = :get_number_or_symbol
83
+
84
+ def get_sexp
85
+ while ch = getc()
86
+ func = @read_table.fetch(ch, nil) and return func.call(ch)
87
+ /\A[\s\n]/ =~ ch or return @read_table.default.call(ch)
88
+ end
89
+ Nil.instance
90
+ end
91
+
92
+ def skip_spaces
93
+ while ch = getc()
94
+ break unless /\A[\s\n]/ =~ ch
95
+ end
96
+ ch
97
+ end
98
+
99
+ def get_list(lparen)
100
+ ch = skip_spaces()
101
+ error "Un-closed list, missing right paren before EOF" unless ch
102
+ return Nil.instance if ')' == ch
103
+ @f.ungetc ch
104
+ top = list = List.new
105
+ loop do
106
+ list.car = get_sexp()
107
+ ch = skip_spaces()
108
+ error"Un-closed list, missing right paren before EOF" unless ch
109
+ case ch
110
+ when ')' then break
111
+ when '.'
112
+ list.cdr = get_sexp()
113
+ ch = skip_spaces()
114
+ error "Un-closed list, missing right paren before EOF" unless ch
115
+ error "Not-right paren token follows after dot-pair." unless ch == ')'
116
+ return top
117
+ else
118
+ @f.ungetc ch
119
+ list.cdr = List.new
120
+ list = list.cdr
121
+ end
122
+ end
123
+ top
124
+ end
125
+
126
+ def get_quote(q)
127
+ list = List.new
128
+ list.car = Symbol.new('quote')
129
+ list.cdr = List.new
130
+ list.cdr.car = get_sexp()
131
+ list
132
+ end
133
+
134
+ ESC_SEQ_TABLE = {
135
+ '"' => '"',
136
+ 'n' => "\n",
137
+ 't' => "\t",
138
+ }
139
+
140
+ def get_string(dq)
141
+ buf = ''
142
+ quoted = false
143
+ while ch = getc()
144
+ if quoted
145
+ seq = ESC_SEQ_TABLE[ch] and buf << seq
146
+ quoted = false
147
+ else
148
+ case ch
149
+ when '"' then break
150
+ when '\\' then quoted = true
151
+ else buf << ch
152
+ end
153
+ end
154
+ end
155
+ error "Un-closed string, missing later double quote." unless ch
156
+ String.new(buf)
157
+ end
158
+
159
+ def get_number_or_symbol(char)
160
+ token = char.dup
161
+ while ch = getc()
162
+ case ch
163
+ when /\A[\s\n]/ then break
164
+ when '(', ')'
165
+ @f.ungetc ch
166
+ break
167
+ end
168
+ token << ch
169
+ end
170
+ case token
171
+ when /\A\d+\Z/ then Integer.new(Kernel.Integer(token))
172
+ when 't' then T.instance
173
+ when 'nil' then Nil.instance
174
+ else Symbol.new(token)
175
+ end
176
+ end
177
+ end
178
+
179
+ module Sexp
180
+ def function?
181
+ false
182
+ end
183
+
184
+ def symbol?
185
+ false
186
+ end
187
+
188
+ def atom?
189
+ false
190
+ end
191
+ end
192
+
193
+ class Cell
194
+ include Sexp
195
+
196
+ def initialize
197
+ self.car = Nil.instance
198
+ self.cdr = Nil.instance
199
+ end
200
+
201
+ attr_accessor :car
202
+ attr_accessor :cdr
203
+ end
204
+
205
+ class List < Cell
206
+ def print(f)
207
+ f.print '('
208
+ print_inner(f, [self])
209
+ f.print ')'
210
+ end
211
+
212
+ def print_inner(f, appreaed_list)
213
+ car.print(f)
214
+ case cdr
215
+ when Nil
216
+ ;
217
+ when List
218
+ f.print ' '
219
+ if appreaed_list.any?{|x| x.equal?(cdr) }
220
+ f.print '...'
221
+ else
222
+ appreaed_list << cdr
223
+ cdr.print_inner(f, appreaed_list)
224
+ end
225
+ else
226
+ f.print ' . '
227
+ cdr.print(f)
228
+ end
229
+ end
230
+
231
+ def serialize
232
+ inspect
233
+ end
234
+
235
+ def evaluate(intp)
236
+ operator = car.evaluate(intp)
237
+ intp.apply(operator, cdr)
238
+ end
239
+
240
+ def to_a
241
+ ret = []
242
+ to_a_main ret, self
243
+ ret
244
+ end
245
+
246
+ def to_a_main(buf, lst)
247
+ unless lst == Nil.instance
248
+ buf << lst.car
249
+ to_a_main(buf, lst.cdr)
250
+ end
251
+ end
252
+
253
+ def length
254
+ length_main self
255
+ end
256
+
257
+ private
258
+
259
+ def length_main(lst)
260
+ lst == Nil.instance ? 0 : 1 + length_main(lst.cdr)
261
+ end
262
+ end
263
+
264
+ class Nil
265
+ include Sexp
266
+ include Singleton
267
+
268
+ def print(f)
269
+ f.print "NIL"
270
+ end
271
+
272
+ def serialize
273
+ "NIL"
274
+ end
275
+
276
+ def evaluate(intp)
277
+ self
278
+ end
279
+
280
+ def to_a
281
+ []
282
+ end
283
+
284
+ def atom?
285
+ true
286
+ end
287
+ end
288
+
289
+ class Atom
290
+ include Sexp
291
+
292
+ def atom?
293
+ true
294
+ end
295
+ end
296
+
297
+ class T < Atom
298
+ include Singleton
299
+
300
+ def print(f)
301
+ f.print "T"
302
+ end
303
+
304
+ def serialize
305
+ "T"
306
+ end
307
+
308
+ def evaluate(intp)
309
+ self
310
+ end
311
+ end
312
+
313
+ class Symbol < Atom
314
+ CACHE = {}
315
+
316
+ def self.new(name)
317
+ CACHE[name] ||= super(name)
318
+ end
319
+
320
+ def initialize(name)
321
+ @name = name
322
+ end
323
+
324
+ attr_reader :name
325
+
326
+ def print(f)
327
+ f.print serialize()
328
+ end
329
+
330
+ def serialize
331
+ name.upcase
332
+ end
333
+
334
+ def evaluate(intp)
335
+ intp.symbol_value(self)
336
+ end
337
+
338
+ def symbol?
339
+ true
340
+ end
341
+ end
342
+
343
+ class Number < Atom
344
+ end
345
+
346
+ class Integer < Number
347
+ def initialize(n)
348
+ @value = n
349
+ end
350
+
351
+ attr_reader :value
352
+
353
+ def print(f)
354
+ f.print serialize()
355
+ end
356
+
357
+ def serialize
358
+ value.to_s
359
+ end
360
+
361
+ def evaluate(intp)
362
+ self
363
+ end
364
+
365
+ def +(other)
366
+ Integer.new(self.value + other.value)
367
+ end
368
+ end
369
+
370
+ class String < Atom
371
+ def initialize(value)
372
+ @value = value
373
+ end
374
+
375
+ attr_reader :value
376
+
377
+ def print(f)
378
+ f.print serialize()
379
+ end
380
+
381
+ def serialize
382
+ value
383
+ end
384
+
385
+ def evaluate(intp)
386
+ self
387
+ end
388
+ end
389
+
390
+ class NativeFunction < Atom
391
+ def function?
392
+ true
393
+ end
394
+
395
+ def initialize(arity = nil, &body)
396
+ @arity = arity
397
+ @body = body
398
+ end
399
+
400
+ def print(f)
401
+ f.print serialize
402
+ end
403
+
404
+ def serialize
405
+ "#{inspect.split(/\s+/)[0]}>"
406
+ end
407
+
408
+ def call(intp, args)
409
+ args = args.to_a
410
+ if @arity && @arity != args.size
411
+ raise RuntimeError, "wrong number of arguments (#{args.size} for #{@arity})"
412
+ end
413
+ @body.call(*args)
414
+ end
415
+ end
416
+
417
+ class Function < Atom
418
+ def function?
419
+ true
420
+ end
421
+
422
+ def initialize(params, body)
423
+ @params = params.to_a
424
+ @body = body
425
+ end
426
+
427
+ def print(f)
428
+ f.print serialize
429
+ end
430
+
431
+ def serialize
432
+ "#{inspect.split(/\s+/)[0]}>"
433
+ end
434
+
435
+ def call(intp, args)
436
+ args = args.to_a
437
+ unless @params.size == args.size
438
+ raise RuntimeError, "wrong number of arguments (#{args.size} for #{@params.size})"
439
+ end
440
+ ret = nil
441
+ intp.local_environment(@params.zip(args)) do
442
+ @body.each{|s| ret = s.evaluate(intp) }
443
+ end
444
+ ret
445
+ end
446
+ end
447
+
448
+ class RuntimeError < ::RuntimeError ; end
449
+
450
+ class Interpreter
451
+ def initialize
452
+ @specials = {}
453
+ @frames = []
454
+ @specials[Symbol.new('car')] = NativeFunction.new(1){|list|
455
+ list.evaluate(self).car
456
+ }
457
+ @specials[Symbol.new('cdr')] = NativeFunction.new(1){|list|
458
+ list.evaluate(self).cdr
459
+ }
460
+ @specials[Symbol.new('cons')] = NativeFunction.new(2){|car, cdr|
461
+ list = List.new
462
+ list.car = car.evaluate(self)
463
+ list.cdr = cdr.evaluate(self)
464
+ list
465
+ }
466
+ @specials[Symbol.new('eq')] = NativeFunction.new(2){|x, y|
467
+ x.evaluate(self).equal?(y.evaluate(self)) ? T.instance : Nil.instance
468
+ }
469
+ @specials[Symbol.new('atom')] = NativeFunction.new(1){|sexp|
470
+ sexp.evaluate(self).atom? ? T.instance : Nil.instance
471
+ }
472
+ @specials[Symbol.new('quote')] = NativeFunction.new(1){|sexp|
473
+ sexp
474
+ }
475
+ @specials[Symbol.new('cond')] = NativeFunction.new{|*forms|
476
+ result = forms.each{|form|
477
+ test, *body = form.to_a
478
+ if test.evaluate(self) == T.instance
479
+ ret = nil
480
+ body.each{|s| ret = s.evaluate(self) }
481
+ break ret
482
+ end
483
+ }
484
+ result.equal?(forms) ? Nil.instance : result
485
+ }
486
+ @specials[Symbol.new('define')] = NativeFunction.new(2){|bindee, value|
487
+ case
488
+ when bindee.symbol?
489
+ (@frames.last || @specials)[bindee] = value.evaluate(self)
490
+ else
491
+ raise RuntimeError, "#{bindee.serialize} is not a symbol."
492
+ end
493
+ }
494
+ @specials[Symbol.new('lambda')] = NativeFunction.new{|params, *body|
495
+ Function.new(params, body)
496
+ }
497
+ @specials[Symbol.new('+')] = NativeFunction.new{|*args|
498
+ args.map{|arg| arg.evaluate(self) }.inject(Integer.new(0), :+)
499
+ }
500
+ end
501
+
502
+ def local_environment(alist)
503
+ f = alist.each_with_object({}){|(sym, val), h| h[sym] = val }
504
+ @frames.push f
505
+ ret = yield
506
+ @frames.pop
507
+ ret
508
+ end
509
+
510
+ def symbol_value(sym)
511
+ @frames.reverse_each do |frame|
512
+ v = frame[sym] and return v
513
+ end
514
+ @specials[sym] or raise RuntimeError, "unbound variable - `#{sym.name}'"
515
+ end
516
+
517
+ def apply(function, args)
518
+ raise RuntimeError, "not a function - #{function}" unless function.function?
519
+ function.call(self, args)
520
+ end
521
+ end
522
+ end
@@ -0,0 +1,25 @@
1
+ require 'expectations'
2
+ require 'stringio'
3
+ require 'risp'
4
+
5
+ Expectations do
6
+ expect Risp::Integer do
7
+ Risp::Reader.new(StringIO.new("123")).read
8
+ end
9
+
10
+ expect 123 do
11
+ Risp::Reader.new(StringIO.new("123")).read.value
12
+ end
13
+ end
14
+
15
+
16
+ __END__
17
+ require 'test/unit'
18
+ require 'stringio'
19
+
20
+ class TestRispReader < Test::Unit::TestCase
21
+ def test_integer
22
+ sexp = Risp::Reader.new(StringIO.new("123")).read
23
+ assert_kind_of Risp::Integer, sexp
24
+ end
25
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: risp
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - arikui
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-19 00:00:00 +09:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: A toy lisp interpreter.
23
+ email: arikui.ruby@gmail.com
24
+ executables:
25
+ - risp
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README
30
+ files:
31
+ - README
32
+ - Rakefile
33
+ - bin/risp
34
+ - test/test_risp_reader.rb
35
+ - lib/risp.rb
36
+ has_rdoc: true
37
+ homepage: http://wiki.github.com/arikui1911/risp
38
+ licenses: []
39
+
40
+ post_install_message:
41
+ rdoc_options:
42
+ - --title
43
+ - risp documentation
44
+ - --charset
45
+ - utf-8
46
+ - --opname
47
+ - index.html
48
+ - --line-numbers
49
+ - --main
50
+ - README
51
+ - --inline-source
52
+ - --exclude
53
+ - ^(examples|extras)/
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ requirements: []
75
+
76
+ rubyforge_project: risp
77
+ rubygems_version: 1.3.7
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: A toy lisp interpreter; provides `pure-lisp' functions and Lisp-1 namespaces. Currently it lacks package system and macro(!!).
81
+ test_files:
82
+ - test/test_risp_reader.rb