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