lisp 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 728f826f5c7ad7f2b90d6861cdd6d0792c9af21f
4
- data.tar.gz: 21b608d9ee103ad308ab4a2b346f459609684120
3
+ metadata.gz: 8415c51f19fcf2d2407b4e648726362aed1ff518
4
+ data.tar.gz: d7fa8e0de34061c8dcdb030a50b382fd77a9d627
5
5
  SHA512:
6
- metadata.gz: 451e92aa8b46ea6b0ad3b6d7bab7b0118052f2ec43fdc3c9779ce93817e6a178e6cf99c11e92732e193b952d8f65375eac2338f0360bac181ad892270d14d999
7
- data.tar.gz: d297679c014dfa9f0c52be2e8e73baf9c9175e4b3a1038440da0cb20d2597139a526a68d90845d0ab6efdec0f2ef55ae567af36c0219a45ec333d02c31554b3e
6
+ metadata.gz: 3c38eaf6967bc43c5ab122095664cd41ae9a2f36dde51207f4c926592c4ff7431a033942ad8cf0c695385f59e011f6f68571141ee77ed2e0774e967c4154e905
7
+ data.tar.gz: 14f4a2af0e2b7413301f6b86ee1d3ce0228f1806244ac98cccf5c6179bbbac28dd33e6a21a6e17cec7a2015dc6a8f255c8f8ec028599b328522f51c9ca360f2a
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  Gemfile.lock
2
2
  env
3
3
  pkg
4
+ coverage
data/Gemfile CHANGED
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- group :development do
3
+ group :test do
4
+ gem "simplecov"
4
5
  gem "codeclimate-test-reporter", require: nil
5
6
  end
