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/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>
|