From 21f59078d5e8ec5e4311ac38b9f72fb104220eb6 Mon Sep 17 00:00:00 2001 From: Cesar Roux Dit Buisson <cr1013@imperial.ac.uk> Date: Wed, 16 Sep 2015 16:26:24 +0100 Subject: [PATCH] Change interpreter example to calc with stack example --- generator/tests/calc.ml | 2 +- interp.js | 238 +++++++++++++++++++++++++++++++--------- source.js | 4 +- 3 files changed, 192 insertions(+), 52 deletions(-) diff --git a/generator/tests/calc.ml b/generator/tests/calc.ml index 62caab4..1a288a0 100644 --- a/generator/tests/calc.ml +++ b/generator/tests/calc.ml @@ -37,5 +37,5 @@ and print_sexpr sexpr = match sexpr with let f = (*let bli = Stack.C(1, Stack.N) in let blii = (Stack.push 2 bli) in*) - let source = parse "Pop(Push(1, Push(5, Emp))) - 7" in + let source = parse "Pop(Push(1, Push(5, Emp)) - 7" in print ((print_expr source) + " = " + to_string (eval_ source)) diff --git a/interp.js b/interp.js index ab8797f..637cdc4 100644 --- a/interp.js +++ b/interp.js @@ -254,39 +254,152 @@ function run_trm(expr) { var ctx = ctx_empty(); ctx = ctx_push(ctx, "expr", expr, "term"); log(1, ctx, "run_trm"); - return (function () { - switch (expr.type) { - case "Const": var n = expr.value; - ctx_push(ctx, "n", n, "value"); - log(5 , ctx, "Const"); - - return n; - case "Add": var ls = expr.left, rs = expr.right; - ctx_push(ctx, "ls", ls, "value"); - ctx_push(ctx, "rs", rs, "value"); - log(8 , ctx, "Add"); - - return run_trm_wrap(10, ls) + run_trm_wrap(10, rs); - case "Sub": var ls = expr.left, rs = expr.right; - ctx_push(ctx, "ls", ls, "value"); - ctx_push(ctx, "rs", rs, "value"); - log(11 , ctx, "Sub"); - - return run_trm_wrap(13, ls) - run_trm_wrap(13, rs); - case "Mul": var ls = expr.left, rs = expr.right; - ctx_push(ctx, "ls", ls, "value"); - ctx_push(ctx, "rs", rs, "value"); - log(14 , ctx, "Mul"); - - return run_trm_wrap(16, ls) * run_trm_wrap(13, rs); - case "Div": var ls = expr.left, rs = expr.right; - ctx_push(ctx, "ls", ls, "value"); - ctx_push(ctx, "rs", rs, "value"); - log(17 , ctx, "Div"); - - return run_trm_wrap(19, ls) / run_trm_wrap(19, rs); - } - }()) + return (function (expr) { + var Stack = { + is_empty: function (s) { + return s === {type: "N"}; + }, + + push: function (x, stack) { + return {type: "C", value: x, stack: stack}; + }, + + pop: function (stack) { + return (function () { + switch (stack.type) { + case "C": var x = stack.value, xs = stack.stack; + return x; + case "K": var x = stack.value, xs = stack.stack; + return x; + case "B": + return stuck("Empty list"); + case "N": + return stuck("Empty list"); + } + }()) + ; + }, + + } + + var eval_ = function (expr) { + return (function () { + switch (expr.type) { + case "Const": var n = expr.value; + ctx_push(ctx, "n", n, "value"); + log(30 , ctx, "Const"); + + return n; + case "Add": var ls = expr.left, rs = expr.right; + ctx_push(ctx, "ls", ls, "value"); + ctx_push(ctx, "rs", rs, "value"); + log(32 , ctx, "Add"); + + return eval_(ls) + eval_(rs); + case "Sub": var ls = expr.left, rs = expr.right; + ctx_push(ctx, "ls", ls, "value"); + ctx_push(ctx, "rs", rs, "value"); + log(34 , ctx, "Sub"); + + return eval_(ls) - eval_(rs); + case "Mul": var ls = expr.left, rs = expr.right; + ctx_push(ctx, "ls", ls, "value"); + ctx_push(ctx, "rs", rs, "value"); + log(36 , ctx, "Mul"); + + return eval_(ls) * eval_(rs); + case "Div": var ls = expr.left, rs = expr.right; + ctx_push(ctx, "ls", ls, "value"); + ctx_push(ctx, "rs", rs, "value"); + log(38 , ctx, "Div"); + + return eval_(ls) / eval_(rs); + case "Pop": var s = expr.stack; + ctx_push(ctx, "s", s, "value"); + log(40 , ctx, "Pop"); + + return Stack.pop(evals(s)); + } + }()) + ; + }; + + var evals = function (sexpr) { + return (function () { + switch (sexpr.type) { + case "Emp": + return {type: "Stack.N"}; + case "Push": var v = sexpr.value, s = sexpr.stack; + ctx_push(ctx, "v", v, "value"); + ctx_push(ctx, "s", s, "value"); + log(52 , ctx, "Push"); + + return Stack.push(eval_(v), evals(s)); + } + }()) + ; + }; + + var print_expr = function (expr) { + return (function () { + switch (expr.type) { + case "Const": var n = expr.value; + ctx_push(ctx, "n", n, "value"); + log(62 , ctx, "Const"); + + return to_string(n); + case "Add": var ls = expr.left, rs = expr.right; + ctx_push(ctx, "ls", ls, "value"); + ctx_push(ctx, "rs", rs, "value"); + log(64 , ctx, "Add"); + + return "(" + print_expr(ls) + ")" + " + " + print_expr(rs); + case "Sub": var ls = expr.left, rs = expr.right; + ctx_push(ctx, "ls", ls, "value"); + ctx_push(ctx, "rs", rs, "value"); + log(66 , ctx, "Sub"); + + return "(" + print_expr(ls) + ")" + " - " + print_expr(rs); + case "Mul": var ls = expr.left, rs = expr.right; + ctx_push(ctx, "ls", ls, "value"); + ctx_push(ctx, "rs", rs, "value"); + log(68 , ctx, "Mul"); + + return "(" + print_expr(ls) + ")" + " * " + print_expr(rs); + case "Div": var ls = expr.left, rs = expr.right; + ctx_push(ctx, "ls", ls, "value"); + ctx_push(ctx, "rs", rs, "value"); + log(70 , ctx, "Div"); + + return "(" + print_expr(ls) + ")" + " / " + print_expr(rs); + case "Pop": var s = expr.stack; + ctx_push(ctx, "s", s, "value"); + log(72 , ctx, "Pop"); + + return "Pop(" + print_sexpr(s) + ")"; + } + }()) + ; + }; + + var print_sexpr = function (sexpr) { + return (function () { + switch (sexpr.type) { + case "Emp": + return "Emp"; + case "Push": var v = sexpr.value, s = sexpr.stack; + ctx_push(ctx, "v", v, "value"); + ctx_push(ctx, "s", s, "value"); + log(84 , ctx, "Push"); + + return "Push(" + print_expr(v) + ", " + print_sexpr(s) + ")"; + } + }()) + ; + }; + + return eval_(expr); + }(expr)) ; }; @@ -363,31 +476,58 @@ var parse = function (source) { var ast = esprima.parse(source).body[0].expression; function transform (tree) { - if (tree === undefined) { - } else { + if (tree === undefined) { + } else { + // Javascript style instructions are well handled with no additional creation. switch (tree.operator) { - case '+': - tree.type = "Add"; tree.operator = undefined; break; - case '-': - tree.type = "Sub"; tree.operator = undefined; break; - case "*": - tree.type = "Mul"; tree.operator = undefined; break; - case "/": - tree.type = "Div"; tree.operator = undefined; break; - default: break; + case '+': + tree.type = "Add"; tree.operator = undefined; break; + case '-': + tree.type = "Sub"; tree.operator = undefined; break; + case "*": + tree.type = "Mul"; tree.operator = undefined; break; + case "/": + tree.type = "Div"; tree.operator = undefined; break; + default: break; } - switch (tree.type) { - case "Literal": - tree.type = "Const"; break; - default: break; + if (tree.type === "Literal") { + tree.type = "Const"; } + // tree.left and tree.right from parser interpretation if (tree.left !== undefined) tree.left = transform(tree.left); if (tree.right !== undefined) tree.right = transform(tree.right); + + // Esprima sees these standalone type instructions as Identifiers + if (tree.type === "Identifier") { + switch (tree.name) { + case "Emp": + tree.type = "Emp"; break; + default: console.log("Unknown ident"); break; + } + } + + // Esprima generates a function type structure that needs reshaping to the + // automatically generated structure, respecting label names! + if (tree.type === "CallExpression") { + switch (tree.callee.name) { + case "Push": + tree.type = "Push"; + tree.value = transform(tree.arguments[0]); + tree.stack = transform(tree.arguments[1]); + break; + case "Pop": + tree.type = "Pop"; + tree.stack = transform(tree.arguments[0]); + break; + default: console.log("Unknown callexpr"); break; + } + } + return tree; + } } - } return transform(ast); } diff --git a/source.js b/source.js index 951872d..55ffdc7 100644 --- a/source.js +++ b/source.js @@ -1,13 +1,13 @@ // Source file loaded initially -var source_file = '((1972 / 29) / 2) + 8'; +var source_file = 'Pop(Push(1, Push(5, Emp))) - 7'; // 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.js', contents: 'function run_trm(expr) {\n var ctx = ctx_empty();\n return (function () {\n switch (expr.type) {\n case "Const": var n = expr.value;\n\n return n;\n case "Add": var ls = expr.left, rs = expr.right;\n\n return run_trm(ls) + run_trm(rs);\n case "Sub": var ls = expr.left, rs = expr.right;\n\n return run_trm(ls) - run_trm(rs);\n case "Mul": var ls = expr.left, rs = expr.right;\n\n return run_trm(ls) * run_trm(rs);\n case "Div": var ls = expr.left, rs = expr.right;\n\n return run_trm(ls) / run_trm(rs);\n }\n }());\n };' + { file: 'interp.js', contents: 'var Stack = {\n is_empty: function (s) {\n return s === {type: "N"};\n },\n\n push: function (x, stack) {\n return {type: "C", value: x, stack: stack};\n },\n\n pop: function (stack) {\n return (function () {\n switch (stack.type) {\n case "C": var x = stack.value, xs = stack.stack;\n return x;\n case "K": var x = stack.value, xs = stack.stack;\n return x;\n case "B": \n return stuck("Empty list");\n case "N": \n return stuck("Empty list");\n }\n }())\n ;\n },\n\n}\nvar eval_ = function (expr) {\n return (function () {\n switch (expr.type) {\n case "Const": var n = expr.value;\n return n;\n case "Add": var ls = expr.left, rs = expr.right;\n return eval_(ls) + eval_(rs);\n case "Sub": var ls = expr.left, rs = expr.right;\n return eval_(ls) - eval_(rs);\n case "Mul": var ls = expr.left, rs = expr.right;\n return eval_(ls) * eval_(rs);\n case "Div": var ls = expr.left, rs = expr.right;\n return eval_(ls) / eval_(rs);\n case "Pop": var s = expr.stack;\n return Stack.pop(evals(s));\n }\n }())\n ;\n };\n \nvar evals = function (sexpr) {\n return (function () {\n switch (sexpr.type) {\n case "Emp": \n return {type: "Stack.N"};\n case "Push": var v = sexpr.value, s = sexpr.stack;\n return Stack.push(eval_(v), evals(s));\n }\n }())\n ;\n};\n\nvar print_expr = function (expr) {\n return (function () {\n switch (expr.type) {\n case "Const": var n = expr.value;\n return to_string(n);\n case "Add": var ls = expr.left, rs = expr.right;\n return "(" + print_expr(ls) + ")" + " + " + print_expr(rs);\n case "Sub": var ls = expr.left, rs = expr.right;\n return "(" + print_expr(ls) + ")" + " - " + print_expr(rs);\n case "Mul": var ls = expr.left, rs = expr.right;\n return "(" + print_expr(ls) + ")" + " * " + print_expr(rs);\n case "Div": var ls = expr.left, rs = expr.right;\n return "(" + print_expr(ls) + ")" + " / " + print_expr(rs);\n case "Pop": var s = expr.stack;\n return "Pop(" + print_sexpr(s) + ")";\n }\n }())\n ;\n};\n\nvar print_sexpr = function (sexpr) {\n return (function () {\n switch (sexpr.type) {\n case "Emp": \n return "Emp";\n case "Push": var v = sexpr.value, s = sexpr.stack;\n return "Push(" + print_expr(v) + ", " + print_sexpr(s) + ")";\n }\n }())\n ;\n};\n\nreturn eval_(expr);' } ] -- GitLab