Skip to content

Commit 398ac4c

Browse files
committed
refactoring OPT with hooks
1 parent 303a196 commit 398ac4c

5 files changed

Lines changed: 301 additions & 2 deletions

File tree

example-code/Postfix.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import java.util.Stack;
21
public class Postfix {
32
public static void main(String[] args) {
43
Stack<Integer> stacky = new Stack<>();

example-code/Strings.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
public class Strings {
22
public static void main(String[] args) {
3+
// In "options", enable "Show String... objects"
34
String a = "Hello, world!";
45
String b = "Hello, world!!".substring(0, 13);
56
String c = "Hello, ";

index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,9 @@
6060
<link type="text/css" href="./OnlinePythonTutor/v3/css/jquery.qtip.css" rel="stylesheet" />
6161

6262
<script type="text/javascript" src="./OnlinePythonTutor/v3/js/pytutor.js?4"></script>
63+
<script type="text/javascript" src="pytutor-customizations.js?1"></script>
6364
<link rel="stylesheet" href="./OnlinePythonTutor/v3/css/pytutor.css"/>
64-
65+
<link rel="stylesheet" href="pytutor-customizations.css"/>
6566

6667
<!-- requirements for opt-frontend.js -->
6768

pytutor-customizations.css

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
div.ExecutionVisualizer .numberObj {
2+
white-space: nowrap;
3+
}
4+
5+
div.ExecutionVisualizer div#codeDisplayDiv {
6+
width: default;
7+
}
8+
9+
div.ExecutionVisualizer #pyStdout {
10+
-moz-box-sizing: border-box;
11+
box-sizing: border-box;
12+
13+
width: 100%;
14+
}
15+
16+
div.ExecutionVisualizer table.queueTbl,
17+
div.ExecutionVisualizer table.stackTbl {
18+
background-color: #ffffc6;
19+
}
20+
21+
div.ExecutionVisualizer table.queueTbl,
22+
div.ExecutionVisualizer table.stackTbl {
23+
border: 0px solid black;
24+
border-spacing: 0px;
25+
}
26+
27+
div.ExecutionVisualizer table.stackTbl td.stackElt,
28+
div.ExecutionVisualizer table.queueTbl td.queueElt {
29+
padding-left: 8px;
30+
padding-right: 8px;
31+
padding-top: 2px;
32+
padding-bottom: 3px;
33+
border-top: 1px solid #555555;
34+
border-bottom: 1px solid #555555;
35+
border-left: 1px dashed #555555;
36+
}
37+
38+
div.ExecutionVisualizer table.stackTbl td.stackFElt,
39+
div.ExecutionVisualizer table.queueTbl td.queueFElt {
40+
background-color: white;
41+
border-top: 1px solid #555555;
42+
border-bottom: 1px solid #555555;
43+
}
44+
45+
div.ExecutionVisualizer table.stackTbl td.stackLElt {
46+
background-color: white;
47+
border-left: 1px solid #555555;
48+
}
49+
50+
div.ExecutionVisualizer table.queueTbl td.queueLElt {
51+
background-color: white;
52+
border-top: 1px solid#555555;
53+
border-bottom: 1px solid #555555;
54+
border-left: 1px dashed #555555;
55+
}
56+
57+
/* TODO: update this to reflect the addition of queue and stack types.
58+
only add a border to dicts if they're embedded within another object
59+
div.ExecutionVisualizer td.listElt table.dictTbl,
60+
div.ExecutionVisualizer td.tupleElt table.dictTbl,
61+
div.ExecutionVisualizer td.dictVal table.dictTbl,
62+
div.ExecutionVisualizer td.instVal table.dictTbl,
63+
div.ExecutionVisualizer td.classVal table.dictTbl {
64+
border: 1px #888 solid;
65+
} */
66+
67+
div.ExecutionVisualizer .highlight-cur {
68+
background-color: #FFFF66;
69+
}
70+
71+
.symbolic {
72+
font-size: 18pt;
73+
}

pytutor-customizations.js

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
add_pytutor_hook(
2+
"renderPrimitiveObject",
3+
function(obj, d3DomElement) {
4+
var typ = typeof obj;
5+
if (obj == null)
6+
d3DomElement.append('<span class="nullObj">null</span>');
7+
else if (typ == "number")
8+
d3DomElement.append('<span class="numberObj">' + obj + '</span>');
9+
else if (typ == "boolean") {
10+
if (obj)
11+
d3DomElement.append('<span class="boolObj">true</span>');
12+
else
13+
d3DomElement.append('<span class="boolObj">false</span>');
14+
}
15+
else if (obj instanceof Array && obj[0] == "VOID") {
16+
d3DomElement.append('<span class="voidObj">void</span>');
17+
}
18+
else if (obj instanceof Array && obj[0] == "NUMBER-LITERAL") {
19+
// actually transmitted as a string
20+
d3DomElement.append('<span class="numberObj">' + obj[1] + '</span>');
21+
}
22+
else if (obj instanceof Array && obj[0] == "CHAR-LITERAL") {
23+
var asc = obj[1].charCodeAt(0);
24+
var ch = obj[1];
25+
26+
// default
27+
var show = asc.toString(16);
28+
while (show.length < 4) show = "0" + show;
29+
show = "\\u" + show;
30+
31+
if (ch == "\n") show = "\\n";
32+
else if (ch == "\r") show = "\\r";
33+
else if (ch == "\t") show = "\\t";
34+
else if (ch == "\b") show = "\\b";
35+
else if (ch == "\f") show = "\\f";
36+
else if (ch == "\'") show = "\\\'";
37+
else if (ch == "\"") show = "\\\"";
38+
else if (ch == "\\") show = "\\\\";
39+
else if (asc >= 32) show = ch;
40+
41+
// stringObj to make monospace
42+
d3DomElement.append('<span class="stringObj">\'' + show + '\'</span>');
43+
}
44+
else
45+
return [false]; // we didn't handle it
46+
return [true]; // we handled it
47+
});
48+
49+
add_pytutor_hook(
50+
"isPrimitiveType",
51+
function(obj) {
52+
if ((obj instanceof Array && obj[0] == "VOID")
53+
|| (obj instanceof Array && obj[0] == "NUMBER-LITERAL")
54+
|| (obj instanceof Array && obj[0] == "CHAR-LITERAL")
55+
|| (obj instanceof Array && obj[0] == "ELIDE"))
56+
return [true, true]; // we handled it, it's primitive
57+
return [false]; // didn't handle it
58+
});
59+
60+
add_pytutor_hook(
61+
"end_updateOutput",
62+
function(myViz) {
63+
var curEntry = myViz.curTrace[myViz.curInstr];
64+
if (myViz.params.stdin && myViz.params.stdin != "") {
65+
var stdinPosition = curEntry.stdinPosition || 0;
66+
var stdinContent =
67+
'<span style="color:lightgray;text-decoration: line-through">'+
68+
escapeHtml(myViz.params.stdin.substr(0, stdinPosition))+
69+
'</span>'+
70+
escapeHtml(myViz.params.stdin.substr(stdinPosition));
71+
myViz.domRoot.find('#stdinShow').html(stdinContent);
72+
}
73+
return [false];
74+
});
75+
76+
add_pytutor_hook(
77+
"end_constructor",
78+
function(myViz) {
79+
if ((myViz.curTrace.length > 0)
80+
&& myViz.curTrace[myViz.curTrace.length-1]
81+
&& myViz.curTrace[myViz.curTrace.length-1].stdout) {
82+
myViz.hasStdout = true;
83+
myViz.stdoutLines = myViz.curTrace[myViz.curTrace.length-1].stdout.split("\n").length;
84+
}
85+
// if last frame is a step limit
86+
else if ((myViz.curTrace.length > 1)
87+
&& myViz.curTrace[myViz.curTrace.length-2]
88+
&& myViz.curTrace[myViz.curTrace.length-2].stdout) {
89+
myViz.hasStdout = true;
90+
myViz.stdoutLines = myViz.curTrace[myViz.curTrace.length-2].stdout.split("\n").length;
91+
}
92+
else {
93+
myViz.stdoutLines = -1;
94+
}
95+
if (myViz.hasStdout)
96+
for (var i=0; i<myViz.curTrace.length; i++)
97+
if (!(myViz.curTrace[i].stdout))
98+
myViz.curTrace[i].stdout=" "; // always show it, if it's ever used
99+
});
100+
101+
add_pytutor_hook(
102+
"end_render",
103+
function(myViz) {
104+
myViz.domRoot.find('#pyStdout').attr('cols', 1);
105+
myViz.domRoot.find('#pyStdout').attr('rows', Math.min(10, myViz.stdoutLines));
106+
107+
if (myViz.params.stdin && myViz.params.stdin != "") {
108+
var stdinHTML = '<div id="stdinWrap">stdin:<pre id="stdinShow" style="border:1px solid gray"></pre></div>';
109+
myViz.domRoot.find('#dataViz').append(stdinHTML);
110+
}
111+
112+
myViz.domRoot.find('#'+myViz.generateID('globals_header')).html("Static fields");
113+
});
114+
115+
add_pytutor_hook(
116+
"isLinearObject",
117+
function(heapObj) {
118+
if (heapObj[0]=='STACK' || heapObj[0]=='QUEUE')
119+
return ['true', 'true'];
120+
return ['false'];
121+
});
122+
123+
add_pytutor_hook(
124+
"renderCompoundObject",
125+
function(objID, d3DomElement, isTopLevel, obj, typeLabelPrefix, renderNestedObject) {
126+
if (!(obj[0] == 'LIST' || obj[0] == 'QUEUE' || obj[0] == 'STACK'))
127+
return [false]; // didn't handle
128+
129+
var label = obj[0].toLowerCase();
130+
var visibleLabel = {list:'array', queue:'queue', stack:'stack'}[label];
131+
132+
if (obj.length == 1) {
133+
d3DomElement.append('<div class="typeLabel">' + typeLabelPrefix + 'empty ' + visibleLabel + '</div>');
134+
return [true]; //handled
135+
}
136+
137+
d3DomElement.append('<div class="typeLabel">' + typeLabelPrefix + visibleLabel + '</div>');
138+
d3DomElement.append('<table class="' + label + 'Tbl"></table>');
139+
var tbl = d3DomElement.children('table');
140+
141+
if (obj[0] == 'LIST') {
142+
tbl.append('<tr></tr><tr></tr>');
143+
var headerTr = tbl.find('tr:first');
144+
var contentTr = tbl.find('tr:last');
145+
146+
// i: actual index in json object; ind: apparent index
147+
for (var i=1, ind=0; i<obj.length; i++) {
148+
val = obj[i];
149+
var elide = val instanceof Array && val[0] == 'ELIDE';
150+
151+
// add a new column and then pass in that newly-added column
152+
// as d3DomElement to the recursive call to child:
153+
headerTr.append('<td class="' + label + 'Header"></td>');
154+
headerTr.find('td:last').append(elide ? "&hellip;" : ind);
155+
156+
contentTr.append('<td class="'+ label + 'Elt"></td>');
157+
if (!elide) {
158+
renderNestedObject(val, contentTr.find('td:last'));
159+
ind++;
160+
}
161+
else {
162+
contentTr.find('td:last').append("&hellip;");
163+
ind += val[1]; // val[1] is the number of cells to skip
164+
}
165+
}
166+
} // end of LIST handling
167+
168+
/* The table produced for stacks and queues is formed slightly differently than the others,
169+
missing the header row. Two rows made the dashed border not line up properly */
170+
if (obj[0] == 'STACK') {
171+
tbl.append('<tr></tr><tr></tr>');
172+
var contentTr = tbl.find('tr:last');
173+
contentTr.append('<td class="'+ label + 'FElt">'+'<span class="stringObj symbolic">&#8596;</span>'+'</td>');
174+
$.each(obj, function(ind, val) {
175+
if (ind < 1) return; // skip type tag and ID entry
176+
contentTr.append('<td class="'+ label + 'Elt"></td>');
177+
renderNestedObject(val, contentTr.find('td:last'));
178+
});
179+
contentTr.append('<td class="'+ label + 'LElt">'+'</td>');
180+
}
181+
182+
if (obj[0] == 'QUEUE') {
183+
tbl.append('<tr></tr><tr></tr>');
184+
var contentTr = tbl.find('tr:last');
185+
// Add arrows showing in/out direction
186+
contentTr.append('<td class="'+ label + 'FElt">'+'<span class="stringObj symbolic">&#8592;</span></td>');
187+
$.each(obj, function(ind, val) {
188+
if (ind < 1) return; // skip type tag and ID entry
189+
contentTr.append('<td class="'+ label + 'Elt"></td>');
190+
renderNestedObject(val, contentTr.find('td:last'));
191+
});
192+
contentTr.append('<td class="'+ label + 'LElt">'+'<span class="stringObj symbolic">&#8592;</span></td>');
193+
}
194+
195+
return [true]; // did handle
196+
});
197+
198+
add_pytutor_hook(
199+
"end_renderDataStructures",
200+
function (myViz) {
201+
myViz.domRoot.find("td.instKey:contains('___NO_LABEL!___')").hide();
202+
myViz.domRoot.find(".typeLabel:contains('dict')").each(
203+
function(i) {
204+
if ($(this).html()=='dict')
205+
$(this).html('symbol table');
206+
if ($(this).html()=='empty dict')
207+
$(this).html('empty symbol table');
208+
});
209+
});
210+
211+
var entityMap = {
212+
"&": "&amp;",
213+
"<": "&lt;",
214+
">": "&gt;",
215+
'"': '&quot;',
216+
"'": '&#39;',
217+
"/": '&#x2F;'
218+
};
219+
220+
var escapeHtml = function(string) {
221+
return String(string).replace(/[&<>"'\/]/g, function (s) {
222+
return entityMap[s];
223+
});
224+
};
225+

0 commit comments

Comments
 (0)