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,32 @@
1
+ module Apricot
2
+ # (def name value?)
3
+ SpecialForm.define(:def) do |g, args|
4
+ g.compile_error "Too few arguments to def" if args.count < 1
5
+ g.compile_error "Too many arguments to def" if args.count > 2
6
+
7
+ id, value = *args
8
+
9
+ g.compile_error "First argument to def must be an identifier" unless id.is_a? Identifier
10
+
11
+ if id.constant?
12
+ if id.const_names.length == 1
13
+ g.push_scope
14
+ else
15
+ g.push_const id.const_names[0]
16
+ id.const_names[1..-2].each {|n| g.find_const n }
17
+ end
18
+
19
+ g.push_literal id.const_names.last
20
+ Compiler.bytecode(g, value)
21
+ g.send :const_set, 2
22
+ else
23
+ g.compile_error "Can't change the value of self" if id.name == :self
24
+
25
+ g.push_const :Apricot
26
+ g.send :current_namespace, 0
27
+ g.push_literal id.name
28
+ Compiler.bytecode(g, value)
29
+ g.send :set_var, 2
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,23 @@
1
+ module Apricot
2
+ # (do body*)
3
+ SpecialForm.define(:do) do |g, args|
4
+ if args.empty?
5
+ g.push_nil
6
+ else
7
+ tail_position = g.tail_position?
8
+ last_index = args.count - 1
9
+
10
+ args.each_with_index do |a, i|
11
+ g.pop unless i == 0
12
+
13
+ if i == last_index && tail_position
14
+ g.tail_position = true
15
+ else
16
+ g.tail_position = false
17
+ end
18
+
19
+ Compiler.bytecode(g, a)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,112 @@
1
+ module Apricot
2
+ # (. receiver method args*)
3
+ # (. receiver method args* & rest)
4
+ # (. receiver method args* | block)
5
+ # (. receiver method args* & rest | block)
6
+ # (. receiver (method args*))
7
+ # (. receiver (method args* & rest))
8
+ # (. receiver (method args* | block))
9
+ # (. receiver (method args* & rest | block))
10
+ SpecialForm.define(:'.') do |g, args|
11
+ g.compile_error "Too few arguments to send expression, expecting (. receiver method ...)" if args.count < 2
12
+
13
+ g.tail_position = false
14
+
15
+ # TODO: Don't convert to an array, just deal with the List.
16
+ args = args.to_a
17
+
18
+ receiver, method_or_list = args.shift(2)
19
+
20
+ # Handle the (. receiver (method args*)) form
21
+ if method_or_list.is_a? Seq
22
+ g.compile_error "Invalid send expression, expecting (. receiver (method ...))" unless args.empty?
23
+
24
+ method, args = method_or_list.first, method_or_list.rest.to_a
25
+ else
26
+ method = method_or_list
27
+ end
28
+
29
+ g.compile_error "Method in send expression must be an identifier" unless method.is_a? Identifier
30
+
31
+ block_arg = nil
32
+ splat_arg = nil
33
+
34
+ if args[-2].is_a?(Identifier) && args[-2].name == :|
35
+ block_arg = args.last
36
+ args.pop(2)
37
+ end
38
+
39
+ if args[-2].is_a?(Identifier) && args[-2].name == :&
40
+ splat_arg = args.last
41
+ args.pop(2)
42
+ end
43
+
44
+ args.each do |arg|
45
+ next unless arg.is_a?(Identifier)
46
+ g.compile_error "Incorrect use of & in send expression" if arg.name == :&
47
+ g.compile_error "Incorrect use of | in send expression" if arg.name == :|
48
+ end
49
+
50
+ Compiler.bytecode(g, receiver)
51
+
52
+ if block_arg || splat_arg
53
+ args.each {|a| Compiler.bytecode(g, a) }
54
+
55
+ if splat_arg
56
+ Compiler.bytecode(g, splat_arg)
57
+ g.cast_array unless splat_arg.is_a?(Array)
58
+ end
59
+
60
+ if block_arg
61
+ nil_block = g.new_label
62
+ Compiler.bytecode(g, block_arg)
63
+ g.dup
64
+ g.is_nil
65
+ g.git nil_block
66
+
67
+ g.push_const :Proc
68
+
69
+ g.swap
70
+ g.send :__from_block__, 1
71
+
72
+ nil_block.set!
73
+ else
74
+ g.push_nil
75
+ end
76
+
77
+ if splat_arg
78
+ g.send_with_splat method.name, args.length
79
+ else
80
+ g.send_with_block method.name, args.length
81
+ end
82
+
83
+ elsif method.name == :new
84
+ slow = g.new_label
85
+ done = g.new_label
86
+
87
+ g.dup # dup the receiver
88
+ g.check_serial :new, Rubinius::CompiledMethod::KernelMethodSerial
89
+ g.gif slow
90
+
91
+ # fast path
92
+ g.send :allocate, 0, true
93
+ g.dup
94
+ args.each {|a| Compiler.bytecode(g, a) }
95
+ g.send :initialize, args.length, true
96
+ g.pop
97
+
98
+ g.goto done
99
+
100
+ # slow path
101
+ slow.set!
102
+ args.each {|a| Compiler.bytecode(g, a) }
103
+ g.send :new, args.length
104
+
105
+ done.set!
106
+
107
+ else
108
+ args.each {|a| Compiler.bytecode(g, a) }
109
+ g.send method.name, args.length
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,342 @@
1
+ module Apricot
2
+ class SpecialForm
3
+ class ArgList
4
+ attr_reader :required_args, :optional_args, :rest_arg, :block_arg,
5
+ :num_required, :num_optional, :num_total
6
+
7
+ def initialize(args, g)
8
+ state = :required
9
+
10
+ @required_args = []
11
+ @optional_args = []
12
+ @rest_arg = nil
13
+ @block_arg = nil
14
+
15
+ args.each do |arg|
16
+ # Check if we got one of the special identifiers which moves us to a
17
+ # different part of the argument list. If so, move to the new state
18
+ # and skip to the next argument. Also check that the current state
19
+ # is allowed to move to the new state (the arguments must come in a
20
+ # strict order: required, optional, rest, block).
21
+ if arg.is_a? Identifier
22
+ case arg.name
23
+ # '?' starts the optional arguments section.
24
+ when :'?'
25
+ case state
26
+ when :required
27
+ state = :start_optional
28
+ next
29
+ else
30
+ g.compile_error "Unexpected '?' in argument list"
31
+ end
32
+
33
+ # '&' precedes the rest argument.
34
+ when :&
35
+ case state
36
+ when :required, :optional
37
+ state = :rest
38
+ next
39
+ else
40
+ g.compile_error "Unexpected '&' in argument list"
41
+ end
42
+
43
+ # '|' precedes the block argument.
44
+ when :|
45
+ case state
46
+ when :required, :optional, :after_rest
47
+ state = :block
48
+ next
49
+ else
50
+ g.compile_error "Unexpected '|' in argument list"
51
+ end
52
+ end
53
+ end
54
+
55
+ # Deal with the argument based on the current state.
56
+ case state
57
+ when :required
58
+ g.compile_error "Required argument in argument list must be an identifier" unless arg.is_a? Identifier
59
+ @required_args << arg.name
60
+
61
+ when :optional, :start_optional
62
+ unless arg.is_a?(Seq) && arg.count == 2 && arg.first.is_a?(Identifier)
63
+ g.compile_error "Optional argument in argument list must be of the form (name default)"
64
+ end
65
+
66
+ state = :optional
67
+ @optional_args << [arg.first.name, arg.rest.first]
68
+
69
+ when :rest
70
+ g.compile_error "Rest argument in argument list must be an identifier" unless arg.is_a? Identifier
71
+ @rest_arg = arg.name
72
+ state = :after_rest
73
+
74
+ when :block
75
+ g.compile_error "Block argument in argument list must be an identifier" unless arg.is_a? Identifier
76
+ @block_arg = arg.name
77
+ state = :after_block
78
+
79
+ when :after_rest
80
+ g.compile_error "Unexpected argument after rest argument"
81
+
82
+ when :after_block
83
+ g.compile_error "Unexpected arguments after block argument"
84
+ end
85
+ end
86
+
87
+ # Check if we finished in the middle of things without getting an
88
+ # argument where we expected one.
89
+ case state
90
+ when :start_optional
91
+ g.compile_error "Expected optional arguments after '?' in argument list"
92
+
93
+ when :rest
94
+ g.compile_error "Expected rest argument after '&' in argument list"
95
+
96
+ when :block
97
+ g.compile_error "Expected block argument after '|' in argument list"
98
+ end
99
+
100
+ @num_required = @required_args.length
101
+ @num_optional = @optional_args.length
102
+ @num_total = @num_required + @num_optional
103
+ end
104
+
105
+ def to_array
106
+ args = @required_args.map {|id| Identifier.intern(id) }
107
+ args += @optional_args.map {|name, val| [Identifier.intern(name), val.to_value] }
108
+ args += [Identifier.intern(:|), Identifier.intern(@block_arg)] if @block_arg
109
+ args += [Identifier.intern(:&), Identifier.intern(@rest_arg)] if @rest_arg
110
+ args
111
+ end
112
+ end
113
+
114
+ Overload = Struct.new(:arglist, :body)
115
+
116
+ # (fn name? [args*] body*)
117
+ # (fn name? [args* | block] body*)
118
+ # (fn name? [args* & rest] body*)
119
+ # (fn name? [args* & rest | block] body*)
120
+ # (fn name? ([args*] body*) ... ([args*] body*))
121
+ SpecialForm.define(:fn) do |g, args|
122
+ fn_name, args = args.first.name, args.rest if args.first.is_a? Identifier
123
+ doc_string, args = args.first, args.rest if args.first.is_a? String
124
+
125
+ overloads = []
126
+
127
+ case args.first
128
+ when Seq
129
+ # This is the multi-arity form (fn name? ([args*] body*) ... ([args*] body*))
130
+ args.each do |overload|
131
+ # Each overload is of the form ([args*] body*)
132
+ g.compile_error "Expected an arity overload (a list)" unless overload.is_a? Seq
133
+ arglist, body = overload.first, overload.rest
134
+ g.compile_error "Argument list in overload must be an array literal" unless arglist.is_a? Array
135
+ arglist = ArgList.new(arglist, g)
136
+ overloads << Overload.new(arglist, body)
137
+ end
138
+ when Array
139
+ # This is the single-arity form (fn name? [args*] body*)
140
+ arglist, body = args.first, args.rest
141
+ arglist = ArgList.new(arglist, g)
142
+ overloads << Overload.new(arglist, body)
143
+ else
144
+ # Didn't match any of the legal forms.
145
+ g.compile_error "Expected argument list or arity overload in fn definition"
146
+ end
147
+
148
+ # Check that the overloads do not conflict with each other.
149
+ if overloads.length > 1
150
+ variadic, normals = overloads.partition {|overload| overload.arglist.rest_arg }
151
+
152
+ g.compile_error "Can't have more than one variadic overload" if variadic.length > 1
153
+
154
+ # Sort the non-variadic overloads by ascending number of required arguments.
155
+ normals.sort_by! {|overload| overload.arglist.num_required }
156
+
157
+ if variadic.length == 1
158
+ # If there is a variadic overload, it should have at least as many
159
+ # required arguments as the next highest overload.
160
+ variadic_arglist = variadic.first.arglist
161
+ if variadic_arglist.num_required < normals.last.arglist.num_required
162
+ g.compile_error "Can't have a fixed arity overload with more params than a variadic overload"
163
+ end
164
+
165
+ # Can't have two overloads with same number of required args unless
166
+ # they have no optional args and one of them is the variadic overload.
167
+ if variadic_arglist.num_required == normals.last.arglist.num_required &&
168
+ (variadic_arglist.num_optional != 0 || normals.last.arglist.num_optional != 0)
169
+ g.compile_error "Can't have two overloads with the same arity"
170
+ elsif normals.last.arglist.num_total > variadic_arglist.num_required
171
+ g.compile_error "Can't have an overload with more total (required + optional) arguments than the variadic overload has required argument"
172
+ end
173
+ end
174
+
175
+ # Compare each consecutive two non-variadic overloads.
176
+ normals.each_cons(2) do |o1, o2|
177
+ arglist1 = o1.arglist
178
+ arglist2 = o2.arglist
179
+ if arglist1.num_required == arglist2.num_required
180
+ g.compile_error "Can't have two overloads with the same arity"
181
+ elsif arglist1.num_total >= arglist2.num_required
182
+ g.compile_error "Can't have an overload with as many total (required + optional) arguments as another overload has required arguments"
183
+ end
184
+ end
185
+
186
+ overloads = normals + variadic
187
+ end
188
+
189
+ fn = g.class.new
190
+ fn.name = fn_name || :__fn__
191
+ fn.file = g.file
192
+
193
+ fn.definition_line g.line
194
+ fn.set_line g.line
195
+
196
+ fn.total_args = 0
197
+ fn.required_args = 0
198
+ fn.local_count = 0
199
+ fn.local_names = []
200
+
201
+ fn_scope = FnScope.new(g.scope, fn_name)
202
+
203
+ # Generate the code that selects and jumps to the correct overload based
204
+ # on the number of arguments passed.
205
+ if overloads.length > 1
206
+ overload_labels = overloads.map { fn.new_label }
207
+ nomatch_possible = false # Is it possible to match no overload?
208
+ nomatch = fn.new_label
209
+
210
+ last_args = overloads.last.arglist
211
+ if last_args.rest_arg
212
+ if overloads[-2].arglist.num_required == last_args.num_required
213
+ fn.passed_arg last_args.num_required
214
+ else
215
+ fn.passed_arg last_args.num_required - 1
216
+ end
217
+ fn.git overload_labels.last
218
+ else
219
+ fn.passed_arg last_args.num_required - 1
220
+ fn.git overload_labels.last
221
+ end
222
+
223
+ prev_num_required = last_args.num_required
224
+
225
+ (overloads.length - 2).downto(0) do |i|
226
+ arglist = overloads[i].arglist
227
+
228
+ jump = prev_num_required - arglist.num_total
229
+ if jump > 1
230
+ nomatch_possible = true
231
+ fn.passed_arg arglist.num_total
232
+ fn.git nomatch
233
+ end
234
+
235
+ if arglist.num_required == 0
236
+ if nomatch_possible
237
+ fn.goto overload_labels[i]
238
+ end
239
+ else
240
+ fn.passed_arg arglist.num_required - 1
241
+ fn.git overload_labels[i]
242
+ end
243
+
244
+ prev_num_required = arglist.num_required
245
+ end
246
+
247
+ if nomatch_possible
248
+ nomatch.set!
249
+ fn.push_const :ArgumentError
250
+ fn.push_literal "No matching overload"
251
+ fn.string_dup
252
+ fn.send :new, 1
253
+ fn.raise_exc
254
+ end
255
+ end
256
+
257
+ overloads.each_with_index do |overload, i|
258
+ arglist, body = overload.arglist, overload.body
259
+ overload_scope = OverloadScope.new(fn_scope)
260
+ fn.scopes << overload_scope
261
+
262
+ # Check if there are any duplicate names in the argument list.
263
+ argnames = arglist.required_args + arglist.optional_args.map(&:first)
264
+ argnames << arglist.rest_arg if arglist.rest_arg
265
+ argnames << arglist.block_arg if arglist.block_arg
266
+ dup_name = argnames.detect {|name| argnames.count(name) > 1 }
267
+ g.compile_error "Duplicate argument name '#{dup_name}'" if dup_name
268
+
269
+ overload_labels[i].set! if overloads.length > 1
270
+
271
+ # Allocate slots for the required arguments
272
+ arglist.required_args.each {|arg| overload_scope.new_local(arg) }
273
+
274
+ next_optional = fn.new_label
275
+
276
+ arglist.optional_args.each_with_index do |(name, value), i|
277
+ # Calculate the position of this optional arg, off the end of the
278
+ # required args
279
+ arg_index = arglist.num_required + i
280
+
281
+ # Allocate a slot for this optional argument
282
+ overload_scope.new_local(name)
283
+
284
+ fn.passed_arg arg_index
285
+ fn.git next_optional
286
+
287
+ Compiler.bytecode(fn, value)
288
+ fn.set_local arg_index
289
+ fn.pop
290
+
291
+ next_optional.set!
292
+ next_optional = fn.new_label
293
+ end
294
+
295
+ if arglist.rest_arg
296
+ # Allocate the slot for the rest argument
297
+ overload_scope.new_local(arglist.rest_arg)
298
+ overload_scope.splat = true
299
+ end
300
+
301
+ overload_scope.loop_label = next_optional
302
+ overload_scope.loop_label.set!
303
+
304
+ # Allocate the slot for the block argument
305
+ if arglist.block_arg
306
+ overload_scope.new_local(arglist.block_arg)
307
+ overload_scope.block_arg = arglist.block_arg
308
+ fn.push_proc
309
+ fn.set_local overload_scope.find_var(arglist.block_arg).slot
310
+ fn.pop
311
+ end
312
+
313
+ fn.tail_position = true
314
+ SpecialForm[:do].bytecode(fn, body)
315
+ fn.ret
316
+
317
+ # TODO: does this make any sense with overloads?
318
+ fn.local_count += overload_scope.local_count
319
+ fn.local_names += overload_scope.local_names
320
+
321
+ # Pop the overload scope
322
+ fn.scopes.pop
323
+ end
324
+
325
+ fn.close
326
+
327
+ # Use the maximum total args
328
+ fn.total_args = overloads.last.arglist.num_total
329
+ # Use the minimum required args
330
+ fn.required_args = overloads.first.arglist.num_required
331
+
332
+ # If there is a rest arg, it will appear after all the required and
333
+ # optional arguments.
334
+ fn.splat_index = overloads.last.arglist.num_total if overloads.last.arglist.rest_arg
335
+
336
+ g.push_const :Kernel
337
+ g.create_block fn
338
+ g.send_with_block :lambda, 0
339
+ g.set_local fn_scope.self_reference.slot if fn_name
340
+ end
341
+ end
342
+ end