razyk 0.0.1 → 0.1.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/.gitignore +25 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +54 -0
- data/Rakefile +7 -55
- data/bin/razyk +1 -67
- data/examples/air_on_the_g_string.lazy +489 -0
- data/examples/air_on_the_g_string.score +14 -0
- data/examples/encoder.rb +62 -0
- data/examples/hello_world.lazy +39 -0
- data/examples/major_scale.lazy +20 -0
- data/examples/minor_scale.lazy +20 -0
- data/examples/score2lazy.rb +38 -0
- data/lib/razyk.rb +7 -2
- data/lib/razyk/application.rb +108 -0
- data/lib/razyk/audio.rb +8 -0
- data/lib/razyk/audio/player.rb +68 -0
- data/lib/razyk/audio/port.rb +36 -0
- data/lib/razyk/node.rb +49 -1
- data/lib/razyk/parser.rb +16 -20
- data/lib/razyk/parser.y +15 -19
- data/lib/razyk/version.rb +3 -0
- data/lib/razyk/vm.rb +52 -54
- data/lib/razyk/webapp.rb +61 -108
- data/lib/razyk/webapp/templates/main.html +216 -49
- data/razyk.gemspec +27 -66
- metadata +163 -86
- data/spec/node_spec.rb +0 -58
- data/spec/spec_helper.rb +0 -5
- data/spec/vm_spec.rb +0 -128
data/lib/razyk/node.rb
CHANGED
@@ -54,15 +54,54 @@ module RazyK
|
|
54
54
|
self.class.disconnect(self, a)
|
55
55
|
self.class.connect(self, b)
|
56
56
|
end
|
57
|
+
|
58
|
+
def integer?
|
59
|
+
@label.is_a?(Integer) or (/\A\d+\z/ =~ @label.to_s)
|
60
|
+
end
|
61
|
+
|
62
|
+
def integer
|
63
|
+
unless integer?
|
64
|
+
raise "#{self} is not a integer"
|
65
|
+
end
|
66
|
+
case @label
|
67
|
+
when Integer
|
68
|
+
@label
|
69
|
+
else
|
70
|
+
Integer(@label.to_s)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def as_json
|
75
|
+
{name: @label.to_s}
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.list(*args, terminator: nil, memory: {})
|
79
|
+
cons = lambda{|x, y| Pair.cons(x, y, memory) }
|
80
|
+
term = (terminator || cons[:K, 256])
|
81
|
+
args.reverse.each do |i|
|
82
|
+
term = cons[cons[:S, cons[cons[:S, :I], cons[:K, i]]], cons[:K, term]]
|
83
|
+
end
|
84
|
+
term
|
85
|
+
end
|
57
86
|
end
|
58
87
|
|
59
88
|
class Combinator < Node
|
89
|
+
def self.get(comb, mem)
|
90
|
+
n = comb.to_s
|
91
|
+
mem[n] ||= self.new(comb)
|
92
|
+
end
|
93
|
+
|
60
94
|
def initialize(comb)
|
61
95
|
super(comb)
|
62
96
|
end
|
63
97
|
|
64
98
|
def to_s
|
65
|
-
@label.to_s
|
99
|
+
case l = @label.to_s
|
100
|
+
when "S", "K", "I"
|
101
|
+
l
|
102
|
+
else
|
103
|
+
"$" + l
|
104
|
+
end
|
66
105
|
end
|
67
106
|
def inspect
|
68
107
|
to_s
|
@@ -73,6 +112,11 @@ module RazyK
|
|
73
112
|
# Pair has only two child node (car and cdr).
|
74
113
|
# It represent term of combinators or terms.
|
75
114
|
class Pair < Node
|
115
|
+
def self.cons(car, cdr, mem)
|
116
|
+
n = "(#{car} #{cdr})"
|
117
|
+
mem[n] ||= self.new(car, cdr)
|
118
|
+
end
|
119
|
+
|
76
120
|
def initialize(car, cdr)
|
77
121
|
car = Combinator.new(car) unless car.is_a?(Node)
|
78
122
|
cdr = Combinator.new(cdr) unless cdr.is_a?(Node)
|
@@ -113,5 +157,9 @@ module RazyK
|
|
113
157
|
def inspect
|
114
158
|
to_s
|
115
159
|
end
|
160
|
+
|
161
|
+
def as_json
|
162
|
+
{name: "", children: [@car.as_json, @cdr.as_json]}
|
163
|
+
end
|
116
164
|
end
|
117
165
|
end
|
data/lib/razyk/parser.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# DO NOT MODIFY!!!!
|
3
|
-
# This file is automatically generated by Racc 1.4.
|
3
|
+
# This file is automatically generated by Racc 1.4.13
|
4
4
|
# from Racc grammer file "".
|
5
5
|
#
|
6
6
|
|
@@ -15,12 +15,7 @@ module RazyK
|
|
15
15
|
module_eval(<<'...end parser.y/module_eval...', 'parser.y', 114)
|
16
16
|
|
17
17
|
def str2list(str)
|
18
|
-
|
19
|
-
head = Pair.new(:K, 256)
|
20
|
-
str.unpack("C*").reverse_each do |ch|
|
21
|
-
head = Pair.new(Pair.new(:CONS, ch), head)
|
22
|
-
end
|
23
|
-
head
|
18
|
+
Node.list(*str.unpack("C*"), memory: @memory)
|
24
19
|
end
|
25
20
|
|
26
21
|
def scan
|
@@ -121,6 +116,7 @@ end
|
|
121
116
|
def parse(str, opt={})
|
122
117
|
@buf = str
|
123
118
|
@jot = []
|
119
|
+
@memory = opt[:memory] || {}
|
124
120
|
yyparse self, :scan
|
125
121
|
end
|
126
122
|
|
@@ -269,7 +265,7 @@ Racc_debug_parser = false
|
|
269
265
|
|
270
266
|
module_eval(<<'.,.,', 'parser.y', 16)
|
271
267
|
def _reduce_1(val, _values, result)
|
272
|
-
result = val[0] || Combinator.
|
268
|
+
result = val[0] || Combinator.get(:I, @memory)
|
273
269
|
|
274
270
|
result
|
275
271
|
end
|
@@ -288,7 +284,7 @@ module_eval(<<'.,.,', 'parser.y', 26)
|
|
288
284
|
if val[0].nil?
|
289
285
|
result = val[1]
|
290
286
|
else
|
291
|
-
result = Pair.
|
287
|
+
result = Pair.cons(val[0], val[1], @memory)
|
292
288
|
end
|
293
289
|
|
294
290
|
result
|
@@ -297,7 +293,7 @@ module_eval(<<'.,.,', 'parser.y', 26)
|
|
297
293
|
|
298
294
|
module_eval(<<'.,.,', 'parser.y', 36)
|
299
295
|
def _reduce_4(val, _values, result)
|
300
|
-
result = Combinator.
|
296
|
+
result = Combinator.get(:I, @memory)
|
301
297
|
|
302
298
|
result
|
303
299
|
end
|
@@ -307,7 +303,7 @@ module_eval(<<'.,.,', 'parser.y', 36)
|
|
307
303
|
|
308
304
|
module_eval(<<'.,.,', 'parser.y', 43)
|
309
305
|
def _reduce_6(val, _values, result)
|
310
|
-
result = Combinator.
|
306
|
+
result = Combinator.get(:IOTA, @memory)
|
311
307
|
|
312
308
|
result
|
313
309
|
end
|
@@ -317,7 +313,7 @@ module_eval(<<'.,.,', 'parser.y', 43)
|
|
317
313
|
|
318
314
|
module_eval(<<'.,.,', 'parser.y', 50)
|
319
315
|
def _reduce_8(val, _values, result)
|
320
|
-
result = Combinator.
|
316
|
+
result = Combinator.get(:I, @memory)
|
321
317
|
|
322
318
|
result
|
323
319
|
end
|
@@ -325,7 +321,7 @@ module_eval(<<'.,.,', 'parser.y', 50)
|
|
325
321
|
|
326
322
|
module_eval(<<'.,.,', 'parser.y', 54)
|
327
323
|
def _reduce_9(val, _values, result)
|
328
|
-
result = Combinator.
|
324
|
+
result = Combinator.get(:K, @memory)
|
329
325
|
|
330
326
|
result
|
331
327
|
end
|
@@ -333,7 +329,7 @@ module_eval(<<'.,.,', 'parser.y', 54)
|
|
333
329
|
|
334
330
|
module_eval(<<'.,.,', 'parser.y', 58)
|
335
331
|
def _reduce_10(val, _values, result)
|
336
|
-
result = Combinator.
|
332
|
+
result = Combinator.get(:S, @memory)
|
337
333
|
|
338
334
|
result
|
339
335
|
end
|
@@ -341,13 +337,13 @@ module_eval(<<'.,.,', 'parser.y', 58)
|
|
341
337
|
|
342
338
|
module_eval(<<'.,.,', 'parser.y', 62)
|
343
339
|
def _reduce_11(val, _values, result)
|
344
|
-
comb = Combinator.
|
340
|
+
comb = Combinator.get(:I, @memory)
|
345
341
|
@jot.reverse_each do |i|
|
346
342
|
case i
|
347
343
|
when 0
|
348
|
-
comb = Pair.
|
344
|
+
comb = Pair.cons(Pair.cons(comb, :S, @memory), :K, @memory)
|
349
345
|
when 1
|
350
|
-
comb = Pair.
|
346
|
+
comb = Pair.cons(:S, Pair.cons(:K, comb, @memory), @memory)
|
351
347
|
end
|
352
348
|
end
|
353
349
|
@jot.clear
|
@@ -359,7 +355,7 @@ module_eval(<<'.,.,', 'parser.y', 62)
|
|
359
355
|
|
360
356
|
module_eval(<<'.,.,', 'parser.y', 76)
|
361
357
|
def _reduce_12(val, _values, result)
|
362
|
-
result = Pair.
|
358
|
+
result = Pair.cons(val[1], val[2], @memory)
|
363
359
|
|
364
360
|
result
|
365
361
|
end
|
@@ -367,7 +363,7 @@ module_eval(<<'.,.,', 'parser.y', 76)
|
|
367
363
|
|
368
364
|
module_eval(<<'.,.,', 'parser.y', 80)
|
369
365
|
def _reduce_13(val, _values, result)
|
370
|
-
result = Pair.
|
366
|
+
result = Pair.cons(val[1], val[2], @memory)
|
371
367
|
|
372
368
|
result
|
373
369
|
end
|
@@ -383,7 +379,7 @@ module_eval(<<'.,.,', 'parser.y', 84)
|
|
383
379
|
|
384
380
|
module_eval(<<'.,.,', 'parser.y', 88)
|
385
381
|
def _reduce_15(val, _values, result)
|
386
|
-
result = Combinator.
|
382
|
+
result = Combinator.get(val[0].to_sym, @memory)
|
387
383
|
|
388
384
|
result
|
389
385
|
end
|
data/lib/razyk/parser.y
CHANGED
@@ -14,7 +14,7 @@ rule
|
|
14
14
|
|
15
15
|
program : ccexpr
|
16
16
|
{
|
17
|
-
result = val[0] || Combinator.
|
17
|
+
result = val[0] || Combinator.get(:I, @memory)
|
18
18
|
}
|
19
19
|
;
|
20
20
|
|
@@ -27,46 +27,46 @@ ccexpr : /* epsilon */
|
|
27
27
|
if val[0].nil?
|
28
28
|
result = val[1]
|
29
29
|
else
|
30
|
-
result = Pair.
|
30
|
+
result = Pair.cons(val[0], val[1], @memory)
|
31
31
|
end
|
32
32
|
}
|
33
33
|
;
|
34
34
|
|
35
35
|
expr : SMALL_I
|
36
36
|
{
|
37
|
-
result = Combinator.
|
37
|
+
result = Combinator.get(:I, @memory)
|
38
38
|
}
|
39
39
|
| expr2
|
40
40
|
;
|
41
41
|
|
42
42
|
iotaexpr: SMALL_I
|
43
43
|
{
|
44
|
-
result = Combinator.
|
44
|
+
result = Combinator.get(:IOTA, @memory)
|
45
45
|
}
|
46
46
|
| expr2
|
47
47
|
;
|
48
48
|
|
49
49
|
expr2 : I
|
50
50
|
{
|
51
|
-
result = Combinator.
|
51
|
+
result = Combinator.get(:I, @memory)
|
52
52
|
}
|
53
53
|
| K
|
54
54
|
{
|
55
|
-
result = Combinator.
|
55
|
+
result = Combinator.get(:K, @memory)
|
56
56
|
}
|
57
57
|
| S
|
58
58
|
{
|
59
|
-
result = Combinator.
|
59
|
+
result = Combinator.get(:S, @memory)
|
60
60
|
}
|
61
61
|
| no_empty_jot_expr
|
62
62
|
{
|
63
|
-
comb = Combinator.
|
63
|
+
comb = Combinator.get(:I, @memory)
|
64
64
|
@jot.reverse_each do |i|
|
65
65
|
case i
|
66
66
|
when 0
|
67
|
-
comb = Pair.
|
67
|
+
comb = Pair.cons(Pair.cons(comb, :S, @memory), :K, @memory)
|
68
68
|
when 1
|
69
|
-
comb = Pair.
|
69
|
+
comb = Pair.cons(:S, Pair.cons(:K, comb, @memory), @memory)
|
70
70
|
end
|
71
71
|
end
|
72
72
|
@jot.clear
|
@@ -74,11 +74,11 @@ expr2 : I
|
|
74
74
|
}
|
75
75
|
| BACKSLASH expr expr
|
76
76
|
{
|
77
|
-
result = Pair.
|
77
|
+
result = Pair.cons(val[1], val[2], @memory)
|
78
78
|
}
|
79
79
|
| ASTAR iotaexpr iotaexpr
|
80
80
|
{
|
81
|
-
result = Pair.
|
81
|
+
result = Pair.cons(val[1], val[2], @memory)
|
82
82
|
}
|
83
83
|
| LPAR ccexpr RPAR
|
84
84
|
{
|
@@ -86,7 +86,7 @@ expr2 : I
|
|
86
86
|
}
|
87
87
|
| LITERAL
|
88
88
|
{
|
89
|
-
result = Combinator.
|
89
|
+
result = Combinator.get(val[0].to_sym, @memory)
|
90
90
|
}
|
91
91
|
| STRING
|
92
92
|
{
|
@@ -113,12 +113,7 @@ require "razyk/node"
|
|
113
113
|
---- inner
|
114
114
|
|
115
115
|
def str2list(str)
|
116
|
-
|
117
|
-
head = Pair.new(:K, 256)
|
118
|
-
str.unpack("C*").reverse_each do |ch|
|
119
|
-
head = Pair.new(Pair.new(:CONS, ch), head)
|
120
|
-
end
|
121
|
-
head
|
116
|
+
Node.list(*str.unpack("C*"), memory: @memory)
|
122
117
|
end
|
123
118
|
|
124
119
|
def scan
|
@@ -219,6 +214,7 @@ end
|
|
219
214
|
def parse(str, opt={})
|
220
215
|
@buf = str
|
221
216
|
@jot = []
|
217
|
+
@memory = opt[:memory] || {}
|
222
218
|
yyparse self, :scan
|
223
219
|
end
|
224
220
|
|
data/lib/razyk/vm.rb
CHANGED
@@ -12,12 +12,13 @@ module RazyK
|
|
12
12
|
class VM
|
13
13
|
class StackUnderflow < StandardError; end
|
14
14
|
|
15
|
-
def initialize(tree, input=$stdin, output=$stdout, recursive
|
15
|
+
def initialize(tree, input=$stdin, output=$stdout, recursive: false, statistics: nil)
|
16
16
|
@root = Node.new(:root, [], [tree])
|
17
17
|
@generator = nil
|
18
18
|
@input = input
|
19
19
|
@output = output
|
20
20
|
@recursive = recursive
|
21
|
+
@statistics = statistics
|
21
22
|
end
|
22
23
|
|
23
24
|
def tree
|
@@ -54,21 +55,22 @@ module RazyK
|
|
54
55
|
stack.push(new_root)
|
55
56
|
end
|
56
57
|
|
57
|
-
def evaluate(root,
|
58
|
+
def evaluate(root, &blk)
|
58
59
|
stack = [root]
|
59
|
-
until step(stack,
|
60
|
-
if
|
61
|
-
|
60
|
+
until step(stack, &blk).nil?
|
61
|
+
if blk
|
62
|
+
blk.call(self)
|
62
63
|
end
|
63
64
|
end
|
64
65
|
if @recursive and stack.last.is_a?(Pair)
|
65
|
-
evaluate(stack.last.cdr,
|
66
|
+
evaluate(stack.last.cdr, &blk)
|
66
67
|
end
|
67
68
|
nil
|
68
69
|
end
|
69
70
|
|
70
|
-
def step(stack,
|
71
|
+
def step(stack, &blk)
|
71
72
|
return nil if stack.empty?
|
73
|
+
@statistics[:count] += 1 if @statistics
|
72
74
|
while stack.last.is_a?(Pair)
|
73
75
|
stack.push(stack.last.car)
|
74
76
|
end
|
@@ -92,40 +94,19 @@ module RazyK
|
|
92
94
|
root, x = pop_pairs(stack, 1)
|
93
95
|
new_root = Pair.new(Pair.new(x, :S), :K)
|
94
96
|
replace_root(stack, root, new_root)
|
95
|
-
when Integer
|
96
|
-
# (<N> f x) -> x (N == 0)
|
97
|
-
# -> (f (<N-1> f x)) (N > 0)
|
98
|
-
root, f, x = pop_pairs(stack, 2)
|
99
|
-
num = comb.label
|
100
|
-
if num == 0
|
101
|
-
replace_root(stack, root, x)
|
102
|
-
else
|
103
|
-
# shortcut
|
104
|
-
if f.label == :INC and x.label.is_a?(Integer)
|
105
|
-
replace_root(stack, root, Combinator.new(num + x.label))
|
106
|
-
else
|
107
|
-
dec_pair = Pair.new(Combinator.new(num-1), f)
|
108
|
-
new_root = Pair.new(f, Pair.new(dec_pair, x))
|
109
|
-
replace_root(stack, root, new_root)
|
110
|
-
end
|
111
|
-
end
|
112
97
|
when :CONS
|
113
98
|
# (CONS a d f) -> (f a d)
|
114
99
|
root, a, d, f = pop_pairs(stack, 3)
|
115
100
|
new_root = Pair.new(Pair.new(f, a), d)
|
116
101
|
replace_root(stack, root, new_root)
|
117
102
|
when :IN
|
118
|
-
# (IN f) -> (
|
119
|
-
ch = @input.
|
103
|
+
# (IN f) -> (S (S I (K <CH>)) (K IN)) where <CH> is a byte from stdin
|
104
|
+
ch = @input.getbyte
|
120
105
|
if ch.nil?
|
121
106
|
ch = 256
|
122
|
-
else
|
123
|
-
ch = ch.unpack("C")[0]
|
124
107
|
end
|
125
|
-
new_root =
|
126
|
-
:DUMMY) # reuse :IN combinator
|
108
|
+
new_root = Node.list(Combinator.new(ch), terminator: Combinator.new(:IN))
|
127
109
|
comb.replace(new_root)
|
128
|
-
new_root.cdr = comb
|
129
110
|
stack.push(new_root)
|
130
111
|
when :CAR
|
131
112
|
# (CAR x) -> (x K) (CAR = (Lx.x TRUE), TRUE = (Lxy.x) = K)
|
@@ -142,16 +123,16 @@ module RazyK
|
|
142
123
|
root, f = pop_pairs(stack, 1)
|
143
124
|
new_root = Pair.new(
|
144
125
|
Pair.new(:PUTC,
|
145
|
-
Pair.new(Pair.new(Pair.new(
|
126
|
+
Pair.new(Pair.new(Pair.new(f, :K), :INC), 0)),
|
146
127
|
Pair.new(comb, # reuse :OUT combinator
|
147
|
-
Pair.new(:
|
128
|
+
Pair.new(f, Pair.new(:S, :K))))
|
148
129
|
replace_root(stack, root, new_root)
|
149
130
|
when :INC
|
150
131
|
# (INC n) -> n+1 : increment church number
|
151
132
|
raise StackUnderflow if stack.empty?
|
152
|
-
evaluate(stack.last.cdr,
|
133
|
+
evaluate(stack.last.cdr, &blk)
|
153
134
|
root, n = pop_pairs(stack, 1)
|
154
|
-
unless n.
|
135
|
+
unless n.integer?
|
155
136
|
begin
|
156
137
|
msg = "argument of INC combinator is not a church number but #{n.inspect}"
|
157
138
|
rescue
|
@@ -159,13 +140,13 @@ module RazyK
|
|
159
140
|
end
|
160
141
|
raise msg
|
161
142
|
end
|
162
|
-
replace_root(stack, root, Combinator.new(n.
|
143
|
+
replace_root(stack, root, Combinator.new(n.integer + 1))
|
163
144
|
when :PUTC
|
164
145
|
# (PUTC x y) -> y : evaluate x and putchar it
|
165
146
|
raise StackUnderflow if stack.size < 2
|
166
147
|
x = stack.pop
|
167
|
-
evaluate(x.cdr,
|
168
|
-
unless x.cdr.
|
148
|
+
evaluate(x.cdr, &blk)
|
149
|
+
unless x.cdr.integer?
|
169
150
|
begin
|
170
151
|
msg = "output is not church number but #{x.cdr.inspect}"
|
171
152
|
rescue
|
@@ -173,16 +154,38 @@ module RazyK
|
|
173
154
|
end
|
174
155
|
raise msg
|
175
156
|
end
|
176
|
-
num = x.cdr.
|
157
|
+
num = x.cdr.integer
|
177
158
|
if num >= 256
|
159
|
+
if @output != $stdout and @output != STDOUT
|
160
|
+
@output.close_write
|
161
|
+
end
|
178
162
|
return nil
|
179
163
|
end
|
180
164
|
@output.write([num].pack("C"))
|
181
165
|
root = stack.pop
|
182
166
|
y = root.cut_cdr
|
183
167
|
replace_root(stack, root, y)
|
184
|
-
else
|
185
|
-
|
168
|
+
else
|
169
|
+
if comb.integer?
|
170
|
+
# (<N> f x) -> x (N == 0)
|
171
|
+
# -> (f (<N-1> f x)) (N > 0)
|
172
|
+
root, f, x = pop_pairs(stack, 2)
|
173
|
+
num = comb.integer
|
174
|
+
if num == 0
|
175
|
+
replace_root(stack, root, x)
|
176
|
+
else
|
177
|
+
# shortcut
|
178
|
+
if f.label == :INC and x.integer?
|
179
|
+
replace_root(stack, root, Combinator.new(num + x.integer))
|
180
|
+
else
|
181
|
+
dec_pair = Pair.new(Combinator.new(num-1), f)
|
182
|
+
new_root = Pair.new(f, Pair.new(dec_pair, x))
|
183
|
+
replace_root(stack, root, new_root)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
else # unknown combinator... treat as combinator without enough arguments
|
187
|
+
raise StackUnderflow
|
188
|
+
end
|
186
189
|
end
|
187
190
|
true
|
188
191
|
rescue StackUnderflow
|
@@ -190,22 +193,17 @@ module RazyK
|
|
190
193
|
end
|
191
194
|
|
192
195
|
def reduce
|
193
|
-
|
194
|
-
|
195
|
-
@generator.next
|
196
|
-
self
|
197
|
-
rescue StopIteration
|
198
|
-
nil
|
199
|
-
end
|
196
|
+
evaluate(self.tree) {|vm| return vm }
|
197
|
+
nil
|
200
198
|
end
|
201
199
|
|
202
200
|
def run(&blk)
|
203
|
-
if
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
201
|
+
if @statistics
|
202
|
+
@statistics[:started_at] = Time.now
|
203
|
+
end
|
204
|
+
evaluate(self.tree, &blk)
|
205
|
+
if @statistics
|
206
|
+
@statistics[:finished_at] = Time.now
|
209
207
|
end
|
210
208
|
end
|
211
209
|
end
|