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.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/missinglisp.rb +174 -0
  3. 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
@@ -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: []