dslisprb 0.0.1 → 0.0.2

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