apricot 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +1 -0
  5. data/Gemfile.lock +229 -11
  6. data/README.md +46 -29
  7. data/Rakefile +1 -1
  8. data/apricot.gemspec +7 -3
  9. data/benchmarks/factorial.rb +51 -0
  10. data/benchmarks/interpolate.rb +20 -0
  11. data/bin/apricot +5 -23
  12. data/examples/bot.apr +1 -4
  13. data/examples/cinch-bot.apr +3 -3
  14. data/examples/sinatra.apr +9 -0
  15. data/kernel/core.apr +124 -75
  16. data/kernel/repl.apr +37 -0
  17. data/lib/apricot.rb +7 -26
  18. data/lib/apricot/boot.rb +24 -0
  19. data/lib/apricot/code_loader.rb +108 -0
  20. data/lib/apricot/compiler.rb +265 -32
  21. data/lib/apricot/generator.rb +10 -3
  22. data/lib/apricot/identifier.rb +25 -10
  23. data/lib/apricot/list.rb +28 -41
  24. data/lib/apricot/macroexpand.rb +14 -8
  25. data/lib/apricot/misc.rb +2 -1
  26. data/lib/apricot/namespace.rb +20 -3
  27. data/lib/apricot/{parser.rb → reader.rb} +221 -194
  28. data/lib/apricot/repl.rb +67 -24
  29. data/lib/apricot/ruby_ext.rb +27 -16
  30. data/lib/apricot/scopes.rb +159 -0
  31. data/lib/apricot/seq.rb +43 -1
  32. data/lib/apricot/special_forms.rb +16 -695
  33. data/lib/apricot/special_forms/def.rb +32 -0
  34. data/lib/apricot/special_forms/do.rb +23 -0
  35. data/lib/apricot/special_forms/dot.rb +112 -0
  36. data/lib/apricot/special_forms/fn.rb +342 -0
  37. data/lib/apricot/special_forms/if.rb +31 -0
  38. data/lib/apricot/special_forms/let.rb +8 -0
  39. data/lib/apricot/special_forms/loop.rb +10 -0
  40. data/lib/apricot/special_forms/quote.rb +9 -0
  41. data/lib/apricot/special_forms/recur.rb +26 -0
  42. data/lib/apricot/special_forms/try.rb +146 -0
  43. data/lib/apricot/variables.rb +65 -0
  44. data/lib/apricot/version.rb +1 -1
  45. data/spec/compiler_spec.rb +53 -450
  46. data/spec/fn_spec.rb +206 -0
  47. data/spec/list_spec.rb +1 -1
  48. data/spec/reader_spec.rb +349 -0
  49. data/spec/spec_helper.rb +40 -4
  50. data/spec/special_forms_spec.rb +203 -0
  51. metadata +99 -133
  52. data/lib/apricot/ast.rb +0 -3
  53. data/lib/apricot/ast/identifier.rb +0 -111
  54. data/lib/apricot/ast/list.rb +0 -99
  55. data/lib/apricot/ast/literals.rb +0 -240
  56. data/lib/apricot/ast/node.rb +0 -45
  57. data/lib/apricot/ast/scopes.rb +0 -147
  58. data/lib/apricot/ast/toplevel.rb +0 -66
  59. data/lib/apricot/ast/variables.rb +0 -64
  60. data/lib/apricot/printers.rb +0 -12
  61. data/lib/apricot/stages.rb +0 -60
  62. data/spec/parser_spec.rb +0 -312
