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.
Files changed (49) hide show
  1. data/.gitignore +3 -0
  2. data/.rspec +1 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +7 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +26 -0
  7. data/README.md +90 -0
  8. data/Rakefile +9 -0
  9. data/apricot.gemspec +22 -0
  10. data/bin/apricot +58 -0
  11. data/examples/bot.apr +23 -0
  12. data/examples/cinch-bot.apr +12 -0
  13. data/examples/hanoi.apr +10 -0
  14. data/examples/hello.apr +1 -0
  15. data/examples/plot.apr +28 -0
  16. data/examples/quine.apr +1 -0
  17. data/kernel/core.apr +928 -0
  18. data/lib/apricot/ast/identifier.rb +111 -0
  19. data/lib/apricot/ast/list.rb +99 -0
  20. data/lib/apricot/ast/literals.rb +240 -0
  21. data/lib/apricot/ast/node.rb +45 -0
  22. data/lib/apricot/ast/scopes.rb +147 -0
  23. data/lib/apricot/ast/toplevel.rb +66 -0
  24. data/lib/apricot/ast/variables.rb +64 -0
  25. data/lib/apricot/ast.rb +3 -0
  26. data/lib/apricot/compiler.rb +55 -0
  27. data/lib/apricot/cons.rb +27 -0
  28. data/lib/apricot/errors.rb +38 -0
  29. data/lib/apricot/generator.rb +15 -0
  30. data/lib/apricot/identifier.rb +91 -0
  31. data/lib/apricot/list.rb +96 -0
  32. data/lib/apricot/macroexpand.rb +47 -0
  33. data/lib/apricot/misc.rb +11 -0
  34. data/lib/apricot/namespace.rb +59 -0
  35. data/lib/apricot/parser.rb +541 -0
  36. data/lib/apricot/printers.rb +12 -0
  37. data/lib/apricot/repl.rb +254 -0
  38. data/lib/apricot/ruby_ext.rb +254 -0
  39. data/lib/apricot/seq.rb +44 -0
  40. data/lib/apricot/special_forms.rb +735 -0
  41. data/lib/apricot/stages.rb +60 -0
  42. data/lib/apricot/version.rb +3 -0
  43. data/lib/apricot.rb +30 -0
  44. data/spec/compiler_spec.rb +499 -0
  45. data/spec/identifier_spec.rb +58 -0
  46. data/spec/list_spec.rb +96 -0
  47. data/spec/parser_spec.rb +312 -0
  48. data/spec/spec_helper.rb +10 -0
  49. metadata +188 -0
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *.rbc
2
+ .rbx
3
+ *.gem
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
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - rbx-19mode
4
+
5
+ notifications:
6
+ webhooks:
7
+ - http://rcmp.tenthbit.net/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ # It seems impossible to make Travis CI and my computer agree on this.
4
+ #ruby "1.9.3", :engine => "rbx", :engine_version => "2.0.0.rc1"
5
+
6
+ gemspec
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 [![Build Status](https://secure.travis-ci.org/programble/apricot.png?branch=master)](http://travis-ci.org/programble/apricot) [![Dependency Status](https://gemnasium.com/programble/apricot.png?travis)](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
@@ -0,0 +1,9 @@
1
+ require 'bundler/setup'
2
+ require 'rspec/core'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec) do |spec|
6
+ spec.pattern = FileList['spec/**/*_spec.rb']
7
+ end
8
+
9
+ task :default => :spec
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")
@@ -0,0 +1,12 @@
1
+ (require "cinch")
2
+
3
+ (doto (Cinch::Bot.)
4
+ (.configure | #(doto %
5
+ (.server= "irc.tenthbit.net")
6
+ (.nick= "apribot")
7
+ (.channels= ["#programming"])))
8
+
9
+ (.on :message #r/^apribot[:,]?\s+(.+)/
10
+ | (fn [m msg] (.reply m msg true)))
11
+
12
+ .start)
@@ -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")
@@ -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)
@@ -0,0 +1 @@
1
+ ((fn [x] (println (list x (list (quote quote) x)))) (quote (fn [x] (println (list x (list (quote quote) x))))))