From a8a7c2a8e9c86f145651be8ad918ffd6209959cf Mon Sep 17 00:00:00 2001
From: Andrea Shepard <andrea@persephoneslair.org>
Date: Thu, 17 Nov 2016 23:27:08 +0000
Subject: [PATCH] Charset exec plan pretty printer

---
 src/backends/llvm.c | 143 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 143 insertions(+)

diff --git a/src/backends/llvm.c b/src/backends/llvm.c
index 1df15086..49537914 100644
--- a/src/backends/llvm.c
+++ b/src/backends/llvm.c
@@ -517,6 +517,148 @@ static void h_llvm_free_charset_exec_plan(HAllocator* mm__,
   }
 }
 
+/*
+ * Pretty-print a charset exec plan to stdout
+ */
+
+static void h_llvm_pretty_print_charset_exec_plan_impl(HAllocator *mm__, llvm_charset_exec_plan_t *cep,
+                                                       const char *pfx_on_action_line, const char *pfx,
+                                                       int depth) {
+  const char *action_string = NULL, *pfx_incr = NULL;
+  const char *pfx_incr_child_action = NULL, *pfx_incr_last_child = NULL;
+  char *next_pfx = NULL, *next_pfx_child_action_line = NULL, *next_pfx_last_child = NULL;
+  int n_children = 0, i, j, next_pfx_len;
+  uint8_t ch;
+
+  if (!cep) {
+    action_string = "NULL";
+  } else {
+    switch (cep->action) {
+      case CHARSET_ACTION_ACCEPT:
+        action_string = "CHARSET_ACTION_ACCEPT";
+        break;
+      case CHARSET_ACTION_SCAN:
+        action_string = "CHARSET_ACTION_SCAN";
+        break;
+      case CHARSET_ACTION_COMPLEMENT:
+        action_string = "CHARSET_ACTION_COMPLEMENT";
+        n_children = 1;
+        break;
+      case CHARSET_ACTION_SPLIT:
+        action_string = "CHARSET_ACTION_SPLIT";
+        n_children = 2;
+        break;
+      default:
+        action_string = "UNKNOWN";
+        break;
+    }
+  }
+
+  if (n_children > 0) {
+    pfx_incr = " | ";
+  } else {
+    pfx_incr = "   ";
+  }
+
+
+  if (depth > 0 || strlen(pfx_on_action_line) > 0) {
+    printf("%s-%s\n", pfx_on_action_line, action_string);
+    pfx_incr = (n_children > 0) ? " | " : "   ";
+    pfx_incr_child_action = " +-";
+    pfx_incr_last_child = "   ";
+  } else {
+    printf("%s\n", action_string);
+    pfx_incr = (n_children > 0) ? "| " : "  ";
+    pfx_incr_child_action = "+-";
+    pfx_incr_last_child = "  ";
+  }
+
+  /*
+   * Now do the charset, 8 lines of 32 bits with spaces in between to
+   * fit [] range markers and | split point marker.
+   */
+  int open = 0, close = 0, split = 0;
+  for (ch = 0, i = 0; i < 8; ++i) {
+    /* Special case: [ should go before first char on line */
+    if (ch == cep->idx_start) {
+      printf("%s%s [", pfx, pfx_incr);
+    } else {
+      printf("%s%s  ", pfx, pfx_incr);
+    }
+    for (j = 0; j < 32; ++j, ++ch) {
+      open = close = split = 0;
+      /* Figure out markers, avoid wraparound */
+      if (cep->idx_start != 0 && ch + 1 == cep->idx_start && j > 0) {
+        /* There should be a [ right after this char */
+        open = 1;
+      } else if (ch == cep->idx_end) {
+        /* There should be a ] right after this char */
+        close = 1;
+      } else if (ch == cep->split_point &&
+                 cep->action == CHARSET_ACTION_SPLIT) {
+        /* There should be a | right after this char */
+        split = 1;
+      }
+
+      if (charset_isset(cep->cs, ch)) printf("X");
+      else printf(".");
+
+      if (open) printf("[");
+      else if (close) printf("]");
+      else if (split) printf("|");
+      else printf(" ");
+    }
+    printf("\n");
+  }
+
+  if (cep->action == CHARSET_ACTION_SPLIT) {
+    printf("%s%s idx_start = %u, split_point = %u, idx_end = %u\n",
+           pfx, pfx_incr, cep->idx_start, cep->split_point, cep->idx_end);
+  } else {
+    printf("%s%s idx_start = %u, idx_end = %u\n",
+           pfx, pfx_incr, cep->idx_start, cep->idx_end);
+  }
+
+  printf("%s%s cost = %d\n", pfx, pfx_incr, cep->cost);
+
+  if (n_children > 0) {
+    if (n_children > 1) {
+      next_pfx_len = strlen(pfx) + strlen(pfx_incr) + 1;
+      next_pfx = h_new(char, next_pfx_len);
+      snprintf(next_pfx, next_pfx_len, "%s%s", pfx, pfx_incr);
+    } else {
+      /* Won't be needed */
+      next_pfx = NULL;
+    }
+    next_pfx_len = strlen(pfx) + strlen(pfx_incr_child_action) + 1;
+    next_pfx_child_action_line = h_new(char, next_pfx_len);
+    snprintf(next_pfx_child_action_line, next_pfx_len,
+             "%s%s", pfx, pfx_incr_child_action);
+    next_pfx_len = strlen(pfx) + strlen(pfx_incr_last_child) + 1;
+    next_pfx_last_child = h_new(char, next_pfx_len);
+    snprintf(next_pfx_last_child, next_pfx_len,
+             "%s%s", pfx, pfx_incr_last_child);
+
+    for (i = 0; i < n_children; ++i) {
+      /* Space things out */
+      printf("%s%s\n", pfx, pfx_incr);
+      h_llvm_pretty_print_charset_exec_plan_impl(mm__, cep->children[i],
+          next_pfx_child_action_line, (i + 1 == n_children) ? next_pfx_last_child : next_pfx,
+          depth + 1);
+    }
+
+    if (next_pfx) h_free(next_pfx);
+    h_free(next_pfx_last_child);
+    h_free(next_pfx_child_action_line);
+  }
+}
+
+static void h_llvm_pretty_print_charset_exec_plan(HAllocator *mm__, llvm_charset_exec_plan_t *cep) {
+  /* Start at depth 0, and always emit an initial newline */
+  printf("\n");
+  h_llvm_pretty_print_charset_exec_plan_impl(mm__, cep, "", "", 0);
+}
+
 /*
  * Construct LLVM IR to decide if a runtime value is a member of a compile-time
  * character set, and branch depending on the result.
@@ -556,6 +698,7 @@ void h_llvm_make_charset_membership_test(HAllocator* mm__,
     bool ok = h_llvm_check_charset_exec_plan(cep);
     if (ok) fprintf(stderr, "cep %p passes consistency check\n", (void *)cep);
     else fprintf(stderr, "cep %p fails consistency check\n", (void *)cep);
+    h_llvm_pretty_print_charset_exec_plan(mm__, cep);
     h_llvm_free_charset_exec_plan(mm__, cep);
     cep = NULL;
   } else {
-- 
GitLab