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/webapp.rb
CHANGED
@@ -3,23 +3,33 @@ require "rack"
|
|
3
3
|
require "tempfile"
|
4
4
|
require "thread"
|
5
5
|
require "stringio"
|
6
|
-
|
7
|
-
require "razyk/graph"
|
6
|
+
require "json"
|
8
7
|
|
9
8
|
module RazyK
|
10
9
|
class WebApp
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
10
|
+
class InputStream
|
11
|
+
def initialize(str="")
|
12
|
+
@buf = str.b
|
13
|
+
@chars = []
|
14
|
+
end
|
15
|
+
def getbyte
|
16
|
+
if @buf
|
17
|
+
ret = @buf.unpack("C")[0]
|
18
|
+
@buf = @buf[1..-1]
|
19
|
+
if ret
|
20
|
+
@chars << ret
|
21
|
+
end
|
22
|
+
ret
|
23
|
+
else
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
def wrote
|
28
|
+
@chars.pack("C*")
|
29
|
+
end
|
30
|
+
def remain
|
31
|
+
@buf || ""
|
32
|
+
end
|
23
33
|
end
|
24
34
|
|
25
35
|
def template(name)
|
@@ -27,7 +37,6 @@ module RazyK
|
|
27
37
|
end
|
28
38
|
|
29
39
|
def main_page(req)
|
30
|
-
reset
|
31
40
|
res = Rack::Response.new
|
32
41
|
res.status = 200
|
33
42
|
res.write File.read(template("main.html"))
|
@@ -44,96 +53,46 @@ module RazyK
|
|
44
53
|
res
|
45
54
|
end
|
46
55
|
|
47
|
-
def
|
48
|
-
|
49
|
-
begin
|
50
|
-
q.push(vm.reduce)
|
51
|
-
rescue
|
52
|
-
q.push($!)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
+
def parse(req)
|
57
|
+
expression = req.params["expression"] || "(OUT (I IN))"
|
56
58
|
|
57
|
-
|
59
|
+
memory = {}
|
60
|
+
tree = RazyK::Parser.parse(expression, memory: memory)
|
58
61
|
res = Rack::Response.new
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
root = tree
|
67
|
-
recursive = true
|
68
|
-
end
|
69
|
-
# discard previous vm and thread
|
70
|
-
if @thread
|
71
|
-
@thread.kill
|
72
|
-
@thread = nil
|
73
|
-
end
|
74
|
-
@vm = VM.new(root, @port_in, @port_out, recursive)
|
75
|
-
# start Thread for reduction
|
76
|
-
@thread = Thread.start do reduce_thread(@vm) end
|
77
|
-
rescue
|
78
|
-
res.status = 501
|
79
|
-
puts $!.message, $@
|
80
|
-
return res
|
81
|
-
end
|
82
|
-
res.header["Content-Type"] = "text/json"
|
83
|
-
res.write('{"status":"success"}')
|
62
|
+
res.header["Content-Type"] = "application/json"
|
63
|
+
json_state = JSON::State.from_state(nil)
|
64
|
+
json_state.max_nesting = 0
|
65
|
+
res.write({
|
66
|
+
expression: tree.inspect,
|
67
|
+
nodes: tree.as_json,
|
68
|
+
}.to_json(json_state))
|
84
69
|
res
|
85
70
|
end
|
86
71
|
|
87
|
-
def
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
raise ret
|
96
|
-
end
|
97
|
-
if ret
|
98
|
-
@step += 1
|
99
|
-
end
|
100
|
-
res.write("OK")
|
101
|
-
else
|
102
|
-
res.write("enter program first")
|
103
|
-
end
|
104
|
-
res
|
105
|
-
end
|
106
|
-
|
107
|
-
def stdout(req)
|
108
|
-
res = Rack::Response.new
|
109
|
-
res.header["Content-Type"] = "text/plain"
|
110
|
-
res.write(@port_out.string.inspect)
|
111
|
-
res
|
112
|
-
end
|
72
|
+
def reduce(req)
|
73
|
+
stdin_read = req.params["stdin_read"] || ""
|
74
|
+
stdin_remain = req.params["stdin_remain"] || ""
|
75
|
+
stdout = req.params["stdout"] || ""
|
76
|
+
expression = req.params["expression"] || "(OUT (I IN))"
|
77
|
+
recursive = (req.params["recursive"] == "true")
|
78
|
+
port_in = InputStream.new(stdin_remain)
|
79
|
+
port_out = StringIO.new("")
|
113
80
|
|
114
|
-
|
81
|
+
memory = {}
|
82
|
+
tree = RazyK::Parser.parse(expression, memory: memory)
|
83
|
+
vm = VM.new(tree, port_in, port_out, recursive: recursive)
|
84
|
+
vm.reduce
|
115
85
|
res = Rack::Response.new
|
116
|
-
res.header["Content-Type"] = "
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
res = Rack::Response.new
|
127
|
-
if @vm
|
128
|
-
res.header["Content-Type"] = "image/svg+xml"
|
129
|
-
tmpfile = Tempfile.new("razyk_graph")
|
130
|
-
RazyK::Graph.graph(@vm.tree, :style => :dag).output(:svg => tmpfile.path)
|
131
|
-
res.write(tmpfile.read)
|
132
|
-
tmpfile.unlink
|
133
|
-
else
|
134
|
-
res.header["Content-Type"] = "text/plain"
|
135
|
-
res.write("enter program first")
|
136
|
-
end
|
86
|
+
res.header["Content-Type"] = "application/json"
|
87
|
+
json_state = JSON::State.from_state(nil)
|
88
|
+
json_state.max_nesting = 0
|
89
|
+
res.write({
|
90
|
+
expression: vm.tree.inspect,
|
91
|
+
nodes: vm.tree.as_json,
|
92
|
+
stdin_read: stdin_read + port_in.wrote,
|
93
|
+
stdin_remain: port_in.remain,
|
94
|
+
stdout: stdout + port_out.string,
|
95
|
+
}.to_json(json_state))
|
137
96
|
res
|
138
97
|
end
|
139
98
|
|
@@ -142,16 +101,10 @@ module RazyK
|
|
142
101
|
case req.path
|
143
102
|
when "/"
|
144
103
|
res = main_page(req)
|
145
|
-
when "/
|
146
|
-
res =
|
147
|
-
when "/
|
148
|
-
res =
|
149
|
-
when "/stdout"
|
150
|
-
res = stdout(req)
|
151
|
-
when "/expression"
|
152
|
-
res = expression(req)
|
153
|
-
when "/graph"
|
154
|
-
res = graph(req)
|
104
|
+
when "/parse"
|
105
|
+
res = parse(req)
|
106
|
+
when "/reduce"
|
107
|
+
res = reduce(req)
|
155
108
|
else
|
156
109
|
res = not_found(req)
|
157
110
|
end
|
@@ -2,68 +2,235 @@
|
|
2
2
|
<html>
|
3
3
|
<head>
|
4
4
|
<title>RazyK</title>
|
5
|
-
<
|
5
|
+
<meta charset="UTF-8">
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
8
|
+
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
9
|
+
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
|
10
|
+
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
|
11
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
|
6
12
|
<script type="text/javascript">
|
7
|
-
function
|
8
|
-
|
9
|
-
|
13
|
+
var RazyK = function(expression, nodes, stdin_read, stdin_remain, stdout, recursive) {
|
14
|
+
this.expression = expression;
|
15
|
+
this.nodes = nodes;
|
16
|
+
this.stdin_read = stdin_read;
|
17
|
+
this.stdin_remain = stdin_remain;
|
18
|
+
this.stdout = stdout;
|
19
|
+
this.recursive = recursive;
|
20
|
+
};
|
21
|
+
|
22
|
+
function draw(razyk) {
|
23
|
+
toggle_mode();
|
24
|
+
if ($("#lazyk_mode").is(":checked")) {
|
25
|
+
$("#stdin_progress").text(razyk.stdin_read + "_" + razyk.stdin_remain);
|
26
|
+
$("#stdout").text(razyk.stdout);
|
27
|
+
}
|
28
|
+
$("#expression").text(razyk.expression);
|
29
|
+
|
30
|
+
var max_depth_f = function(node, depth) {
|
31
|
+
if (node.children) {
|
32
|
+
return Math.max.apply(null, node.children.map(function(elm){ return max_depth_f(elm, depth+1); }));
|
33
|
+
}
|
34
|
+
return depth;
|
35
|
+
}
|
36
|
+
var max_width_f = function(node, depth, widths) {
|
37
|
+
if (widths[depth]) {
|
38
|
+
widths[depth] += 1;
|
39
|
+
} else {
|
40
|
+
widths[depth] = 1;
|
41
|
+
}
|
42
|
+
if (node.children) {
|
43
|
+
node.children.forEach(function(elm){
|
44
|
+
max_width_f(elm, depth+1, widths);
|
45
|
+
});
|
46
|
+
}
|
47
|
+
if (depth == 1) {
|
48
|
+
return Math.max.apply(null, Object.keys(widths).map(function(elm) { return widths[elm] }));
|
49
|
+
} else {
|
50
|
+
return null;
|
51
|
+
}
|
10
52
|
}
|
11
|
-
|
12
|
-
|
53
|
+
var max_depth = max_depth_f(razyk.nodes, 1);
|
54
|
+
var max_width = max_width_f(razyk.nodes, 1, {});
|
55
|
+
$("div#graph").empty();
|
56
|
+
var svg = d3.select("div#graph").append("svg");
|
57
|
+
var width = max_width * 20;
|
58
|
+
var height = max_depth * 20;
|
59
|
+
if (width < 500) { width = 500; }
|
60
|
+
if (width < 1000) { width = 1000; }
|
61
|
+
svg.attr("width", width + 50);
|
62
|
+
svg.attr("height", height + 50);
|
63
|
+
var tree = d3.layout.tree().size([width, height]);
|
64
|
+
var nodes = tree.nodes(razyk.nodes);
|
65
|
+
// segments
|
66
|
+
svg.selectAll("path")
|
67
|
+
.data(tree.links(nodes))
|
68
|
+
.enter()
|
69
|
+
.append("path")
|
70
|
+
.attr("d", d3.svg.diagonal())
|
71
|
+
.attr("fill", "none")
|
72
|
+
.attr("stroke", "black")
|
73
|
+
.attr("stroke-width", 2)
|
74
|
+
.attr("transform", "translate(0, 15)");
|
75
|
+
// circles
|
76
|
+
var coloring = function(d) {
|
77
|
+
if (d.name == "") {
|
78
|
+
return "black";
|
79
|
+
} else if (d.name == "I") {
|
80
|
+
return "blue";
|
81
|
+
} else if (d.name == "K") {
|
82
|
+
return "green";
|
83
|
+
} else if (d.name == "S") {
|
84
|
+
return "red";
|
85
|
+
} else if (d.name == "OUT" || d.name == "PUTC") {
|
86
|
+
return "purple";
|
87
|
+
} else if (d.name == "IN") {
|
88
|
+
return "yellow";
|
89
|
+
} else {
|
90
|
+
return "black";
|
91
|
+
}
|
92
|
+
};
|
93
|
+
svg.selectAll("circle")
|
94
|
+
.data(nodes)
|
95
|
+
.enter()
|
96
|
+
.append("circle")
|
97
|
+
.attr("cx", function(d){return d.x;})
|
98
|
+
.attr("cy", function(d){return d.y+15;})
|
99
|
+
.attr("r", function(d) { if (d.name == "") { return 2; } else { return 10; } })
|
100
|
+
.style("fill", coloring);
|
13
101
|
}
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
102
|
+
|
103
|
+
function set_program(cb) {
|
104
|
+
program = $("#program").val();
|
105
|
+
recursive = true;
|
106
|
+
|
107
|
+
if ($("#lazyk_mode").is(":checked")) {
|
108
|
+
program = "($OUT (" + program + " $IN))";
|
109
|
+
recursive = false;
|
110
|
+
}
|
111
|
+
window.razyk = new RazyK(program, {name: ""}, "", $("#input_buffer").val(), "", recursive);
|
112
|
+
$.post("/parse", {expression: program},
|
113
|
+
function(data) {
|
114
|
+
window.razyk.expression = data.expression;
|
115
|
+
window.razyk.nodes = data.nodes;
|
116
|
+
draw(window.razyk);
|
117
|
+
if (cb) { cb(); }
|
118
|
+
});
|
24
119
|
}
|
25
120
|
|
26
|
-
function
|
27
|
-
|
28
|
-
|
29
|
-
|
121
|
+
function reduce(cb) {
|
122
|
+
r = window.razyk;
|
123
|
+
$.post("/reduce",
|
124
|
+
{expression: r.expression, stdin_read: r.stdin_read, stdin_remain: r.stdin_remain, stdout: r.stdout, recursive: r.recursive},
|
125
|
+
function(data) {
|
126
|
+
finished = r.expression == data.expression;
|
127
|
+
window.razyk = new RazyK(data.expression, data.nodes, data.stdin_read, data.stdin_remain, data.stdout, window.razyk.recursive);
|
128
|
+
draw(window.razyk);
|
129
|
+
if (cb) { cb(finished); }
|
30
130
|
});
|
31
131
|
}
|
32
132
|
|
133
|
+
function run() {
|
134
|
+
var wait = 500;
|
135
|
+
if (!window.running) { return; }
|
136
|
+
if ( window.razyk == undefined ) {
|
137
|
+
set_program(function() {
|
138
|
+
setTimeout(run, wait);
|
139
|
+
});
|
140
|
+
} else {
|
141
|
+
reduce(function(finished) {
|
142
|
+
if (!finished) {
|
143
|
+
setTimeout(run, wait);
|
144
|
+
} else {
|
145
|
+
window.running = false;
|
146
|
+
}
|
147
|
+
});
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
function start() {
|
152
|
+
window.running = true;
|
153
|
+
run();
|
154
|
+
}
|
155
|
+
|
156
|
+
function stop() {
|
157
|
+
window.running = false;
|
158
|
+
}
|
159
|
+
|
33
160
|
function toggle_mode() {
|
34
|
-
if ($("#
|
35
|
-
$("
|
161
|
+
if ($("#lazyk_mode").is(":checked")) {
|
162
|
+
$(".inout_pane").show("fast");
|
36
163
|
} else {
|
37
|
-
$("
|
164
|
+
$(".inout_pane").hide("fast");
|
38
165
|
}
|
39
166
|
}
|
40
167
|
</script>
|
41
168
|
</head>
|
42
|
-
<body>
|
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
|
-
|
169
|
+
<body class="bg-info">
|
170
|
+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
|
171
|
+
<div class="container-fluid bg-info">
|
172
|
+
<div class="row"><div class="col-lg-1"></div><div class="col-lg-10">
|
173
|
+
<div class="row form-group">
|
174
|
+
<div class="col-lg-12">
|
175
|
+
<label for="program">enter program</label>
|
176
|
+
<textarea id="program" class="form-control" cols="100">SKKI</textarea>
|
177
|
+
</div>
|
178
|
+
</div>
|
179
|
+
<div class="row form-group">
|
180
|
+
<div class="col-sm-3">
|
181
|
+
<label class="checkbox-inline">
|
182
|
+
<input type="checkbox" id="lazyk_mode" onchange="toggle_mode();" /> LazyK application
|
183
|
+
</label>
|
184
|
+
</div>
|
185
|
+
<div class="col-sm-1"><input type="button" class="form-control btn btn-default" value="reset" onclick="set_program();" /></div>
|
186
|
+
<div class="col-sm-1"><input type="button" class="form-control btn btn-default" value="step" onclick="reduce();" /></div>
|
187
|
+
<div class="col-sm-1"><input type="button" class="form-control btn btn-default" value="run" onclick="start();" /></div>
|
188
|
+
<div class="col-sm-1"><input type="button" class="form-control btn btn-default" value="stop" onclick="stop();" /></div>
|
189
|
+
</div>
|
190
|
+
<div class="row inout_pane form-group" style="display: none">
|
191
|
+
<div class="col-lg-12">
|
192
|
+
<label for="input_buffer">stdin</label>
|
193
|
+
<div>
|
194
|
+
<textarea id="input_buffer" class="form-control" cols="100"></textarea>
|
195
|
+
</div>
|
196
|
+
</div>
|
197
|
+
</div>
|
198
|
+
<div class="row">
|
199
|
+
</div>
|
200
|
+
<div class="row"></div>
|
201
|
+
<div class="row inout_pane" style="display: none">
|
202
|
+
<div class="col-lg-12">
|
203
|
+
<div class="panel panel-default">
|
204
|
+
<div class="panel-heading">
|
205
|
+
<div class="panel-title">stdin</div>
|
206
|
+
</div>
|
207
|
+
<div id="stdin_progress" class="panel-body"></div>
|
208
|
+
</div>
|
209
|
+
<div class="panel panel-default">
|
210
|
+
<div class="panel-heading">
|
211
|
+
<div class="panel-title">stdout</div>
|
212
|
+
</div>
|
213
|
+
<div id="stdout" class="panel-body"></div>
|
214
|
+
</div>
|
215
|
+
</div>
|
216
|
+
</div>
|
217
|
+
<div class="row">
|
218
|
+
<div class="col-lg-12">
|
219
|
+
<div class="panel panel-default">
|
220
|
+
<div class="panel-heading"><div class="panel-title">combinator expression</div></div>
|
221
|
+
<div id="expression" class="panel-body"> </div>
|
222
|
+
</div>
|
223
|
+
</div>
|
224
|
+
</div>
|
225
|
+
<div class="row">
|
226
|
+
<div class="col-lg-12">
|
227
|
+
<div class="panel panel-default">
|
228
|
+
<div class="panel-heading"><div class="panel-title">graph</div></div>
|
229
|
+
<div id="graph" class="panel-body"> </div>
|
230
|
+
</div>
|
231
|
+
</div>
|
232
|
+
</div>
|
233
|
+
</div><div class="col-lg-1"></div></div>
|
234
|
+
</div>
|
68
235
|
</body>
|
69
236
|
</html>
|