@@ -0,0 +1,31 @@
1
+ module Apricot
2
+ # (if cond body else_body?)
3
+ SpecialForm.define(:if) do |g, args|
4
+ g.compile_error "Too few arguments to if" if args.count < 2
5
+ g.compile_error "Too many arguments to if" if args.count > 3
6
+
7
+ cond, body, else_body = *args
8
+ else_label = g.new_label
9
+ end_label = g.new_label
10
+
11
+ tail_position = g.tail_position?
12
+
13
+ g.tail_position = false
14
+ Compiler.bytecode(g, cond)
15
+ g.gif else_label
16
+
17
+ g.tail_position = tail_position
18
+ Compiler.bytecode(g, body)
19
+ g.goto end_label
20
+
21
+ g.tail_position = tail_position
22
+ else_label.set!
23
+ if else_body
24
+ Compiler.bytecode(g, else_body)
25
+ else
26
+ g.push_nil
27
+ end
28
+
29
+ end_label.set!
30
+ end
31
+ end
@@ -0,0 +1,8 @@
1
+ module Apricot
2
+ # (let [binding*] body*) where binding is an identifier followed by a value
3
+ SpecialForm.define(:let) do |g, args|
4
+ # loop and let share a lot of code. See special_forms.rb for the shared
5
+ # definition.
6
+ let(g, args, :let)
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ module Apricot
2
+ # (loop [binding*] body*) where binding is an identifier followed by a value
3
+ # Just like let but also introduces a loop target for (recur ...)
4
+ SpecialForm.define(:loop) do |g, args|
5
+ # loop and let share a lot of code. See special_forms.rb for the shared
6
+ # definition.
7
+ g.tail_position = true
8
+ let(g, args, :loop)
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module Apricot
2
+ # (quote form)
3
+ SpecialForm.define(:quote) do |g, args|
4
+ g.compile_error "Too few arguments to quote" if args.count < 1
5
+ g.compile_error "Too many arguments to quote" if args.count > 1
6
+
7
+ Compiler.bytecode(g, args.first, true)
8
+ end
9
+ end
@@ -0,0 +1,26 @@
1
+ module Apricot
2
+ # (recur args*)
3
+ # Rebinds the arguments of the nearest enclosing loop or fn and jumps to the
4
+ # top of the loop/fn. Argument rebinding is done in parallel (rebinding a
5
+ # variable in a recur will not affect uses of that variable in the other
6
+ # recur bindings.)
7
+ SpecialForm.define(:recur) do |g, args|
8
+ target = g.scope.find_recur_target
9
+ g.compile_error "No recursion target found for recur" unless target
10
+
11
+ g.compile_error "Can only recur from tail position" unless g.tail_position?
12
+
13
+ vars = target.variables.values
14
+ g.compile_error "Arity of recur does not match enclosing loop or fn" unless vars.length == args.count
15
+
16
+ args.each {|arg| Compiler.bytecode(g, arg) }
17
+
18
+ vars.reverse_each do |var|
19
+ g.set_local var
20
+ g.pop
21
+ end
22
+
23
+ g.check_interrupts
24
+ g.goto target.loop_label
25
+ end
26
+ end
@@ -0,0 +1,146 @@
1
+ module Apricot
2
+ # (try body* (rescue name|[name condition*] body*)* (ensure body*)?)
3
+ SpecialForm.define(:try) do |g, args|
4
+ body = []
5
+ rescue_clauses = []
6
+ ensure_clause = nil
7
+
8
+ args.each do |arg|
9
+ g.compile_error "Unexpected form after ensure clause" if ensure_clause
10
+
11
+ if arg.is_a?(Seq) && arg.first == Identifier.intern(:rescue)
12
+ rescue_clauses << arg.rest
13
+ elsif arg.is_a?(Seq) && arg.first == Identifier.intern(:ensure)
14
+ ensure_clause = arg.rest
15
+ else
16
+ g.compile_error "Unexpected form after rescue clause" unless rescue_clauses.empty?
17
+ body << arg
18
+ end
19
+ end
20
+
21
+ # Set up ensure
22
+ if ensure_clause
23
+ ensure_ex = g.new_label
24
+ ensure_ok = g.new_label
25
+ g.setup_unwind ensure_ex, 1
26
+ end
27
+
28
+ ex = g.new_label
29
+ done = g.new_label
30
+
31
+ g.push_exception_state
32
+ ex_state = g.new_stack_local
33
+ g.set_stack_local ex_state
34
+ g.pop
35
+
36
+ # Evaluate body
37
+ g.setup_unwind ex, 0
38
+ SpecialForm[:do].bytecode(g, body)
39
+ g.pop_unwind
40
+ g.goto done
41
+
42
+ # Body raised an exception
43
+ ex.set!
44
+
45
+ # Save exception state for re-raise
46
+ g.push_exception_state
47
+ raised_ex_state = g.new_stack_local
48
+ g.set_stack_local raised_ex_state
49
+ g.pop
50
+
51
+ # Push exception for rescue conditions
52
+ g.push_current_exception
53
+
54
+ rescue_clauses.each do |clause|
55
+ # Parse either (rescue e body) or (rescue [e Exception*] body)
56
+ if clause.first.is_a? Identifier
57
+ name, clause = clause.first, clause.rest
58
+ conditions = []
59
+ elsif clause.first.is_a? Array
60
+ conditions, clause = clause.first, clause.rest
61
+ name = conditions.shift
62
+ g.compile_error "Expected identifier as first form of rescue clause binding" unless name.is_a? Identifier
63
+ else
64
+ g.compile_error "Expected identifier or array as first form of rescue clause"
65
+ end
66
+
67
+ # Default to StandardError for (rescue e body) and (rescue [e] body)
68
+ conditions << Identifier.intern(:StandardError) if conditions.empty?
69
+
70
+ body = g.new_label
71
+ next_rescue = g.new_label
72
+
73
+ conditions.each do |cond|
74
+ g.dup # The exception
75
+ Compiler.bytecode(g, cond)
76
+ g.swap
77
+ g.send :===, 1
78
+ g.git body
79
+ end
80
+ g.goto next_rescue
81
+
82
+ # This rescue condition matched
83
+ body.set!
84
+
85
+ # Create a new scope to hold the exception
86
+ scope = LetScope.new(g.scope)
87
+ g.scopes << scope
88
+
89
+ # Exception is still on the stack
90
+ g.set_local scope.new_local(name)
91
+ g.pop
92
+
93
+ SpecialForm[:do].bytecode(g, clause)
94
+
95
+ # Yay!
96
+ g.clear_exception
97
+ g.goto done
98
+
99
+ g.scopes.pop
100
+
101
+ # Rescue condition did not match
102
+ next_rescue.set!
103
+ end
104
+
105
+ # No rescue conditions matched, re-raise
106
+ g.pop # The exception
107
+
108
+ # Re-raise the original exception
109
+ g.push_stack_local raised_ex_state
110
+ g.restore_exception_state
111
+ g.reraise
112
+
113
+ # Body executed without exception or was rescued
114
+ done.set!
115
+
116
+ g.push_stack_local raised_ex_state
117
+ g.restore_exception_state
118
+
119
+ if ensure_clause
120
+ g.pop_unwind
121
+ g.goto ensure_ok
122
+
123
+ # Body raised an exception
124
+ ensure_ex.set!
125
+
126
+ # Execute ensure clause
127
+ g.push_exception_state
128
+ ensure_clause.each do |expr|
129
+ Compiler.bytecode(g, expr)
130
+ g.pop # Ensure cannot return anything
131
+ end
132
+ g.restore_exception_state
133
+
134
+ g.reraise
135
+
136
+ # Body executed without exception or was rescued
137
+ ensure_ok.set!
138
+
139
+ # Execute ensure clause
140
+ ensure_clause.each do |expr|
141
+ Compiler.bytecode(g, expr)
142
+ g.pop
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,65 @@
1
+ module Apricot
2
+ class LocalReference
3
+ attr_reader :slot, :depth
4
+
5
+ def initialize(slot, depth = 0)
6
+ @slot = slot
7
+ @depth = depth
8
+ end
9
+
10
+ def bytecode(g)
11
+ if @depth == 0
12
+ g.push_local @slot
13
+ else
14
+ g.push_local_depth @depth, @slot
15
+ end
16
+ end
17
+ end
18
+
19
+ class QualifiedReference
20
+ def initialize(name, qualifier)
21
+ unless qualifier.is_a? Module # Namespaces are Modules as well.
22
+ raise ArgumentError, "qualifier for #{self.class} must be a Namespace or Module"
23
+ end
24
+
25
+ @name = name
26
+ @qualifier = qualifier
27
+ @on_namespace = qualifier.is_a? Namespace
28
+ end
29
+
30
+ def bytecode(g)
31
+ if @qualifier.is_a?(Namespace) && !@qualifier.has_var?(@name)
32
+ g.compile_error "Unable to resolve name #{@name} in namespace #{@qualifier}"
33
+ end
34
+
35
+ ns_id = Identifier.intern(@qualifier.name)
36
+ g.push_const ns_id.const_names.first
37
+ ns_id.const_names.drop(1).each {|n| g.find_const(n) }
38
+
39
+ g.push_literal @name
40
+
41
+ if on_namespace?
42
+ g.send :get_var, 1
43
+ else # @qualifier is a regular Ruby module
44
+ g.send :method, 1
45
+ end
46
+ end
47
+
48
+ def on_namespace?
49
+ @on_namespace
50
+ end
51
+
52
+ def meta
53
+ on_namespace? && @qualifier.vars[@name] &&
54
+ @qualifier.vars[@name].apricot_meta
55
+ end
56
+
57
+ def fn?
58
+ on_namespace? && @qualifier.fns.include?(@name)
59
+ end
60
+
61
+ def method?
62
+ !on_namespace? && @qualifier.respond_to?(@name)
63
+ end
64
+ end
65
+ end
@@ -1,3 +1,3 @@
1
1
  module Apricot
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
@@ -1,499 +1,102 @@
1
1
  describe 'Apricot' do
