dslisprb 0.0.1 → 0.0.2

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
@@ -0,0 +1,7 @@
1
+ 0.0.2 conditional structure if and cond
2
+
3
+ mapcar and mapcan
4
+
5
+ Defined functions and variable persistance between multiple evaluate calls by using binding
6
+
7
+ 0.0.1 First release
@@ -20,8 +20,6 @@ allowing reuse of the ruby stack instead of reimplement it
20
20
 
21
21
  == TODO:
22
22
 
23
- * MAPCAR
24
- * Defined functions and variable persistent between multiple evaluate calls
25
23
  * caaaar, cdadar, cddra, etc...
26
24
 
27
25
  == SYNOPSIS:
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.1'
10
+ s.version = '0.0.2'
11
11
  s.author = 'Dario Seminara'
12
12
  s.email = 'robertodarioseminara@gmail.com'
13
13
  s.platform = Gem::Platform::RUBY
data/TODO CHANGED
@@ -1,3 +1 @@
1
- * MAPCAR
2
- * Defined functions and variable persistent between multiple evaluate calls
3
1
  * caaaar, cdadar, cddra, etc...
@@ -11,7 +11,7 @@ if ARGV[0]
11
11
  evaluate lisp expression, shows the result on standard output and exit
12
12
 
13
13
  Example:
14
- dslisprb \"(car '(1 2 3))\"
14
+ dslisprb \"(cdr '(1 2 3))\"
15
15
  (2 3)
16
16
 
17
17
  dslisprb without arguments starts the repl
@@ -29,7 +29,13 @@ class DsLisp
29
29
  end
30
30
  end
31
31
  else
32
- code.inspect
32
+ if code == :nil
33
+ nil
34
+ elsif code == :T
35
+ true
36
+ else
37
+ code.inspect
38
+ end
33
39
  end
34
40
  end
35
41
  end
@@ -41,6 +47,23 @@ class DsLisp
41
47
  code[1].inspect
42
48
  end
43
49
 
50
+ def cond(code)
51
+ "(nil.tap {
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
+ end
56
+
57
+ def if(code)
58
+ "(if (#{ToRuby.to_ruby code[1]})
59
+ #{ToRuby.to_ruby code[2]}
60
+ else
61
+ #{ToRuby.to_ruby code[3]}
62
+ end
63
+ )
64
+ "
65
+ end
66
+
44
67
  def lambda(code)
45
68
  arguments = code[1].map(&:to_s).join(",")
46
69
  "lambda{|#{arguments}| #{ToRuby.to_ruby(code[2])}}.lisp_inner_code(#{code.lisp_inspect.inspect})"
@@ -127,46 +150,75 @@ class DsLisp
127
150
  if String === code
128
151
  return evaluate(parse code)
129
152
  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
153
 
167
154
  # generate ruby code for lisp ast
168
155
  ruby_code = ToRuby.to_ruby(code)
