risp 0.0.1

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