apricot 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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))))))