Skip to content
Snippets Groups Projects
Commit 7fac4c29 authored by Alan Schmitt's avatar Alan Schmitt
Browse files

restoring the proof of concept code

parent edf0e1e5
No related branches found
No related tags found
No related merge requests found
......@@ -109,7 +109,7 @@ function log_reset() {
}
function log_custom(arg) {
arg.file = "interp.js";
arg.file = "interp-poc.js";
arg.heap = heap;
arg.env = env;
arg.start_line = arg.line;
......
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript Reference Tracer</title>
<script src="../../interp/tracer/jquery-2.1.1.min.js"></script>
<link rel=stylesheet href="../../interp/tracer/codemirror/lib/codemirror.css">
<script src="../../interp/tracer/codemirror/lib/codemirror.js"></script>
<!-- styles needed by jScrollPane - include in your own sites -->
<link type="text/css" href="jquery_scroll/jquery.jscrollpane.css" rel="stylesheet" media="all" />
<!-- the mousewheel plugin -->
<script type="text/javascript" src="jquery_scroll/jquery.mousewheel.js"></script>
<!-- the jScrollPane script -->
<script type="text/javascript" src="jquery_scroll/jquery.jscrollpane.min.js"></script>
<!--
<link rel="stylesheet" href="http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="http://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
-->
<link rel="stylesheet" href="jquery-ui-1.11.4.custom/jquery-ui.css">
<script src="jquery-ui-1.11.4.custom/jquery-ui.js"></script>
<script src="https://cdn.rawgit.com/jquery/esprima/1.2/esprima.js"></script>
<script src="sparray.js"></script>
<script type = "text/javascript" src="source-poc.js"></script>
<script src="interp-poc.js"></script>
<style>
.source_div {
border-top: 1px solid black;
border-bottom: 1px solid black;
}
.heap_link {
color: black;
}
#file_list {
height: 1em;
padding-top: 8px;
padding-bottom: 8px;
border-bottom: 1px solid black;
}
.file_item, .file_item_current {
margin-right: 5px;
padding: 5px;
text-decoration: underline;
}
.file_item, .file_item_current:hover {
cursor: pointer;
cursor: hand;
}
.file_item {
background-color: #FAFAFA;
}
.file_item_current {
background-color: #FFCCCC;
}
#main_table td {
vertical-align: top;
border: 1px solid black;
}
.CodeMirror-selected { background: #F3F781; }
.CodeMirror-focused .CodeMirror-selected { background: #F3F781; }
.scroll-pane
{
width: 100%;
height: 200px;
overflow: auto;
}
</style>
</head>
<body>
<h2>Mini-ML Interpreter</h2>
<div class='source_div'>
<table id='main_table'><tr>
<td>
<textarea id='source_code' class='source' rows='6' cols='60'>source code here</textarea>
</td>
<td width='600'>
<div class="scroll-pane" style="height: 10em">
<div id='disp_env'>ctx here</div>
</div>
</td>
</tr></table>
</div>
<br/>
<div>
<input type="button" id="button_run" value="RUN" />
Navigation:
<input type="textbox" id='navigation_step' style="width:3em" value="0"/>
/ <span id="navigation_total"></span>
<input type="button" id='button_reset' value="Reset" />
<input type="button" id='button_prev' value="Prev" />
<input type="button" id='button_next' value="Next" />
Reach condition:
<input type="textbox" id='text_condition' style="width:30em" />
<input type="button" id='button_reach' value="Reach" />
<span id="reach_output"></span>
</div>
<div id="action_output"></div>
<br/>
<div class='source_div'>
<table id='main_table'><tr>
<td>
<div id='file_list'></div>
<textarea id='interpreter_code' class='source' rows='20' cols='60'></textarea>
</td>
<td width='600'>
<div id='disp_infos'></div>
<div id='disp_ctx'>ctx here</div>
</td>
</tr></table>
</div>
<script src="navig-poc.js"></script>
<!--
<script language="javascript">
$(function() {
$('.scroll-pane').jScrollPane();
});
</script>
-->
<!--div style="font-size:0.8em">Instructions: from console, the variable "h" denotes the current heap.</div-->
<div style="font-size:0.8em">Instructions: type 'S' for step (next function call), 'N' for next (next call at same level), 'B' for backstep (symmetric to step), 'P' for previous (symmetric to next), 'F' for finish (next call at upper level), 'R' for restart.</div>
<div style="font-size:0.8em">Examples of conditions:
<ul>
<li><pre style = "display:inline">X.type === "fun" && (X.v1, true)</pre> (we are at the beginning of a function and v1 is defined in the local interpreter context),</li>
<li><pre style = "display:inline">X.line === 32 && X.t.tag === "trm_set" && X.t.field === "bar"</pre> (we are at line 32 and we are setting the field “bar” of the current location),</li>
<li><pre style = "display:inline">y.foo === 12</pre> (the program variable “y” points to an object whose field “foo” is equal to 12),</li>
<li><pre style = "display:inline">X.heap[0].bar === 12</pre> (the first cell of the heap has a field “bar” defined equal to 12).</li>
</ul></div>
</body>
</html>
<!---
$timeout(function() {codeMirror.refresh();});
this.codeMirrorInstance.setValue(content);
var that = this;
setTimeout(function() {
that.codeMirrorInstance.refresh();
},1);
http://codemirror.net/demo/buffers.html
//CodeMirror.Doc(text
---->
var handlers = [];
var parsedTree;
(function(check_pred){
var tracer_items = [];
var tracer_length = 0;
var tracer_pos = 0;
$("#source_code").val(source_file);
function stepTo(step) {
tracer_pos = step;
updateSelection();
}
// Take a predicate in form of a JavaScript code (string) and returns either true or an error message (string).
function goToPred(pred) {
function check(i){
var item = datalog[i];
var jsheap = jsheap_of_heap(item.heap);
var obj = jsenv_of_env(jsheap, item.env);
var objX = {};
if (item.ctx !== undefined){
objX = jsenv_of_env(jsheap, item.ctx);
}
objX.line = item.line;
objX.type = item.type;
objX.heap = jsheap;
obj.X = objX; // If we want to change the “X” identifier, just change this line.
try {
if (check_pred(pred, obj)){
stepTo(i);
return true;
}
} catch(e){
error++;
}
return false;
}
var error = 0;
if (datalog.length === 0)
return false;
for (var i = (tracer_pos + 1) % datalog.length, current = tracer_pos;
i !== current;
i++, i %= datalog.length)
if (check(i))
return true;
if (check(tracer_pos))
return true;
if (error === datalog.length)
return "There was an execution error at every execution of your condition: are you sure that this is a valid JavaScript code?";
return "Not found";
}
function button_reach_handler() {
var pred = $("#text_condition").val();
var res = goToPred(pred);
if (res !== true){
$("#action_output").html(res);
var timeoutID =
window.setTimeout(function() {
$("#action_output").html(""); }, 3000);
}
};
$('#text_condition').keypress(function(e){
var keycode = (e.keyCode ? e.keyCode : e.which);
if (keycode == '13') {
button_reach_handler();
}
});
$("#button_reach").click(button_reach_handler);
$("#navigation_step").change(function(e) {
var n = + $("#navigation_step").val();
n = Math.max(0, Math.min(tracer_length - 1, n));
stepTo(n);
});
$("#button_run").click(function() {
try {
var code = source.getValue();
//console.log(code);
parsedTree = esprima.parse(code, {loc:true});
// console.log(parsedTree);
program = esprimaToAST(parsedTree);
// console.log(program);
run();
$("#action_output").html("Run successful!");
} catch(_){
$("#action_output").html("Error during the run.");
};
var timeoutID = window.setTimeout(function() { $("#run_output").html(""); }, 1000);
});
$("#button_reset").click(function() {
stepTo(0);
});
$("#button_prev").click(function() {
stepTo(Math.max(0, tracer_pos-1));
});
$("#button_next").click(function() {
stepTo(Math.min(tracer_length-1, tracer_pos+1));
});
// Assumes tracer_files to be an array of objects with two field:
// - file, containing the name of the file,
// - contents, a string containing its source code
// Assumes tracer_items to be an array with items, e.g.:
// { type: 'enter', file: 'foo.ml', start_line: 4, start_col: 0, end_line: 5, end_col: 10 },
// { type: 'exit', file: 'foo.ml', start_line: 4, start_col: 0, end_line: 5, end_col: 10 },
// { type: 'other_event', file: 'foo.ml', start_line: 4, start_col: 0, end_line: 5, end_col: 10 },
function tracer_valid_pos(i) {
return (i >= 0 && i < tracer_length);
}
// dir is -1 or +1
function shared_step(dir) {
var i = tracer_pos;
i += dir;
if (! tracer_valid_pos(i))
return; // not found, we don’t update the tracer position.
tracer_pos = i;
}
// dir is -1 or +1,
// target (= target depth) is 0 for (next/prev) or -1 (finish)
function shared_next(dir, target) {
var i = tracer_pos;
var depth = 0;
var ty = tracer_items[i].type;
if (dir === +1 && ty === 'exit') {
depth = 1;
} else if (dir === -1 && ty === 'enter') {
depth = -1;
}
while (true) {
if (! tracer_valid_pos(i)) {
tracer_pos = i - dir; // just before out of range
return; // not found
}
if (i !== tracer_pos && depth === target) {
tracer_pos = i;
return;
}
var ty = tracer_items[i].type;
if (ty === 'enter') {
depth++;
} else if (ty === 'exit') {
depth--;
}
i += dir;
}
}
function restart() { tracer_pos = 0; }
function step() { shared_step(+1); }
function backstep() { shared_step(-1); }
function next() { shared_next(+1, 0); }
function previous() { shared_next(-1, 0); }
function finish() { shared_next(+1, -1); }
var curfile = '';
var docs = {};
for (var i = 0; i < tracer_files.length; i++) {
var file = tracer_files[i].file;
var txt = tracer_files[i].contents;
docs[file] = CodeMirror.Doc(txt, 'js');
}
var editor = null;
var source = null;
function viewFile(file) {
if (curfile !== file) {
curfile = file;
editor.swapDoc(docs[curfile]);
editor.focus();
updateFileList();
}
}
function updateFileList() {
var s = '';
for (var i = 0; i < tracer_files.length; i++) {
var file = tracer_files[i].file;
s += "<span class=\"file_item" + ((curfile == file) ? '_current' : '') + "\" onclick=\"viewFile('" + file + "')\">" + file + "</span> ";
}
$('#file_list').html(s);
}
function text_of_cst(c) {
switch (c.tag) {
case "cst_bool":
return c.bool + "";
case "cst_number":
return c.number + "";
default:
return "unrecognized cst";
}
}
var next_fresh_id = 0;
function fresh_id() {
return "fresh_id_" + (next_fresh_id++);
}
function show_value(heap, v, target, depth) {
var contents_init = $("#" + target).html();
var s = "";
switch (v.tag) {
case "val_cst":
s = text_of_cst(v.cst);
break;
case "val_loc":
var contents_rest = "<span class='heap_link'><a onclick=\"handlers['" + target + "']()\">&lt;Object&gt;(" + v.loc + ")</a></span>";
var contents_default = contents_init + contents_rest;
function handler_close() {
handlers[target] = handler_open;
$("#" + target).html(contents_default);
editor.focus();
}
function handler_open() {
handlers[target] = handler_close;
var obj = heap.get(v.loc).asReadOnlyArray(); // type object
var count = 0;
for (var x in obj) {
if (obj[x] === undefined) continue; // LATER remove!
count++;
var targetsub = fresh_id();
$("#" + target).append("<div style='margin-left:1em' id='" + targetsub + "'></div>");
$("#" + targetsub).html(x + ": ");
show_value(heap, obj[x], targetsub, depth-1);
}
if (count === 0)
$("#" + target).append("<div style='margin-left:1em'>(empty object)</div>");
editor.focus();
};
handlers[target] = handler_open;
$("#" + target).html(contents_default);
if (depth > 0)
handler_open();
return;
case "val_abs":
s = "&lt;Closure&gt;";
break;
default:
s = "<pre style='margin:0; padding: 0; margin-left:1em'>" + JSON.stringify(v, null, 2) + "</pre>";
break;
}
$("#" + target).append(s);
}
function updateContext(targetid, heap, env) {
$(targetid).html("");
if (env === undefined)
return;
array_of_env(env).map(function(env){
var target = fresh_id();
$(targetid).append("<div id='" + target + "'></div>");
$("#" + target).html(env.name + ": ");
var depth = 1;
show_value(heap, env.val, target, depth);
});
}
var source_select = undefined;
function updateSourceSelection() {
if (source_select === undefined) {
return;
}
// TODO: rename column into col
var anchor = {line: source_select.start.line-1 , ch: source_select.start.column };
var head = {line: source_select.end.line-1, ch: source_select.end.column };
source.setSelection(anchor, head);
/* deprecated:
var anchor = {line: source_select-1, ch: 0 };
var head = {line: source_select-1, ch: 100 } */;
}
function updateSelection() {
var item = tracer_items[tracer_pos];
source.setSelection({line: 0, ch:0}, {line: 0, ch:0}); // TODO: fct reset
if (item !== undefined) {
// console.log(item);
// $("#disp_infos").html();
if (item.line === undefined)
alert("missing line in log event");
// source panel
source_select = item.source_select;
// console.log(source_select);
updateSourceSelection();
// ctx panel
updateContext("#disp_ctx", item.heap, item.ctx);
// file panel
viewFile(item.file);
//console.log("pos: " + tracer_pos);
// var color = (item.type === 'enter') ? '#F3F781' : '#CCCCCC';
var color = '#F3F781';
$('.CodeMirror-selected').css({ background: color });
$('.CodeMirror-focused .CodeMirror-selected').css({ background: color });
var anchor = {line: item.start_line-1 , ch: item.start_col };
var head = {line: item.end_line-1, ch: item.end_col };
editor.setSelection(anchor, head);
// env panel
updateContext("#disp_env", item.heap, item.env);
// navig panel
$("#navigation_step").val(tracer_pos);
}
updateFileList();
editor.focus();
}
source = CodeMirror.fromTextArea(document.getElementById('source_code'), {
mode: 'js',
lineNumbers: true,
lineWrapping: true,
});
source.setSize(300, 150);
editor = CodeMirror.fromTextArea(document.getElementById('interpreter_code'), {
mode: 'js',
lineNumbers: true,
lineWrapping: true,
readOnly: true,
extraKeys: {
'R': function(cm) { restart(); updateSelection(); },
'S': function(cm) { step(); updateSelection(); },
'B': function(cm) { backstep(); updateSelection(); },
'N': function(cm) { next(); updateSelection(); },
'P': function(cm) { previous(); updateSelection(); },
'F': function(cm) { finish(); updateSelection(); },
},
});
editor.setSize(600,250);
/* ==> try in new version of codemirror*/
try {
$(editor.getWrapperElement()).resizable({
resize: function() {
editor.setSize($(this).width(), $(this).height());
}
});
} catch(e) { }
editor.on('dblclick', function() {
var line = editor.getCursor().line;
var txt = editor.getLine(line);
var prefix = "#sec-";
var pos_start = txt.indexOf(prefix);
if (pos_start === -1)
return;
var pos_end = txt.indexOf("*", pos_start);
if (pos_end === -1)
return;
var sec = txt.substring(pos_start, pos_end);
var url = "http://www.ecma-international.org/ecma-262/5.1/" + sec;
window.open(url, '_blank');
});
editor.focus();
// used to ensure that most events have an associated term
function completeTermsInDatalog(items) {
var last = undefined;
for (var k = 0; k < datalog.length; k++) {
var item = datalog[k];
item.source_select = last;
if (item.ctx !== undefined) {
var ctx_as_array = array_of_env(item.ctx);
if (ctx_as_array.length > 0 && ctx_as_array[0].name === "t") {
var t = ctx_as_array[0].val;
if (! (t === undefined || t.start === undefined || t.end === undefined)) {
item.source_select = { start: t.start, end: t.end };
// TODO: avoir un t.location
last = t;
}
}
}
}
}
function run() {
run_program(program);
completeTermsInDatalog(datalog);
tracer_items = datalog;
tracer_length = tracer_items.length
$("#navigation_total").html(tracer_length - 1);
stepTo(0); // calls updateSelection();
}
// Note: for the demo
// run();
// stepTo(78);
/* demo
var j = jsheap_of_heap(heap);
for (var k = 0; k < datalog.length; k++) {
var item = datalog[k];
var jsheap = jsheap_of_heap(item.heap);
item.heap = jsheap;
item.env = jsenv_of_env(jsheap, item.env);
if (item.ctx !== undefined) {
item.ctx = jsenv_of_env(jsheap, item.ctx);
}
}
*/
}(function check_pred(p, obj) {
with (obj){
return eval(p)
}
}));
// Source file loaded initially
var source_file = 'var x = alloc;\n{ x.foo = 12;\n x.bar = x.foo;\n x.cycle = x; }\n';
// Source code for the interpreter
// This code was generated from the code placed in comments in "interp.js",
// which was itself obtained by dropping the "log" and "ctx" lines from
// the instrumented interpreter just above.
var tracer_files = [
{ file: 'interp-poc.js', contents: 'function run_trm(t) {\n switch (t.tag) {\n case "trm_var":\n var v = lookup_var(t.name);\n return res_val(v);\n case "trm_cst":\n return res_val({ tag: "val_cst", cst: t.cst });\n case "trm_let":\n return if_success(run_trm(t.t1), function(v1) {\n env_push(t.name, v1);\n var res = run_trm(t.t2);\n env_pop();\n return res;\n });\n case "trm_seq":\n return if_success(run_trm(t.t1), function(v1) {\n return if_success(run_trm(t.t2), function (v2) {\n return(res_val(v2)); \n });\n });\n case "trm_alloc":\n var loc = heap_alloc();\n return res_val({ tag: "val_loc", loc: loc });\n case "trm_get":\n return if_success(run_trm(t.loc), function(loc) {\n var v = heap_get(loc, t.field);\n return res_val(v);\n });\n case "trm_set":\n return if_success(run_trm(t.loc), function(loc) {\n return if_success(run_trm(t.arg), function(arg) {\n heap_set(loc, t.field, arg);\n return res_val(arg);\n });\n });\n case "trm_if":\n return if_success(run_trm(t.cond), function(cond) {\n return if_bool(cond, function(b) {\n if (b) {\n return if_success(run_trm(t.then), function(v) {\n return res_val(v);\n });\n } else if (t.else_option !== undefined) {\n return if_success(run_trm(t.else), function(v) {\n return res_val(v);\n });\n } else {\n return res_val({tag:"val_cst", cst:{tag:"cst_bool", bool:true}});\n }\n });\n });\n }\n}' }
]
/* DEPRECATED
var tracer_items = [
{ type: 'enter', file: 'interp.ml', start_line: 4, start_col: 0, end_line: 5, end_col: 1 },
{ type: 'exit', file: 'interp.ml', start_line: 5, start_col: 1, end_line: 5, end_col: 1 },
{ type: 'enter', file: 'interp.ml', start_line: 5, start_col: 0, end_line: 5, end_col: 4 },
{ type: 'enter', file: 'interp.ml', start_line: 0, start_col: 4, end_line: 0, end_col: 1 },
{ type: 'exit', file: 'interp.ml', start_line: 0, start_col: 5, end_line: 0, end_col: 1 },
{ type: 'exit', file: 'interp.ml', start_line: 5, start_col: 1, end_line: 5, end_col: 4 },
];
*/
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment