dslisprb 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ 0.0.3 fixed interpretation of special nil and T symbols
2
+
3
+ implemented autocompletion of lisp variable names on dslisp console
4
+
5
+ fixed variable assignment stack to match lisp behavior (see spec/stack.rb)
6
+
7
+ fixed variable eval (before (if T x y) was evaluated as x symbol instead of the value associated to x)
8
+
9
+ fixed bug on boolean evaluation of empty list
10
+
1
11
  0.0.2 conditional structure if and cond
2
12
 
3
13
  mapcar and mapcan
data/Rakefile CHANGED
@@ -7,7 +7,7 @@ require "rspec/core/rake_task"
7
7
 
8
8
  spec = Gem::Specification.new do |s|
9
9
  s.name = 'dslisprb'
10
- s.version = '0.0.2'
10
+ s.version = '0.0.3'
11
11
  s.author = 'Dario Seminara'
12
12
  s.email = 'robertodarioseminara@gmail.com'
13
13
  s.platform = Gem::Platform::RUBY
data/bin/dslisprb CHANGED
@@ -29,6 +29,11 @@ else
29
29
  stty_save = `stty -g`.chomp
30
30
  trap('INT') { system('stty', stty_save); exit }
31
31
 
32
+ Readline.completion_append_character = " "
33
+ Readline.completion_proc = proc do |s|
34
+ dslisp.variables.grep( /^#{Regexp.escape(s)}/ )
35
+ end
36
+
32
37
  while cmd = Readline.readline('> ', true)
33
38
  if cmd == "quit"
34
39
  exit
data/lib/dslisprb.rb CHANGED
@@ -1,6 +1,11 @@
1
1
  class DsLisp
2
2
  class ToRuby
3
3
  class << self
4
+
5
+ def convert_name(name)
6
+ {:lt => "<", :ht => :>, :plus => :+, :mult => "*", :divide => "/", :minus => "-" }[name] || name[1..-1]
7
+ end
8
+
4
9
  def name_convert(name)
5
10
  {:< => "lt", :> => "ht", :+ => "plus", :* => "mult" , :/ => "divide", :- => "minus" }[name] || "_" + name.to_s
6
11
  end
@@ -15,24 +20,19 @@ class DsLisp
15
20
  CommonLispOperators.send(function_name, code)
16
21
  else
17
22
  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
+ "(#{to_ruby(x)})"
23
24
  }.join(",")
24
25
 
25
- if Symbol === function_name
26
- "#{name_convert(function_name)}.call(#{strargs})"
27
- else
28
- "#{to_ruby(code.first)}.call(#{strargs})"
29
- end
26
+ "#{to_ruby(code.first)}.call(#{strargs})"
30
27
  end
31
28
  else
32
29
  if code == :nil
33
- nil
30
+ "nil"
34
31
  elsif code == :T
35
- true
32
+ "true"
33
+ elsif Symbol === code
34
+ # "(local_variables.include?(#{name_convert(code)}) ? #{name_convert(code)} : nil)"
35
+ name_convert(code).to_s
36
36
  else
37
37
  code.inspect
38
38
  end
@@ -50,12 +50,12 @@ class DsLisp
50
50
  def cond(code)
51
51
  "(nil.tap {
52
52
  " + code[1..-1].map{ |condition_code|
53
- "(break (#{ToRuby.to_ruby condition_code[1]}) if (#{ToRuby.to_ruby condition_code[0]}))"
53
+ "(break (#{ToRuby.to_ruby condition_code[1]}) if (aux = (#{ToRuby.to_ruby condition_code[0]}); aux != [] and aux != nil) )"
54
54
  }.join(";") + "})"
55
55
  end
56
56
 
57
57
  def if(code)
58
- "(if (#{ToRuby.to_ruby code[1]})
58
+ "(if (aux = (#{ToRuby.to_ruby code[1]}); aux != [] and aux != nil)
59
59
  #{ToRuby.to_ruby code[2]}
60
60
  else
61
61
  #{ToRuby.to_ruby code[3]}
@@ -65,8 +65,17 @@ class DsLisp
65
65
  end
66
66
 
67
67
  def lambda(code)
