dslisprb 0.0.2 → 0.0.3

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.
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