lisp 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1cf99f338dad8c4b0c1a7c3b9495bb34c8afbdf8
4
+ data.tar.gz: 7f01cbd73045d4926fb1243afda90cc2c7b0b0b4
5
+ SHA512:
6
+ metadata.gz: 05a8a58b45328fd3e20c2dfb53be58040dd17962195bd15695d0530ab0425dfcdd437aa9378d640b5d39c399d7958519a96c6875909c3827495ede68b5293bc7
7
+ data.tar.gz: b3964b63d8e79e3ccf5f64b89615c184b3579a1e6b96c95eba1d4c89b58bdde10da15a7b98b822efda97625f852eadcb25167b62282af11e1678f71986d5144d
@@ -0,0 +1,2 @@
1
+ env
2
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ group :development do
4
+ gem "codeclimate-test-reporter", require: nil
5
+ end
6
+
7
+ gemspec
@@ -0,0 +1,35 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ lisp (1.0.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ codeclimate-test-reporter (0.3.0)
10
+ simplecov (>= 0.7.1, < 1.0.0)
11
+ coderay (1.1.0)
12
+ docile (1.1.3)
13
+ method_source (0.8.2)
14
+ multi_json (1.10.1)
15
+ pry (0.9.12.6)
16
+ coderay (~> 1.0)
17
+ method_source (~> 0.8)
18
+ slop (~> 3.4)
19
+ rake (10.3.1)
20
+ simplecov (0.8.2)
21
+ docile (~> 1.1.0)
22
+ multi_json
23
+ simplecov-html (~> 0.8.0)
24
+ simplecov-html (0.8.0)
25
+ slop (3.5.0)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ bundler (~> 1.6)
32
+ codeclimate-test-reporter
33
+ lisp!
34
+ pry
35
+ rake
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 James Moriarty
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,51 @@
1
+ lisp-rb
2
+ =======
3
+
4
+ [![Code Climate](https://codeclimate.com/github/jamesmoriarty/lisp-rb.png)](https://codeclimate.com/github/jamesmoriarty/lisp-rb) [![Code Climate](https://codeclimate.com/github/jamesmoriarty/lisp-rb/coverage.png)](https://codeclimate.com/github/jamesmoriarty/lisp-rb)
5
+
6
+ Lisp Interpreter in Ruby. Inspired by [Lis.py](http://norvig.com/lispy.html).
7
+
8
+ ```
9
+ > (define pi 3.14)
10
+ 3.14
11
+ > (* pi 2)
12
+ 6.28
13
+ > (define area (lambda (r) (* 3.141592653 (* r r))))
14
+ #<Proc:0x007f8af9c59ff0@./lisp.rb:44>
15
+ > (area 3)
16
+ 28.274333877
17
+ > (define fact (lambda (n) (if (<= n 1) 1 (* n (fact (- n 1))))))
18
+ #<Proc:0x007f9a4cc4acf0@./lisp.rb:63 (lambda)>
19
+ > (fact 10)
20
+ 3628800.0
21
+ ```
22
+
23
+ Install
24
+ -------
25
+ [![Gem Version](https://badge.fury.io/rb/lisp.svg)](http://badge.fury.io/rb/lisp)
26
+
27
+ ```
28
+ gem install lisp
29
+ ```
30
+
31
+ Features
32
+ --------
33
+
34
+ - [x] __constant literal number__ - A number evaluates to itself. _Example: 12 or -3.45e+6_
35
+
36
+ - [x] __procedure call__ - (proc exp...) If proc is anything other than one of the symbols if, set!, define, lambda, begin, or quote then it is treated as a procedure. It is evaluated using the same rules defined here. All the expressions are evaluated as well, and then the procedure is called with the list of expressions as arguments. _Example: (square 12) ⇒ 144_
37
+
38
+ - [x] __variable reference__ - var A symbol is interpreted as a variable name; its value is the variable's value. _Example: x_
39
+
40
+ - [x] __definition__ - (define var exp) Define a new variable and give it the value of evaluating the expression exp. _Examples: (define r 3) or (define square (lambda (x) (* x x)))._
41
+
42
+ - [x] __procedure__ - (lambda (var...) exp) Create a procedure with parameter(s) named var... and the expression as the body. _Example: (lambda (r) (* 3.141592653 (* r r)))_
43
+
44
+ - [x] __conditional__ - (if test conseq alt) Evaluate test; if true, evaluate and return conseq; otherwise evaluate and return alt. _Example: (if (< 10 20) (+ 1 1) (+ 3 3)) ⇒ 2_
45
+
46
+ - [ ] __quotation__ - (quote exp) Return the exp literally; do not evaluate it. _Example: (quote (a b c)) ⇒ (a b c)_
47
+
48
+ - [ ] __assignment__ - (set! var exp) Evaluate exp and assign that value to var, which must have been previously defined (with a define or as a parameter to an enclosing procedure). _Example: (set! x2 (* x x))_
49
+
50
+
51
+ - [ ] __sequencing__ - (begin exp...) Evaluate each of the expressions in left-to-right order, and return the final value. _Example: (begin (set! x 1) (set! x (+ x 1)) (* x 2)) ⇒ 4_
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+
5
+ task :default do
6
+ Dir.glob('./test/*.rb').each { |file| require file}
7
+ end
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "lisp/version"
5
+ require "lisp/scope"
6
+
7
+ module Lisp
8
+ def self.repl
9
+ puts "ctrl-c to exit"
10
+ catch(:exit) do
11
+ loop do
12
+ print "> "
13
+ puts begin
14
+ eval gets
15
+ rescue Exception => e
16
+ e.message
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ def self.eval(string)
23
+ execute(parse(tokenize(string)))
24
+ end
25
+
26
+ def self.tokenize(string)
27
+ string.gsub("("," ( ").gsub(")"," ) ").split
28
+ end
29
+
30
+ def self.parse(tokens, tree = [])
31
+ raise "unexpected: eof" if tokens.size.zero?
32
+ token = tokens.shift
33
+ case token
34
+ when "("
35
+ while tokens[0] != ")" do
36
+ tree.push parse(tokens)
37
+ end
38
+ tokens.shift
39
+ tree
40
+ when ")"
41
+ raise "unexpected: )"
42
+ else
43
+ evaluator(token)
44
+ end
45
+ end
46
+
47
+ def self.evaluator(token)
48
+ case token
49
+ when /\d/
50
+ token.to_f
51
+ else
52
+ token.to_sym
53
+ end
54
+ end
55
+
56
+ def self.execute(exp, scope = global)
57
+ case exp
58
+ when Array
59
+ case exp[0]
60
+ when :define
61
+ _, var, exp = exp
62
+ scope[var] = execute(exp, scope)
63
+ when :lambda
64
+ _, params, exp = exp
65
+ lambda { |*args| execute(exp, Scope.new(params, args, scope)) }
66
+ when :if
67
+ _, test, conseq, alt = exp
68
+ exp = execute(test, scope) ? conseq : alt
69
+ execute(exp, scope)
70
+ else
71
+ func, *args = exp.map { |exp| execute(exp, scope) }
72
+ func.call(*args)
73
+ end
74
+ when Symbol
75
+ scope[exp]
76
+ else
77
+ exp
78
+ end
79
+ end
80
+
81
+ def self.global
82
+ @scope ||= begin
83
+ methods = [:==, :"!=", :"<", :"<=", :">", :">=", :+, :-, :*, :/]
84
+ methods.inject(Scope.new) do |scope, method|
85
+ scope.merge(method => lambda { |*args| args.inject(&method) })
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ if __FILE__ == $0
92
+ trap("SIGINT") { throw :exit }
93
+ Lisp.repl
94
+ end
@@ -0,0 +1,14 @@
1
+ module Lisp
2
+ class Scope < Hash
3
+ attr_accessor :outer
4
+
5
+ def initialize(params = [], args = [], outer = nil)
6
+ update(Hash[params.zip(args)])
7
+ self.outer = outer
8
+ end
9
+
10
+ def [](name)
11
+ super or outer[name]
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module Lisp
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'lisp/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "lisp"
8
+ spec.version = Lisp::VERSION
9
+ spec.authors = ["James Moriarty"]
10
+ spec.email = ["jamespaulmoriarty@gmail.com"]
11
+ spec.summary = %q{Lisp Interpreter in Ruby.}
12
+ spec.description = ""
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "pry"
24
+ end
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+ require "bundler/setup"
3
+ require "codeclimate-test-reporter"
4
+ CodeClimate::TestReporter.start
5
+ require "minitest/autorun"
6
+ require "pry"
7
+
8
+ require_relative "../lib/lisp"
9
+
10
+ class TestLisp < MiniTest::Unit::TestCase
11
+
12
+ # parser
13
+
14
+ def test_tokenize
15
+ assert_equal ["(", "+", "1", "1", ")"], Lisp.tokenize("(+ 1 1)")
16
+ end
17
+
18
+ def test_parse
19
+ assert_raises(RuntimeError) { Lisp.parse(Lisp.tokenize("(")) }
20
+ assert_raises(RuntimeError) { Lisp.parse(Lisp.tokenize(")")) }
21
+ end
22
+
23
+ # representation
24
+
25
+ def test_representation
26
+ assert_equal [:*, 2, [:+, 1, 0]], Lisp.parse(Lisp.tokenize("(* 2 (+ 1 0) )"))
27
+ assert_equal [:lambda, [:r], [:*, 3.141592653, [:*, :r, :r]]], Lisp.parse(Lisp.tokenize("(lambda (r) (* 3.141592653 (* r r)))"))
28
+ end
29
+
30
+ # execution
31
+
32
+ def test_execution
33
+ assert_equal 1, Lisp.execute(1)
34
+ assert_equal 2, Lisp.execute([:*, 2, [:+, 1, 0]])
35
+ end
36
+
37
+ def test_eval
38
+ assert_equal 2, Lisp.eval("(* 2 (+ 1 0) )")
39
+ end
40
+
41
+ def test_define
42
+ Lisp.eval("(define pi 3.141592653)")
43
+ assert_equal 6.283185306, Lisp.eval("(* pi 2)")
44
+ end
45
+
46
+ def test_if
47
+ assert_equal 2, Lisp.eval("(if(== 1 2) 1 2)")
48
+ assert_equal 1, Lisp.eval("(if(!= 1 2) 1 2)")
49
+ end
50
+
51
+ def test_lambda
52
+ Lisp.eval("(define area (lambda (r) (* 3.141592653 (* r r))))")
53
+ assert_equal 28.274333877, Lisp.eval("(area 3)")
54
+ Lisp.eval("(define fact (lambda (n) (if (<= n 1) 1 (* n (fact (- n 1))))))")
55
+ assert_equal 3628800, Lisp.eval("(fact 10)")
56
+ end
57
+
58
+ def test_repl
59
+ assert_output "ctrl-c to exit\n> " do
60
+ thread = Thread.new { Lisp.repl }
61
+ sleep 1.0/10.0
62
+ thread.terminate
63
+ end
64
+ end
65
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lisp
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - James Moriarty
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: ''
56
+ email:
57
+ - jamespaulmoriarty@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - Gemfile.lock
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - lib/lisp.rb
69
+ - lib/lisp/scope.rb
70
+ - lib/lisp/version.rb
71
+ - lisp.gemspec
72
+ - test/test_lisp.rb
73
+ homepage: ''
74
+ licenses:
75
+ - MIT
76
+ metadata: {}
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 2.2.0
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Lisp Interpreter in Ruby.
97
+ test_files:
98
+ - test/test_lisp.rb