169
- eval(ruby_code)
156
+ eval(ruby_code, main_binding)
157
+ end
158
+
159
+ private
160
+
161
+ def main_binding
162
+ unless @binding
163
+ @binding = binding
164
+
165
+ # arithmethic
166
+ plus = lambda{|x,y| x+y}
167
+ mult = lambda{|x,y| x*y}
168
+ divide = lambda{|x,y| x/y}
169
+ minus = lambda{|x,y| x-y}
170
+
171
+ lt = lambda{|x,y| x<y || nil}
172
+ ht = lambda{|x,y| x>y || nil}
173
+ _eq = lambda{|x,y| x==y || nil}
174
+
175
+
176
+ # list selectors
177
+ _car = lambda{|x| x.first}
178
+ _cdr = lambda{|x| x[1..-1]}
179
+ _nth = lambda{|index,list| list[index-1]}
180
+
181
+ # list constructors
182
+ _cons = lambda{|element, list| [element]+list}
183
+ _append = plus
184
+ _list = lambda{|*args| args}
185
+
186
+ # recognizers
187
+ _null = lambda{|element| (element == nil or element == []) || nil}
188
+ _atom = lambda{|element| (not Array === element) || nil}
189
+ _numberp = lambda{|element| Numeric === element || nil}
190
+ _symbolp = lambda{|element| Symbol === element || nil}
191
+ _listp = lambda{|element| Array === element || nil}
192
+ _length = lambda{|list| list.size}
193
+
194
+ # nil
195
+ _nil = lambda{nil}
196
+
197
+ # 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}
201
+
202
+
203
+ as_function = lambda{|object|
204
+ if Symbol === object
205
+ eval(ToRuby.name_convert(object),@binding)
206
+ elsif not object.respond_to?(:call)
207
+ lambda{|*x| object}
208
+ else
209
+ object
210
+ end
211
+ }
212
+
213
+ _mapcan = lambda{|function, list|
214
+ list.map(&as_function.call(function)).map{|x|
215
+ x || []
216
+ }.inject(&:+)
217
+ }
218
+
219
+ _mapcar = lambda{|function, list| list.map(&as_function.call(function))}
220
+ end
221
+ @binding
170
222
  end
171
223
  end
172
224
 
@@ -29,7 +29,13 @@ class DsLisp
29
29
  end
30
30
  end
31
31
  else
32
- code.inspect
32
+ if code == :nil
33
+ nil
34
+ elsif code == :T
35
+ true
36
+ else
37
+ code.inspect
38
+ end
33
39
  end
34
40
  end
35
41
  end
@@ -41,6 +47,24 @@ class DsLisp
41
47
  code[1].inspect
42
48
  end
43
49
 
50
+ def cond(code)
51
+ "(nil.tap {
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
+ + "})"
56
+ end
57
+
58
+ def if(code)
59
+ "(if (#{ToRuby.to_ruby code[1]})
60
+ #{ToRuby.to_ruby code[2]}
61
+ else
62
+ #{ToRuby.to_ruby code[3]}
63
+ end
64
+ )
65
+ "
66
+ end
67
+
44
68
  def lambda(code)
45
69
  arguments = code[1].map(&:to_s).join(",")
46
70
  "lambda{|#{arguments}| #{ToRuby.to_ruby(code[2])}}.lisp_inner_code(#{code.lisp_inspect.inspect})"
@@ -90,7 +114,7 @@ class DsLisp
90
114
 
91
115
  def parse(str)
92
116
  if str.count("(") != str.count(")")
93
- raise "Parentheshis count does not match, try adding parenthesis to the end :P"
117
+ raise "Parentheshis count does not match, try adding parenthesis at the end of string :P"
94
118
  end
95
119
 
96
120
  if matchdata = /^\s*\'(.*)\s*$/.match(str)
@@ -127,46 +151,75 @@ class DsLisp
127
151
  if String === code
128
152
  return evaluate(parse code)
129
153
  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
154
 
167
155
  # generate ruby code for lisp ast
168
156
  ruby_code = ToRuby.to_ruby(code)