2
- def apricot(code)
3
- Apricot::Compiler.eval code
4
- end
5
-
6
- def bad_apricot(code)
7
- expect { apricot(code) }.to raise_error(CompileError)
8
- end
2
+ include CompilerSpec
9
3
 
10
4
  it 'compiles an empty program' do
11
- apricot('').should == nil
5
+ apr('').should == nil
12
6
  end
13
7
 
14
8
  it 'compiles false, true and nil' do
15
- apricot('true').should == true
16
- apricot('false').should == false
17
- apricot('nil').should == nil
9
+ apr('true').should == true
10
+ apr('false').should == false
11
+ apr('nil').should == nil
18
12
  end
19
13
 
20
14
  it 'compiles numbers' do
21
- apricot('1').should == 1
22
- apricot('1.0').should == 1.0
23
- apricot('1/3').should == Rational(1, 3)
15
+ apr('1').should == 1
16
+ apr('1.0').should == 1.0
17
+ apr('1/3').should == Rational(1, 3)
24
18
  end
25
19
 
26
20
  it 'compiles symbols' do
27
- apricot(':foo').should == :foo
21
+ apr(':foo').should == :foo
22
+ end
23
+
24
+ it "doesn't mix up symbols and keywords in lists" do
25
+ # There once was a bug where :true would get compiled as the value true.
26
+ apr('(.class :true)').should == Symbol
28
27
  end
