apricot 0.0.1
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/.gitignore +3 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +26 -0
- data/README.md +90 -0
- data/Rakefile +9 -0
- data/apricot.gemspec +22 -0
- data/bin/apricot +58 -0
- data/examples/bot.apr +23 -0
- data/examples/cinch-bot.apr +12 -0
- data/examples/hanoi.apr +10 -0
- data/examples/hello.apr +1 -0
- data/examples/plot.apr +28 -0
- data/examples/quine.apr +1 -0
- data/kernel/core.apr +928 -0
- data/lib/apricot/ast/identifier.rb +111 -0
- data/lib/apricot/ast/list.rb +99 -0
- data/lib/apricot/ast/literals.rb +240 -0
- data/lib/apricot/ast/node.rb +45 -0
- data/lib/apricot/ast/scopes.rb +147 -0
- data/lib/apricot/ast/toplevel.rb +66 -0
- data/lib/apricot/ast/variables.rb +64 -0
- data/lib/apricot/ast.rb +3 -0
- data/lib/apricot/compiler.rb +55 -0
- data/lib/apricot/cons.rb +27 -0
- data/lib/apricot/errors.rb +38 -0
- data/lib/apricot/generator.rb +15 -0
- data/lib/apricot/identifier.rb +91 -0
- data/lib/apricot/list.rb +96 -0
- data/lib/apricot/macroexpand.rb +47 -0
- data/lib/apricot/misc.rb +11 -0
- data/lib/apricot/namespace.rb +59 -0
- data/lib/apricot/parser.rb +541 -0
- data/lib/apricot/printers.rb +12 -0
- data/lib/apricot/repl.rb +254 -0
- data/lib/apricot/ruby_ext.rb +254 -0
- data/lib/apricot/seq.rb +44 -0
- data/lib/apricot/special_forms.rb +735 -0
- data/lib/apricot/stages.rb +60 -0
- data/lib/apricot/version.rb +3 -0
- data/lib/apricot.rb +30 -0
- data/spec/compiler_spec.rb +499 -0
- data/spec/identifier_spec.rb +58 -0
- data/spec/list_spec.rb +96 -0
- data/spec/parser_spec.rb +312 -0
- data/spec/spec_helper.rb +10 -0
- metadata +188 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color --require spec_helper
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rbx-head
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
apricot (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.2.1)
|
10
|
+
rake (10.0.3)
|
11
|
+
rspec (2.13.0)
|
12
|
+
rspec-core (~> 2.13.0)
|
13
|
+
rspec-expectations (~> 2.13.0)
|
14
|
+
rspec-mocks (~> 2.13.0)
|
15
|
+
rspec-core (2.13.0)
|
16
|
+
rspec-expectations (2.13.0)
|
17
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
18
|
+
rspec-mocks (2.13.0)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
apricot!
|
25
|
+
rake (~> 10.0.3)
|
26
|
+
rspec (~> 2.13.0)
|
data/README.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# Apricot [](http://travis-ci.org/programble/apricot) [](https://gemnasium.com/programble/apricot)
|
2
|
+
|
3
|
+
A Clojure-like Lisp on Rubinius.
|
4
|
+
|
5
|
+
Try to contain your excitement, please.
|
6
|
+
|
7
|
+
|
8
|
+
## Setup
|
9
|
+
To get Apricot up and running, make sure you have Rubinius and Bundler
|
10
|
+
installed. The easiest way to get Rubinius is with [RVM](https://rvm.io/).
|
11
|
+
Whenever you are using Apricot you need to be running Rubinius in Ruby 1.9
|
12
|
+
mode. We make this easy in the Apricot repository with the `.ruby-version`
|
13
|
+
file which RVM automatically reads to figure out which Ruby to switch to.
|
14
|
+
|
15
|
+
``` sh
|
16
|
+
$ rvm install rbx-head --1.9
|
17
|
+
$ rvm use rbx-head
|
18
|
+
$ gem install bundler
|
19
|
+
$ bundle
|
20
|
+
```
|
21
|
+
|
22
|
+
## The REPL
|
23
|
+
Apricot provides a nice read-eval-print-loop with line editing, history,
|
24
|
+
tab-completion, and some interesting commands like `!bytecode`. To enter the
|
25
|
+
REPL just run:
|
26
|
+
|
27
|
+
``` sh
|
28
|
+
$ bin/apricot
|
29
|
+
```
|
30
|
+
|
31
|
+
Once in the repl you can ask for help by using `!help` and you can exit with
|
32
|
+
`!exit`. See the documentation of any function with `(doc <name>)`. Play
|
33
|
+
around, read `kernel/core.apr` and try out our functions, and make some of
|
34
|
+
your own. Experiment. Tell us what you think!
|
35
|
+
|
36
|
+
``` clojure
|
37
|
+
apr> (+ 1 2 3)
|
38
|
+
=> 6
|
39
|
+
apr> (map (fn [x] (* x x)) (Range. 1 10))
|
40
|
+
=> [1 4 9 16 25 36 49 64 81 100]
|
41
|
+
apr> (defn square [x] (* x x))
|
42
|
+
=> #<Proc:0x330@(eval):3 (lambda)>
|
43
|
+
apr> (map square (Range. 1 10))
|
44
|
+
=> [1 4 9 16 25 36 49 64 81 100]
|
45
|
+
apr> (map (comp str square) (Range. 1 10))
|
46
|
+
=> ["1" "4" "9" "16" "25" "36" "49" "64" "81" "100"]
|
47
|
+
apr> (doc comp)
|
48
|
+
-------------------------
|
49
|
+
comp
|
50
|
+
([] [f] [f g] [f g h] [f1 f2 f3 & fs])
|
51
|
+
Take a set of functions and return a fn that is the composition of those
|
52
|
+
fns. The returned fn takes a variable number of args, applies the rightmost
|
53
|
+
of fns to the args, the next fn (right-to-left) to the result, etc.
|
54
|
+
=> nil
|
55
|
+
```
|
56
|
+
|
57
|
+
## Hello World
|
58
|
+
So you want to put your program in a file and not type it into the REPL? Sure:
|
59
|
+
|
60
|
+
``` sh
|
61
|
+
$ cat hello.apr
|
62
|
+
(puts "Hello, world!")
|
63
|
+
$ bin/apricot hello.apr
|
64
|
+
Hello, world!
|
65
|
+
```
|
66
|
+
|
67
|
+
## Contact / Bug Reports
|
68
|
+
Come visit us on [freenode](http://freenode.net/) in the #apricot channel, or
|
69
|
+
drop one of us an email. Please send your bug reports to the GitHub
|
70
|
+
[issue tracker](https://github.com/programble/apricot/issues). They will be
|
71
|
+
greatly appreciated!
|
72
|
+
|
73
|
+
|
74
|
+
## License
|
75
|
+
|
76
|
+
Copyright (c) 2012-2013, Curtis McEnroe <programble@gmail.com>
|
77
|
+
|
78
|
+
Copyright (c) 2012-2013, Scott Olson <scott@scott-olson.org>
|
79
|
+
|
80
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
81
|
+
purpose with or without fee is hereby granted, provided that the above
|
82
|
+
copyright notice and this permission notice appear in all copies.
|
83
|
+
|
84
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
85
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
86
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
87
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
88
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
89
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
90
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
data/Rakefile
ADDED
data/apricot.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
$LOAD_PATH.push File.expand_path("../lib", __FILE__)
|
2
|
+
require "apricot/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "apricot"
|
6
|
+
s.version = Apricot::VERSION
|
7
|
+
s.authors = ["Curtis McEnroe", "Scott Olson"]
|
8
|
+
s.email = ["programble@gmail.com", "scott@scott-olson.org"]
|
9
|
+
s.homepage = "https://github.com/programble/apricot"
|
10
|
+
s.license = "ISC"
|
11
|
+
s.summary = "A Clojure-like programming language on Rubinius"
|
12
|
+
s.description = "A compiler for a Clojure-like programming language on the Rubinius VM"
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
|
19
|
+
s.add_development_dependency "rake", "~> 10.0.3"
|
20
|
+
s.add_development_dependency "rspec", "~> 2.13.0"
|
21
|
+
end
|
22
|
+
|
data/bin/apricot
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/bin/env rbx
|
2
|
+
# vim: ft=ruby:
|
3
|
+
|
4
|
+
unless defined?(Rubinius)
|
5
|
+
$stderr.puts "Error: Apricot must be run on Rubinius."
|
6
|
+
exit 1
|
7
|
+
end
|
8
|
+
|
9
|
+
unless Rubinius.ruby19?
|
10
|
+
$stderr.puts "Warning: Apricot must be run in Ruby 1.9 mode, executing rbx -X19..."
|
11
|
+
exec("/usr/bin/env", "rbx", "-X19", file, *ARGV)
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'apricot'
|
15
|
+
|
16
|
+
evals = []
|
17
|
+
bytecode = false
|
18
|
+
|
19
|
+
options = Rubinius::Options.new "Usage: #{$0} [options] [program]", 20
|
20
|
+
options.doc "OPTIONS:"
|
21
|
+
|
22
|
+
options.on "-e", "CODE", "evaluate CODE and print the result" do |code|
|
23
|
+
evals << [:eval, code]
|
24
|
+
end
|
25
|
+
|
26
|
+
options.on "-B", "--bytecode", "print bytecode after compiling" do
|
27
|
+
bytecode = true
|
28
|
+
end
|
29
|
+
|
30
|
+
options.on "-h", "--help", "display this help" do
|
31
|
+
puts options
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
|
35
|
+
options.parse(ARGV).each do |file|
|
36
|
+
evals << [:file, file]
|
37
|
+
end
|
38
|
+
|
39
|
+
if evals.empty?
|
40
|
+
if $stdin.tty?
|
41
|
+
require 'apricot/repl'
|
42
|
+
Apricot::REPL.new('apr> ', bytecode).run
|
43
|
+
else
|
44
|
+
evals << [:stdin]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
evals.each do |type, *args|
|
49
|
+
case type
|
50
|
+
when :eval
|
51
|
+
Apricot::Compiler.eval(args.first, "(eval)", 1, bytecode)
|
52
|
+
when :stdin
|
53
|
+
Apricot::Compiler.eval(STDIN.read, "(stdin)", 1, bytecode)
|
54
|
+
when :file
|
55
|
+
# The code is executed as it compiles.
|
56
|
+
Apricot::Compiler.compile(args.first, nil, bytecode)
|
57
|
+
end
|
58
|
+
end
|
data/examples/bot.apr
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
; An example IRC bot. This does not reflect our vision for Apricot, just what
|
2
|
+
; features we currently have working.
|
3
|
+
|
4
|
+
(require "socket")
|
5
|
+
|
6
|
+
(defn send [io & parts]
|
7
|
+
(let [msg (apply str parts)]
|
8
|
+
(println "<< " msg)
|
9
|
+
(.print io msg "\r\n")))
|
10
|
+
|
11
|
+
(defn run-bot [nick username realname channel server [port 6667]]
|
12
|
+
(let [irc (TCPSocket. server port)]
|
13
|
+
(send irc "NICK " nick)
|
14
|
+
(send irc "USER " username " * * :" realname)
|
15
|
+
(while-let [line (.gets irc)]
|
16
|
+
(println ">> " line)
|
17
|
+
(when (.start_with? line "PING")
|
18
|
+
(send irc (.sub line "PING" "PONG")))
|
19
|
+
(when (.include? line "001")
|
20
|
+
(send irc "JOIN " channel)
|
21
|
+
(send irc "PRIVMSG " channel " :It works!")))))
|
22
|
+
|
23
|
+
(run-bot "apribot" "apr" "Apribot" "#apricot" "irc.freenode.net")
|
data/examples/hanoi.apr
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
; Print the solution of a towers of hanoi puzzle with n disks using pegs a, b,
|
2
|
+
; and c.
|
3
|
+
(defn hanoi [n a b c]
|
4
|
+
(when-not (zero? n)
|
5
|
+
(hanoi (dec n) a c b)
|
6
|
+
(println "Move disk " n " from peg " a " to peg " c)
|
7
|
+
(hanoi (dec n) b a c)))
|
8
|
+
|
9
|
+
; 5-disk example:
|
10
|
+
(hanoi 5 "A" "B" "C")
|
data/examples/hello.apr
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
(println "Hello, world!")
|
data/examples/plot.apr
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
; Just a quick and dirty graph plotter.
|
2
|
+
|
3
|
+
(defn plot [f x1 x2 xscale y1 y2 yscale]
|
4
|
+
(let [width (.ceil (* (- x2 x1) xscale))
|
5
|
+
height (.ceil (* (- y2 y1) yscale))
|
6
|
+
points (map (fn [x] [(.round (* xscale (- x x1)))
|
7
|
+
(.round (* yscale (- (f x) y1)))])
|
8
|
+
(.step x1 x2 (/ xscale)))
|
9
|
+
graph (Array. (inc height) | #(* " " width))]
|
10
|
+
(each [p points]
|
11
|
+
(let [x (first p)
|
12
|
+
y (second p)]
|
13
|
+
(when (<= 0 y height)
|
14
|
+
(#|.[]=| (graph (- height y)) x "*"))))
|
15
|
+
(each [line graph]
|
16
|
+
(println line))))
|
17
|
+
|
18
|
+
(println "Exponential:")
|
19
|
+
(plot Math/exp 0 5 10 0 20 1)
|
20
|
+
|
21
|
+
(println "Logarithm base 10:")
|
22
|
+
(plot Math/log10 1 15 5 0 1.5 10)
|
23
|
+
|
24
|
+
(println "Sine:")
|
25
|
+
(plot Math/sin 0 (* 4 Math::PI) 5 -1 1 5)
|
26
|
+
|
27
|
+
(println "Tangent:")
|
28
|
+
(plot Math/tan 0 (* 2 Math::PI) 10 -5 5 2)
|
data/examples/quine.apr
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
((fn [x] (println (list x (list (quote quote) x)))) (quote (fn [x] (println (list x (list (quote quote) x))))))
|