169
- eval(ruby_code)
157
+ eval(ruby_code, main_binding)
158
+ end
159
+
160
+ private
161
+
162
+ def main_binding
163
+ unless @binding
164
+ @binding = binding
165
+
166
+ # arithmethic
167
+ plus = lambda{|x,y| x+y}
168
+ mult = lambda{|x,y| x*y}
169
+ divide = lambda{|x,y| x/y}
170
+ minus = lambda{|x,y| x-y}
171
+
172
+ lt = lambda{|x,y| x<y || nil}
173
+ ht = lambda{|x,y| x>y || nil}
174
+ _eq = lambda{|x,y| x==y || nil}
175
+
176
+
177
+ # list selectors
178
+ _car = lambda{|x| x.first}
179
+ _cdr = lambda{|x| x[1..-1]}
180
+ _nth = lambda{|index,list| list[index-1]}
181
+
182
+ # list constructors
183
+ _cons = lambda{|element, list| [element]+list}
184
+ _append = plus
185
+ _list = lambda{|*args| args}
186
+
187
+ # recognizers
188
+ _null = lambda{|element| (element == nil or element == []) || nil}
189
+ _atom = lambda{|element| (not Array === element) || nil}
190
+ _numberp = lambda{|element| Numeric === element || nil}
191
+ _symbolp = lambda{|element| Symbol === element || nil}
192
+ _listp = lambda{|element| Array === element || nil}
193
+ _length = lambda{|list| list.size}
194
+
195
+ # nil
196
+ _nil = lambda{nil}
197
+
198
+ # 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}
202
+
203
+
204
+ as_function = lambda{|object|
205
+ if Symbol === object
206
+ eval(ToRuby.name_convert(object),@binding)
207
+ elsif not object.respond_to?(:call)
208
+ lambda{|*x| object}
209
+ else
210
+ object
211
+ end
212
+ }
213
+
214
+ _mapcan = lambda{|function, list|
215
+ list.map(&as_function.call(function)).map{|x|
216
+ x || []
217
+ }.inject(&:+)
218
+ }
219
+
220
+ _mapcar = lambda{|function, list| list.map(&as_function.call(function))}
221
+ end
222
+ @binding
170
223
  end
171
224
  end
172
225
 
@@ -20,6 +20,12 @@ describe DsLisp, "ds lisp execution" do
20
20
 
21
21
  it "should evaluate quote call to define literals" do
22
22
  DsLisp.new.evaluate([:quote, [1, 2, 3]]).should be == [1, 2, 3]
23
+ end
24
+
25
+ it "should preserve variables through multiple function calls" do
26
+ dslisp = DsLisp.new
27
+ dslisp.evaluate("(defun foo (x) (+ x 1))")
28
+ dslisp.evaluate("(foo 3)").should be == 4
23
29
  end
24
30
  end
25
31
 
@@ -19,7 +19,11 @@ describe DsLisp, "ds lisp execution" do
19
19
  end
20
20
 
21
21
  it "should evaluate quote call to define literals" do