29
28
 
30
29
  it 'compiles strings' do
31
- apricot('"foo"').should == "foo"
30
+ apr('"foo"').should == "foo"
32
31
  end
33
32
 
34
33
  it 'compiles regexes' do
35
- apricot('#r"foo"').should == /foo/
36
- apricot('#r/foo/x').should == /foo/x
37
- apricot('#r[foo]xim').should == /foo/xim
34
+ apr('#r"foo"').should == /foo/
35
+ apr('#r/foo/x').should == /foo/x
36
+ apr('#r[foo]xim').should == /foo/xim
38
37
  end
39
38
 
40
39
  it 'compiles arrays' do
41
- apricot('[]').should == []
42
- apricot('[1 2 3]').should == [1, 2, 3]
40
+ apr('[]').should == []
41
+ apr('[1 2 3]').should == [1, 2, 3]
43
42
  end
44
43
 
45
44
  it 'compiles hashes' do
46
- apricot('{}').should == {}
47
- apricot('{:foo 1, :bar 2}').should == {:foo => 1, :bar => 2}
45
+ apr('{}').should == {}
46
+ apr('{:foo 1, :bar 2}').should == {:foo => 1, :bar => 2}
48
47
  end
49
48
 
50
49
  it 'compiles sets' do
51
- apricot('#{}').should == Set.new
52
- apricot('#{:foo :foo :bar}').should == Set[:foo, :foo, :bar]
50
+ apr('#{}').should == Set.new
51
+ apr('#{:foo :foo :bar}').should == Set[:foo, :foo, :bar]
53
52
  end
54
53
 
55
54
  it 'compiles constants' do
56
- apricot('Array').should == Array
57
- apricot('Rubinius::Compiler').should == Rubinius::Compiler
55
+ apr('Array').should == Array
56
+ apr('Enumerable::Enumerator').should == Enumerable::Enumerator
58
57
  end
59
58
 
60
59
  it 'compiles call forms with data structures' do
61
- apricot('([:a :b] 1)').should == :b
62
- apricot('([:a :b] 3)').should == nil
63
- apricot('(#{:a :b} :b)').should == :b
64
- apricot('(#{:a :b} :c)').should == nil
65
- apricot('({:a 1} :a)').should == 1
66
- apricot('({:a 1} :b)').should == nil
60
+ apr('([:a :b] 1)').should == :b
61
+ apr('([:a :b] 3)').should == nil
62
+ apr('(#{:a :b} :b)').should == :b
63
+ apr('(#{:a :b} :c)').should == nil
64
+ apr('({:a 1} :a)').should == 1
65
+ apr('({:a 1} :b)').should == nil
67
66
  end
68
67
 
69
68
  it 'compiles symbol call forms' do
