From 5623bdce6bcf24a586b3a13bfea5cce50e62f365 Mon Sep 17 00:00:00 2001 From: overflowerror Date: Tue, 8 Jun 2021 19:17:18 +0200 Subject: [PATCH] parent handling done --- src/main.c | 52 +++++++++++++++++++++- src/parser.y | 8 +++- src/templates.c | 113 ++++++++++++++++++++++++++++++++---------------- src/tree.c | 16 ++++--- src/tree.h | 3 +- 5 files changed, 142 insertions(+), 50 deletions(-) diff --git a/src/main.c b/src/main.c index 2d418b6..b76a0a5 100644 --- a/src/main.c +++ b/src/main.c @@ -2,12 +2,14 @@ #include #include #include +#include #include "tree.h" #include "common.h" #define PRINT_PREFIX ("print_template") #define SIZE_PREFIX ("size_template") +#define END_SUFFIX ("end") #define SIZE_ACCUMULATOR_VAR ("_total_size_") @@ -21,14 +23,19 @@ FILE* output; char* name; const char* filename; +bool isAbstract = false; + void generateHeader() { fprintf(output, "#include \n"); fprintf(output, "#include \n"); fprintf(output, "#include \n"); + fprintf(output, "#include \n"); fprintf(output, "\n"); fprintf(output, "#include \n"); fprintf(output, "\n"); - fprintf(output, "extern void _registerTemplate(const char*, void (*)(FILE*, va_list), size_t (*)(va_list));\n"); + fprintf(output, "extern void _registerTemplate(const char*, bool, void (*)(FILE*, va_list), void (*)(FILE*, va_list), size_t (*)(va_list));\n"); + fprintf(output, "extern void renderTemplateStart(const char*, FILE*, ...);\n") + fprintf(output, "extern void renderTemplateEnd(const char*, FILE*, ...);\n") fprintf(output, "\n"); fprintf(output, "#define _renderTemplate(f, t, ...) renderTemplate(t, f, __VA_ARGS__)\n"); fprintf(output, "\n"); @@ -139,6 +146,9 @@ void parseTreeSize(int indentation, struct tree tree) { case RENDER_NODE: generateRenderNodeSize(indentation, tree.kids[i]); break; + case CHILD_NODE: + // ignore CHILD_NODE for size calculation + break; default: panic("unknown node type"); } @@ -185,6 +195,13 @@ void generateRenderNode(int indentation, struct node node) { fprintf(output, "_renderTemplate(out, %s);\n", node.value.text); } +void generateChildNode() { + // assuming we are at root level in tree + fprintf(output, "}\n"); + fprintf(output, "static void %s_%s_%s_(FILE* out, va_list argptr) {\n", PRINT_PREFIX, name, END_SUFFIX); + generateArguments(); +} + void parseTree(int indentation, struct tree tree) { for (size_t i = 0; i < tree.kidsno; i++) { switch(tree.kids[i].type) { @@ -200,6 +217,9 @@ void parseTree(int indentation, struct tree tree) { case RENDER_NODE: generateRenderNode(indentation, tree.kids[i]); break; + case CHILD_NODE: + generateChildNode(); + break; default: panic("unknown node type"); } @@ -217,7 +237,11 @@ void generateTree() { void generateConstructor() { fprintf(output, "__attribute__((constructor)) static void _register() {\n"); - fprintf(output, "\t_registerTemplate(\"%s\", &%s_%s_, &%s_%s_);\n", filename, PRINT_PREFIX, name, SIZE_PREFIX, name); + if (isAbstract) { + fprintf(output, "\t_registerTemplate(\"%s\", true, &%s_%s_, &%s_%s_%s_, &%s_%s_);\n", filename, PRINT_PREFIX, name, PRINT_PREFIX, name, END_SUFFIX, SIZE_PREFIX, name); + } else { + fprintf(output, "\t_registerTemplate(\"%s\", false, &%s_%s_, NULL, &%s_%s_);\n", filename, PRINT_PREFIX, name, SIZE_PREFIX, name); + } fprintf(output, "}\n"); } @@ -234,6 +258,28 @@ void fixName() { } } +void preprocessTree(int depth, struct tree tree); + +void preprocessNode(int depth, struct node node) { + if (node.type == CHILD_NODE) { + if (depth > 0) { + panic("child command not allowed in statement block"); + } + if (isAbstract) { + panic("only one child command allowed per template"); + } + isAbstract = true; + } else if (node.type == STATEMENT_NODE) { + preprocessTree(depth + 1, *node.value.tree); + } +} + +void preprocessTree(int depth, struct tree tree) { + for (size_t i = 0; i < tree.kidsno; i++) { + preprocessNode(depth, tree.kids[i]); + } +} + int main(int argc, char** argv) { // TODO: build sane argument parsing if (argc != 2) { @@ -257,6 +303,8 @@ int main(int argc, char** argv) { return 1; } + preprocessTree(0, result.tree); + generateHeader(); generateSize(); generateTree(); diff --git a/src/parser.y b/src/parser.y index 116417b..91e3b87 100644 --- a/src/parser.y +++ b/src/parser.y @@ -96,7 +96,11 @@ metaSection: /* empty */ yyerror("child command not allowed in meta section; ignoring"); break; case EXTENDS_TOKEN: - yyerror("extends command not yet implemented; ignoring"); + if ($$.parent != NULL) { + yyerror("template can only extent one parent"); + YYERROR; + } + $$.parent = $6; break; default: yyerror("unhandled structure block command (internal error)"); @@ -165,7 +169,7 @@ mainSection: /* empty */ addNode(&$$, newRenderNode($7)); break; case CHILD_NODE: - yyerror("child command not yet implemented; ignoring"); + addNode(&$$, newChildNode()); break; case EXTENDS_TOKEN: yyerror("extends command not allowed in main section; ignoring"); diff --git a/src/templates.c b/src/templates.c index d9f9863..cb4ac14 100644 --- a/src/templates.c +++ b/src/templates.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "templates.h" #include "common.h" @@ -13,43 +14,39 @@ typedef size_t (*template_length_t)(va_list); struct entry { const char* name; - template_t f; + bool abstract; + template_t start; + template_t end; template_length_t s; } templates[MAX_TEMPLATES]; size_t templateno = 0; -static template_t _findTemplate(const char* name) { +static struct entry _findTemplate(const char* name) { for (size_t i = 0; i < templateno; i++) { if (strcmp(templates[i].name, name) == 0) { - return templates[i].f; + return templates[i]; } } - return NULL; + return (struct entry) { + .name = NULL + }; } -static template_length_t _findTemplateSize(const char* name) { - for (size_t i = 0; i < templateno; i++) { - if (strcmp(templates[i].name, name) == 0) { - return templates[i].s; - } - } - - return NULL; -} - -void _registerTemplate(const char* name, template_t f, template_length_t s) { +void _registerTemplate(const char* name, bool abstract, template_t start, template_t end, template_length_t s) { if (templateno >= MAX_TEMPLATES) { panic("max number of templates exceeded"); } - if (_findTemplate(name) != NULL) { + if (_findTemplate(name).name != NULL) { fprintf(stderr, "warning: template name '%s' already registered; ignoring this one\n", name); return; } + templates[templateno].abstract = abstract; templates[templateno].name = name; - templates[templateno].f = f; + templates[templateno].start = start; + templates[templateno].end = end; templates[templateno++].s = s; } @@ -57,14 +54,49 @@ void _registerTemplate(const char* name, template_t f, template_length_t s) { static size_t emptyTemplateSize(va_list _) { return 0; } static void emptyTemplate(FILE* out, va_list _) { } -void _renderTemplate(const char* name, FILE* out, va_list argptr) { - template_t t = _findTemplate(name); - - if (t == NULL) { +template_t findTemplate(bool abstract, bool start, const char* name) { + struct entry t = _findTemplate(name); + if (t.name == NULL) { fprintf(stderr, "warning: template '%s' does not exist.\n", name); - t = &emptyTemplate; + return &emptyTemplate; } - + if (t.abstract) { + if (!abstract) { + fprintf(stderr, "warning: template name '%s' is abstract\n", name); + return &emptyTemplate; + } else { + if (start) { + return t.start; + } else { + return t.end; + } + } + } else { + return t.start; + } +} + +static template_length_t findTemplateSize(const char* name) { + struct entry t = _findTemplate(name); + if (t.name == NULL) { + fprintf(stderr, "warning: template '%s' does not exist.\n", name); + return &emptyTemplateSize; + } + return t.s; +} + +static void _renderTemplate(const char* name, FILE* out, va_list argptr) { + template_t t = findTemplate(false, false, name); + t(out, argptr); +} + +static void _renderTemplateStart(const char* name, FILE* out, va_list argptr) { + template_t t = findTemplate(true, true, name); + t(out, argptr); +} + +static void _renderTemplateEnd(const char* name, FILE* out, va_list argptr) { + template_t t = findTemplate(true, false, name); t(out, argptr); } @@ -77,14 +109,26 @@ void renderTemplate(const char* name, FILE* out, ...) { va_end(argptr); } -size_t _sizeTemplate(const char* name, va_list argptr) { - template_length_t s = _findTemplateSize(name); +void renderTemplateStart(const char* name, FILE* out, ...) { + va_list argptr; + va_start(argptr, out); - if (s == NULL) { - fprintf(stderr, "warning: template '%s' does not exist.\n", name); - s = &emptyTemplateSize; - } + _renderTemplateStart(name, out, argptr); + va_end(argptr); +} + +void renderTemplateEnd(const char* name, FILE* out, ...) { + va_list argptr; + va_start(argptr, out); + + _renderTemplateEnd(name, out, argptr); + + va_end(argptr); +} + +static size_t _sizeTemplate(const char* name, va_list argptr) { + template_length_t s = findTemplateSize(name); return s(argptr); } @@ -102,14 +146,8 @@ size_t sizeTemplate(const char* name, ...) { } char* renderTemplateStr(const char* name, ...) { - template_t t = _findTemplate(name); - template_length_t s = _findTemplateSize(name); - - if (t == NULL) { - fprintf(stderr, "warning: template '%s' does not exist.\n", name); - t = &emptyTemplate; - s = &emptyTemplateSize; - } + template_t t = findTemplate(false, false, name); + template_length_t s = findTemplateSize(name); size_t length; char* result; @@ -119,7 +157,6 @@ char* renderTemplateStr(const char* name, ...) { va_copy(argptr2, argptr); length = s(argptr); - va_end(argptr); result = malloc(length + 1); diff --git a/src/tree.c b/src/tree.c index 32e4150..2d47b19 100644 --- a/src/tree.c +++ b/src/tree.c @@ -58,6 +58,12 @@ struct node newRenderNode(char* arguments) { }; } +struct node newChildNode() { + return (struct node) { + .type = CHILD_NODE, + }; +} + struct tree newTree() { return (struct tree) { .kids = NULL, @@ -148,8 +154,7 @@ struct params combineParams(struct params p1, struct params p2) { struct stats newStats() { return (struct stats) { .texts = NULL, - .no = 0, - .parent = NULL + .no = 0 }; } @@ -164,15 +169,12 @@ void addStat(struct stats* stats, char* text) { stats->texts[stats->no++] = text; } -void setParent(struct stats* stats, char* parent) { - stats->parent = parent; -} - struct template newTemplate() { return (struct template) { .params = newParams(), .stats = newStats(), - .tree = newTree() + .tree = newTree(), + .parent = NULL }; } diff --git a/src/tree.h b/src/tree.h index e002465..bb227a6 100644 --- a/src/tree.h +++ b/src/tree.h @@ -31,6 +31,7 @@ struct node newTextNode(char*); struct node newStatementNode(char*, struct tree); struct node newOutputNode(char*); struct node newRenderNode(char*); +struct node newChildNode(); struct tree newTree(); void addNode(struct tree*, struct node); @@ -49,7 +50,6 @@ struct params combineParams(struct params, struct params); struct stats { char** texts; size_t no; - char* parent; }; struct stats newStats(); @@ -59,6 +59,7 @@ struct template { struct params params; struct tree tree; struct stats stats; + const char* parent; }; struct template newTemplate();