missinglisp 0.0.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 +7 -0
- data/lib/missinglisp.rb +174 -0
- metadata +39 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 42f4de8720dddb978bf21be93ef48d8aab819a588ac139245dcbafd541251e32
|
4
|
+
data.tar.gz: e370720f4a3f0eadda1afa9f38fb371eb68be30b886e8274241786d0549dbda0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e15a0228df6251a9615609bafdf2f182193ac01b71ef840640e14690571d3309eefe791fa1a76cfdc20db972dbc674de9fb45a413782560ba5bbf1e2d1912e50
|
7
|
+
data.tar.gz: ca39b773ab93ad1e52a0867810faa28537761da5a7840988e9e8cf77f9cd17e1d8983147d3e320eb23748914e51878ae20f4e713742dcabb9971b5401d88908b
|
data/lib/missinglisp.rb
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
class Lisp
|
2
|
+
def initial_env
|
3
|
+
{
|
4
|
+
car: ->(*ls) { ls[0][0] },
|
5
|
+
cdr: ->(*ls) { ls[0].drop 1 },
|
6
|
+
cons: ->(e, cell, *) { [e] + cell },
|
7
|
+
list: ->(*ls) { ls },
|
8
|
+
add: ->(*ls) { ls.sum },
|
9
|
+
sub: ->(hd, *tl) { tl.reduce(hd) { |sum, v| sum - v } },
|
10
|
+
mult: ->(*ls) { ls.reduce(:*) },
|
11
|
+
div: ->(hd, *tl) { tl.reduce(hd) { |sum, v| sum / v } },
|
12
|
+
|
13
|
+
eq: ->(a, b, *) { a == b },
|
14
|
+
lt: ->(a, b, *) { a < b },
|
15
|
+
leq: ->(a, b, *) { a <= b },
|
16
|
+
gt: ->(a, b, *) { a > b },
|
17
|
+
geq: ->(a, b, *) { a >= b },
|
18
|
+
|
19
|
+
p: ->(*ls) { p ls },
|
20
|
+
|
21
|
+
nil: []
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def eval(exp, env)
|
26
|
+
return exp if exp.is_a? Numeric
|
27
|
+
return env[exp] if exp.is_a? Symbol
|
28
|
+
|
29
|
+
# list
|
30
|
+
# Special forms
|
31
|
+
if exp[0] == :quote
|
32
|
+
return exp[1..]
|
33
|
+
elsif exp[0] == :if
|
34
|
+
_, test, e1, e2 = exp
|
35
|
+
test = self.eval(test, env)
|
36
|
+
return self.eval(e1, env) if test.is_a?(Array) && !test.empty?
|
37
|
+
return self.eval(e1, env) unless test.is_a?(Array) || !test
|
38
|
+
|
39
|
+
return self.eval(e2, env)
|
40
|
+
elsif exp[0] == :define
|
41
|
+
_, var, e = exp
|
42
|
+
env[var] = self.eval(e, env)
|
43
|
+
return []
|
44
|
+
elsif exp[0] == :lambda
|
45
|
+
_, params, e = exp
|
46
|
+
return ->(*args) { self.eval(e, env.merge(Hash[params.zip(args)])) }
|
47
|
+
end
|
48
|
+
|
49
|
+
args = exp[1..].map { |c| self.eval(c, env) }
|
50
|
+
env[exp.first]
|
51
|
+
.call(*args)
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse(program)
|
55
|
+
tokens = tokenize program
|
56
|
+
_parse tokens
|
57
|
+
end
|
58
|
+
|
59
|
+
def _parse(tokens)
|
60
|
+
return if tokens.empty?
|
61
|
+
|
62
|
+
token = tokens.shift
|
63
|
+
|
64
|
+
case token
|
65
|
+
when :L
|
66
|
+
list = []
|
67
|
+
|
68
|
+
while tokens.first != :J
|
69
|
+
raise 'unexpected end of input' if tokens.empty?
|
70
|
+
|
71
|
+
list << _parse(tokens)
|
72
|
+
end
|
73
|
+
tokens.shift
|
74
|
+
|
75
|
+
list
|
76
|
+
when :J
|
77
|
+
raise 'unexpected \'J\''
|
78
|
+
else
|
79
|
+
token
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def tokenize(s)
|
84
|
+
res = []
|
85
|
+
cur = ''
|
86
|
+
is_reading_digit = false
|
87
|
+
s.each_char do |c|
|
88
|
+
case c
|
89
|
+
when '_'
|
90
|
+
if cur != ''
|
91
|
+
if is_reading_digit
|
92
|
+
res.push cur.to_i
|
93
|
+
else
|
94
|
+
res.push cur.to_sym
|
95
|
+
end
|
96
|
+
|
97
|
+
cur = ''
|
98
|
+
is_reading_digit = false
|
99
|
+
end
|
100
|
+
when 'L'
|
101
|
+
if cur != ''
|
102
|
+
if is_reading_digit
|
103
|
+
res.push cur.to_i
|
104
|
+
cur = ''
|
105
|
+
is_reading_digit = false
|
106
|
+
res.push :L
|
107
|
+
next
|
108
|
+
end
|
109
|
+
|
110
|
+
cur += 'L' and next
|
111
|
+
end
|
112
|
+
|
113
|
+
res.push :L
|
114
|
+
when 'J'
|
115
|
+
if cur != ''
|
116
|
+
if is_reading_digit
|
117
|
+
res.push cur.to_i
|
118
|
+
cur = ''
|
119
|
+
is_reading_digit = false
|
120
|
+
res.push :J
|
121
|
+
next
|
122
|
+
end
|
123
|
+
|
124
|
+
cur += 'J' and next
|
125
|
+
end
|
126
|
+
|
127
|
+
res.push :J
|
128
|
+
when '0'..'9'
|
129
|
+
cur += c and next if cur != ''
|
130
|
+
|
131
|
+
is_reading_digit = true
|
132
|
+
cur = c
|
133
|
+
else
|
134
|
+
if is_reading_digit
|
135
|
+
res.push cur.to_i
|
136
|
+
cur = ''
|
137
|
+
is_reading_digit = false
|
138
|
+
end
|
139
|
+
|
140
|
+
cur += c
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
res.push cur.to_sym if cur != ''
|
145
|
+
|
146
|
+
res
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
module Kernel
|
151
|
+
# For irb
|
152
|
+
WHITE_LIST = %I[gets to_ary to_io to_str to_hash translate]
|
153
|
+
alias_method :base_method_missing, :method_missing
|
154
|
+
|
155
|
+
def eval_lisp(s)
|
156
|
+
@l ||= Lisp.new
|
157
|
+
@e ||= @l.initial_env
|
158
|
+
@l.eval(@l.parse(s), @e)
|
159
|
+
end
|
160
|
+
|
161
|
+
def method_missing(m, *args, &block)
|
162
|
+
if WHITE_LIST.include? m
|
163
|
+
base_method_missing(m, args, block)
|
164
|
+
end
|
165
|
+
|
166
|
+
eval_lisp m.to_s
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class Object
|
171
|
+
def self.const_missing(id)
|
172
|
+
eval_lisp id.to_s
|
173
|
+
end
|
174
|
+
end
|
metadata
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: missinglisp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yajima Soichi
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-05-10 00:00:00.000000000 Z
|
11
|
+
dependencies: []
|
12
|
+
email: jajima.jp@gmail.com
|
13
|
+
executables: []
|
14
|
+
extensions: []
|
15
|
+
extra_rdoc_files: []
|
16
|
+
files:
|
17
|
+
- lib/missinglisp.rb
|
18
|
+
homepage: https://github.com/jajimajp/missinglisp
|
19
|
+
licenses:
|
20
|
+
- MIT
|
21
|
+
metadata: {}
|
22
|
+
rdoc_options: []
|
23
|
+
require_paths:
|
24
|
+
- lib
|
25
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
requirements: []
|
36
|
+
rubygems_version: 3.6.2
|
37
|
+
specification_version: 4
|
38
|
+
summary: Lisp in Ruby variable names
|
39
|
+
test_files: []
|