70
- apricot('(:a {:a 1 :b 2})').should == 1
71
- apricot('(:c {:a 1 :b 2})').should == nil
72
- apricot('(:a #{:a :b})').should == :a
73
- apricot('(:c #{:a :b})').should == nil
74
- end
75
-
76
- it 'compiles send forms' do
77
- apricot('(. 1 class)').should == Fixnum
78
- apricot('(. 1 (class))').should == Fixnum
79
- apricot('(. "foo" append "bar")').should == "foobar"
80
- apricot('(. "foo" (append "bar"))').should == "foobar"
81
- end
82
-
83
- it 'compiles send forms with block args' do
84
- apricot('(. [1 2 3] map | :to_s)').should == ['1', '2', '3']
85
- apricot('(. [1 2 3] (map | :to_s))').should == ['1', '2', '3']
86
- apricot('(. [1 2 3] map | #(. % + 1))').should == [2, 3, 4]
87
- apricot('(. [1 2 3] (map | #(. % + 1)))').should == [2, 3, 4]
88
- end
89
-
90
- it 'compiles shorthand send forms' do
91
- apricot('(.class 1)').should == Fixnum
92
- apricot('(.append "foo" "bar")').should == "foobar"
93
- end
94
-
95
- it 'compiles shorthand send forms with block args' do
96
- apricot('(.map [1 2 3] | :to_s)').should == ['1', '2', '3']
97
- apricot('(.map [1 2 3] | #(. % + 1))').should == [2, 3, 4]
98
- end
99
-
100
- it 'macroexpands shorthand send forms' do
101
- form = apricot "'(.meth recv arg1 arg2)"
102
- ex = Apricot.macroexpand(form)
103
-
104
- dot = Identifier.intern(:'.')
105
- recv = Identifier.intern(:recv)
106
- meth = Identifier.intern(:meth)
107
- arg1 = Identifier.intern(:arg1)
108
- arg2 = Identifier.intern(:arg2)
109
- ex.should == List[dot, recv, meth, arg1, arg2]
110
- end
111
-
112
- it 'compiles shorthand new forms' do
113
- apricot('(Range. 1 10)').should == (1..10)
114
- apricot('(Array. 2 5)').should == [5, 5]
115
- end
116
-
117
- it 'compiles shorthand new forms with block args' do
118
- apricot('(Array. 3 | :to_s)').should == ["0", "1", "2"]
119
- apricot('(Array. 5 | #(* % %))').should == [0, 1, 4, 9, 16]
120
- end
121
-
122
- it 'macroexpands shorthand new forms' do
123
- form = apricot "'(Klass. arg1 arg2)"
124
- ex = Apricot.macroexpand(form)
125
-
126
- dot = Identifier.intern(:'.')
127
- klass = Identifier.intern(:Klass)
128
- new = Identifier.intern(:new)
129
- arg1 = Identifier.intern(:arg1)
130
- arg2 = Identifier.intern(:arg2)
131
- ex.should == List[dot, klass, new, arg1, arg2]
69
+ apr('(:a {:a 1 :b 2})').should == 1
70
+ apr('(:c {:a 1 :b 2})').should == nil
71
+ apr('(:a #{:a :b})').should == :a
72
+ apr('(:c #{:a :b})').should == nil
132
73
  end
133
74
 
134
75
  it 'compiles constant defs' do
135
76
  expect { Foo }.to raise_error(NameError)
136
- apricot '(def Foo 1)'
77
+ apr '(def Foo 1)'
137
78
  Foo.should == 1
138
79
  end
139
80
 
