razyk 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|