lisp 1.3.0 → 1.4.0
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile +2 -1
- data/README.md +4 -4
- data/bin/lisp-rb +1 -1
- data/lib/lisp.rb +26 -26
- data/lib/lisp/repl.rb +58 -13
- data/lib/lisp/version.rb +1 -1
- data/lisp.gemspec +1 -1
- data/test/support/codeclimate.rb +2 -0
- data/test/support/simplecov.rb +5 -0
- data/test/test_lisp.rb +67 -12
- metadata +26 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8415c51f19fcf2d2407b4e648726362aed1ff518
|
4
|
+
data.tar.gz: d7fa8e0de34061c8dcdb030a50b382fd77a9d627
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c38eaf6967bc43c5ab122095664cd41ae9a2f36dde51207f4c926592c4ff7431a033942ad8cf0c695385f59e011f6f68571141ee77ed2e0774e967c4154e905
|
7
|
+
data.tar.gz: 14f4a2af0e2b7413301f6b86ee1d3ce0228f1806244ac98cccf5c6179bbbac28dd33e6a21a6e17cec7a2015dc6a8f255c8f8ec028599b328522f51c9ca360f2a
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
lisp
|
2
|
-
|
1
|
+
lisp
|
2
|
+
====
|
3
3
|
|
4
|
-
[](https://codeclimate.com/github/jamesmoriarty/lisp-rb) [](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
|
data/bin/lisp-rb
CHANGED
data/lib/lisp.rb
CHANGED
@@ -4,64 +4,64 @@ require "lisp/version"
|
|
4
4
|
require "lisp/repl"
|
5
5
|
|
6
6
|
module Lisp
|
7
|
-
def self.eval
|
8
|
-
execute
|
7
|
+
def self.eval string
|
8
|
+
execute parse tokenize string
|
9
9
|
end
|
10
10
|
|
11
|
-
def self.tokenize
|
11
|
+
def self.tokenize string
|
12
12
|
string.gsub("("," ( ").gsub(")"," ) ").split
|
13
13
|
end
|
14
14
|
|
15
|
-
def self.parse
|
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
|
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
|
-
|
28
|
+
atom token
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
def self.
|
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
|
42
|
-
return scope[
|
43
|
-
return
|
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
|
45
|
+
case expression[0]
|
46
46
|
when :define
|
47
|
-
_, var,
|
48
|
-
scope[var]
|
47
|
+
_, var, expression = expression
|
48
|
+
scope[var] = execute expression, scope
|
49
49
|
when :lambda
|
50
|
-
_, params,
|
51
|
-
lambda { |*args| execute
|
50
|
+
_, params, expression = expression
|
51
|
+
lambda { |*args| execute expression, scope.merge(Hash[params.zip(args)]) }
|
52
52
|
when :if
|
53
|
-
_, test,
|
54
|
-
|
55
|
-
execute
|
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,
|
58
|
-
if scope.has_key?(var) then scope[var] = execute
|
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
|
-
_, *
|
61
|
-
|
60
|
+
_, *expression = expression
|
61
|
+
expression.map { |expression| execute expression }.last
|
62
62
|
else
|
63
|
-
|
64
|
-
|
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
|
72
|
+
scope.merge operator => lambda { |*args| args.inject &operator }
|
73
73
|
end
|
74
74
|
end
|
75
75
|
end
|
data/lib/lisp/repl.rb
CHANGED
@@ -1,22 +1,67 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require "coolline"
|
3
|
+
require "coderay"
|
3
4
|
|
4
5
|
module Lisp
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
21
|
-
|
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
|
data/lib/lisp/version.rb
CHANGED
data/lisp.gemspec
CHANGED
@@ -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
|
data/test/test_lisp.rb
CHANGED
@@ -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
|
-
|
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(
|
43
|
-
|
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(
|
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(
|
61
|
-
|
62
|
-
|
63
|
-
|
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.
|
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:
|
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:
|
28
|
+
name: coderay
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - '>='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
34
|
-
type: :
|
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: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
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: '
|
54
|
+
version: '1.6'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
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
|
-
-
|
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.
|
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
|