22
- DsLisp.new.evaluate([:quote, [1, 2, 3]).should be == [1, 2, 3]
22
+ DsLisp.new.evaluate([:quote, [1, 2, 3]]).should be == [1, 2, 3]
23
+ end
24
+
25
+ it "should preserve variables through multiple function calls" do
26
+ DsLisp.new.evaluate([:quote, [1, 2, 3]]).should be == [1, 2, 3]
23
27
  end
24
28
  end
25
29
 
@@ -0,0 +1,24 @@
1
+ require "dslisprb"
2
+
3
+ describe DsLisp, "ds lisp flow control" do
4
+ it "should execute second statement of if when first statement return true" do
5
+ DsLisp.new.evaluate([:if, :T, [:+, 110, 1], [:+, 220, 2]]).should be == 111
6
+ end
7
+
8
+ it "should execute third statement of if when first statement return false" do
9
+ DsLisp.new.evaluate([:if, :nil, [:+, 110, 1], [:+, 220, 2]]).should be == 222
10
+ end
11
+
12
+ it "should return nil when first statement return false and there is no second statement" do
13
+ DsLisp.new.evaluate([:if, :nil, [:+, 110, 1]]).should be == nil
14
+ end
15
+
16
+ it "should execute cond statement" do
17
+ DsLisp.new.evaluate([:cond, [:T, [:+, 120, 3]]]).should be == 123
18
+ end
19
+
20
+ it "should execute second statement of cond if the first fail" do
21
+ DsLisp.new.evaluate([:cond, [:nil, [:+, 120, 3]], [:T, [:+, 120, 5]]]).should be == 125
22
+ end
23
+ end
24
+
@@ -0,0 +1,33 @@
1
+ require "dslisprb"
2
+
3
+ describe DsLisp, "ds lisp flow control" do
4
+ it "should execute second statement of if when first statement return true" do
5
+ DsLisp.new.evaluate([:if, :T, [:+, 110, 1], [:+, 220, 2]]).should be == 111
6
+ end
7
+
8
+ it "should execute third statement of if when first statement return false" do
9
+ DsLisp.new.evaluate([:if, :nil, [:+, 110, 1], [:+, 220, 2]]).should be == 222
10
+ end
11
+
12
+ it "should return nil when first statement return false and there is no second statement" do
13
+ DsLisp.new.evaluate([:if, :nil, [:+, 110, 1]]).should be == nil
14
+ end
15
+
16
+ it "should execute cond statement" do
17
+ DsLisp.new.evaluate([:cond, [:T, [:+, 120, 3]]]).should be == 123
18
+ end
19
+
20
+ it "should execute second statement of cond if the first fail" do
21
+ DsLisp.new.evaluate([:cond, [:nil, [:+, 120, 3]], [:T, [:+, 120, 5]]]).should be == 125
22
+ end
23
+
24
+ it "should execute third statement of if when first statement return false" do
25
+ DsLisp.new.evaluate([:if, :nil, [:+, 110, 1], [:+, 220, 2]]).should be == 222
26
+ end
27
+
28
+ it "should return nil when first statement return false and there is no second statement" do
29
+ DsLisp.new.evaluate([:if, :nil, [:+, 110, 1]]).should be == nil
30
+ end
31
+
32
+ end
33
+
@@ -127,6 +127,19 @@ describe DsLisp, "ds lisp functions" do
127
127
  end
128
128
  end
129
129
 
130
+ it "should execute mapcan" do
131
+ DsLisp.new.evaluate("(mapcan (lambda (x) (and (numberp x) (list x))) '(a 1 b c 3 4 d 5))").should be == [1, 3, 4, 5]
132
+ end
133
+
134
+ it "should execute mapcar" do
135
+ DsLisp.new.evaluate("(mapcar (lambda (x) (+ x 1)) '(1 2 3 4))").should be == [2, 3, 4, 5]
136
+ end
137
+
138
+ it "should execute mapcar with defined function" do
139
+ dslisp = DsLisp.new
140
+ dslisp.evaluate("(defun foo (x) (+ x 1))")
141
+ dslisp.evaluate("(mapcar foo '(1 2 3 4))").should be == [2, 3, 4, 5]
142
+ end
130
143
  end
131
144
 
132
145
 
@@ -1,6 +1,6 @@
1
1
  require "dslisprb"
2
2
 
3
- describe DsLisp::CommonLispFunctions, "ds lisp functions" do
3
+ describe DsLisp, "ds lisp functions" do
4
4
 
5
5
  # selectors
6
6
  it "should return 1 for (car (quote (1 2)))" do
@@ -127,6 +127,13 @@ describe DsLisp::CommonLispFunctions, "ds lisp functions" do
127
127
  end
128
128
  end
129
129
 
130
+ it "should execute mapcan" do
131
+ DsLisp.new.evaluate("(mapcan (lambda (x) (and (numberp x) (list x))) '(a 1 b c 3 4 d 5))").should be == [1, 3, 4, 5]
132
+ end
133
+
134
+ it "should execute mapcar" do
135
+ DsLisp.new.evaluate("(mapcar (lambda (x) (+ x 1)) '(1 2 3 4))").should be == [2, 3, 4, 5]
136
+ end
130
137
  end
131
138
 
132
139
 
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.1
4
+ version: 0.0.2
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-25 00:00:00.000000000Z
12
+ date: 2012-05-27 00:00:00.000000000Z
13
13
  dependencies: []
14
14
  description:
15
15
  email: robertodarioseminara@gmail.com
@@ -20,7 +20,9 @@ extra_rdoc_files: []
20
20
  files:
21
21
  - lib/dslisprb.rb
22
22
  - lib/dslisprb.rb~
23
+ - spec/flowcontrol.rb~
23
24
  - spec/macro.rb
25
+ - spec/flowcontrol.rb
24
26
  - spec/ast.rb
25
27
  - spec/defun.rb~
26
28
  - spec/execution.rb~