diff --git a/src/lx/main.c b/src/lx/main.c index 2c485ec59..f17007599 100644 --- a/src/lx/main.c +++ b/src/lx/main.c @@ -125,6 +125,7 @@ print_name(const char *name) { "test", NULL }, { "dot", lx_print_dot }, { "dump", lx_print_dump }, + { "json", lx_print_json }, { "zdot", lx_print_zdot }, { "c", lx_print_c }, { "h", lx_print_h } diff --git a/src/lx/print.h b/src/lx/print.h index 118ec208c..78b4c07b4 100644 --- a/src/lx/print.h +++ b/src/lx/print.h @@ -54,6 +54,7 @@ lx_print lx_print_c; lx_print lx_print_h; lx_print lx_print_dot; lx_print lx_print_dump; +lx_print lx_print_json; lx_print lx_print_zdot; #endif diff --git a/src/lx/print/Makefile b/src/lx/print/Makefile index dc2e3f4ea..2304cc4ca 100644 --- a/src/lx/print/Makefile +++ b/src/lx/print/Makefile @@ -4,6 +4,7 @@ SRC += src/lx/print/c.c SRC += src/lx/print/h.c SRC += src/lx/print/dot.c SRC += src/lx/print/dump.c +SRC += src/lx/print/json.c SRC += src/lx/print/zdot.c .for src in ${SRC:Msrc/lx/print/*.c} diff --git a/src/lx/print/json.c b/src/lx/print/json.c new file mode 100644 index 000000000..d1c61f07c --- /dev/null +++ b/src/lx/print/json.c @@ -0,0 +1,163 @@ +/* + * Copyright 2019 Jamey Sharp + * + * See LICENCE for the full copyright terms. + */ + +#include +#include +#include + +#include + +#include +#include + +#include "libfsm/internal.h" /* XXX */ + +#include "lx/ast.h" +#include "lx/print.h" + +/* TODO: centralise with libfsm */ +static unsigned int +indexof(const struct fsm *fsm, const struct fsm_state *state) +{ + struct fsm_state *s; + unsigned int i; + + assert(fsm != NULL); + assert(state != NULL); + + for (s = fsm->sl, i = 0; s != NULL; s = s->next, i++) { + if (s == state) { + return i; + } + } + + assert(!"unreached"); + return 0; +} + +static unsigned int +zindexof(const struct ast *ast, const struct ast_zone *zone) +{ + struct ast_zone *z; + unsigned int i; + + assert(ast != NULL); + assert(zone != NULL); + + for (z = ast->zl, i = 0; z != NULL; z = z->next, i++) { + if (z == zone) { + return i; + } + } + + assert(!"unreached"); + return 0; +} + +static int +print_zone(FILE *f, const struct ast *ast, const struct ast_zone *z) +{ + struct fsm_state *s, *st; + int ret; + + assert(f != NULL); + assert(z != NULL); + assert(z->fsm != NULL); + assert(fsm_all(z->fsm, fsm_isdfa)); + assert(ast != NULL); + + fprintf(f, " {\n"); + fprintf(f, " \"initial_state\": %u,\n", indexof(z->fsm, z->fsm->start)); + fprintf(f, " \"states\": [\n"); + + for (s = z->fsm->sl; s != NULL; s = s->next) { + struct fsm_edge *e; + struct set_iter it; + + fprintf(f, " {\n"); + + e = set_first(s->edges, &it); + + if (fsm_isend(z->fsm, s)) { + const struct ast_mapping *m = s->opaque; + assert(m != NULL); + + if (m->token != NULL) { + fprintf(f, " \"token\": \"$%s\",\n", m->token->s); + } + if (m->to != NULL) { + fprintf(f, " \"next_zone\": %u,\n", zindexof(ast, m->to)); + } + + fprintf(f, " \"accepts\": true%s\n", e != NULL ? "," : ""); + } + + if (e != NULL) { + int first = 1; + fprintf(f, " \"transitions\": ["); + for (; e != NULL; e = set_next(&it)) { + struct set_iter jt; + for (st = set_first(e->sl, &jt); st != NULL; st = set_next(&jt)) { + fprintf(f, "%s\n { \"symbol\": %u, \"target\": %u }", + first ? "" : ",", + e->symbol, + indexof(z->fsm, st)); + first = 0; + } + } + fprintf(f, "\n ]\n"); + } + + fprintf(f, " }%s\n", s->next ? "," : ""); + } + + fprintf(f, " ]\n"); + fprintf(f, " }%s\n", z->next ? "," : ""); + + return 0; +} + +void +lx_print_json(FILE *f, const struct ast *ast) +{ + const struct ast_zone *z; + unsigned int zn; + + assert(f != NULL); + + for (z = ast->zl; z != NULL; z = z->next) { + if (!fsm_all(z->fsm, fsm_isdfa)) { + errno = EINVAL; + return; + } + } + + fprintf(f, "{\n"); + fprintf(f, " \"prefix\": { \"api\": \"%s\", \"tok\": \"%s\", \"lx\": \"%s\" },\n", + prefix.api, prefix.tok, prefix.lx); + fprintf(f, " \"initial_zone\": %u,\n", zindexof(ast, ast->global)); + fprintf(f, " \"zones\": [\n"); + + if (print_progress) { + zn = 0; + } + + for (z = ast->zl; z != NULL; z = z->next) { + if (print_progress) { + if (important(zn)) { + fprintf(stderr, " z%u", zn); + } + zn++; + } + + if (-1 == print_zone(f, ast, z)) { + return; /* XXX: handle error */ + } + } + + fprintf(f, " ]\n"); + fprintf(f, "}\n"); +}