14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
|
# File 'lib/obtuse/evaluator.rb', line 14
def eval(input, parsed = false)
if parsed == false
input = @transform.apply(@parser.parse(input))
end
input.each do |atom|
case atom
when Integer, String, Array, AST::Lambda
push atom
when :+, :-, :*, :/, :%, :^
atom = :** if atom == :^
x, y = pop 2
if Integer === x && Integer === y
push x.send(atom, y)
elsif String === x && Integer === y
case atom
when :+
push x + y.to_s
when :*
push x * y
when :%
push x % y
end
elsif String === x && String === y
case atom
when :+
push x + y
when :-
push (x.chars.to_a - y.chars.to_a).join
when :*
push x.chars.to_a.join(y)
end
elsif String === x && Array === y
case atom
when :%
push x % y
end
elsif Array === x
case atom
when :+
push x + Array(y)
when :-
push x - Array(y)
when :*
if Integer === y
push x * y
elsif String === y
push x.join(y)
elsif Array === y
first = x.shift
push x.reduce([first]) {|fold, el| fold + y + [el] }
elsif AST::Lambda === y
push x.shift
x.each do |el|
push el
eval y.expression, true
end
end
when :%
if AST::Lambda === y
stash
x.each do |el|
push el
eval y.expression, true
end
stack = @stack
unstash
push stack
end
end
else
end
when :"#"
x = pop
if Integer === x
push [*0...x]
elsif String === x || Array === x
push x.length
end
when :"$"
x = pop
if Integer === x
push @stack[-x - 1] if @stack[-x - 1]
elsif String === x
push x.chars.sort.join
elsif Array === x
push x.sort
elsif AST::Lambda === x
y = x
x = pop
case x
when String, Array
stash
array = String === x ? x.chars.to_a : x
array.sort_by! do |el|
@stack = []
push el
eval y.expression, true
@stack
end
unstash
push String === x ? array.join : array
end
end
when :~
x = pop
case x
when String
eval x
when Array
@stack += x
when AST::Lambda
eval x.expression, true
end
when :!
push truthy?(pop) ? 0 : 1
when :"@"
x, y, z = pop 3
push y; push z; push x
when :"."
x = peek
push x if x
when :";"
pop
when :"["
stash
when :"]"
stack = @stack
unstash
push stack
when :"=", :<, :>
atom = :== if atom == :"="
x, y = pop 2
if Integer === x && Integer === y ||
String === x && String === y ||
Array === x && Array === y
push x.send(atom, y) ? 1 : 0
end
when :"\\"
x, y = pop 2
push y; push x;
when :I
x, y, z = pop 3
if AST::Lambda === x
eval x.expression, true
if truthy?(pop)
AST::Lambda === y ? eval(y.expression, true) : push(y)
else
AST::Lambda === z ? eval(z.expression, true) : push(z)
end
else
if truthy?(x)
AST::Lambda === y ? eval(y.expression, true) : push(y)
else
AST::Lambda === z ? eval(z.expression, true) : push(z)
end
end
when :W
x, y = pop 2
if AST::Lambda === x && AST::Lambda === y
loop do
eval x.expression, true
break unless truthy?(pop)
eval y.expression, true
end
end
when :Ic
push pop.to_i.chr
when :Sg
x, y, z = pop 3
if (Integer === x || String === x) &&
(Integer === y || String === y) &&
(Integer === z || String === z)
push x.to_s.gsub(y.to_s, z.to_s)
end
when :Sl
push pop.to_s.downcase
when :Su
push pop.to_s.upcase
when :Sc
push pop.to_s.capitalize
when :So
push pop.to_s.ord
when :Si
x, y = pop 2
push x.to_s.include?(y.to_s) ? 1 : 0
when :St
x, y, z = pop 3
push x.to_s.tr(y.to_s, z.to_s)
when :Ra
push stdin.read.chomp
when :Rl
push stdin.gets.chomp
end
end
end
|