68
- arguments = code[1].map(&:to_s).join(",")
69
- "lambda{|#{arguments}| #{ToRuby.to_ruby(code[2])}}.lisp_inner_code(#{code.lisp_inspect.inspect})"
68
+ arguments = code[1].map(&ToRuby.method(:name_convert)).map(&:to_s)
69
+ "(#{arguments.join(",")} = #{code[1].map{"nil"}.join(",")} ;lambda{|*x|
70
+ oldargs = [ #{arguments.join(",")} ] # save current bindings
71
+ #{(0..arguments.size-1).map{|i| "#{arguments[i]} = x[#{i}]" }.join(";")}
72
+ begin
73
+ aux = #{ToRuby.to_ruby(code[2])}
74
+ ensure
75
+ #{arguments.join(",")} = oldargs # restore bindings
76
+ end
77
+ aux
78
+ }.lisp_inner_code(#{code.lisp_inspect.inspect}))"
70
79
  end
71
80
 
72
81
  def block(code)
@@ -156,8 +165,19 @@ class DsLisp
156
165
  eval(ruby_code, main_binding)
157
166
  end
158
167
 
168
+ def variables
169
+ eval("local_variables", main_binding).map(&ToRuby.method(:convert_name))
170
+ end
171
+
159
172
  private
160
-
173
+ def null(element)
174
+ element == nil or element == []
175
+ end
176
+
177
+ def not_null(element)
178
+ element != nil and element != []
179
+ end
180
+
161
181
  def main_binding
162
182
  unless @binding
163
183
  @binding = binding
@@ -184,7 +204,7 @@ private
184
204
  _list = lambda{|*args| args}
185
205
 
186
206
  # recognizers
187
- _null = lambda{|element| (element == nil or element == []) || nil}
207
+ _null = lambda{|element| null(element) ? true : nil}
188
208
  _atom = lambda{|element| (not Array === element) || nil}
189
209
  _numberp = lambda{|element| Numeric === element || nil}
190
210
  _symbolp = lambda{|element| Symbol === element || nil}
@@ -195,9 +215,15 @@ private
195
215
  _nil = lambda{nil}
196
216
 
197
217
  # boolean
198
- _not = lambda{|a| (not a) || nil}
199
- _and = lambda{|a,b| (a and b) || nil}
200
- _or = lambda{|a,b| (a or b) || nil}
218
+ _not = lambda{|a| null(a) ? true : nil}
219
+ _and = lambda{|a,b| (not_null(a) and not_null(b)) ? b : nil}
220
+ _or = lambda{|a,b|
221
+ if not_null(a)
222
+ a
223
+ else
224
+ b
225
+ end
226
+ }
201
227
 
202
228
 
203
229
  as_function = lambda{|object|
@@ -234,6 +260,12 @@ class Symbol
234
260
  end
235
261
  end
236
262
 
263
+ class TrueClass
264
+ def lisp_inspect
265
+ "T"
266
+ end
267
+ end
268
+
237
269
  class Array
238
270
  def lisp_inspect
239
271
  "(" + map(&:lisp_inspect).join(" ") + ")"
data/lib/dslisprb.rb~ CHANGED
@@ -1,6 +1,11 @@
1
1
  class DsLisp
2
2
  class ToRuby
3
3
  class << self
4
+
5
+ def convert_name(name)
6
+ {:lt => "<", :ht => :>, :plus => :+, :mult => "*", :divide => "/", :minus => "-" }[name] || name[1..-1]
7
+ end
8
+
4
9
  def name_convert(name)
5
10
  {:< => "lt", :> => "ht", :+ => "plus", :* => "mult" , :/ => "divide", :- => "minus" }[name] || "_" + name.to_s
6
11
  end
@@ -15,24 +20,19 @@ class DsLisp
15
20
  CommonLispOperators.send(function_name, code)
16
21
  else
17
22
  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
+ "(#{to_ruby(x)})"
23
24
  }.join(",")
24
25
 
25
- if Symbol === function_name
26
- "#{name_convert(function_name)}.call(#{strargs})"
27
- else
28
- "#{to_ruby(code.first)}.call(#{strargs})"
29
- end
26
+ "#{to_ruby(code.first)}.call(#{strargs})"
30
27
  end
31
28
  else
32
29
  if code == :nil
33
- nil
30
+ "nil"
34
31
  elsif code == :T
35
- true
32
+ "true"
33
+ elsif Symbol === code
34
+ # "(local_variables.include?(#{name_convert(code)}) ? #{name_convert(code)} : nil)"
35
+ name_convert(code).to_s
36
36
  else
37
37
  code.inspect
38
38
  end
@@ -50,13 +50,12 @@ class DsLisp
50
50
  def cond(code)
51
51
  "(nil.tap {
52
52
  " + code[1..-1].map{ |condition_code|
53
- "(break (#{ToRuby.to_ruby condition_code[1]}) if (#{ToRuby.to_ruby condition_code[0]}))"
54
- }.join(";")
55
- + "})"
53
+ "(break (#{ToRuby.to_ruby condition_code[1]}) if (aux = (#{ToRuby.to_ruby condition_code[0]}); aux != [] and aux != nil) )"
54
+ }.join(";") + "})"
56
55
  end
