lisp 1.5.0 → 1.5.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.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yaml +19 -0
- data/.gitignore +2 -0
- data/Gemfile +3 -3
- data/README.md +27 -3
- data/Rakefile +25 -3
- data/lib/lisp.rb +2 -70
- data/lib/lisp/interpreter.rb +74 -0
- data/lib/lisp/repl.rb +0 -2
- data/lib/lisp/version.rb +1 -1
- data/lisp.gemspec +1 -0
- data/test/{test_lisp.rb → lisp_test.rb} +5 -2
- metadata +7 -7
- data/.travis.yml +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3140fcbe7a7a85548c0efa3d612b29cc3fdd0cb152f90c913c6c3814c8425b36
|
4
|
+
data.tar.gz: 2c48b33ebed20827bd71168ff5c3a54ee064682d3dc1abfaaf3a5679f7f92777
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e642ce75f5b2aea99869cf57049c722dedb51afaff16d49d9108ef665bc500564589c848a64bdb9ca3822866a2e7c0ce74cfa59723d675608c9862600d3c2262
|
7
|
+
data.tar.gz: 0511e2a95f6bf7851f29ab4e46ce33f2a927deb9efd9e463ad819b836113b3d3953781adb1301e86d35a3634a7b8e04bd141cbe4839a0ac7bf182da03f524b15
|
@@ -0,0 +1,19 @@
|
|
1
|
+
name: Continuous Integration
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
build:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
|
9
|
+
strategy:
|
10
|
+
matrix:
|
11
|
+
ruby: [ '2.3', '2.7' ]
|
12
|
+
|
13
|
+
steps:
|
14
|
+
- uses: actions/checkout@v2
|
15
|
+
- uses: ruby/setup-ruby@v1
|
16
|
+
with:
|
17
|
+
ruby-version: ${{ matrix.ruby }}
|
18
|
+
bundler-cache: true
|
19
|
+
- run: bundle exec rake
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
lisp
|
2
2
|
====
|
3
3
|
|
4
|
-
![Gem][1] ![Build Status][2]
|
4
|
+
![Gem Version][3] ![Gem][1] ![Build Status][2]
|
5
5
|
|
6
|
-
Lisp
|
6
|
+
Minimal Lisp interpreter using 75LOC and only standard libraries excluding the REPL. Inspired by [Lis.py](http://norvig.com/lispy.html).
|
7
7
|
|
8
8
|
```clojure
|
9
9
|
$ lisp-repl
|
@@ -20,12 +20,36 @@ ctrl-c to exit
|
|
20
20
|
|
21
21
|
Install
|
22
22
|
-------
|
23
|
-
![Gem Version][3]
|
24
23
|
|
25
24
|
```
|
26
25
|
gem install lisp
|
27
26
|
```
|
28
27
|
|
28
|
+
Usage
|
29
|
+
-----
|
30
|
+
|
31
|
+
```clojure
|
32
|
+
require "lisp"
|
33
|
+
|
34
|
+
Lisp.eval(<<-eos)
|
35
|
+
(begin
|
36
|
+
(define fact
|
37
|
+
(lambda (n)
|
38
|
+
(if (<= n 1)
|
39
|
+
1
|
40
|
+
(* n (fact (- n 1))))))
|
41
|
+
(fact 10))
|
42
|
+
eos # => 3628800
|
43
|
+
```
|
44
|
+
|
45
|
+
Commandline
|
46
|
+
-----------
|
47
|
+
|
48
|
+
```
|
49
|
+
lisp-repl
|
50
|
+
```
|
51
|
+
|
52
|
+
|
29
53
|
Features
|
30
54
|
--------
|
31
55
|
|
data/Rakefile
CHANGED
@@ -1,7 +1,29 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
+
require "rake/testtask"
|
3
|
+
require 'yard'
|
2
4
|
|
3
|
-
|
5
|
+
YARD::Rake::YardocTask.new do |t|
|
6
|
+
t.files = ['lib/**/*.rb', 'README', 'CHANGELOG', 'CODE_OF_CONDUCT']
|
7
|
+
t.options = []
|
8
|
+
t.stats_options = ['--list-undoc']
|
9
|
+
end
|
10
|
+
|
11
|
+
Rake::TestTask.new(:test) do |t|
|
12
|
+
t.libs << "test"
|
13
|
+
t.libs << "lib"
|
14
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
15
|
+
end
|
4
16
|
|
5
|
-
|
6
|
-
|
17
|
+
namespace :gh do
|
18
|
+
desc "Deploy yard docs to github pages"
|
19
|
+
task :pages => :yard do
|
20
|
+
`git add -f doc`
|
21
|
+
`git commit -am "update: $(date)"`
|
22
|
+
`git subtree split --prefix doc -b gh-pages`
|
23
|
+
`git push -f origin gh-pages:gh-pages`
|
24
|
+
`git branch -D gh-pages`
|
25
|
+
`git reset head~1`
|
26
|
+
end
|
7
27
|
end
|
28
|
+
|
29
|
+
task :default => :test
|
data/lib/lisp.rb
CHANGED
@@ -1,76 +1,8 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
2
|
|
3
3
|
require "lisp/version"
|
4
|
+
require "lisp/interpreter"
|
4
5
|
require "lisp/repl"
|
5
6
|
|
6
7
|
module Lisp
|
7
|
-
def self.eval string
|
8
|
-
execute parse tokenize string
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.tokenize string
|
12
|
-
string.gsub("("," ( ").gsub(")"," ) ").split
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.parse tokens, tree = []
|
16
|
-
raise "unexpected: eof" if tokens.size.zero?
|
17
|
-
|
18
|
-
case token = tokens.shift
|
19
|
-
when "("
|
20
|
-
while tokens[0] != ")" do
|
21
|
-
tree.push parse tokens
|
22
|
-
end
|
23
|
-
tokens.shift
|
24
|
-
tree
|
25
|
-
when ")"
|
26
|
-
raise "unexpected: )"
|
27
|
-
else
|
28
|
-
atom token
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.atom token
|
33
|
-
case token
|
34
|
-
when /\d/
|
35
|
-
token.to_f % 1 > 0 ? token.to_f : token.to_i
|
36
|
-
else
|
37
|
-
token.to_sym
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.execute expression, scope = global
|
42
|
-
return scope.fetch(expression) { |var| raise "#{var} is undefined" } if expression.is_a? Symbol
|
43
|
-
return expression unless expression.is_a? Array
|
44
|
-
|
45
|
-
case expression[0]
|
46
|
-
when :define
|
47
|
-
_, var, expression = expression
|
48
|
-
scope[var] = execute expression, scope
|
49
|
-
when :lambda
|
50
|
-
_, params, expression = expression
|
51
|
-
lambda { |*args| execute expression, scope.merge(Hash[params.zip(args)]) }
|
52
|
-
when :if
|
53
|
-
_, test, consequent, alternative = expression
|
54
|
-
expression = if execute test, scope then consequent else alternative end
|
55
|
-
execute expression, scope
|
56
|
-
when :set!
|
57
|
-
_, var, expression = expression
|
58
|
-
if scope.has_key?(var) then scope[var] = execute expression, scope else raise "#{var} is undefined" end
|
59
|
-
when :begin
|
60
|
-
_, *expression = expression
|
61
|
-
expression.map { |expression| execute expression, scope }.last
|
62
|
-
else
|
63
|
-
function, *args = expression.map { |expression| execute expression, scope }
|
64
|
-
function.call *args
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def self.global
|
69
|
-
@scope ||= begin
|
70
|
-
operators = [:==, :"!=", :"<", :"<=", :">", :">=", :+, :-, :*, :/]
|
71
|
-
operators.inject({}) do |scope, operator|
|
72
|
-
scope.merge operator => lambda { |*args| args.inject &operator }
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
8
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Lisp
|
2
|
+
class << self
|
3
|
+
def eval string
|
4
|
+
execute parse tokenize string
|
5
|
+
end
|
6
|
+
|
7
|
+
def tokenize string
|
8
|
+
string.gsub("(", " ( ").gsub(")", " ) ").split
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse tokens, tree = []
|
12
|
+
raise "unexpected: eof" if tokens.size.zero?
|
13
|
+
|
14
|
+
case token = tokens.shift
|
15
|
+
when "("
|
16
|
+
while tokens[0] != ")" do
|
17
|
+
tree.push parse tokens
|
18
|
+
end
|
19
|
+
tokens.shift
|
20
|
+
tree
|
21
|
+
when ")"
|
22
|
+
raise "unexpected: )"
|
23
|
+
else
|
24
|
+
atom token
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def execute expression, scope = global
|
29
|
+
return scope.fetch(expression) { |var| raise "#{var} is undefined" } if expression.is_a? Symbol
|
30
|
+
return expression unless expression.is_a? Array
|
31
|
+
|
32
|
+
case expression[0]
|
33
|
+
when :define
|
34
|
+
_, var, expression = expression
|
35
|
+
scope[var] = execute expression, scope
|
36
|
+
when :lambda
|
37
|
+
_, params, expression = expression
|
38
|
+
lambda { |*args| execute expression, scope.merge(Hash[params.zip(args)]) }
|
39
|
+
when :if
|
40
|
+
_, test, consequent, alternative = expression
|
41
|
+
expression = if execute test, scope then consequent else alternative end
|
42
|
+
execute expression, scope
|
43
|
+
when :set!
|
44
|
+
_, var, expression = expression
|
45
|
+
if scope.has_key?(var) then scope[var] = execute expression, scope else raise "#{var} is undefined" end
|
46
|
+
when :begin
|
47
|
+
_, *expression = expression
|
48
|
+
expression.map { |expression| execute expression, scope }.last
|
49
|
+
else
|
50
|
+
function, *args = expression.map { |expression| execute expression, scope }
|
51
|
+
function.call *args
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def atom token
|
58
|
+
case token
|
59
|
+
when /^[\p{N}\.]+$/
|
60
|
+
token.to_f % 1 > 0 ? token.to_f : token.to_i
|
61
|
+
else
|
62
|
+
token.to_sym
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def global
|
67
|
+
operators = [:==, :"!=", :"<", :"<=", :">", :">=", :+, :-, :*, :/]
|
68
|
+
|
69
|
+
operators.inject({}) do |scope, operator|
|
70
|
+
scope.merge operator => lambda { |*args| args.inject &operator }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/lisp/repl.rb
CHANGED
data/lib/lisp/version.rb
CHANGED
data/lisp.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require "bundler/setup"
|
3
3
|
|
4
|
-
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support', '*.rb'))].each { |file| require file }
|
4
|
+
Dir[File.expand_path(File.join(File.dirname(__FILE__), 'support', '*.rb'))].each { |file| require file }
|
5
5
|
|
6
6
|
require "lisp"
|
7
7
|
require "minitest/autorun"
|
@@ -29,7 +29,8 @@ class TestLisp < MiniTest::Unit::TestCase
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def test_ast_call
|
32
|
-
assert_equal [:lambda, [:r], [:*, 3.141592653, [:*, :r, :r]]],
|
32
|
+
assert_equal [:lambda, [:r], [:*, 3.141592653, [:*, :r, :r]]],
|
33
|
+
Lisp.parse(Lisp.tokenize("(lambda (r) (* 3.141592653 (* r r)))"))
|
33
34
|
end
|
34
35
|
|
35
36
|
# execution
|
@@ -126,6 +127,8 @@ class TestLisp < MiniTest::Unit::TestCase
|
|
126
127
|
end
|
127
128
|
|
128
129
|
def test_repl
|
130
|
+
skip if ENV['CI']
|
131
|
+
|
129
132
|
pid = Process.pid
|
130
133
|
subject = Lisp::REPL.new
|
131
134
|
thread = Thread.new do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lisp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.
|
4
|
+
version: 1.5.1
|
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: 2021-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: coolline
|
@@ -88,19 +88,20 @@ executables:
|
|
88
88
|
extensions: []
|
89
89
|
extra_rdoc_files: []
|
90
90
|
files:
|
91
|
+
- ".github/workflows/ci.yaml"
|
91
92
|
- ".gitignore"
|
92
|
-
- ".travis.yml"
|
93
93
|
- Gemfile
|
94
94
|
- LICENSE.txt
|
95
95
|
- README.md
|
96
96
|
- Rakefile
|
97
97
|
- bin/lisp-repl
|
98
98
|
- lib/lisp.rb
|
99
|
+
- lib/lisp/interpreter.rb
|
99
100
|
- lib/lisp/repl.rb
|
100
101
|
- lib/lisp/version.rb
|
101
102
|
- lisp.gemspec
|
103
|
+
- test/lisp_test.rb
|
102
104
|
- test/support/simplecov.rb
|
103
|
-
- test/test_lisp.rb
|
104
105
|
homepage: ''
|
105
106
|
licenses:
|
106
107
|
- MIT
|
@@ -120,11 +121,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
121
|
- !ruby/object:Gem::Version
|
121
122
|
version: '0'
|
122
123
|
requirements: []
|
123
|
-
|
124
|
-
rubygems_version: 2.5.2.3
|
124
|
+
rubygems_version: 3.0.3
|
125
125
|
signing_key:
|
126
126
|
specification_version: 4
|
127
127
|
summary: Lisp Interpreter in Ruby.
|
128
128
|
test_files:
|
129
|
+
- test/lisp_test.rb
|
129
130
|
- test/support/simplecov.rb
|
130
|
-
- test/test_lisp.rb
|
data/.travis.yml
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
sudo: false
|
2
|
-
|
3
|
-
language: ruby
|
4
|
-
|
5
|
-
rvm:
|
6
|
-
- 2.3.8
|
7
|
-
|
8
|
-
env:
|
9
|
-
global:
|
10
|
-
- CC_TEST_REPORTER_ID=0a4c13b71635c00cee43aba776853ade9404cc745c42977e25a5877a3e148527
|
11
|
-
|
12
|
-
before_script:
|
13
|
-
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
14
|
-
- chmod +x ./cc-test-reporter
|
15
|
-
- ./cc-test-reporter before-build
|
16
|
-
- gem install bundler -v 2.0.2
|
17
|
-
|
18
|
-
after_script:
|
19
|
-
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|