dslisprb 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +0 -0
- data/README.rdoc +63 -0
- data/Rakefile +44 -0
- data/TODO +3 -0
- data/bin/dslisprb +44 -0
- data/lib/dslisprb.rb +201 -0
- data/lib/dslisprb.rb~ +201 -0
- data/spec/ast.rb +55 -0
- data/spec/ast.rb~ +55 -0
- data/spec/defun.rb +27 -0
- data/spec/defun.rb~ +27 -0
- data/spec/execution.rb +25 -0
- data/spec/execution.rb~ +25 -0
- data/spec/functions.rb +132 -0
- data/spec/functions.rb~ +132 -0
- data/spec/macro.rb +11 -0
- data/spec/macro.rb~ +11 -0
- metadata +62 -0
data/CHANGELOG
ADDED
File without changes
|
data/README.rdoc
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
dslisprb (dseminara 'lisp)
|
2
|
+
http://github.com/tario/dslisprb
|
3
|
+
Dario Seminara (http://tario-project.blogspot.com.ar/)
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
dseminara 'lisp is my own implementation of lisp on ruby, created as an excercise in preparation for finals
|
8
|
+
|
9
|
+
dslisprb try to be minimalist (only 200 lines of ruby code including parser, default
|
10
|
+
functions and macros and about 30 lines for the repl) by using ruby code generation where possible
|
11
|
+
|
12
|
+
For example, lisp lambdas are represented as ruby lambdas defined with the code translated from lisp to ruby
|
13
|
+
and lisp variables (including those where default functions/lambda are stored) are translated as ruby variables
|
14
|
+
allowing reuse of the ruby stack instead of reimplement it
|
15
|
+
|
16
|
+
== FEATURES:
|
17
|
+
|
18
|
+
* dslisprb executable with readline
|
19
|
+
* Basic common lisp functions
|
20
|
+
|
21
|
+
== TODO:
|
22
|
+
|
23
|
+
* MAPCAR
|
24
|
+
* Defined functions and variable persistent between multiple evaluate calls
|
25
|
+
* caaaar, cdadar, cddra, etc...
|
26
|
+
|
27
|
+
== SYNOPSIS:
|
28
|
+
|
29
|
+
See 'dslisprb --help' for usage information.
|
30
|
+
|
31
|
+
== REQUIREMENTS:
|
32
|
+
|
33
|
+
* Ruby
|
34
|
+
|
35
|
+
== INSTALL:
|
36
|
+
|
37
|
+
* gem install dslisprb
|
38
|
+
|
39
|
+
== LICENSE:
|
40
|
+
|
41
|
+
(The MIT License)
|
42
|
+
|
43
|
+
Copyright (c) 2012 Dario Seminara
|
44
|
+
|
45
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
46
|
+
a copy of this software and associated documentation files (the
|
47
|
+
'Software'), to deal in the Software without restriction, including
|
48
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
49
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
50
|
+
permit persons to whom the Software is furnished to do so, subject to
|
51
|
+
the following conditions:
|
52
|
+
|
53
|
+
The above copyright notice and this permission notice shall be
|
54
|
+
included in all copies or substantial portions of the Software.
|
55
|
+
|
56
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
57
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
58
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
59
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
60
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
61
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
62
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
63
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rdoc/task'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
require "rspec/core/rake_task"
|
7
|
+
|
8
|
+
spec = Gem::Specification.new do |s|
|
9
|
+
s.name = 'dslisprb'
|
10
|
+
s.version = '0.0.1'
|
11
|
+
s.author = 'Dario Seminara'
|
12
|
+
s.email = 'robertodarioseminara@gmail.com'
|
13
|
+
s.platform = Gem::Platform::RUBY
|
14
|
+
s.summary = 'Lisp interpreter written in ruby, using code generation'
|
15
|
+
s.homepage = "http://github.com/tario/dslisprb"
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.executables = ["dslisprb"]
|
18
|
+
s.files = Dir.glob("{lib,spec}/**/*") + [ 'README.rdoc', 'Rakefile', 'TODO', 'CHANGELOG' ]
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Run tests'
|
22
|
+
|
23
|
+
RSpec::Core::RakeTask.new("test:units") do |t|
|
24
|
+
t.pattern= 'spec/**/*.rb'
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Generate RDoc'
|
28
|
+
Rake::RDocTask.new :rdoc do |rd|
|
29
|
+
rd.rdoc_dir = 'doc'
|
30
|
+
rd.rdoc_files.add 'lib', 'README.rdoc'
|
31
|
+
rd.main = 'README.rdoc'
|
32
|
+
end
|
33
|
+
|
34
|
+
desc 'Build Gem'
|
35
|
+
Rake::GemPackageTask.new spec do |pkg|
|
36
|
+
pkg.need_tar = true
|
37
|
+
end
|
38
|
+
|
39
|
+
desc 'Clean up'
|
40
|
+
task :clean => [ :clobber_rdoc, :clobber_package ]
|
41
|
+
|
42
|
+
desc 'Clean up'
|
43
|
+
task :clobber => [ :clean ]
|
44
|
+
|
data/TODO
ADDED
data/bin/dslisprb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "dslisprb"
|
3
|
+
|
4
|
+
dslisp = DsLisp.new
|
5
|
+
if ARGV[0]
|
6
|
+
if ARGV[0] == '--help'
|
7
|
+
print "
|
8
|
+
dslisprb --help
|
9
|
+
show this message
|
10
|
+
dslisprb <lisp expression>
|
11
|
+
evaluate lisp expression, shows the result on standard output and exit
|
12
|
+
|
13
|
+
Example:
|
14
|
+
dslisprb \"(car '(1 2 3))\"
|
15
|
+
(2 3)
|
16
|
+
|
17
|
+
dslisprb without arguments starts the repl
|
18
|
+
"
|
19
|
+
|
20
|
+
else
|
21
|
+
# execute and exit
|
22
|
+
print dslisp.evaluate(ARGV[0]).lisp_inspect,"\n"
|
23
|
+
end
|
24
|
+
else
|
25
|
+
# repl
|
26
|
+
require 'readline'
|
27
|
+
print "enter lisp commands or quit to exit\n"
|
28
|
+
|
29
|
+
stty_save = `stty -g`.chomp
|
30
|
+
trap('INT') { system('stty', stty_save); exit }
|
31
|
+
|
32
|
+
while cmd = Readline.readline('> ', true)
|
33
|
+
if cmd == "quit"
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
|
37
|
+
begin
|
38
|
+
print dslisp.evaluate(cmd).lisp_inspect,"\n"
|
39
|
+
rescue Exception => e
|
40
|
+
p e
|
41
|
+
print e.backtrace.join("\n"),"\n"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/dslisprb.rb
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
class DsLisp
|
2
|
+
class ToRuby
|
3
|
+
class << self
|
4
|
+
def name_convert(name)
|
5
|
+
{:< => "lt", :> => "ht", :+ => "plus", :* => "mult" , :/ => "divide", :- => "minus" }[name] || "_" + name.to_s
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_ruby(code)
|
9
|
+
if Array === code
|
10
|
+
# lisp call
|
11
|
+
|
12
|
+
function_name = code.first
|
13
|
+
|
14
|
+
if (CommonLispOperators.methods - Class.methods).include?(function_name)
|
15
|
+
CommonLispOperators.send(function_name, code)
|
16
|
+
else
|
17
|
+
strargs = code[1..-1].map{|x|
|
18
|
+
if Symbol === x
|
19
|
+
"(local_variables.include?(:#{x}) ? #{x} : (#{to_ruby(x)}))"
|
20
|
+
else
|
21
|
+
"(#{to_ruby(x)})"
|
22
|
+
end
|
23
|
+
}.join(",")
|
24
|
+
|
25
|
+
if Symbol === function_name
|
26
|
+
"#{name_convert(function_name)}.call(#{strargs})"
|
27
|
+
else
|
28
|
+
"#{to_ruby(code.first)}.call(#{strargs})"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
else
|
32
|
+
code.inspect
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module CommonLispOperators
|
39
|
+
class << self
|
40
|
+
def quote(code)
|
41
|
+
code[1].inspect
|
42
|
+
end
|
43
|
+
|
44
|
+
def lambda(code)
|
45
|
+
arguments = code[1].map(&:to_s).join(",")
|
46
|
+
"lambda{|#{arguments}| #{ToRuby.to_ruby(code[2])}}.lisp_inner_code(#{code.lisp_inspect.inspect})"
|
47
|
+
end
|
48
|
+
|
49
|
+
def block(code)
|
50
|
+
code[1..-1].map(&ToRuby.method(:to_ruby)).join(";")
|
51
|
+
end
|
52
|
+
|
53
|
+
def set(code)
|
54
|
+
"#{ToRuby.name_convert(code[1])} = #{ToRuby.to_ruby(code[2])}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def defun(code)
|
58
|
+
newcode = [:set, code[1], [:lambda, code[2], code[3]]]
|
59
|
+
ToRuby.to_ruby(newcode)
|
60
|
+
end
|
61
|
+
|
62
|
+
def defmacro(code)
|
63
|
+
name = code[1]
|
64
|
+
arguments = code[2]
|
65
|
+
impl = code[3][1]
|
66
|
+
|
67
|
+
subsl = Kernel.lambda{|_code, rplmap|
|
68
|
+
_code.map{|subcode|
|
69
|
+
if Array === subcode
|
70
|
+
subsl.call(subcode, rplmap)
|
71
|
+
else
|
72
|
+
rplmap[subcode] || subcode
|
73
|
+
end
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
CommonLispOperators.define_singleton_method(name) do |_code|
|
78
|
+
rplmap = {}
|
79
|
+
(0..arguments.size-1).each do |i|
|
80
|
+
rplmap[arguments[i]] = _code[i+1]
|
81
|
+
end
|
82
|
+
|
83
|
+
ToRuby.to_ruby subsl.call(impl, rplmap)
|
84
|
+
end
|
85
|
+
|
86
|
+
""
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def parse(str)
|
92
|
+
if str.count("(") != str.count(")")
|
93
|
+
raise "Parentheshis count does not match, try adding parenthesis at the end of string :P"
|
94
|
+
end
|
95
|
+
|
96
|
+
if matchdata = /^\s*\'(.*)\s*$/.match(str)
|
97
|
+
[:quote, parse(matchdata[1].sub("'",""))]
|
98
|
+
elsif matchdata = /^\s*\((.*)\)\s*$/.match(str)
|
99
|
+
inside_code = matchdata[1]
|
100
|
+
if inside_code =~ /^\s*$/
|
101
|
+
[]
|
102
|
+
else
|
103
|
+
# split tokens preserving parenthesis count
|
104
|
+
tokens = []
|
105
|
+
newtoken = ""
|
106
|
+
inside_code.split.each do |str|
|
107
|
+
newtoken << " "
|
108
|
+
newtoken << str
|
109
|
+
if newtoken.count("(") == newtoken.count(")")
|
110
|
+
tokens << newtoken
|
111
|
+
newtoken = ""
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
tokens.map(&method(:parse))
|
116
|
+
end
|
117
|
+
else
|
118
|
+
if str =~ /^\s*\d+\s*$/
|
119
|
+
str.to_i
|
120
|
+
else
|
121
|
+
str.strip.to_sym
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def evaluate(code)
|
127
|
+
if String === code
|
128
|
+
return evaluate(parse code)
|
129
|
+
end
|
130
|
+
# arithmethic
|
131
|
+
plus = lambda{|x,y| x+y}
|
132
|
+
mult = lambda{|x,y| x*y}
|
133
|
+
divide = lambda{|x,y| x/y}
|
134
|
+
minus = lambda{|x,y| x-y}
|
135
|
+
|
136
|
+
lt = lambda{|x,y| x<y || nil}
|
137
|
+
ht = lambda{|x,y| x>y || nil}
|
138
|
+
_eq = lambda{|x,y| x==y || nil}
|
139
|
+
|
140
|
+
|
141
|
+
# list selectors
|
142
|
+
_car = lambda{|x| x.first}
|
143
|
+
_cdr = lambda{|x| x[1..-1]}
|
144
|
+
_nth = lambda{|index,list| list[index-1]}
|
145
|
+
|
146
|
+
# list constructors
|
147
|
+
_cons = lambda{|element, list| [element]+list}
|
148
|
+
_append = plus
|
149
|
+
_list = lambda{|*args| args}
|
150
|
+
|
151
|
+
# recognizers
|
152
|
+
_null = lambda{|element| (element == nil or element == []) || nil}
|
153
|
+
_atom = lambda{|element| (not Array === element) || nil}
|
154
|
+
_numberp = lambda{|element| Numeric === element || nil}
|
155
|
+
_symbolp = lambda{|element| Symbol === element || nil}
|
156
|
+
_listp = lambda{|element| Array === element || nil}
|
157
|
+
_length = lambda{|list| list.size}
|
158
|
+
|
159
|
+
# nil
|
160
|
+
_nil = lambda{nil}
|
161
|
+
|
162
|
+
# boolean
|
163
|
+
_not = lambda{|a| (not a) || nil}
|
164
|
+
_and = lambda{|a,b| (a and b) || nil}
|
165
|
+
_or = lambda{|a,b| (a or b) || nil}
|
166
|
+
|
167
|
+
# generate ruby code for lisp ast
|
168
|
+
ruby_code = ToRuby.to_ruby(code)
|
169
|
+
eval(ruby_code)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
class Object
|
174
|
+
def lisp_inspect
|
175
|
+
inspect
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
class Symbol
|
180
|
+
def lisp_inspect
|
181
|
+
to_s
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class Array
|
186
|
+
def lisp_inspect
|
187
|
+
"(" + map(&:lisp_inspect).join(" ") + ")"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
class Proc
|
192
|
+
def lisp_inspect
|
193
|
+
@inner_code
|
194
|
+
end
|
195
|
+
|
196
|
+
def lisp_inner_code(code)
|
197
|
+
@inner_code = code
|
198
|
+
self
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
data/lib/dslisprb.rb~
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
class DsLisp
|
2
|
+
class ToRuby
|
3
|
+
class << self
|
4
|
+
def name_convert(name)
|
5
|
+
{:< => "lt", :> => "ht", :+ => "plus", :* => "mult" , :/ => "divide", :- => "minus" }[name] || "_" + name.to_s
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_ruby(code)
|
9
|
+
if Array === code
|
10
|
+
# lisp call
|
11
|
+
|
12
|
+
function_name = code.first
|
13
|
+
|
14
|
+
if (CommonLispOperators.methods - Class.methods).include?(function_name)
|
15
|
+
CommonLispOperators.send(function_name, code)
|
16
|
+
else
|
17
|
+
strargs = code[1..-1].map{|x|
|
18
|
+
if Symbol === x
|
19
|
+
"(local_variables.include?(:#{x}) ? #{x} : (#{to_ruby(x)}))"
|
20
|
+
else
|
21
|
+
"(#{to_ruby(x)})"
|
22
|
+
end
|
23
|
+
}.join(",")
|
24
|
+
|
25
|
+
if Symbol === function_name
|
26
|
+
"#{name_convert(function_name)}.call(#{strargs})"
|
27
|
+
else
|
28
|
+
"#{to_ruby(code.first)}.call(#{strargs})"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
else
|
32
|
+
code.inspect
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module CommonLispOperators
|
39
|
+
class << self
|
40
|
+
def quote(code)
|
41
|
+
code[1].inspect
|
42
|
+
end
|
43
|
+
|
44
|
+
def lambda(code)
|
45
|
+
arguments = code[1].map(&:to_s).join(",")
|
46
|
+
"lambda{|#{arguments}| #{ToRuby.to_ruby(code[2])}}.lisp_inner_code(#{code.lisp_inspect.inspect})"
|
47
|
+
end
|
48
|
+
|
49
|
+
def block(code)
|
50
|
+
code[1..-1].map(&ToRuby.method(:to_ruby)).join(";")
|
51
|
+
end
|
52
|
+
|
53
|
+
def set(code)
|
54
|
+
"#{ToRuby.name_convert(code[1])} = #{ToRuby.to_ruby(code[2])}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def defun(code)
|
58
|
+
newcode = [:set, code[1], [:lambda, code[2], code[3]]]
|
59
|
+
ToRuby.to_ruby(newcode)
|
60
|
+
end
|
61
|
+
|
62
|
+
def defmacro(code)
|
63
|
+
name = code[1]
|
64
|
+
arguments = code[2]
|
65
|
+
impl = code[3][1]
|
66
|
+
|
67
|
+
subsl = Kernel.lambda{|_code, rplmap|
|
68
|
+
_code.map{|subcode|
|
69
|
+
if Array === subcode
|
70
|
+
subsl.call(subcode, rplmap)
|
71
|
+
else
|
72
|
+
rplmap[subcode] || subcode
|
73
|
+
end
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
CommonLispOperators.define_singleton_method(name) do |_code|
|
78
|
+
rplmap = {}
|
79
|
+
(0..arguments.size-1).each do |i|
|
80
|
+
rplmap[arguments[i]] = _code[i+1]
|
81
|
+
end
|
82
|
+
|
83
|
+
ToRuby.to_ruby subsl.call(impl, rplmap)
|
84
|
+
end
|
85
|
+
|
86
|
+
""
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def parse(str)
|
92
|
+
if str.count("(") != str.count(")")
|
93
|
+
raise "Parentheshis count does not match, try adding parenthesis to the end :P"
|
94
|
+
end
|
95
|
+
|
96
|
+
if matchdata = /^\s*\'(.*)\s*$/.match(str)
|
97
|
+
[:quote, parse(matchdata[1].sub("'",""))]
|
98
|
+
elsif matchdata = /^\s*\((.*)\)\s*$/.match(str)
|
99
|
+
inside_code = matchdata[1]
|
100
|
+
if inside_code =~ /^\s*$/
|
101
|
+
[]
|
102
|
+
else
|
103
|
+
# split tokens preserving parenthesis count
|
104
|
+
tokens = []
|
105
|
+
newtoken = ""
|
106
|
+
inside_code.split.each do |str|
|
107
|
+
newtoken << " "
|
108
|
+
newtoken << str
|
109
|
+
if newtoken.count("(") == newtoken.count(")")
|
110
|
+
tokens << newtoken
|
111
|
+
newtoken = ""
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
tokens.map(&method(:parse))
|
116
|
+
end
|
117
|
+
else
|
118
|
+
if str =~ /^\s*\d+\s*$/
|
119
|
+
str.to_i
|
120
|
+
else
|
121
|
+
str.strip.to_sym
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def evaluate(code)
|
127
|
+
if String === code
|
128
|
+
return evaluate(parse code)
|
129
|
+
end
|
130
|
+
# arithmethic
|
131
|
+
plus = lambda{|x,y| x+y}
|
132
|
+
mult = lambda{|x,y| x*y}
|
133
|
+
divide = lambda{|x,y| x/y}
|
134
|
+
minus = lambda{|x,y| x-y}
|
135
|
+
|
136
|
+
lt = lambda{|x,y| x<y || nil}
|
137
|
+
ht = lambda{|x,y| x>y || nil}
|
138
|
+
_eq = lambda{|x,y| x==y || nil}
|
139
|
+
|
140
|
+
|
141
|
+
# list selectors
|
142
|
+
_car = lambda{|x| x.first}
|
143
|
+
_cdr = lambda{|x| x[1..-1]}
|
144
|
+
_nth = lambda{|index,list| list[index-1]}
|
145
|
+
|
146
|
+
# list constructors
|
147
|
+
_cons = lambda{|element, list| [element]+list}
|
148
|
+
_append = plus
|
149
|
+
_list = lambda{|*args| args}
|
150
|
+
|
151
|
+
# recognizers
|
152
|
+
_null = lambda{|element| (element == nil or element == []) || nil}
|
153
|
+
_atom = lambda{|element| (not Array === element) || nil}
|
154
|
+
_numberp = lambda{|element| Numeric === element || nil}
|
155
|
+
_symbolp = lambda{|element| Symbol === element || nil}
|
156
|
+
_listp = lambda{|element| Array === element || nil}
|
157
|
+
_length = lambda{|list| list.size}
|
158
|
+
|
159
|
+
# nil
|
160
|
+
_nil = lambda{nil}
|
161
|
+
|
162
|
+
# boolean
|
163
|
+
_not = lambda{|a| (not a) || nil}
|
164
|
+
_and = lambda{|a,b| (a and b) || nil}
|
165
|
+
_or = lambda{|a,b| (a or b) || nil}
|
166
|
+
|
167
|
+
# generate ruby code for lisp ast
|
168
|
+
ruby_code = ToRuby.to_ruby(code)
|
169
|
+
eval(ruby_code)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
class Object
|
174
|
+
def lisp_inspect
|
175
|
+
inspect
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
class Symbol
|
180
|
+
def lisp_inspect
|
181
|
+
to_s
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class Array
|
186
|
+
def lisp_inspect
|
187
|
+
"(" + map(&:lisp_inspect).join(" ") + ")"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
class Proc
|
192
|
+
def lisp_inspect
|
193
|
+
@inner_code
|
194
|
+
end
|
195
|
+
|
196
|
+
def lisp_inner_code(code)
|
197
|
+
@inner_code = code
|
198
|
+
self
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
data/spec/ast.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require "dslisprb"
|
2
|
+
|
3
|
+
describe DsLisp, "ds lisp" do
|
4
|
+
|
5
|
+
(1..10).each do |i|
|
6
|
+
it "should parse simple numeric atom #{i}" do
|
7
|
+
DsLisp.new.parse(i.to_s).should be == i
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
(1..10).each do |i|
|
12
|
+
it "should parse simple numeric atom #{i} with spaces around" do
|
13
|
+
DsLisp.new.parse(" " + i.to_s + " ").should be == i
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
[:x,:y,:z].each do |symbol|
|
18
|
+
it "should parse simple symbolic atom #{symbol}" do
|
19
|
+
DsLisp.new.parse(symbol.to_s).should be == symbol
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should parse empty list" do
|
24
|
+
DsLisp.new.parse('()').should be == []
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should parse list with atom inside" do
|
28
|
+
DsLisp.new.parse('(1)').should be == [1]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should parse list with two atoms inside" do
|
32
|
+
DsLisp.new.parse('(1 2)').should be == [1, 2]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should parse list with a list with two atoms inside" do
|
36
|
+
DsLisp.new.parse('((1 2))').should be == [[1, 2]]
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should parse list with two list with two atoms inside" do
|
40
|
+
DsLisp.new.parse('((1 2) (3 4))').should be == [[1, 2],[3, 4]]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should parse list with two list with two symbolic atoms inside" do
|
44
|
+
DsLisp.new.parse('((a b) (c d))').should be == [[:a, :b],[:c, :d]]
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should parse quote with atoms" do
|
48
|
+
DsLisp.new.parse("'car").should be == [:quote, :car]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should parse quote with lists" do
|
52
|
+
DsLisp.new.parse("'(1 2 3)").should be == [:quote, [1,2,3]]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
data/spec/ast.rb~
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require "dslisprb"
|
2
|
+
|
3
|
+
describe DsLisp, "ds lisp" do
|
4
|
+
|
5
|
+
(1..10).each do |i|
|
6
|
+
it "should parse simple numeric atom #{i}" do
|
7
|
+
DsLisp.new.parse(i.to_s).should be == i
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
(1..10).each do |i|
|
12
|
+
it "should parse simple numeric atom #{i} with spaces around" do
|
13
|
+
DsLisp.new.parse(" " + i.to_s + " ").should be == i
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
[:x,:y,:z].each do |symbol|
|
18
|
+
it "should parse simple symbolic atom #{symbol}" do
|
19
|
+
DsLisp.new.parse(symbol.to_s).should be == symbol
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should parse empty list" do
|
24
|
+
DsLisp.new.parse('()').should be == []
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should parse list with atom inside" do
|
28
|
+
DsLisp.new.parse('(1)').should be == [1]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should parse list with two atoms inside" do
|
32
|
+
DsLisp.new.parse('(1 2)').should be == [1, 2]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should parse list with a list with two atoms inside" do
|
36
|
+
DsLisp.new.parse('((1 2))').should be == [[1, 2]]
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should parse list with two list with two atoms inside" do
|
40
|
+
DsLisp.new.parse('((1 2) (3 4))').should be == [[1, 2],[3, 4]]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should parse list with two list with two symbolic atoms inside" do
|
44
|
+
DsLisp.new.parse('((a b) (c d))').should be == [[:a, :b],[:c, :d]]
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should parse quote with atoms" do
|
48
|
+
DsLisp.new.parse("'car").should be == [:quote, :car]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should parse quote with lists" do
|
52
|
+
DsLisp.new.parse("'(1,2,3)").should be == [:quote, [1,2,3]]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
data/spec/defun.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "dslisprb"
|
2
|
+
|
3
|
+
describe DsLisp, "ds lisp defun" do
|
4
|
+
it "should allow lambda" do
|
5
|
+
DsLisp.new.evaluate([:lambda, [:x], [:+, :x, 1]]).call(1).should be == 2
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should allow lambda assign and call" do
|
9
|
+
DsLisp.new.evaluate([:block,
|
10
|
+
[:set, :lambda_test, [:lambda, [:x], [:+, :x, 1]]],
|
11
|
+
[:lambda_test, 1]
|
12
|
+
]).should be == 2
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should allow lambda returning 3" do
|
16
|
+
DsLisp.new.evaluate([:lambda, [:x], [:+, :x, 2]]).call(1).should be == 3
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should allow defun as brief for lambda assign" do
|
20
|
+
DsLisp.new.evaluate([:block,
|
21
|
+
[:defun, :lambda_test, [:x], [:+, :x, 1]],
|
22
|
+
[:lambda_test, 1]
|
23
|
+
]).should be == 2
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
data/spec/defun.rb~
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "dslisprb"
|
2
|
+
|
3
|
+
describe DsLisp, "ds lisp defun" do
|
4
|
+
it "should allow lambda" do
|
5
|
+
DsLisp.new.evaluate([:lambda, [:x], [:+, :x, 1]]).call(1).should be == 2
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should allow lambda assign and call" do
|
9
|
+
DsLisp.new.evaluate([:block,
|
10
|
+
[:set, :lambda_test, [:lambda, [:x], [:+, :x, 1]]],
|
11
|
+
[:lambda_test, 1]
|
12
|
+
]).should be == 2
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should allow lambda returning 3" do
|
16
|
+
DsLisp.new.evaluate([:lambda, [:x], [:+, :x, 2]]).call(1).should be == 3
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should allow defun as brief for lambda assign" do
|
20
|
+
DsLisp.new.evaluate([:block,
|
21
|
+
[:defun, :lambda_test, [:x], [:+, :x, 1]],
|
22
|
+
[:lambda_test, 1]
|
23
|
+
]).should be == 2
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
data/spec/execution.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require "dslisprb"
|
2
|
+
|
3
|
+
describe DsLisp, "ds lisp execution" do
|
4
|
+
|
5
|
+
(1..10).each do |i|
|
6
|
+
it "should evaluate simple numeric atom #{i}" do
|
7
|
+
DsLisp.new.evaluate(i).should be == i
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
[:x,:y,:z].each do |symbol|
|
12
|
+
it "should parse simple symbolic atom #{symbol}" do
|
13
|
+
DsLisp.new.evaluate(symbol).should be == symbol
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should evaluate call to arithmetic method +" do
|
18
|
+
DsLisp.new.evaluate([:+, 1, 2]).should be == 3
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should evaluate quote call to define literals" do
|
22
|
+
DsLisp.new.evaluate([:quote, [1, 2, 3]]).should be == [1, 2, 3]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
data/spec/execution.rb~
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require "dslisprb"
|
2
|
+
|
3
|
+
describe DsLisp, "ds lisp execution" do
|
4
|
+
|
5
|
+
(1..10).each do |i|
|
6
|
+
it "should evaluate simple numeric atom #{i}" do
|
7
|
+
DsLisp.new.evaluate(i).should be == i
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
[:x,:y,:z].each do |symbol|
|
12
|
+
it "should parse simple symbolic atom #{symbol}" do
|
13
|
+
DsLisp.new.evaluate(symbol).should be == symbol
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should evaluate call to arithmetic method +" do
|
18
|
+
DsLisp.new.evaluate([:+, 1, 2]).should be == 3
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should evaluate quote call to define literals" do
|
22
|
+
DsLisp.new.evaluate([:quote, [1, 2, 3]).should be == [1, 2, 3]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
data/spec/functions.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require "dslisprb"
|
2
|
+
|
3
|
+
describe DsLisp, "ds lisp functions" do
|
4
|
+
|
5
|
+
# selectors
|
6
|
+
it "should return 1 for (car (quote (1 2)))" do
|
7
|
+
DsLisp.new.evaluate([:car, [:quote, [1, 2]]]).should be == 1
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should return (2 3) for (cdr (quote (1 2 3)))" do
|
11
|
+
DsLisp.new.evaluate([:cdr, [:quote, [1, 2, 3]]]).should be == [2, 3]
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return 5 for (nth 2 (quote (4 5 6)))" do
|
15
|
+
DsLisp.new.evaluate([:nth, 2, [:quote, [4, 5, 6]]]).should be == 5
|
16
|
+
end
|
17
|
+
|
18
|
+
# constructors
|
19
|
+
it "should return (1 2 3 4) for (cons 1 (quote (2 3 4)))" do
|
20
|
+
DsLisp.new.evaluate([:cons, 1, [:quote, [2, 3, 4]]]).should be == [1,2,3,4]
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return (1 2 3 4 5) for (append (quote (1 2)) (quote (3 4 5)))" do
|
24
|
+
DsLisp.new.evaluate([:append, [:quote, [1,2]], [:quote, [3, 4, 5]]]).should be == [1,2,3,4,5]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return (1 2) for (list 1 2)" do
|
28
|
+
DsLisp.new.evaluate([:list, 1, 2]).should be == [1,2]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return (1 2 3) for (list 1 2 3)" do
|
32
|
+
DsLisp.new.evaluate([:list, 1, 2, 3]).should be == [1,2,3]
|
33
|
+
end
|
34
|
+
|
35
|
+
# type recognizers
|
36
|
+
[:a, 1, [1,2,3,4], [], nil].each do |obj|
|
37
|
+
result = (obj == nil or obj == []) ? true : nil
|
38
|
+
it "should return #{result} for (null #{obj})" do
|
39
|
+
DsLisp.new.evaluate([:null, [:quote, obj]]).should be == result
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
[:a, 1, [1,2,3,4]].each do |obj|
|
44
|
+
result = (not Array === obj) ? true : nil
|
45
|
+
it "should return #{result} for (atom #{obj})" do
|
46
|
+
DsLisp.new.evaluate([:atom, [:quote, obj]]).should be == result
|
47
|
+
end
|
48
|
+
|
49
|
+
numberp_result = (Numeric === obj) ? true : nil
|
50
|
+
it "should return #{result} for (numberp #{obj})" do
|
51
|
+
DsLisp.new.evaluate([:numberp, [:quote, obj]]).should be == numberp_result
|
52
|
+
end
|
53
|
+
|
54
|
+
symbolp_result = (Symbol === obj) ? true : nil
|
55
|
+
it "should return #{result} for (symbolp #{obj})" do
|
56
|
+
DsLisp.new.evaluate([:symbolp, [:quote, obj]]).should be == symbolp_result
|
57
|
+
end
|
58
|
+
|
59
|
+
listp_result = (Array === obj) ? true : nil
|
60
|
+
it "should return #{result} for (listp #{obj})" do
|
61
|
+
DsLisp.new.evaluate([:listp, [:quote, obj]]).should be == listp_result
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
[[1], [1,2], [1,2,3], [1,2,3,4]].each do |obj|
|
66
|
+
result = obj.size
|
67
|
+
it "should return #{result} for (length #{obj})" do
|
68
|
+
DsLisp.new.evaluate([:length, [:quote, obj]]).should be == result
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should return nil on nil function" do
|
73
|
+
DsLisp.new.evaluate([:nil]).should be == nil
|
74
|
+
end
|
75
|
+
|
76
|
+
# arithmetic
|
77
|
+
it "should call +" do
|
78
|
+
DsLisp.new.evaluate([:+,1,2]).should be == 3
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should call -" do
|
82
|
+
DsLisp.new.evaluate([:-,7,4]).should be == 3
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should call *" do
|
86
|
+
DsLisp.new.evaluate([:*,5,6]).should be == 30
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should call /" do
|
90
|
+
DsLisp.new.evaluate([:/,10,2]).should be == 5
|
91
|
+
end
|
92
|
+
|
93
|
+
# relational
|
94
|
+
[[3,2],[3,3],[3,4]].each do |pair|
|
95
|
+
result = pair.first < pair.last || nil
|
96
|
+
it "should call <" do
|
97
|
+
DsLisp.new.evaluate([:<,pair.first,pair.last]).should be == result
|
98
|
+
end
|
99
|
+
|
100
|
+
resultht = pair.first > pair.last || nil
|
101
|
+
it "should call >" do
|
102
|
+
DsLisp.new.evaluate([:>,pair.first,pair.last]).should be == resultht
|
103
|
+
end
|
104
|
+
|
105
|
+
resulteq = pair.first == pair.last || nil
|
106
|
+
it "should call eq" do
|
107
|
+
DsLisp.new.evaluate([:eq,pair.first,pair.last]).should be == resulteq
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# boolean
|
112
|
+
[[true,true],[true,nil],[nil,true],[nil,nil]].each do |pair|
|
113
|
+
resultor = (pair.first or pair.last) || nil
|
114
|
+
resultand = (pair.first and pair.last) || nil
|
115
|
+
resultnot = (not pair.first) || nil
|
116
|
+
|
117
|
+
it "should call or with #{pair} and return #{resultor}" do
|
118
|
+
DsLisp.new.evaluate([:or,pair.first,pair.last]).should be == resultor
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should call and with #{pair} and return #{resultand}" do
|
122
|
+
DsLisp.new.evaluate([:and,pair.first,pair.last]).should be == resultand
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should call not" do
|
126
|
+
DsLisp.new.evaluate([:not,pair.first]).should be == resultnot
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
|
data/spec/functions.rb~
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require "dslisprb"
|
2
|
+
|
3
|
+
describe DsLisp::CommonLispFunctions, "ds lisp functions" do
|
4
|
+
|
5
|
+
# selectors
|
6
|
+
it "should return 1 for (car (quote (1 2)))" do
|
7
|
+
DsLisp.new.evaluate([:car, [:quote, [1, 2]]]).should be == 1
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should return (2 3) for (cdr (quote (1 2 3)))" do
|
11
|
+
DsLisp.new.evaluate([:cdr, [:quote, [1, 2, 3]]]).should be == [2, 3]
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return 5 for (nth 2 (quote (4 5 6)))" do
|
15
|
+
DsLisp.new.evaluate([:nth, 2, [:quote, [4, 5, 6]]]).should be == 5
|
16
|
+
end
|
17
|
+
|
18
|
+
# constructors
|
19
|
+
it "should return (1 2 3 4) for (cons 1 (quote (2 3 4)))" do
|
20
|
+
DsLisp.new.evaluate([:cons, 1, [:quote, [2, 3, 4]]]).should be == [1,2,3,4]
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return (1 2 3 4 5) for (append (quote (1 2)) (quote (3 4 5)))" do
|
24
|
+
DsLisp.new.evaluate([:append, [:quote, [1,2]], [:quote, [3, 4, 5]]]).should be == [1,2,3,4,5]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return (1 2) for (list 1 2)" do
|
28
|
+
DsLisp.new.evaluate([:list, 1, 2]).should be == [1,2]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return (1 2 3) for (list 1 2 3)" do
|
32
|
+
DsLisp.new.evaluate([:list, 1, 2, 3]).should be == [1,2,3]
|
33
|
+
end
|
34
|
+
|
35
|
+
# type recognizers
|
36
|
+
[:a, 1, [1,2,3,4], [], nil].each do |obj|
|
37
|
+
result = (obj == nil or obj == []) ? true : nil
|
38
|
+
it "should return #{result} for (null #{obj})" do
|
39
|
+
DsLisp.new.evaluate([:null, [:quote, obj]]).should be == result
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
[:a, 1, [1,2,3,4]].each do |obj|
|
44
|
+
result = (not Array === obj) ? true : nil
|
45
|
+
it "should return #{result} for (atom #{obj})" do
|
46
|
+
DsLisp.new.evaluate([:atom, [:quote, obj]]).should be == result
|
47
|
+
end
|
48
|
+
|
49
|
+
numberp_result = (Numeric === obj) ? true : nil
|
50
|
+
it "should return #{result} for (numberp #{obj})" do
|
51
|
+
DsLisp.new.evaluate([:numberp, [:quote, obj]]).should be == numberp_result
|
52
|
+
end
|
53
|
+
|
54
|
+
symbolp_result = (Symbol === obj) ? true : nil
|
55
|
+
it "should return #{result} for (symbolp #{obj})" do
|
56
|
+
DsLisp.new.evaluate([:symbolp, [:quote, obj]]).should be == symbolp_result
|
57
|
+
end
|
58
|
+
|
59
|
+
listp_result = (Array === obj) ? true : nil
|
60
|
+
it "should return #{result} for (listp #{obj})" do
|
61
|
+
DsLisp.new.evaluate([:listp, [:quote, obj]]).should be == listp_result
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
[[1], [1,2], [1,2,3], [1,2,3,4]].each do |obj|
|
66
|
+
result = obj.size
|
67
|
+
it "should return #{result} for (length #{obj})" do
|
68
|
+
DsLisp.new.evaluate([:length, [:quote, obj]]).should be == result
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should return nil on nil function" do
|
73
|
+
DsLisp.new.evaluate([:nil]).should be == nil
|
74
|
+
end
|
75
|
+
|
76
|
+
# arithmetic
|
77
|
+
it "should call +" do
|
78
|
+
DsLisp.new.evaluate([:+,1,2]).should be == 3
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should call -" do
|
82
|
+
DsLisp.new.evaluate([:-,7,4]).should be == 3
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should call *" do
|
86
|
+
DsLisp.new.evaluate([:*,5,6]).should be == 30
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should call /" do
|
90
|
+
DsLisp.new.evaluate([:/,10,2]).should be == 5
|
91
|
+
end
|
92
|
+
|
93
|
+
# relational
|
94
|
+
[[3,2],[3,3],[3,4]].each do |pair|
|
95
|
+
result = pair.first < pair.last || nil
|
96
|
+
it "should call <" do
|
97
|
+
DsLisp.new.evaluate([:<,pair.first,pair.last]).should be == result
|
98
|
+
end
|
99
|
+
|
100
|
+
resultht = pair.first > pair.last || nil
|
101
|
+
it "should call >" do
|
102
|
+
DsLisp.new.evaluate([:>,pair.first,pair.last]).should be == resultht
|
103
|
+
end
|
104
|
+
|
105
|
+
resulteq = pair.first == pair.last || nil
|
106
|
+
it "should call eq" do
|
107
|
+
DsLisp.new.evaluate([:eq,pair.first,pair.last]).should be == resulteq
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# boolean
|
112
|
+
[[true,true],[true,nil],[nil,true],[nil,nil]].each do |pair|
|
113
|
+
resultor = (pair.first or pair.last) || nil
|
114
|
+
resultand = (pair.first and pair.last) || nil
|
115
|
+
resultnot = (not pair.first) || nil
|
116
|
+
|
117
|
+
it "should call or with #{pair} and return #{resultor}" do
|
118
|
+
DsLisp.new.evaluate([:or,pair.first,pair.last]).should be == resultor
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should call and with #{pair} and return #{resultand}" do
|
122
|
+
DsLisp.new.evaluate([:and,pair.first,pair.last]).should be == resultand
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should call not" do
|
126
|
+
DsLisp.new.evaluate([:not,pair.first]).should be == resultnot
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
|
data/spec/macro.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require "dslisprb"
|
2
|
+
|
3
|
+
describe DsLisp, "ds lisp macro" do
|
4
|
+
it "should allow defmacro and use on different call" do
|
5
|
+
dslisp = DsLisp.new
|
6
|
+
dslisp.evaluate([:defmacro, :square, [:x], [:quote, [:*, :x, :x]]])
|
7
|
+
dslisp.evaluate([:square, 5]).should be == 25
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
|
data/spec/macro.rb~
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require "dslisprb"
|
2
|
+
|
3
|
+
describe DsLisp, "ds lisp macro" do
|
4
|
+
it "should allow defmacro and use on different call" do
|
5
|
+
dslisp = DsLisp.new
|
6
|
+
dslisp.evaluate([:defmacro, :square, [:z], [:quote, [:*, :x, :x]]])
|
7
|
+
dslisp.evaluate([:square, 5]).should be == 25
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dslisprb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dario Seminara
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-25 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description:
|
15
|
+
email: robertodarioseminara@gmail.com
|
16
|
+
executables:
|
17
|
+
- dslisprb
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/dslisprb.rb
|
22
|
+
- lib/dslisprb.rb~
|
23
|
+
- spec/macro.rb
|
24
|
+
- spec/ast.rb
|
25
|
+
- spec/defun.rb~
|
26
|
+
- spec/execution.rb~
|
27
|
+
- spec/execution.rb
|
28
|
+
- spec/defun.rb
|
29
|
+
- spec/functions.rb~
|
30
|
+
- spec/macro.rb~
|
31
|
+
- spec/functions.rb
|
32
|
+
- spec/ast.rb~
|
33
|
+
- README.rdoc
|
34
|
+
- Rakefile
|
35
|
+
- TODO
|
36
|
+
- CHANGELOG
|
37
|
+
- bin/dslisprb
|
38
|
+
homepage: http://github.com/tario/dslisprb
|
39
|
+
licenses: []
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
requirements: []
|
57
|
+
rubyforge_project:
|
58
|
+
rubygems_version: 1.8.10
|
59
|
+
signing_key:
|
60
|
+
specification_version: 3
|
61
|
+
summary: Lisp interpreter written in ruby, using code generation
|
62
|
+
test_files: []
|