From 03c790d5b61ecc07a34e6d113a5b434b72c835fe Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 8 Jan 2021 01:06:43 -0800 Subject: Renamed viz -> printing, and tidied up the code a bit --- Makefile | 2 +- bp.c | 2 +- printing.c | 267 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ printing.h | 20 +++++ viz.c | 262 ----------------------------------------------------------- viz.h | 18 ----- vm.h | 5 -- 7 files changed, 289 insertions(+), 287 deletions(-) create mode 100644 printing.c create mode 100644 printing.h delete mode 100644 viz.c delete mode 100644 viz.h diff --git a/Makefile b/Makefile index 90b3c40..39ea023 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ CWARN=-Wall -Wpedantic -Wextra -Wsign-conversion -Wtype-limits -Wunused-result G= O=-O3 -CFILES=compiler.c grammar.c utils.c vm.c file_loader.c viz.c json.c +CFILES=compiler.c grammar.c utils.c vm.c file_loader.c printing.c json.c OBJFILES=$(CFILES:.c=.o) all: $(NAME) diff --git a/bp.c b/bp.c index a9ffe01..cefb5aa 100644 --- a/bp.c +++ b/bp.c @@ -15,8 +15,8 @@ #include "file_loader.h" #include "grammar.h" #include "json.h" +#include "printing.h" #include "utils.h" -#include "viz.h" #include "vm.h" static const char *usage = ( diff --git a/printing.c b/printing.c new file mode 100644 index 0000000..68faf22 --- /dev/null +++ b/printing.c @@ -0,0 +1,267 @@ +/* + * printing.c - Code for printing and visualizing matches. + */ + +#include +#include +#include + +#include "printing.h" +#include "types.h" +#include "utils.h" +#include "vm.h" + +typedef struct match_node_s { + match_t *m; + struct match_node_s *next; +} match_node_t; + +typedef struct { + size_t line, printed_line; + const char *color; +} print_state_t; + +static int match_height(match_t *m) +{ + int height = 0; + for (match_t *c = m->child; c; c = c->nextsibling) { + int childheight = match_height(c); + if (childheight > height) height = childheight; + } + return 1 + height; +} + +static void _visualize_matches(match_node_t *firstmatch, int depth, const char *text, size_t textlen) +{ + if (!firstmatch) return; + + const char *V = "│"; // Vertical bar + const char *H = "─"; // Horizontal bar + const char *color = (depth % 2 == 0) ? "34" : "33"; + + match_t *viz = firstmatch->m; + for (match_node_t *p = firstmatch; p; p = p->next) + if (match_height(p->m) > match_height(viz)) + viz = p->m; + const char *viz_type = viz->op->start; + size_t viz_typelen = (size_t)(viz->op->end - viz->op->start); + + printf("\033[%ldG\033[%s;1m", 2*textlen+3, color); + for (size_t i = 0; i < viz_typelen; i++) { + switch (viz_type[i]) { + case '\n': printf("↵"); break; + default: printf("%c", viz_type[i]); break; + } + } + printf("\033[0m"); + + match_node_t *children = NULL; + match_node_t **nextchild = &children; + +#define RIGHT_TYPE(m) (m->m->op->end == m->m->op->start + viz_typelen && strncmp(m->m->op->start, viz_type, viz_typelen) == 0) + // Print nonzero-width first: + for (match_node_t *m = firstmatch; m; m = m->next) { + //tree_text = byteslice(text, tree['start'], tree['end']).replace('\n', '↵') + if (RIGHT_TYPE(m)) { + //if (m->m->op->op != VM_REF) { + for (match_t *c = m->m->child; c; c = c->nextsibling) { + *nextchild = new(match_node_t); + (*nextchild)->m = c; + nextchild = &((*nextchild)->next); + } + //} + if (m->m->end == m->m->start) continue; + printf("\033[%ldG\033[0;2m%s\033[0;7;%sm", 1+2*(m->m->start - text), V, color); + for (const char *c = m->m->start; c < m->m->end; ++c) { + // TODO: newline + if (c > m->m->start) printf(" "); + // TODO: utf8 + //while ((*c & 0xC0) != 0x80) printf("%c", *(c++)); + printf("%c", *c); + } + printf("\033[0;2m%s\033[0m", V); + } else { + *nextchild = new(match_node_t); + (*nextchild)->m = m->m; + nextchild = &((*nextchild)->next); + printf("\033[%ldG\033[0;2m%s", 1+2*(m->m->start - text), V); + for (ssize_t i = (ssize_t)(2*(m->m->end - m->m->start)-1); i > 0; i--) + printf(" "); + if (m->m->end > m->m->start) + printf("\033[0;2m%s", V); + printf("\033[0m"); + } + } + + // Print stars for zero-width: + for (match_node_t *m = firstmatch; m; m = m->next) { + if (m->m->end > m->m->start) continue; + if (RIGHT_TYPE(m)) { + printf("\033[%ldG\033[7;%sm▒\033[0m", 1+2*(m->m->start - text), color); + } else { + printf("\033[%ldG\033[0;2m%s\033[0m", 1+2*(m->m->start - text), V); + } + } + + printf("\n"); + + for (match_node_t *m = firstmatch; m; m = m->next) { + if (m->m->end == m->m->start) { + if (!RIGHT_TYPE(m)) + printf("\033[%ldG\033[0;2m%s", 1 + 2*(m->m->start - text), V); + } else { + const char *l = "└"; + const char *r = "┘"; + for (match_node_t *c = children; c; c = c->next) { + if (c->m->start == m->m->start || c->m->end == m->m->start) l = V; + if (c->m->start == m->m->end || c->m->end == m->m->end) r = V; + } + printf("\033[%ldG\033[0;2m%s", 1 + 2*(m->m->start - text), l); + const char *h = RIGHT_TYPE(m) ? H : " "; + for (ssize_t n = (ssize_t)(2*(m->m->end - m->m->start) - 1); n > 0; n--) + printf("%s", h); + printf("%s\033[0m", r); + } + } +#undef RIGHT_TYPE + + printf("\n"); + + if (children) + _visualize_matches(children, depth+1, text, textlen); + + for (match_node_t *c = children, *next = NULL; c; c = next) { + next = c->next; + free(c); + } +} + +static void _visualize_patterns(match_t *m) +{ + if (m->op->op == VM_REF && streq(m->op->args.s, "pattern")) { + m = m->child; + match_node_t first = {.m = m}; + _visualize_matches(&first, 0, m->start, (size_t)(m->end - m->start)); + } else { + for (match_t *c = m->child; c; c = c->nextsibling) + _visualize_patterns(c); + } +} + +void visualize_match(match_t *m) +{ + printf("\033[?7l"); + //match_node_t first = {.m = m}; + //_visualize_matches(&first, 0, m->start, (m->end - m->start)); + _visualize_patterns(m); + printf("\033[?7h"); +} + +static void print_line_number(FILE *out, print_state_t *state, print_options_t options) +{ + state->printed_line = state->line; + if (!(options & PRINT_LINE_NUMBERS)) return; + if (options & PRINT_COLOR) + fprintf(out, "\033[0;2m% 5ld\033(0\x78\033(B%s", state->line, state->color); + else + fprintf(out, "% 5ld|", state->line); +} + +/* + * Print a match with replacements and highlighting. + */ +static void _print_match(FILE *out, file_t *f, match_t *m, print_state_t *state, print_options_t options) +{ + static const char *hl = "\033[0;31;1m"; + const char *old_color = state->color; + if (m->op->op == VM_HIDE) { + // TODO: handle replacements? + for (const char *p = m->start; p < m->end; p++) { + if (*p == '\n') ++state->line; + } + } else if (m->op->op == VM_REPLACE) { + if (options & PRINT_COLOR && state->color != hl) { + state->color = hl; + fprintf(out, "%s", state->color); + } + const char *text = m->op->args.replace.text; + const char *end = &text[m->op->args.replace.len]; + for (const char *r = text; r < end; ) { + if (*r == '@' && r[1] && r[1] != '@') { + ++r; + match_t *cap = get_capture(m, &r); + if (cap != NULL) { + _print_match(out, f, cap, state, options); + continue; + } else { + --r; + } + } + + if (state->printed_line != state->line) + print_line_number(out, state, options); + + if (*r == '\\') { + ++r; + unsigned char c = unescapechar(r, &r); + fputc(c, out); + if (c == '\n') ++state->line; + continue; + } else if (*r == '\n') { + fputc('\n', out); + ++state->line; + ++r; + continue; + } else { + fputc(*r, out); + ++r; + continue; + } + } + } else { + if (m->op->op == VM_CAPTURE) { + if (options & PRINT_COLOR && state->color != hl) { + state->color = hl; + fprintf(out, "%s", state->color); + } + } + + const char *prev = m->start; + for (match_t *child = m->child; child; child = child->nextsibling) { + // Skip children from e.g. zero-width matches like >@foo + if (!(prev <= child->start && child->start <= m->end && + prev <= child->end && child->end <= m->end)) + continue; + if (child->start > prev) { + for (const char *p = prev; p < child->start; ++p) { + if (state->printed_line != state->line) + print_line_number(out, state, options); + fputc(*p, out); + if (*p == '\n') ++state->line; + } + } + _print_match(out, f, child, state, options); + prev = child->end; + } + if (m->end > prev) { + for (const char *p = prev; p < m->end; ++p) { + if (state->printed_line != state->line) + print_line_number(out, state, options); + fputc(*p, out); + if (*p == '\n') ++state->line; + } + } + } + if (options & PRINT_COLOR && old_color != state->color) { + fprintf(out, "%s", old_color); + state->color = old_color; + } +} + +void print_match(FILE *out, file_t *f, match_t *m, print_options_t options) +{ + print_state_t state = {.line = 1, .color = "\033[0m"}; + _print_match(out, f, m, &state, options); +} + +// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1 diff --git a/printing.h b/printing.h new file mode 100644 index 0000000..7059562 --- /dev/null +++ b/printing.h @@ -0,0 +1,20 @@ +/* + * Header file for printing.c (printing/visualizing matches) + */ +#ifndef PRINTING__H +#define PRINTING__H + +#include "types.h" + +typedef enum { + PRINT_COLOR = 1<<0, + PRINT_LINE_NUMBERS = 1<<1, +} print_options_t; + +__attribute__((nonnull)) +void visualize_match(match_t *m); +__attribute__((nonnull)) +void print_match(FILE *out, file_t *f, match_t *m, print_options_t options); + +#endif +// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1 diff --git a/viz.c b/viz.c deleted file mode 100644 index a4aa565..0000000 --- a/viz.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * viz.c - Visualize matches. - */ - -#include -#include -#include - -#include "types.h" -#include "utils.h" -#include "viz.h" -#include "vm.h" - -typedef struct { - size_t line, printed_line; - const char *color; -} print_state_t; - -static int match_height(match_t *m) -{ - int height = 0; - for (match_t *c = m->child; c; c = c->nextsibling) { - int childheight = match_height(c); - if (childheight > height) height = childheight; - } - return 1 + height; -} - -static void _visualize_matches(match_node_t *firstmatch, int depth, const char *text, size_t textlen) -{ - if (!firstmatch) return; - - const char *V = "│"; // Vertical bar - const char *H = "─"; // Horizontal bar - const char *color = (depth % 2 == 0) ? "34" : "33"; - - match_t *viz = firstmatch->m; - for (match_node_t *p = firstmatch; p; p = p->next) - if (match_height(p->m) > match_height(viz)) - viz = p->m; - const char *viz_type = viz->op->start; - size_t viz_typelen = (size_t)(viz->op->end - viz->op->start); - - printf("\033[%ldG\033[%s;1m", 2*textlen+3, color); - for (size_t i = 0; i < viz_typelen; i++) { - switch (viz_type[i]) { - case '\n': printf("↵"); break; - default: printf("%c", viz_type[i]); break; - } - } - printf("\033[0m"); - - match_node_t *children = NULL; - match_node_t **nextchild = &children; - -#define RIGHT_TYPE(m) (m->m->op->end == m->m->op->start + viz_typelen && strncmp(m->m->op->start, viz_type, viz_typelen) == 0) - // Print nonzero-width first: - for (match_node_t *m = firstmatch; m; m = m->next) { - //tree_text = byteslice(text, tree['start'], tree['end']).replace('\n', '↵') - if (RIGHT_TYPE(m)) { - //if (m->m->op->op != VM_REF) { - for (match_t *c = m->m->child; c; c = c->nextsibling) { - *nextchild = new(match_node_t); - (*nextchild)->m = c; - nextchild = &((*nextchild)->next); - } - //} - if (m->m->end == m->m->start) continue; - printf("\033[%ldG\033[0;2m%s\033[0;7;%sm", 1+2*(m->m->start - text), V, color); - for (const char *c = m->m->start; c < m->m->end; ++c) { - // TODO: newline - if (c > m->m->start) printf(" "); - // TODO: utf8 - //while ((*c & 0xC0) != 0x80) printf("%c", *(c++)); - printf("%c", *c); - } - printf("\033[0;2m%s\033[0m", V); - } else { - *nextchild = new(match_node_t); - (*nextchild)->m = m->m; - nextchild = &((*nextchild)->next); - printf("\033[%ldG\033[0;2m%s", 1+2*(m->m->start - text), V); - for (ssize_t i = (ssize_t)(2*(m->m->end - m->m->start)-1); i > 0; i--) - printf(" "); - if (m->m->end > m->m->start) - printf("\033[0;2m%s", V); - printf("\033[0m"); - } - } - - // Print stars for zero-width: - for (match_node_t *m = firstmatch; m; m = m->next) { - if (m->m->end > m->m->start) continue; - if (RIGHT_TYPE(m)) { - printf("\033[%ldG\033[7;%sm▒\033[0m", 1+2*(m->m->start - text), color); - } else { - printf("\033[%ldG\033[0;2m%s\033[0m", 1+2*(m->m->start - text), V); - } - } - - printf("\n"); - - for (match_node_t *m = firstmatch; m; m = m->next) { - if (m->m->end == m->m->start) { - if (!RIGHT_TYPE(m)) - printf("\033[%ldG\033[0;2m%s", 1 + 2*(m->m->start - text), V); - } else { - const char *l = "└"; - const char *r = "┘"; - for (match_node_t *c = children; c; c = c->next) { - if (c->m->start == m->m->start || c->m->end == m->m->start) l = V; - if (c->m->start == m->m->end || c->m->end == m->m->end) r = V; - } - printf("\033[%ldG\033[0;2m%s", 1 + 2*(m->m->start - text), l); - const char *h = RIGHT_TYPE(m) ? H : " "; - for (ssize_t n = (ssize_t)(2*(m->m->end - m->m->start) - 1); n > 0; n--) - printf("%s", h); - printf("%s\033[0m", r); - } - } -#undef RIGHT_TYPE - - printf("\n"); - - if (children) - _visualize_matches(children, depth+1, text, textlen); - - for (match_node_t *c = children, *next = NULL; c; c = next) { - next = c->next; - free(c); - } -} - -static void _visualize_patterns(match_t *m) -{ - if (m->op->op == VM_REF && streq(m->op->args.s, "pattern")) { - m = m->child; - match_node_t first = {.m = m}; - _visualize_matches(&first, 0, m->start, (size_t)(m->end - m->start)); - } else { - for (match_t *c = m->child; c; c = c->nextsibling) - _visualize_patterns(c); - } -} - -void visualize_match(match_t *m) -{ - printf("\033[?7l"); - //match_node_t first = {.m = m}; - //_visualize_matches(&first, 0, m->start, (m->end - m->start)); - _visualize_patterns(m); - printf("\033[?7h"); -} - -static void print_line_number(FILE *out, print_state_t *state, print_options_t options) -{ - state->printed_line = state->line; - if (!(options & PRINT_LINE_NUMBERS)) return; - if (options & PRINT_COLOR) - fprintf(out, "\033[0;2m% 5ld\033(0\x78\033(B%s", state->line, state->color); - else - fprintf(out, "% 5ld|", state->line); -} - -/* - * Print a match with replacements and highlighting. - */ -static void _print_match(FILE *out, file_t *f, match_t *m, print_state_t *state, print_options_t options) -{ - static const char *hl = "\033[0;31;1m"; - const char *old_color = state->color; - if (m->op->op == VM_HIDE) { - // TODO: handle replacements? - for (const char *p = m->start; p < m->end; p++) { - if (*p == '\n') ++state->line; - } - } else if (m->op->op == VM_REPLACE) { - if (options & PRINT_COLOR && state->color != hl) { - state->color = hl; - fprintf(out, "%s", state->color); - } - const char *text = m->op->args.replace.text; - const char *end = &text[m->op->args.replace.len]; - for (const char *r = text; r < end; ) { - if (*r == '@' && r[1] && r[1] != '@') { - ++r; - match_t *cap = get_capture(m, &r); - if (cap != NULL) { - _print_match(out, f, cap, state, options); - continue; - } else { - --r; - } - } - - if (state->printed_line != state->line) - print_line_number(out, state, options); - - if (*r == '\\') { - ++r; - unsigned char c = unescapechar(r, &r); - fputc(c, out); - if (c == '\n') ++state->line; - continue; - } else if (*r == '\n') { - fputc('\n', out); - ++state->line; - ++r; - continue; - } else { - fputc(*r, out); - ++r; - continue; - } - } - } else { - if (m->op->op == VM_CAPTURE) { - if (options & PRINT_COLOR && state->color != hl) { - state->color = hl; - fprintf(out, "%s", state->color); - } - } - - const char *prev = m->start; - for (match_t *child = m->child; child; child = child->nextsibling) { - // Skip children from e.g. zero-width matches like >@foo - if (!(prev <= child->start && child->start <= m->end && - prev <= child->end && child->end <= m->end)) - continue; - if (child->start > prev) { - for (const char *p = prev; p < child->start; ++p) { - if (state->printed_line != state->line) - print_line_number(out, state, options); - fputc(*p, out); - if (*p == '\n') ++state->line; - } - } - _print_match(out, f, child, state, options); - prev = child->end; - } - if (m->end > prev) { - for (const char *p = prev; p < m->end; ++p) { - if (state->printed_line != state->line) - print_line_number(out, state, options); - fputc(*p, out); - if (*p == '\n') ++state->line; - } - } - } - if (options & PRINT_COLOR && old_color != state->color) { - fprintf(out, "%s", old_color); - state->color = old_color; - } -} - -void print_match(FILE *out, file_t *f, match_t *m, print_options_t options) -{ - print_state_t state = {.line = 1, .color = "\033[0m"}; - _print_match(out, f, m, &state, options); -} - -// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1 diff --git a/viz.h b/viz.h deleted file mode 100644 index 8b11bcc..0000000 --- a/viz.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Header file for viz.c (visualizing matches) - */ -#ifndef VIZ__H -#define VIZ__H - -typedef struct match_node_s { - match_t *m; - struct match_node_s *next; -} match_node_t; - -__attribute__((nonnull)) -void visualize_match(match_t *m); -__attribute__((nonnull)) -void print_match(FILE *out, file_t *f, match_t *m, print_options_t options); - -#endif -// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1 diff --git a/vm.h b/vm.h index 2c17743..148f2b5 100644 --- a/vm.h +++ b/vm.h @@ -8,11 +8,6 @@ #include "types.h" -typedef enum { - PRINT_COLOR = 1<<0, - PRINT_LINE_NUMBERS = 1<<1, -} print_options_t; - const char *opcode_name(enum VMOpcode o); __attribute__((hot, nonnull)) match_t *match(grammar_t *g, file_t *f, const char *str, vm_op_t *op, unsigned int flags); -- cgit v1.2.3