57
56
 
58
57
  def if(code)
59
- "(if (#{ToRuby.to_ruby code[1]})
58
+ "(if (aux = (#{ToRuby.to_ruby code[1]}); aux != [] and aux != nil)
60
59
  #{ToRuby.to_ruby code[2]}
61
60
  else
62
61
  #{ToRuby.to_ruby code[3]}
@@ -66,8 +65,17 @@ class DsLisp
66
65
  end
67
66
 
68
67
  def lambda(code)
69
- arguments = code[1].map(&:to_s).join(",")
70
- "lambda{|#{arguments}| #{ToRuby.to_ruby(code[2])}}.lisp_inner_code(#{code.lisp_inspect.inspect})"
68
+ arguments = code[1].map(&ToRuby.method(:name_convert)).map(&:to_s)
69
+ "(#{arguments.join(",")} = #{code[1].map{"nil"}.join(",")} ;lambda{|*x|
70
+ oldargs = [ #{arguments.join(",")} ] # save current bindings
71
+ #{(0..arguments.size-1).map{|i| "#{arguments[i]} = x[#{i}]" }.join(";")}
72
+ begin
73
+ aux = #{ToRuby.to_ruby(code[2])}
74
+ ensure
75
+ #{arguments.join(",")} = oldargs # restore bindings
76
+ end
77
+ aux
78
+ }.lisp_inner_code(#{code.lisp_inspect.inspect}))"
71
79
  end
72
80
 
73
81
  def block(code)
@@ -157,8 +165,19 @@ class DsLisp
157
165
  eval(ruby_code, main_binding)
158
166
  end
159
167
 
168
+ def variables
169
+ eval("local_variables", main_binding).map(&ToRuby.method(:convert_name))
170
+ end
171
+
160
172
  private
161
-
173
+ def null(element)
174
+ element == nil or element == []
175
+ end
176
+
177
+ def not_null(element)
178
+ element != nil and element != []
179
+ end
180
+
162
181
  def main_binding
163
182
  unless @binding
164
183
  @binding = binding
@@ -185,7 +204,7 @@ private
185
204
  _list = lambda{|*args| args}
186
205
 
187
206
  # recognizers
188
- _null = lambda{|element| (element == nil or element == []) || nil}
207
+ _null = lambda{|element| null(element) ? true : nil}
189
208
  _atom = lambda{|element| (not Array === element) || nil}
190
209
  _numberp = lambda{|element| Numeric === element || nil}
191
210
  _symbolp = lambda{|element| Symbol === element || nil}
@@ -196,9 +215,15 @@ private
196
215
  _nil = lambda{nil}
197
216
 
198
217
  # boolean
199
- _not = lambda{|a| (not a) || nil}
200
- _and = lambda{|a,b| (a and b) || nil}
201
- _or = lambda{|a,b| (a or b) || nil}
218
+ _not = lambda{|a| null(a) ? true : nil}
219
+ _and = lambda{|a,b| (not_null(a) and not_null(b)) ? b : nil}
220
+ _or = lambda{|a,b|
221
+ if not_null(a)
222
+ a
223
+ else
224
+ b
225
+ end
226
+ }
202
227
 
203
228
 
204
229
  as_function = lambda{|object|
data/spec/ast.rb CHANGED
@@ -50,6 +50,14 @@ describe DsLisp, "ds lisp" do
50
50
 
51
51
  it "should parse quote with lists" do
52
52
  DsLisp.new.parse("'(1 2 3)").should be == [:quote, [1,2,3]]
53
- end
53
+ end
54
+
55
+ it "should parse nil" do
56
+ DsLisp.new.parse("nil").should be == :nil
57
+ end
58
+
59
+ it "should parse quoted empty list" do
60
+ DsLisp.new.parse("'()").should be == [:quote, []]
61
+ end
54
62
  end
55
63
 
data/spec/ast.rb~ CHANGED
@@ -49,7 +49,15 @@ describe DsLisp, "ds lisp" do
49
49
  end
50
50
 
51
51
  it "should parse quote with lists" do
52
- DsLisp.new.parse("'(1,2,3)").should be == [:quote, [1,2,3]]
53
- end
52
+ DsLisp.new.parse("'(1 2 3)").should be == [:quote, [1,2,3]]
53
+ end
54
+
55
+ it "should parse nil" do
56
+ DsLisp.new.parse("nil").should be == :nil
57
+ end
58
+
59
+ it "should parse quoted empty list" do
60
+ DsLisp.new.parse("'[]").should be == [:quote, []]
61
+ end
54
62
  end
55
63
 
data/spec/execution.rb CHANGED
@@ -8,9 +8,9 @@ describe DsLisp, "ds lisp execution" do
8
8
  end
9
9
  end
10
10
 
11
- [:x,:y,:z].each do |symbol|
11
+ [:x,:y,:z].map{|x| [:quote,x]}.each do |symbol|
12
12
  it "should parse simple symbolic atom #{symbol}" do
13
- DsLisp.new.evaluate(symbol).should be == symbol
13
+ DsLisp.new.evaluate(symbol).should be == symbol.last
14
14
  end
15
15
  end
16
16
 
@@ -26,6 +26,18 @@ describe DsLisp, "ds lisp execution" do
26
26
  dslisp = DsLisp.new
27
27
  dslisp.evaluate("(defun foo (x) (+ x 1))")
28
28
  dslisp.evaluate("(foo 3)").should be == 4
29
+ end
30
+
31
+ it "should return false for empty list" do
32
+ DsLisp.new.evaluate("(and '() 2)").should be == nil
29
33
  end
34
+
35
+ it "should evaluate empty list as false on if" do
36
+ DsLisp.new.evaluate("(if '() (+ 1 1) (+ 2 2))").should be == 4
37
+ end
38
+
39
+ it "should evaluate empty list as false on cond" do
40
+ DsLisp.new.evaluate("(cond ('() (+ 2 3)) ((> 2 1) (+ 1 2)))").should be == 3
41
+ end
30
42
  end
31
43
 
data/spec/execution.rb~ CHANGED
@@ -8,7 +8,7 @@ describe DsLisp, "ds lisp execution" do
8
8
  end
9
9
  end
10
10
 
11
- [:x,:y,:z].each do |symbol|
11
+ [:x,:y,:z].map{|x| [:quote,x]}.each do |symbol|
12
12
  it "should parse simple symbolic atom #{symbol}" do
13
13
  DsLisp.new.evaluate(symbol).should be == symbol
14
14
  end
@@ -23,7 +23,21 @@ describe DsLisp, "ds lisp execution" do
23
23
  end
24
24
 
25
25
  it "should preserve variables through multiple function calls" do
26
- DsLisp.new.evaluate([:quote, [1, 2, 3]]).should be == [1, 2, 3]
26
+ dslisp = DsLisp.new
27
+ dslisp.evaluate("(defun foo (x) (+ x 1))")
28
+ dslisp.evaluate("(foo 3)").should be == 4
29
+ end
30
+
31
+ it "should return false for empty list" do
32
+ DsLisp.new.evaluate("(and '() 2)").should be == nil
27
33
  end
34
+
35
+ it "should evaluate empty list as false on if" do
36
+ DsLisp.new.evaluate("(if '() (+ 1 1) (+ 2 2))").should be == 4
37
+ end
38
+
39
+ it "should evaluate empty list as false on cond" do
40
+ DsLisp.new.evaluate("(cond ('() (+ 2 3)) ((> 2 1) (+ 1 2)))").should be == 3
41
+ end
28
42
  end
29
43
 
data/spec/functions.rb CHANGED
@@ -69,10 +69,6 @@ describe DsLisp, "ds lisp functions" do
69
69
  end
70
70
  end
71
71
 
72
- it "should return nil on nil function" do
73
- DsLisp.new.evaluate([:nil]).should be == nil
74
- end
75
-
76
72
  # arithmetic
77
73
  it "should call +" do
78
74
  DsLisp.new.evaluate([:+,1,2]).should be == 3
@@ -140,6 +136,14 @@ describe DsLisp, "ds lisp functions" do
140
136
  dslisp.evaluate("(defun foo (x) (+ x 1))")
141
137
  dslisp.evaluate("(mapcar foo '(1 2 3 4))").should be == [2, 3, 4, 5]
142
138
  end
139
+
140
+ it "should interpret nil symbol as nil" do
141
+ DsLisp.new.evaluate(:nil).should be == nil
142
+ end
143
+
144
+ it "should interpret T symbol as true" do
145
+ DsLisp.new.evaluate(:T).should be == true
146
+ end
143
147
  end
144
148
 
145
149
 
data/spec/functions.rb~ CHANGED
@@ -69,10 +69,6 @@ describe DsLisp, "ds lisp functions" do
69
69
  end
70
70
  end
71
71
 
72
- it "should return nil on nil function" do
73
- DsLisp.new.evaluate([:nil]).should be == nil
74
- end
75
-
76
72
  # arithmetic
77
73
  it "should call +" do
78
74
  DsLisp.new.evaluate([:+,1,2]).should be == 3
@@ -134,6 +130,20 @@ describe DsLisp, "ds lisp functions" do
134
130
  it "should execute mapcar" do
135
131
  DsLisp.new.evaluate("(mapcar (lambda (x) (+ x 1)) '(1 2 3 4))").should be == [2, 3, 4, 5]
136
132
  end
133
+
134
+ it "should execute mapcar with defined function" do
135
+ dslisp = DsLisp.new
136
+ dslisp.evaluate("(defun foo (x) (+ x 1))")
137
+ dslisp.evaluate("(mapcar foo '(1 2 3 4))").should be == [2, 3, 4, 5]
138
+ end
139
+
140
+ it "should interpret nil symbol as nil" do
141
+ DsLisp.new.evaluate(:nil).should be == nil
142
+ end
143
+
144
+ it "should interpret T symbol as true" do
145
+ DsLisp.new.evaluate(:T).should be == nil
146
+ end
137
147
  end
138
148
 
139
149
 
data/spec/stack.rb ADDED
@@ -0,0 +1,14 @@
1
+ require "dslisprb"
2
+
3
+ describe DsLisp, "ds lisp stack" do
4
+ it "should change variable value on lambda call" do
5
+
6
+ dslisp = DsLisp.new
7
+
8
+ dslisp.evaluate("(set x 100)")
9
+ dslisp.evaluate("(set foo1 (lambda (z) (+ x z)))")
10
+ dslisp.evaluate("(set foo2 (lambda (x) (foo1 4)))")
11
+ dslisp.evaluate("(foo2 3)").should be == 7
12
+ end
13
+ end
14
+
data/spec/stack.rb~ ADDED
@@ -0,0 +1,14 @@
1
+ require "dslisprb"
2
+
3
+ describe DsLisp, "ds lisp stack" do
4
+ it "should change variable value on lambda call" do
5
+
6
+ dslisp = DsLisp.new
7
+
8
+ dslisp.evaluate("(set x 100)")
9
+ dslisp.evaluate("(set foo1 (lambda (z) (+ x z)))")
10
+ dslisp.evaluate("(set foo2 (lambda (x) (foo1 4)))")
11
+ dslisp.evluaate("(foo2 3)").should be == 7
12
+ end
13
+ end
14
+
data/spec/variable.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "dslisprb"
2
+
3
+ describe DsLisp, "ds lisp variables" do
4
+ it "should evaluate variables on if" do
5
+ DsLisp.new.evaluate("((lambda (x) (if (> x 2) x 2)) 3)").should be == 3
6
+ end
7
+ end
8
+
data/spec/variable.rb~ ADDED
@@ -0,0 +1,8 @@
1
+ require "dslisprb"
2
+
3
+ describe DsLisp, "ds lisp execution" do
4
+ it "should evaluate variables on if" do
5
+ DsLisp.new.evaluate("((lambda (x) (if (> x 2) x 2)) 3)").should be == 3
6
+ end
7
+ end
8
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dslisprb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-27 00:00:00.000000000Z
12
+ date: 2012-05-30 00:00:00.000000000Z
13
13
  dependencies: []
14
14
  description:
15
15
  email: robertodarioseminara@gmail.com
@@ -26,10 +26,14 @@ files:
26
26
  - spec/ast.rb
27
27
  - spec/defun.rb~
28
28
  - spec/execution.rb~
29
+ - spec/variable.rb~
30
+ - spec/variable.rb
31
+ - spec/stack.rb
29
32
  - spec/execution.rb
30
33
  - spec/defun.rb
31
34
  - spec/functions.rb~
32
35
  - spec/macro.rb~
36
+ - spec/stack.rb~
33
37
  - spec/functions.rb
34
38
  - spec/ast.rb~
35
39
  - README.rdoc