140
- it 'compiles if forms' do
141
- apricot('(if true :foo :bar)').should == :foo
142
- apricot('(if false :foo :bar)').should == :bar
143
- apricot('(if true :foo)').should == :foo
144
- apricot('(if false :foo)').should == nil
145
- end
146
-
147
- it 'compiles do forms' do
148
- apricot('(do)').should == nil
149
- apricot('(do 1)').should == 1
150
- apricot('(do 1 2 3)').should == 3
151
- expect { Bar }.to raise_error(NameError)
152
- apricot('(do (def Bar 1) Bar)').should == 1
153
- end
154
-
155
- it 'compiles let forms' do
156
- apricot('(let [])').should == nil
157
- apricot('(let [a 1])').should == nil
158
- apricot('(let [a 1] a)').should == 1
159
- apricot('(let [a 1 b 2] [b a])').should == [2, 1]
160
- apricot('(let [a 1] [(let [a 2] a) a])').should == [2, 1]
161
- apricot('(let [a 1 b 2] (let [a 42] [b a]))').should == [2, 42]
162
- apricot('(let [a 1 b a] [a b])').should == [1, 1]
163
- apricot('(let [a 1] (let [b a] [a b]))').should == [1, 1]
164
- end
165
-
166
- it 'compiles fn forms' do
167
- apricot('((fn []))').should == nil
168
- apricot('((fn [] 42))').should == 42
169
- apricot('((fn [x] x) 42)').should == 42
170
- apricot('((fn [x y] [y x]) 1 2)').should == [2, 1]
171
- end
172
-
173
- it 'compiles fn forms with optional arguments' do
174
- apricot('((fn [[x 42]] x))').should == 42
175
- apricot('((fn [[x 42]] x) 0)').should == 0
176
- apricot('((fn [x [y 2]] [x y]) 1)').should == [1, 2]
177
- apricot('((fn [x [y 2]] [x y]) 3 4)').should == [3, 4]
178
- apricot('((fn [[x 1] [y 2]] [x y]))').should == [1, 2]
179
- apricot('((fn [[x 1] [y 2]] [x y]) 3)').should == [3, 2]
180
- apricot('((fn [[x 1] [y 2]] [x y]) 3 4)').should == [3, 4]
181
- end
182
-
183
- it 'compiles fn forms with splat arguments' do
184
- apricot('((fn [& x] x))').should == []
185
- apricot('((fn [& x] x) 1)').should == [1]
186
- apricot('((fn [& x] x) 1 2)').should == [1, 2]
187
- apricot('((fn [x & y] y) 1)').should == []
188
- apricot('((fn [x & y] y) 1 2 3)').should == [2, 3]
189
- end
190
-
191
- it 'compiles fn forms with optional and splat arguments' do
192
- apricot('((fn [x [y 2] & z] [x y z]) 1)').should == [1, 2, []]
193
- apricot('((fn [x [y 2] & z] [x y z]) 1 3)').should == [1, 3, []]
194
- apricot('((fn [x [y 2] & z] [x y z]) 1 3 4 5)').should == [1, 3, [4, 5]]
195
- end
196
-
197
- it 'compiles fn forms with block arguments' do
198
- apricot('((fn [| block] block))').should == nil
199
- apricot('(.call (fn [| block] (block)) | (fn [] 42))').should == 42
200
-
201
- fn = apricot '(fn [x | block] (block x))'
202
- # Without passing a block, 'block' is nil.
203
- expect { fn.call(2) }.to raise_error(NoMethodError)
204
- fn.call(2) {|x| x + 40 }.should == 42
205
-
206
- reduce_args = apricot <<-CODE
207
- (fn reduce-args
208
- ([x] x)
209
- ([x y | f] (f x y))
210
- ([x y & more | f]
211
- (recur (f x y) (first more) (next more))))
212
- CODE
213
-
214
- reduce_args.call(1).should == 1
215
- reduce_args.call(40, 2) {|x,y| x * y }.should == 80
216
- reduce_args.call(1,2,3,4,5,6) {|x,y| x + y }.should == 21
217
- end
218
-
219
- it 'does not compile invalid fn forms' do
220
- bad_apricot '(fn :foo)'
221
- bad_apricot '(fn [1])'
222
- bad_apricot '(fn [[x 1] y])'
223
- bad_apricot '(fn [[1 1]])'
224
- bad_apricot '(fn [[x]])'
225
- bad_apricot '(fn [&])'
226
- bad_apricot '(fn [& x y])'
227
- bad_apricot '(fn [x x])'
228
- bad_apricot '(fn [x & rest1 & rest2])'
229
- bad_apricot '(fn [a b x c d x e f])'
230
- bad_apricot '(fn [a x b [x 1]])'
231
- bad_apricot '(fn [a b x c d & x])'
232
- bad_apricot '(fn [a b c [x 1] [y 2] [x 3]])'
233
- bad_apricot '(fn [a b [x 1] & x])'
234
- bad_apricot '(fn [|])'
235
- bad_apricot '(fn [| &])'
236
- bad_apricot '(fn [| & a])'
237
- bad_apricot '(fn [| a &])'
238
- bad_apricot '(fn [& x |])'
239
- bad_apricot '(fn [| x y])'
240
- bad_apricot '(fn [| x & y])'
241
- bad_apricot '(fn [x | x])'
242
- bad_apricot '(fn [x | b1 | b2])'
243
- end
244
-
245
- it 'compiles arity-overloaded fn forms' do
246
- apricot('((fn ([] 0)))') == 0
247
- apricot('((fn ([x] x)) 42)') == 42
248
- apricot('((fn ([[x 42]] x)))') == 42
249
- apricot('((fn ([& rest] rest)) 1 2 3)') == [1, 2, 3]
250
- apricot('((fn ([] 0) ([x] x)))') == 0
251
- apricot('((fn ([] 0) ([x] x)) 42)') == 42
252
- apricot('((fn ([x] x) ([x y] y)) 42)') == 42
253
- apricot('((fn ([x] x) ([x y] y)) 42 13)') == 13
254
-
255
- add_fn = apricot <<-CODE
256
- (fn
257
- ([] 0)
258
- ([x] x)
259
- ([x y] (.+ x y))
260
- ([x y & more]
261
- (.reduce more (.+ x y) :+)))
262
- CODE
263
-
264
- add_fn.call.should == 0
265
- add_fn.call(42).should == 42
266
- add_fn.call(1,2).should == 3
267
- add_fn.call(1,2,3).should == 6
268
- add_fn.call(1,2,3,4,5,6,7,8).should == 36
269
-
270
- two_or_three = apricot '(fn ([x y] 2) ([x y z] 3))'
271
- expect { two_or_three.call }.to raise_error(ArgumentError)
272
- expect { two_or_three.call(1) }.to raise_error(ArgumentError)
273
- two_or_three.call(1,2).should == 2
274
- two_or_three.call(1,2,3).should == 3
275
- expect { two_or_three.call(1,2,3,4) }.to raise_error(ArgumentError)
276
- expect { two_or_three.call(1,2,3,4,5) }.to raise_error(ArgumentError)
277
- end
278
-
279
- it 'compiles arity-overloaded fns with no matching overloads for some arities' do
280
- zero_or_two = apricot '(fn ([] 0) ([x y] 2))'
281
- zero_or_two.call.should == 0
282
- expect { zero_or_two.call(1) }.to raise_error(ArgumentError)
283
- zero_or_two.call(1,2).should == 2
284
- expect { zero_or_two.call(1,2,3) }.to raise_error(ArgumentError)
285
-
286
- one_or_four = apricot '(fn ([w] 1) ([w x y z] 4))'
287
- expect { one_or_four.call }.to raise_error(ArgumentError)
288
- one_or_four.call(1).should == 1
289
- expect { one_or_four.call(1,2) }.to raise_error(ArgumentError)
290
- expect { one_or_four.call(1,2,3) }.to raise_error(ArgumentError)
291
- one_or_four.call(1,2,3,4).should == 4
292
- expect { one_or_four.call(1,2,3,4,5) }.to raise_error(ArgumentError)
293
- end
294
-
295
- it 'does not compile invalid arity-overloaded fn forms' do
296
- bad_apricot '(fn ([] 1) :foo)'
297
- bad_apricot '(fn ([] 1) ([] 2))'
298
- bad_apricot '(fn ([[o 1]] 1) ([] 2))'
299
- bad_apricot '(fn ([] 1) ([[o 2]] 2))'
300
- bad_apricot '(fn ([[o 1]] 1) ([[o 2]] 2))'
301
- bad_apricot '(fn ([x [o 1]] 1) ([x] 2))'
302
- bad_apricot '(fn ([x [o 1]] 1) ([[o 2]] 2))'
303
- bad_apricot '(fn ([x y z [o 1]] 1) ([x y z & rest] 2))'
304
- bad_apricot '(fn ([x [o 1] [p 2] [q 3]] 1) ([x y z] 2))'
305
- bad_apricot '(fn ([x & rest] 1) ([x y] 2))'
306
- bad_apricot '(fn ([x & rest] 1) ([x [o 1]] 2))'
307
- bad_apricot '(fn ([x [o 1] & rest] 1) ([x] 2))'
308
- end
309
-
310
- it 'compiles fn forms with self-reference' do
311
- foo = apricot '(fn foo [] foo)'
312
- foo.call.should == foo
313
-
314
- # This one will stack overflow from the infinite loop.
315
- expect { apricot '((fn foo [] (foo)))' }.to raise_error(SystemStackError)
316
-
317
- add = apricot <<-CODE
318
- (fn add
319
- ([] 0)
320
- ([& args]
321
- (.+ (first args) (apply add (rest args)))))
322
- CODE
323
-
324
- add.call.should == 0
325
- add.call(1).should == 1
326
- add.call(1,2,3).should == 6
327
- end
328
-
329
- it 'compiles loop and recur forms' do
330
- apricot('(loop [])').should == nil
331
- apricot('(loop [a 1])').should == nil
332
- apricot('(loop [a 1] a)').should == 1
333
-
334
- apricot(<<-CODE).should == [5,4,3,2,1]
335
- (let [a []]
336
- (loop [x 5]
337
- (if (. x > 0)
338
- (do
339
- (. a << x)
340
- (recur (. x - 1)))))
341
- a)
342
- CODE
343
- end
344
-
345
- it 'compiles recur forms in fns' do
346
- apricot(<<-CODE).should == 15
347
- ((fn [x y]
348
- (if (. x > 0)
349
- (recur (. x - 1) (. y + x))
350
- y))
351
- 5 0)
352
- CODE
353
- end
354
-
355
- it 'compiles recur forms in fns with optional arguments' do
356
- apricot(<<-CODE).should == 150
357
- ((fn [x y [mult 10]]
358
- (if (. x > 0)
359
- (recur (. x - 1) (. y + x) mult)
360
- (* y mult)))
361
- 5 0)
362
- CODE
363
-
364
- apricot(<<-CODE).should == 300
365
- ((fn [x y [mult 10]]
366
- (if (. x > 0)
367
- (recur (. x - 1) (. y + x) mult)
368
- (* y mult)))
369
- 5 0 20)
370
- CODE
371
- end
372
-
373
- it 'does not compile invalid recur forms' do
374
- bad_apricot '(fn [] (recur 1))'
375
- bad_apricot '(fn [x] (recur))'
376
- bad_apricot '(fn [[x 10]] (recur))'
377
- bad_apricot '(fn [x & rest] (recur 1))'
378
- bad_apricot '(fn [x & rest] (recur 1 2 3))'
379
- end
380
-
381
- it 'compiles recur forms in arity-overloaded fns' do
382
- apricot(<<-CODE).should == 0
383
- ((fn
384
- ([] 0)
385
- ([& args] (recur [])))
386
- 1 2 3)
387
- CODE
388
-
389
- apricot(<<-CODE).should == 0
390
- ((fn
391
- ([] 0)
392
- ([& args] (recur (rest args))))
393
- 1 2 3)
394
- CODE
395
-
396
- apricot(<<-CODE).should == 6
397
- ((fn
398
- ([x] x)
399
- ([x & args] (recur (.+ x (first args)) (rest args))))
400
- 1 2 3)
401
- CODE
402
-
403
- apricot(<<-CODE).should == 42
404
- ((fn
405
- ([] 0)
406
- ([x y & args]
407
- (if (.empty? args)
408
- 42
409
- (recur x y (rest args)))))
410
- 1 2 3)
411
- CODE
412
- end
413
-
414
- it 'compiles try forms' do
415
- apricot('(try)').should == nil
416
- apricot('(try :foo)').should == :foo
417
-
418
- apricot('(try :success (rescue e :rescue))').should == :success
419
- expect { apricot '(try (. Kernel raise))' }.to raise_error(RuntimeError)
420
- apricot('(try (. Kernel raise) (rescue e :rescue))').should == :rescue
421
- apricot('(try (. Kernel raise) (rescue [e] :rescue))').should == :rescue
422
- apricot(<<-CODE).should == :rescue
423
- (try
424
- (. Kernel raise)
425
- (rescue [e 1 2 RuntimeError] :rescue))
426
- CODE
427
- apricot(<<-CODE).should == :rescue_bar
428
- (try
429
- (. Kernel raise ArgumentError)
430
- (rescue [e TypeError] :rescue_foo)
431
- (rescue [e ArgumentError] :rescue_bar))
432
- CODE
433
- apricot(<<-CODE).should be_a(TypeError)
434
- (try
435
- (. Kernel raise TypeError)
436
- (rescue e e))
437
- CODE
438
- expect { apricot(<<-CODE) }.to raise_error(TypeError)
439
- (try
440
- (. Kernel raise TypeError)
441
- (rescue [e ArgumentError] :rescue))
442
- CODE
443
-
444
- apricot(<<-CODE).should == :rescue
445
- (try
446
- (try
447
- (. Kernel raise)
448
- (rescue e (. Kernel raise)))
449
- (rescue e :rescue))
450
- CODE
451
-
452
- apricot(<<-CODE).should == []
453
- (let [a [1]]
454
- (try
455
- :success
456
- (ensure (.pop a)))
457
- a)
458
- CODE
459
- apricot(<<-CODE).should == []
460
- (let [a [1]]
461
- (try
462
- (. Kernel raise)
463
- (rescue e :rescue)
464
- (ensure (.pop a)))
465
- a)
466
- CODE
467
- apricot(<<-CODE).should == []
468
- (let [a [1]]
469
- (try
470
- (try
471
- (. Kernel raise)
472
- (ensure (.pop a)))
473
- (rescue e :rescue))
474
- a)
475
- CODE
476
- end
477
-
478
81
  it 'compiles quoted forms' do