6
7
 
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
- lisp-rb
2
- =======
1
+ lisp
2
+ ====
3
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)
4
+ [![Code Climate](https://codeclimate.com/github/jamesmoriarty/lisp-rb/badges/gpa.svg)](https://codeclimate.com/github/jamesmoriarty/lisp-rb) [![Test Coverage](https://codeclimate.com/github/jamesmoriarty/lisp-rb/badges/coverage.svg)](https://codeclimate.com/github/jamesmoriarty/lisp-rb/coverage)
5
5
 
6
- Lisp Interpreter in Ruby. Inspired by [Lis.py](http://norvig.com/lispy.html).
6
+ Lisp Interpreter in the Ruby Programming Language - 70 LOC. Inspired by [Lis.py](http://norvig.com/lispy.html).
7
7
 
8
8
  ```
9
9
  $ lisp-rb
@@ -2,4 +2,4 @@
2
2
 
3
3
  require_relative "../lib/lisp"
4
4
 
5
- Lisp.repl
5
+ Lisp::REPL.new.run
@@ -4,64 +4,64 @@ require "lisp/version"
4
4
  require "lisp/repl"
5
5
 
6
6
  module Lisp
7
- def self.eval(string)
8
- execute(parse(tokenize(string)))
7
+ def self.eval string
8
+ execute parse tokenize string
9
9
  end
10
10
 
11
- def self.tokenize(string)
11
+ def self.tokenize string
12
12
  string.gsub("("," ( ").gsub(")"," ) ").split
13
13
  end
14
14
 
15
- def self.parse(tokens, tree = [])
15
+ def self.parse tokens, tree = []
16
16
  raise "unexpected: eof" if tokens.size.zero?
17
17
 
18
18
  case token = tokens.shift
19
19
  when "("
20
20
  while tokens[0] != ")" do
21
- tree.push parse(tokens)
21
+ tree.push parse tokens
22
22
  end
23
23
  tokens.shift
24
24
  tree
25
25
  when ")"
26
26
  raise "unexpected: )"
27
27
  else
28
- evaluator(token)
28
+ atom token
29
29
  end
30
30
  end
31
31
 
32
- def self.evaluator(token)
32
+ def self.atom token
33
33
  case token
34
34
  when /\d/
35
- token.to_f
35
+ token.to_f % 1 > 0 ? token.to_f : token.to_i
36
36
  else
37
37
  token.to_sym
38
38
  end
39
39
  end
40
40
 
41
- def self.execute(exp, scope = global)
42
- return scope[exp] if exp.is_a? Symbol
43
- return exp unless exp.is_a? Array
41
+ def self.execute expression, scope = global
42
+ return scope[expression] if expression.is_a? Symbol
43
+ return expression unless expression.is_a? Array
44
44
 
45
- case exp[0]
45
+ case expression[0]
46
46
  when :define
47
- _, var, exp = exp
48
- scope[var] = execute(exp, scope)
47
+ _, var, expression = expression
48
+ scope[var] = execute expression, scope
49
49
  when :lambda
50
- _, params, exp = exp
51
- lambda { |*args| execute(exp, scope.merge(Hash[params.zip(args)])) }
50
+ _, params, expression = expression
51
+ lambda { |*args| execute expression, scope.merge(Hash[params.zip(args)]) }
52
52
  when :if
53
- _, test, conseq, alt = exp
54
- exp = execute(test, scope) ? conseq : alt
55
- execute(exp, scope)
53
+ _, test, consequent, alternative = expression
54
+ expression = if execute test, scope then consequent else alternative end
55
+ execute expression, scope
56
56
  when :set!
57
- _, var, exp = exp
58
- if scope.has_key?(var) then scope[var] = execute(exp, scope) else raise "#{var} is undefined" end
57
+ _, var, expression = expression
58
+ if scope.has_key?(var) then scope[var] = execute expression, scope else raise "#{var} is undefined" end
59
59
  when :begin
60
- _, *exp = exp
61
- exp.map { |exp| execute(exp) }.last
60
+ _, *expression = expression
61
+ expression.map { |expression| execute expression }.last
62
62
  else
63
- func, *args = exp.map { |exp| execute(exp, scope) }
64
- func.call(*args)
63
+ function, *args = expression.map { |expression| execute expression, scope }
64
+ function.call *args
65
65
  end
66
66
  end
67
67
 
@@ -69,7 +69,7 @@ module Lisp
69
69
  @scope ||= begin
70
70
  operators = [:==, :"!=", :"<", :"<=", :">", :">=", :+, :-, :*, :/]
71
71
  operators.inject({}) do |scope, operator|
72
- scope.merge(operator => lambda { |*args| args.inject(&operator) })
72
+ scope.merge operator => lambda { |*args| args.inject &operator }
73
73
  end
74
74
  end
75
75
  end
@@ -1,22 +1,67 @@
1
1
  #!/usr/bin/env ruby
2
2
  require "coolline"
3
+ require "coderay"
3
4
 
4
5
  module Lisp
5
- def self.repl
6
- trap("SIGINT") { throw :exit }
7
- puts "ctrl-c to exit"
8
- catch(:exit) do
9
- loop do
10
- puts begin
11
- eval Coolline.new.readline
12
- rescue Exception => e
13
- e.message
6
+ class REPL
7
+ attr_reader :io, :input
8
+
9
+ def initialize
10
+ @io = Coolline.new do |config|
11
+ config.transform_proc = proc do
12
+ CodeRay.scan(config.line, :clojure).term
14
13
  end
15
14
  end
15
+
16
+ reset_input!
17
+ end
18
+
19
+ def run
20
+ trap("SIGINT") { throw :exit }
21
+
22
+ puts "ctrl-c to exit"
23
+
24
+ catch(:exit) do
25
+ loop do
26
+ begin
27
+ @input += io.readline prompt
28
+
29
+ if open_count == close_count
30
+ puts Lisp.eval input
31
+
32
+ reset_input!
33
+ end
34
+ rescue Exception => e
35
+ puts e.message
36
+
37
+ reset_input!
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def prompt
46
+ count = open_count - close_count
47
+ char = count > 0 ? ?( : ?)
48
+ "#{char * count}> "
49
+ end
50
+
51
+ def reset_input!
52
+ @input = String.new
16
53
  end
17
- end
18
- end
19
54
 
20
- if __FILE__ == $0
21
- Lisp.repl
55
+ def open_count
56
+ tokens.count(?()
57
+ end
58
+
59
+ def close_count
60
+ tokens.count(?))
61
+ end
62
+
63
+ def tokens
64
+ Lisp.tokenize input
65
+ end
66
+ end
22
67
  end
@@ -1,3 +1,3 @@
1
1
  module Lisp
2
- VERSION = "1.3.0"
2
+ VERSION = "1.4.0"
3
3
  end
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "coolline"
22
+ spec.add_dependency "coderay"
22
23
  spec.add_development_dependency "bundler", "~> 1.6"
23
24
  spec.add_development_dependency "rake"
24
- spec.add_development_dependency "pry"
25
25
  end
@@ -0,0 +1,2 @@
1
+ require "codeclimate-test-reporter"
2
+ CodeClimate::TestReporter.start
@@ -0,0 +1,5 @@
1
+ require 'simplecov'
2
+
3
+ SimpleCov.add_filter 'vendor'
4
+ SimpleCov.add_filter 'test'
5
+ SimpleCov.start
@@ -1,11 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
  require "bundler/setup"
3
- require "codeclimate-test-reporter"
4
- CodeClimate::TestReporter.start
5
- require "minitest/autorun"
6
- require "pry"
7
3
 
8
- require_relative "../lib/lisp"
4
+ Dir[File.expand_path(File.join(File.dirname(__FILE__),'support', '*.rb'))].each { |file| require file }
5
+
6
+ require "lisp"
7
+ require "minitest/autorun"
9
8
 
10
9
  class TestLisp < MiniTest::Unit::TestCase
11
10
 
@@ -39,8 +38,11 @@ class TestLisp < MiniTest::Unit::TestCase
39
38
  end
40
39
 
41
40
  def test_define
42
- Lisp.eval("(define pi 3.141592653)")
43
- assert_equal 6.283185306, Lisp.eval("(* pi 2)")
41
+ assert_equal 6.283185306, Lisp.eval(<<-eos)
42
+ (begin
43
+ (define pi 3.141592653)
44
+ (* pi 2))
45
+ eos
44
46
  end
45
47
 
46
48
  def test_if
@@ -53,13 +55,66 @@ class TestLisp < MiniTest::Unit::TestCase
53
55
  end
54
56
 
55
57
  def test_begin
56
- assert_equal 4, Lisp.eval("(begin (define x 1) (set! x (+ x 1)) (* x 2))")
58
+ assert_equal 4, Lisp.eval(<<-eos)
59
+ (begin
60
+ (define x 1)
61
+ (set! x (+ x 1)) (* x 2))
62
+ eos
57
63
  end
58
64
 
59
65
  def test_lambda
60
- Lisp.eval("(define area (lambda (r) (* 3.141592653 (* r r))))")
61
- assert_equal 28.274333877, Lisp.eval("(area 3)")
62
- Lisp.eval("(define fact (lambda (n) (if (<= n 1) 1 (* n (fact (- n 1))))))")
63
- assert_equal 3628800, Lisp.eval("(fact 10)")
66
+ assert_equal 28.274333877, Lisp.eval(<<-eos)
67
+ (begin
68
+ (define area
69
+ (lambda (r)
70
+ (* 3.141592653 (* r r))))
71
+ (area 3))
72
+ eos
73
+ end
74
+
75
+ def test_lambda_call_self
76
+ assert_equal 3628800, Lisp.eval(<<-eos)
77
+ (begin
78
+ (define fact
79
+ (lambda (n)
80
+ (if (<= n 1)
81
+ 1
82
+ (* n (fact (- n 1))))))
83
+ (fact 10))
84
+ eos
85
+ end
86
+
87
+ def test_lambda_call_arg
88
+ assert_equal 40, Lisp.eval(<<-eos)
89
+ (begin
90
+ (define twice (lambda (x) (* 2 x)))
91
+ (define repeat (lambda (f) (lambda (x) (f (f x)))))
92
+ ((repeat twice) 10)))
93
+ eos
94
+ end
95
+
96
+ def test_program
97
+ assert_equal 2, Lisp.eval(<<-eos)
98
+ (begin
99
+ (define incf
100
+ (lambda (x)
101
+ (set! x (+ x 1))))
102
+ (define one 1)
103
+ (incf one))
104
+ eos
105
+ end
106
+
107
+ def test_repl
108
+ pid = Process.pid
109
+ subject = Lisp::REPL.new
110
+ thread = Thread.new do
111
+ sleep 1
112
+ Process.kill("INT", pid)
113
+ thread.join
114
+ end
115
+
116
+ assert_output("ctrl-c to exit\n") do
117
+ subject.run
118
+ end
64
119
  end
65
120
  end
metadata CHANGED
@@ -1,69 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lisp
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Moriarty
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-23 00:00:00.000000000 Z
11
+ date: 2016-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: coolline
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - '>='
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: bundler
28
+ name: coderay
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - '>='
32
32
  - !ruby/object:Gem::Version
33
- version: '1.6'
34
- type: :development
33
+ version: '0'
34
+ type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - '>='
39
39
  - !ruby/object:Gem::Version
40
- version: '1.6'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rake
42
+ name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - ~>
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: '1.6'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - ~>
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: '1.6'
55
55
  - !ruby/object:Gem::Dependency
56
- name: pry
56
+ name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - '>='
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  description: ''
@@ -74,7 +74,7 @@ executables:
74
74
  extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
- - ".gitignore"
77
+ - .gitignore
78
78
  - Gemfile
79
79
  - LICENSE.txt
80
80
  - README.md
@@ -84,6 +84,8 @@ files:
84
84
  - lib/lisp/repl.rb
85
85
  - lib/lisp/version.rb
86
86
  - lisp.gemspec
87
+ - test/support/codeclimate.rb
88
+ - test/support/simplecov.rb
87
89
  - test/test_lisp.rb
88
90
  homepage: ''
89
91
  licenses:
@@ -95,19 +97,21 @@ require_paths:
95
97
  - lib
96
98
  required_ruby_version: !ruby/object:Gem::Requirement
97
99
  requirements:
98
- - - ">="
100
+ - - '>='
99
101
  - !ruby/object:Gem::Version
100
102
  version: '0'
101
103
  required_rubygems_version: !ruby/object:Gem::Requirement
102
104
  requirements:
103
- - - ">="
105
+ - - '>='
104
106
  - !ruby/object:Gem::Version
105
107
  version: '0'
106
108
  requirements: []
107
109
  rubyforge_project:
108
- rubygems_version: 2.2.2
110
+ rubygems_version: 2.0.14.1
109
111
  signing_key:
110
112
  specification_version: 4
111
113
  summary: Lisp Interpreter in Ruby.
112
114
  test_files:
115
+ - test/support/codeclimate.rb
116
+ - test/support/simplecov.rb
113
117
  - test/test_lisp.rb