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