479
- apricot("'1").should == 1
480
- apricot("'a").should == Identifier.intern(:a)
481
- apricot("''a").should == List[
82
+ apr("'1").should == 1
83
+ apr("'a").should == Identifier.intern(:a)
84
+ apr("''a").should == List[
482
85
  Identifier.intern(:quote),
483
86
  Identifier.intern(:a)
484
87
  ]
485
- apricot("'1.2").should == 1.2
486
- apricot("'1/2").should == Rational(1,2)
487
- apricot("':a").should == :a
488
- apricot("'()").should == List::EmptyList
489
- apricot("'(1)").should == List[1]
490
- apricot("'[a]").should == [Identifier.intern(:a)]
491
- apricot("'{a 1}").should == {Identifier.intern(:a) => 1}
492
- apricot('\'"foo"').should == "foo"
493
- apricot("'true").should == true
494
- apricot("'false").should == false
495
- apricot("'nil").should == nil
496
- apricot("'self").should == Identifier.intern(:self)
497
- apricot("'Foo::Bar").should == Identifier.intern(:'Foo::Bar')
88
+ apr("'1.2").should == 1.2
89
+ apr("'1/2").should == Rational(1,2)
90
+ apr("':a").should == :a
91
+ apr("'()").should == List::EMPTY_LIST
92
+ apr("'(1)").should == List[1]
93
+ apr("'[a]").should == [Identifier.intern(:a)]
94
+ apr("'{a 1}").should == {Identifier.intern(:a) => 1}
95
+ apr('\'"foo"').should == "foo"
96
+ apr("'true").should == true
97
+ apr("'false").should == false
98
+ apr("'nil").should == nil
99
+ apr("'self").should == Identifier.intern(:self)
100
+ apr("'Foo::Bar").should == Identifier.intern(:'Foo::Bar')
498
101
  end
499
102
  end