git » jacl.git » commit 1acfe6e

initial working optimized GO !!!!

author Alan Dipert
2020-04-11 07:25:37 UTC
committer Alan Dipert
2020-04-11 07:25:37 UTC
parent 90f9d4acde7c2ab213f4b990478148bf22cefe31

initial working optimized GO !!!!

jacl-tests.lisp +10 -2
jacl.js +40 -2

diff --git a/jacl-tests.lisp b/jacl-tests.lisp
index 59ffc72..e371a40 100644
--- a/jacl-tests.lisp
+++ b/jacl-tests.lisp
@@ -67,7 +67,15 @@
      end)
     (assert= x 0)
     (assert= y 10)))
-;
-;(deftest "Dynamic TAGBODY")
+
+(defun countdown (from)
+  (tagbody
+   start
+   (when (> from 0)
+     (log @"from=" from)
+     (setq from (1- from))
+     (go start))))
+
+(countdown 3)
 
 (\. @|QUnit| (|start|))
diff --git a/jacl.js b/jacl.js
index ccfdd17..1f12ed2 100644
--- a/jacl.js
+++ b/jacl.js
@@ -1567,6 +1567,36 @@ const analyze = (env, parent, form) => {
   }
 };
 
+const findNodesByName = (root, op) => {
+  let found = [];
+  if (root.op === op) found.push(root);
+  for (const child of root.children) {
+    found = [...found, ...findNodesByName(child, op)];
+  }
+  return found;
+};
+
+const optimizeTagbody = node => {
+  gos: for (const go of findNodesByName(node, 'go')) {
+    let parent = go.parent;
+    while (parent) {
+      if (parent.op === 'tagbody' && go.tagbodyId === parent.id) {
+        go.op = 'go-continue';
+        continue gos;
+      }
+      if (parent.op === 'lambda') {
+        continue gos;
+      }
+      parent = parent.parent;
+    }
+  }
+};
+
+const optimize = node => {
+  optimizeTagbody(node);
+  return node;
+};
+
 const escapeSingle = name => name.replace(/'/g, "\\'");
 
 const constantCode = val => {
@@ -2010,6 +2040,14 @@ const emitNode = (print, node) => {
       }
       if (context !== 'expr') print(';\n');
       break;
+    } case 'go-continue': {
+      if (context === 'return' || context === 'stmt') {
+        print(`tagbody_${node.tagbodyId}_to=${node.tagId};\n`);
+        print(`continue tagbody_${node.tagbodyId};\n`);
+      } else {
+        throw new Exception(`Unimplemented`);
+      }
+      break;
     } case 'progn': {
       if (context === 'expr' && !node.statements.length) {
         // If there's only a return expression, just emit that.
@@ -2126,7 +2164,7 @@ let replInputStream = new BufferedStream(),
 const startRepl = async () => {
   try {
     for await(const obj of replReader) {
-      const node = analyze(emptyEnv, null, obj);
+      const node = optimize(analyze(emptyEnv, null, obj));
       console.log(node)
       const sb = new StringBuffer();
       emitNode(sb.append.bind(sb), node);
@@ -2153,7 +2191,7 @@ const loadLispScripts = async () => {
       const rdr = new Reader(ss);
       for await(const obj of rdr) {
         if (obj === EOF) break;
-        const node = analyze(emptyEnv, null, obj);
+        const node = optimize(analyze(emptyEnv, null, obj));
         const sb = new StringBuffer();
         emitNode(sb.append.bind(sb), node);
         eval(sb.toString());