From bf42a95568f5efffcc87a9b5a7683b7b270a098f Mon Sep 17 00:00:00 2001 From: "Rafael G. Martins" Date: Fri, 17 Apr 2015 23:49:55 -0300 Subject: replaced leg-based parser with handmade parser for templates yay! no leg parser needed anymore. parsers still needs some work and error handling, though. --- .gitignore | 5 +- Makefile.am | 31 ++--- README.md | 2 +- configure.ac | 31 ----- src/main.c | 8 +- src/output.c | 2 +- src/template-grammar.h | 32 ----- src/template-grammar.leg | 200 ---------------------------- src/template-parser.c | 296 +++++++++++++++++++++++++++++++++++++++++ src/template-parser.h | 31 +++++ tests/check_template_grammar.c | 145 -------------------- tests/check_template_parser.c | 222 +++++++++++++++++++++++++++++++ 12 files changed, 561 insertions(+), 444 deletions(-) delete mode 100644 src/template-grammar.h delete mode 100644 src/template-grammar.leg create mode 100644 src/template-parser.c create mode 100644 src/template-parser.h delete mode 100644 tests/check_template_grammar.c create mode 100644 tests/check_template_parser.c diff --git a/.gitignore b/.gitignore index 92256ca..3ac375c 100644 --- a/.gitignore +++ b/.gitignore @@ -41,11 +41,8 @@ Makefile.in # tests /tests/check_source_parser -/tests/check_template_grammar +/tests/check_template_parser /tests/check_utils -# leg generated source -/src/template-grammar.c - # tarballs blogc-*.tar.* diff --git a/Makefile.am b/Makefile.am index 3138d25..e639307 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,7 +14,6 @@ AM_DISTCHECK_CONFIGURE_FLAGS = \ EXTRA_DIST = \ autogen.sh \ README.md \ - src/template-grammar.leg \ $(NULL) CLEANFILES = \ @@ -23,7 +22,7 @@ CLEANFILES = \ noinst_HEADERS = \ src/output.h \ src/source-parser.h \ - src/template-grammar.h \ + src/template-parser.h \ src/utils/utils.h \ $(NULL) @@ -45,7 +44,7 @@ check_PROGRAMS = \ libblogc_la_SOURCES = \ src/output.c \ src/source-parser.c \ - src/template-grammar.c \ + src/template-parser.c \ src/utils/slist.c \ src/utils/strings.c \ src/utils/trie.c \ @@ -59,10 +58,6 @@ libblogc_la_CFLAGS = \ libblogc_la_LIBADD = \ $(NULL) -if USE_LEG -src/%-grammar.c: src/%-grammar.leg - $(AM_V_GEN)$(LEG) -o $@ $< -endif blogc_SOURCES = \ src/main.c \ @@ -78,23 +73,13 @@ blogc_LDADD = \ $(NULL) -## Build rules: examples - -if BUILD_EXAMPLES - -noinst_PROGRAMS += \ - $(NULL) - -endif - - ## Build rules: tests if USE_CMOCKA check_PROGRAMS += \ tests/check_source_parser \ - tests/check_template_grammar \ + tests/check_template_parser \ tests/check_utils \ $(NULL) @@ -115,19 +100,19 @@ tests_check_source_parser_LDADD = \ libblogc.la \ $(NULL) -tests_check_template_grammar_SOURCES = \ - tests/check_template_grammar.c \ +tests_check_template_parser_SOURCES = \ + tests/check_template_parser.c \ $(NULL) -tests_check_template_grammar_CFLAGS = \ +tests_check_template_parser_CFLAGS = \ $(CMOCKA_CFLAGS) \ $(NULL) -tests_check_template_grammar_LDFLAGS = \ +tests_check_template_parser_LDFLAGS = \ -no-install \ $(NULL) -tests_check_template_grammar_LDADD = \ +tests_check_template_parser_LDADD = \ $(CMOCKA_LIBS) \ libblogc.la \ $(NULL) diff --git a/README.md b/README.md index 6919683..5f6f607 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ The templates can define blocks. These are the block rules: The variables defined in the source file are only available inside of blocks. If something does not depends on the source files, and is global, it must be hardcoded in the template, for the sake of simplicity. -The templates can use conditional statements: ``{% if variable %}``, ``{% else %}`` and ``{% endif %}``. They check if a variable is defined or not. As variables are not available outside of blocks, these conditional statements can't be defined outside of blocks. +The templates can use conditional statements: ``{% if variable %}`` and ``{% endif %}``. They check if a variable is defined or not. As variables are not available outside of blocks, these conditional statements can't be defined outside of blocks. As the compiler is output-agnostic, Atom feeds and sitemaps should be generated using templates as well. diff --git a/configure.ac b/configure.ac index f6b73db..5736a33 100644 --- a/configure.ac +++ b/configure.ac @@ -16,16 +16,6 @@ AS_IF([test "x$ac_cv_prog_cc_c99" = "xno"], [ AC_MSG_ERROR([no C99 compiler found, blogc requires a C99 compiler.]) ]) -AC_ARG_ENABLE([examples], AS_HELP_STRING([--enable-examples], [build examples])) -AS_IF([test "x$enable_examples" = "xyes"], [ - build_examples=yes - EXAMPLES="enabled" -], [ - build_examples=no - EXAMPLES="disabled" -]) -AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" = "xyes"]) - AC_ARG_ENABLE([valgrind], AS_HELP_STRING([--disable-valgrind], [ignore presence of valgrind])) AS_IF([test "x$enable_valgrind" != "xno"], [ @@ -45,25 +35,6 @@ AM_CONDITIONAL([USE_VALGRIND], [test "x$have_valgrind" = "xyes"]) VALGRIND="$ac_cv_path_valgrind" AC_SUBST(VALGRIND) -AC_ARG_ENABLE([leg], AS_HELP_STRING([--disable-leg], - [ignore presence of peg/leg and disable parser grammar regeneration])) -AS_IF([test "x$enable_leg" != "xno"], [ - AC_PATH_PROG([leg], [leg]) - AS_IF([test "x$ac_cv_path_leg" = "x"], [ - have_leg=no - ], [ - have_leg=yes - ]) -]) -AS_IF([test "x$have_leg" = "xyes"], , [ - AS_IF([test "x$enable_leg" = "xyes"], [ - AC_MSG_ERROR([peg/leg requested but not found]) - ]) -]) -AM_CONDITIONAL([USE_LEG], [test "x$have_leg" = "xyes"]) -LEG="$ac_cv_path_leg" -AC_SUBST(LEG) - AC_ARG_ENABLE([cmocka], AS_HELP_STRING([--disable-cmocka], [ignore presence of cmocka. this will disable unit tests])) AS_IF([test "x$enable_cmocka" != "xno"], [ @@ -99,9 +70,7 @@ AS_ECHO(" cflags: ${CFLAGS} ldflags: ${LDFLAGS} - examples: ${EXAMPLES} cmocka: ${CMOCKA} valgrind: ${VALGRIND} - leg: ${LEG} ") diff --git a/src/main.c b/src/main.c index d05c8d6..4e72b6e 100644 --- a/src/main.c +++ b/src/main.c @@ -13,19 +13,13 @@ #include #include "source-parser.h" +#include "template-parser.h" #include int main(int argc, char **argv) { - const char *a = - "\n \nBOLA : guda\n\t\n\n\n\n" - "CHUNDA: asd\n" - "----\n" - "{% block single_source %}\nbola\n\nzas\n"; - blogc_source_t *t = blogc_source_parse(a, strlen(a)); - printf("%s\n", t->content); printf("Hello, World!\n"); return 0; } diff --git a/src/output.c b/src/output.c index bd96b8e..1664afe 100644 --- a/src/output.c +++ b/src/output.c @@ -32,7 +32,7 @@ blogc_parser_syntax_error(const char *name, const char *src, size_t src_len, current++; } - fprintf(stderr, "%s parser error: syntax error near \"%s\"\n", name, + fprintf(stderr, "%s parser error: failed to parse input near \"%s\".\n", name, msg->str); b_string_free(msg, true); diff --git a/src/template-grammar.h b/src/template-grammar.h deleted file mode 100644 index 310acb5..0000000 --- a/src/template-grammar.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2015 Rafael G. Martins - * - * This program can be distributed under the terms of the BSD License. - * See the file COPYING. - */ - -#ifndef _TEMPLATE_GRAMMAR_H -#define _TEMPLATE_GRAMMAR_H - -#include "utils/utils.h" - -typedef enum { - BLOGC_TEMPLATE_IF_STMT, - BLOGC_TEMPLATE_ELSE_STMT, - BLOGC_TEMPLATE_ENDIF_STMT, - BLOGC_TEMPLATE_BLOCK_STMT, - BLOGC_TEMPLATE_ENDBLOCK_STMT, - BLOGC_TEMPLATE_VARIABLE_STMT, - BLOGC_TEMPLATE_CONTENT_STMT, -} blogc_template_stmt_type_t; - -typedef struct { - blogc_template_stmt_type_t type; - char *value; -} blogc_template_stmt_t; - -b_slist_t* blogc_template_parse(const char *tmpl); -void blogc_template_free_stmts(b_slist_t *stmts); - -#endif /* _TEMPLATE_GRAMMAR_H */ diff --git a/src/template-grammar.leg b/src/template-grammar.leg deleted file mode 100644 index 2425582..0000000 --- a/src/template-grammar.leg +++ /dev/null @@ -1,200 +0,0 @@ -# -# blogc: A blog compiler. -# Copyright (C) 2015 Rafael G. Martins -# -# This program can be distributed under the terms of the BSD License. -# See the file COPYING. -# - -%{ - -#include -#include "utils/utils.h" -#include "template-grammar.h" - -#define YY_INPUT(buf, result, max_size) \ -{ \ - int yyc = (charbuf && *charbuf != '\0') ? *charbuf++ : EOF; \ - result = (EOF == yyc) ? 0 : (*buf = yyc, 1); \ -} - - -static b_slist_t *stmts = NULL; -static int if_count = 0; -static int block_count = 0; -static const char *charbuf = NULL; - - -static void -blogc_template_if_stmt(const char *value) -{ - if (block_count <= 0) { - fprintf(stderr, "Syntax error: {" "%% if ... %%" "} statement before " - "any {" "%% block ... %%" "} statement\n"); - exit(1); - } - blogc_template_stmt_t *stmt = malloc(sizeof(blogc_template_stmt_t)); - stmt->value = b_strdup(value); - stmt->type = BLOGC_TEMPLATE_IF_STMT; - stmts = b_slist_append(stmts, stmt); - if_count++; -} - - -static void -blogc_template_else_stmt(void) -{ - if (if_count <= 0) { - fprintf(stderr, "Syntax error: {" "%% else %%" "} statement without " - "any open {" "%% if ... %%" "} statement\n"); - exit(1); - } - blogc_template_stmt_t *stmt = malloc(sizeof(blogc_template_stmt_t)); - stmt->value = NULL; - stmt->type = BLOGC_TEMPLATE_ELSE_STMT; - stmts = b_slist_append(stmts, stmt); -} - - -static void -blogc_template_endif_stmt(void) -{ - if (if_count-- <= 0) { - fprintf(stderr, "Syntax error: {" "%% endif %%" "} statement before " - "any {" "%% if ... %%" "} statement\n"); - exit(1); - } - blogc_template_stmt_t *stmt = malloc(sizeof(blogc_template_stmt_t)); - stmt->value = NULL; - stmt->type = BLOGC_TEMPLATE_ENDIF_STMT; - stmts = b_slist_append(stmts, stmt); -} - - -static void -blogc_template_block_stmt(const char *value) -{ - if (block_count > 0) { - fprintf(stderr, "Syntax error: {" "%% block %%" "} statements " - "can't be nested\n"); - exit(1); - } - blogc_template_stmt_t *stmt = malloc(sizeof(blogc_template_stmt_t)); - stmt->value = b_strdup(value); - stmt->type = BLOGC_TEMPLATE_BLOCK_STMT; - stmts = b_slist_append(stmts, stmt); - block_count++; -} - - -static void -blogc_template_endblock_stmt(void) -{ - if (block_count-- <= 0) { - fprintf(stderr, "Syntax error: {" "%% endblock %%" "} statement before " - "any {" "%% block ... %%" "} statement\n"); - exit(1); - } - blogc_template_stmt_t *stmt = malloc(sizeof(blogc_template_stmt_t)); - stmt->value = NULL; - stmt->type = BLOGC_TEMPLATE_ENDBLOCK_STMT; - stmts = b_slist_append(stmts, stmt); -} - - -static void -blogc_template_variable_stmt(const char *value) -{ - if (block_count <= 0) { - fprintf(stderr, "Syntax error: {{ ... }} statement before " - "any {" "%% block ... %%" "} statement\n"); - exit(1); - } - blogc_template_stmt_t *stmt = malloc(sizeof(blogc_template_stmt_t)); - stmt->value = b_strdup(value); - stmt->type = BLOGC_TEMPLATE_VARIABLE_STMT; - stmts = b_slist_append(stmts, stmt); -} - - -static void -blogc_template_content_stmt(const char *value) -{ - blogc_template_stmt_t *stmt = malloc(sizeof(blogc_template_stmt_t)); - stmt->value = b_strdup(value); - stmt->type = BLOGC_TEMPLATE_CONTENT_STMT; - stmts = b_slist_append(stmts, stmt); -} - -%} - -page = if | else | endif | block | endblock | print | content | anything - { fprintf(stderr, "Syntax error near: %s\n", yytext); exit(1); } - - -# Useful rules -eol = '\n' | '\r\n' | '\r' -eof = !. -- = [\t ]* -id = [A-Z][A-Z0-9_]* -anything = < ( !eol . )* > eol - -# Conditionals -if_open = '{%' - -if_close = - '%}' -if = if_open 'if' ' '+ < id > if_close { blogc_template_if_stmt(yytext); } -else = if_open 'else' if_close { blogc_template_else_stmt(); } -endif = if_open 'endif' if_close { blogc_template_endif_stmt(); } - -# Blocks -block_open = '{%' - -block_close = - '%}' -block_name = ( 'single_source' | 'multiple_sources_once' | 'multiple_sources' ) -block = block_open 'block' ' '+ < block_name > block_close { blogc_template_block_stmt(yytext); } -endblock = block_open 'endblock' block_close { blogc_template_endblock_stmt(); } - -# Print calls -print_open = '{{' - -print_close = - '}}' -print_var = < id > { blogc_template_variable_stmt(yytext); } -print = print_open print_var print_close - -# Generic content -content = < ( !eof !if_open !if_close !block_open !block_close !print_open !print_close . )+ > - { blogc_template_content_stmt(yytext); } - -%% - - -void -blogc_template_free_stmts(b_slist_t *stmts) -{ - for (b_slist_t *tmp = stmts; tmp != NULL; tmp = tmp->next) { - blogc_template_stmt_t *data = tmp->data; - free(data->value); - free(data); - } - b_slist_free(stmts); -} - - -b_slist_t* -blogc_template_parse(const char *tmpl) -{ - if_count = 0; - block_count = 0; - charbuf = tmpl; - while(yyparse()); - if (if_count != 0) { - fprintf(stderr, "Syntax error: You left %d open {" "%% if ... %%" "} statements.\n", if_count); - exit(1); - } - if (block_count != 0) { - fprintf(stderr, "Syntax error: You left %d open {" "%% block ... %%" "} statements.\n", block_count); - exit(1); - } - b_slist_t *rv = stmts; - charbuf = NULL; - stmts = NULL; - return rv; -} diff --git a/src/template-parser.c b/src/template-parser.c new file mode 100644 index 0000000..c5286ea --- /dev/null +++ b/src/template-parser.c @@ -0,0 +1,296 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2015 Rafael G. Martins + * + * This program can be distributed under the terms of the BSD License. + * See the file COPYING. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +#include "utils/utils.h" +#include "template-parser.h" +#include "output.h" + + +typedef enum { + TEMPLATE_START = 1, + TEMPLATE_OPEN_BRACKET, + TEMPLATE_BLOCK_START, + TEMPLATE_BLOCK_TYPE, + TEMPLATE_BLOCK_BLOCK_TYPE_START, + TEMPLATE_BLOCK_BLOCK_TYPE, + TEMPLATE_BLOCK_IF_VARIABLE_START, + TEMPLATE_BLOCK_IF_VARIABLE, + TEMPLATE_BLOCK_END, + TEMPLATE_VARIABLE_START, + TEMPLATE_VARIABLE, + TEMPLATE_VARIABLE_END, + TEMPLATE_CLOSE_BRACKET, +} blogc_template_parser_state_t; + + +b_slist_t* +blogc_template_parse(const char *src, size_t src_len) +{ + size_t current = 0; + size_t start = 0; + size_t end = 0; + size_t remaining = 0; + + bool error = false; + char *tmp = NULL; + + bool open_block = false; + unsigned int if_count = 0; + + b_slist_t *stmts = NULL; + blogc_template_stmt_t *stmt = NULL; + + blogc_template_parser_state_t state = TEMPLATE_START; + blogc_template_stmt_type_t type = BLOGC_TEMPLATE_CONTENT_STMT; + + while (current < src_len) { + char c = src[current]; + bool last = current == src_len - 1; + + switch (state) { + + case TEMPLATE_START: + if (last) { + stmt = malloc(sizeof(blogc_template_stmt_t)); + stmt->type = type; + stmt->value = b_strndup(src + start, src_len - start); + stmts = b_slist_append(stmts, stmt); + stmt = NULL; + } + if (c == '{') { + end = current; + state = TEMPLATE_OPEN_BRACKET; + } + break; + + case TEMPLATE_OPEN_BRACKET: + if (c == '%' || c == '{') { + if (c == '%') + state = TEMPLATE_BLOCK_START; + else + state = TEMPLATE_VARIABLE_START; + if (end > start) { + stmt = malloc(sizeof(blogc_template_stmt_t)); + stmt->type = type; + stmt->value = b_strndup(src + start, end - start); + stmts = b_slist_append(stmts, stmt); + stmt = NULL; + } + } + break; + + case TEMPLATE_BLOCK_START: + if (c == ' ') + break; + if (c >= 'a' && c <= 'z') { + state = TEMPLATE_BLOCK_TYPE; + start = current; + break; + } + error = true; + break; + + case TEMPLATE_BLOCK_TYPE: + if (c >= 'a' && c <= 'z') + break; + if (c == ' ') { + if (0 == strncmp("block", src + start, current - start)) { + if (!open_block) { + state = TEMPLATE_BLOCK_BLOCK_TYPE_START; + type = BLOGC_TEMPLATE_BLOCK_STMT; + start = current; + open_block = true; + break; + } + } + else if (0 == strncmp("endblock", src + start, current - start)) { + if (open_block) { + state = TEMPLATE_BLOCK_END; + type = BLOGC_TEMPLATE_ENDBLOCK_STMT; + open_block = false; + break; + } + } + else if (0 == strncmp("if", src + start, current - start)) { + if (open_block) { + state = TEMPLATE_BLOCK_IF_VARIABLE_START; + type = BLOGC_TEMPLATE_IF_STMT; + start = current; + if_count++; + break; + } + } + else if (0 == strncmp("endif", src + start, current - start)) { + if (open_block) { + if (if_count > 0) { + state = TEMPLATE_BLOCK_END; + type = BLOGC_TEMPLATE_ENDIF_STMT; + if_count--; + break; + } + } + } + } + error = true; + break; + + case TEMPLATE_BLOCK_BLOCK_TYPE_START: + if (c == ' ') + break; + if (c >= 'a' && c <= 'z') { + state = TEMPLATE_BLOCK_BLOCK_TYPE; + start = current; + break; + } + error = true; + break; + + case TEMPLATE_BLOCK_BLOCK_TYPE: + if ((c >= 'a' && c <= 'z') || c == '_') + break; + if (c == ' ') { + if ((0 == strncmp("single_source", src + start, current - start)) || + (0 == strncmp("multiple_sources", src + start, current - start)) || + (0 == strncmp("multiple_sources_once", src + start, current - start))) + { + end = current; + state = TEMPLATE_BLOCK_END; + break; + } + } + error = true; + break; + + case TEMPLATE_BLOCK_IF_VARIABLE_START: + if (c == ' ') + break; + if (c >= 'A' && c <= 'Z') { + state = TEMPLATE_BLOCK_IF_VARIABLE; + start = current; + break; + } + error = true; + break; + + case TEMPLATE_BLOCK_IF_VARIABLE: + if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') + break; + if (c == ' ') { + end = current; + state = TEMPLATE_BLOCK_END; + break; + } + error = true; + break; + + case TEMPLATE_BLOCK_END: + if (c == ' ') + break; + if (c == '%') { + state = TEMPLATE_CLOSE_BRACKET; + break; + } + error = true; + break; + + case TEMPLATE_VARIABLE_START: + if (c == ' ') + break; + if (c >= 'A' && c <= 'Z') { + if (open_block) { + state = TEMPLATE_VARIABLE; + type = BLOGC_TEMPLATE_VARIABLE_STMT; + start = current; + break; + } + } + error = true; + break; + + case TEMPLATE_VARIABLE: + if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') + break; + if (c == ' ') { + end = current; + state = TEMPLATE_VARIABLE_END; + break; + } + if (c == '}') { + end = current; + state = TEMPLATE_CLOSE_BRACKET; + break; + } + error = true; + break; + + case TEMPLATE_VARIABLE_END: + if (c == ' ') + break; + if (c == '}') { + state = TEMPLATE_CLOSE_BRACKET; + break; + } + error = true; + break; + + case TEMPLATE_CLOSE_BRACKET: + if (c == '}') { + stmt = malloc(sizeof(blogc_template_stmt_t)); + stmt->type = type; + stmt->value = NULL; + if (end > start) + stmt->value = b_strndup(src + start, end - start); + stmts = b_slist_append(stmts, stmt); + stmt = NULL; + state = TEMPLATE_START; + type = BLOGC_TEMPLATE_CONTENT_STMT; + start = current + 1; + break; + } + error = true; + break; + + } + + if (error) + break; + + current++; + } + + if (error) { + if (stmt != NULL) { + free(stmt->value); + free(stmt); + } + blogc_template_free_stmts(stmts); + blogc_parser_syntax_error("template", src, src_len, current); + return NULL; + } + + return stmts; +} + + +void +blogc_template_free_stmts(b_slist_t *stmts) +{ + for (b_slist_t *tmp = stmts; tmp != NULL; tmp = tmp->next) { + blogc_template_stmt_t *data = tmp->data; + free(data->value); + free(data); + } + b_slist_free(stmts); +} diff --git a/src/template-parser.h b/src/template-parser.h new file mode 100644 index 0000000..1f43fe8 --- /dev/null +++ b/src/template-parser.h @@ -0,0 +1,31 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2015 Rafael G. Martins + * + * This program can be distributed under the terms of the BSD License. + * See the file COPYING. + */ + +#ifndef _TEMPLATE_PARSER_H +#define _TEMPLATE_PARSER_H + +#include "utils/utils.h" + +typedef enum { + BLOGC_TEMPLATE_IF_STMT = 1, + BLOGC_TEMPLATE_ENDIF_STMT, + BLOGC_TEMPLATE_BLOCK_STMT, + BLOGC_TEMPLATE_ENDBLOCK_STMT, + BLOGC_TEMPLATE_VARIABLE_STMT, + BLOGC_TEMPLATE_CONTENT_STMT, +} blogc_template_stmt_type_t; + +typedef struct { + blogc_template_stmt_type_t type; + char *value; +} blogc_template_stmt_t; + +b_slist_t* blogc_template_parse(const char *src, size_t src_len); +void blogc_template_free_stmts(b_slist_t *stmts); + +#endif /* _TEMPLATE_GRAMMAR_H */ diff --git a/tests/check_template_grammar.c b/tests/check_template_grammar.c deleted file mode 100644 index 3b4dcca..0000000 --- a/tests/check_template_grammar.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2015 Rafael G. Martins - * - * This program can be distributed under the terms of the BSD License. - * See the file COPYING. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif /* HAVE_CONFIG_H */ - -#include -#include -#include -#include -#include "../src/template-grammar.h" - - -static void -blogc_assert_template_stmt(b_slist_t *l, const char *value, - const blogc_template_stmt_type_t type) -{ - blogc_template_stmt_t *stmt = l->data; - if (value == NULL) - assert_null(stmt->value); - else - assert_string_equal(stmt->value, value); - assert_int_equal(stmt->type, type); -} - - -static void -test_template_parse(void **state) -{ - b_slist_t *stmts = blogc_template_parse( - "Test\n" - "\n" - " {% block single_source %}\n" - "{% if CHUNDA %}\n" - "bola\n" - "{% else %}\n" - "guda\n" - "{% endif %}\n" - "{% endblock %}\n" - "{% block multiple_sources %}{{ BOLA }}{% endblock %}\n" - "{% block multiple_sources_once %}asd{% endblock %}\n"); - assert_non_null(stmts); - blogc_assert_template_stmt(stmts, "Test\n\n ", - BLOGC_TEMPLATE_CONTENT_STMT); - blogc_assert_template_stmt(stmts->next, "single_source", - BLOGC_TEMPLATE_BLOCK_STMT); - blogc_assert_template_stmt(stmts->next->next, "\n", - BLOGC_TEMPLATE_CONTENT_STMT); - blogc_assert_template_stmt(stmts->next->next->next, "CHUNDA", - BLOGC_TEMPLATE_IF_STMT); - blogc_assert_template_stmt(stmts->next->next->next->next, "\nbola\n", - BLOGC_TEMPLATE_CONTENT_STMT); - blogc_assert_template_stmt(stmts->next->next->next->next->next, NULL, - BLOGC_TEMPLATE_ELSE_STMT); - blogc_assert_template_stmt(stmts->next->next->next->next->next->next, - "\nguda\n", BLOGC_TEMPLATE_CONTENT_STMT); - blogc_assert_template_stmt(stmts->next->next->next->next->next->next->next, - NULL, BLOGC_TEMPLATE_ENDIF_STMT); - blogc_assert_template_stmt(stmts->next->next->next->next->next->next->next->next, - "\n", BLOGC_TEMPLATE_CONTENT_STMT); - b_slist_t *tmp = stmts->next->next->next->next->next->next->next->next->next; - blogc_assert_template_stmt(tmp, NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT); - blogc_assert_template_stmt(tmp->next, "\n", BLOGC_TEMPLATE_CONTENT_STMT); - blogc_assert_template_stmt(tmp->next->next, "multiple_sources", - BLOGC_TEMPLATE_BLOCK_STMT); - blogc_assert_template_stmt(tmp->next->next->next, "BOLA", - BLOGC_TEMPLATE_VARIABLE_STMT); - blogc_assert_template_stmt(tmp->next->next->next->next, NULL, - BLOGC_TEMPLATE_ENDBLOCK_STMT); - blogc_assert_template_stmt(tmp->next->next->next->next->next, "\n", - BLOGC_TEMPLATE_CONTENT_STMT); - blogc_assert_template_stmt(tmp->next->next->next->next->next->next, - "multiple_sources_once", BLOGC_TEMPLATE_BLOCK_STMT); - blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next, - "asd", BLOGC_TEMPLATE_CONTENT_STMT); - blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next, - NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT); - blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next->next, - "\n", BLOGC_TEMPLATE_CONTENT_STMT); - assert_null(tmp->next->next->next->next->next->next->next->next->next->next); - blogc_template_free_stmts(stmts); -} - - -static void -test_template_parse_html(void **state) -{ - b_slist_t *stmts = blogc_template_parse( - "\n" - " \n" - " {% block single_source %}\n" - " My cool blog >> {{ TITLE }}\n" - " {% endblock %}\n" - " {% block multiple_sources %}\n" - " My cool blog - Main page\n" - " {% endblock %}\n" - " \n" - " \n" - "

My cool blog

\n" - " {% block single_source %}\n" - "

{{ TITLE }}

\n" - " {% if DATE %}

Published in: {{ DATE }}

{% endif %}\n" - "
{{ CONTENT }}
\n" - " {% endblock %}\n" - " {% block multiple_sources_once %}
    {% endblock %}\n" - " {% block multiple_sources %}

    " - "{{ TITLE }}{% if DATE %} - {{ DATE }}{% endif %}

    {% endblock %}\n" - " {% block multiple_sources_once %}
{% endblock %}\n" - " \n" - "\n"); - assert_non_null(stmts); - blogc_assert_template_stmt(stmts, "\n \n ", - BLOGC_TEMPLATE_CONTENT_STMT); - blogc_assert_template_stmt(stmts->next, "single_source", - BLOGC_TEMPLATE_BLOCK_STMT); - blogc_assert_template_stmt(stmts->next->next, - "\n My cool blog >> ", BLOGC_TEMPLATE_CONTENT_STMT); - blogc_assert_template_stmt(stmts->next->next->next, "TITLE", - BLOGC_TEMPLATE_VARIABLE_STMT); - blogc_assert_template_stmt(stmts->next->next->next->next, - "\n ", BLOGC_TEMPLATE_CONTENT_STMT); - - - - - - blogc_template_free_stmts(stmts); -} - - -int -main(void) -{ - const UnitTest tests[] = { - unit_test(test_template_parse), - unit_test(test_template_parse_html), - }; - return run_tests(tests); -} diff --git a/tests/check_template_parser.c b/tests/check_template_parser.c new file mode 100644 index 0000000..7839bbf --- /dev/null +++ b/tests/check_template_parser.c @@ -0,0 +1,222 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2015 Rafael G. Martins + * + * This program can be distributed under the terms of the BSD License. + * See the file COPYING. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include "../src/template-parser.h" + + +static void +blogc_assert_template_stmt(b_slist_t *l, const char *value, + const blogc_template_stmt_type_t type) +{ + blogc_template_stmt_t *stmt = l->data; + if (value == NULL) + assert_null(stmt->value); + else + assert_string_equal(stmt->value, value); + assert_int_equal(stmt->type, type); +} + + +static void +test_template_parse(void **state) +{ + const char *a = + "Test\n" + "\n" + " {% block single_source %}\n" + "{% if CHUNDA %}\n" + "bola\n" + "{% endif %}\n" + "{% endblock %}\n" + "{% block multiple_sources %}{{ BOLA }}{% endblock %}\n" + "{% block multiple_sources_once %}asd{% endblock %}\n"; + b_slist_t *stmts = blogc_template_parse(a, strlen(a)); + assert_non_null(stmts); + blogc_assert_template_stmt(stmts, "Test\n\n ", + BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(stmts->next, "single_source", + BLOGC_TEMPLATE_BLOCK_STMT); + blogc_assert_template_stmt(stmts->next->next, "\n", + BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(stmts->next->next->next, "CHUNDA", + BLOGC_TEMPLATE_IF_STMT); + blogc_assert_template_stmt(stmts->next->next->next->next, "\nbola\n", + BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(stmts->next->next->next->next->next, + NULL, BLOGC_TEMPLATE_ENDIF_STMT); + blogc_assert_template_stmt(stmts->next->next->next->next->next->next, + "\n", BLOGC_TEMPLATE_CONTENT_STMT); + b_slist_t *tmp = stmts->next->next->next->next->next->next->next; + blogc_assert_template_stmt(tmp, NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT); + blogc_assert_template_stmt(tmp->next, "\n", BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(tmp->next->next, "multiple_sources", + BLOGC_TEMPLATE_BLOCK_STMT); + blogc_assert_template_stmt(tmp->next->next->next, "BOLA", + BLOGC_TEMPLATE_VARIABLE_STMT); + blogc_assert_template_stmt(tmp->next->next->next->next, NULL, + BLOGC_TEMPLATE_ENDBLOCK_STMT); + blogc_assert_template_stmt(tmp->next->next->next->next->next, "\n", + BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(tmp->next->next->next->next->next->next, + "multiple_sources_once", BLOGC_TEMPLATE_BLOCK_STMT); + blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next, + "asd", BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next, + NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT); + blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next->next, + "\n", BLOGC_TEMPLATE_CONTENT_STMT); + assert_null(tmp->next->next->next->next->next->next->next->next->next->next); + blogc_template_free_stmts(stmts); +} + + +static void +test_template_parse_html(void **state) +{ + const char *a = + "\n" + " \n" + " {% block single_source %}\n" + " My cool blog >> {{ TITLE }}\n" + " {% endblock %}\n" + " {% block multiple_sources %}\n" + " My cool blog - Main page\n" + " {% endblock %}\n" + " \n" + " \n" + "

My cool blog

\n" + " {% block single_source %}\n" + "

{{ TITLE }}

\n" + " {% if DATE %}

Published in: {{ DATE }}

{% endif %}\n" + "
{{ CONTENT }}
\n" + " {% endblock %}\n" + " {% block multiple_sources_once %}
    {% endblock %}\n" + " {% block multiple_sources %}

    " + "{{ TITLE }}{% if DATE %} - {{ DATE }}{% endif %}

    {% endblock %}\n" + " {% block multiple_sources_once %}
{% endblock %}\n" + " \n" + "\n"; + b_slist_t *stmts = blogc_template_parse(a, strlen(a)); + assert_non_null(stmts); + blogc_assert_template_stmt(stmts, "\n \n ", + BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(stmts->next, "single_source", + BLOGC_TEMPLATE_BLOCK_STMT); + blogc_assert_template_stmt(stmts->next->next, + "\n My cool blog >> ", BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(stmts->next->next->next, "TITLE", + BLOGC_TEMPLATE_VARIABLE_STMT); + blogc_assert_template_stmt(stmts->next->next->next->next, + "\n ", BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(stmts->next->next->next->next->next, NULL, + BLOGC_TEMPLATE_ENDBLOCK_STMT); + blogc_assert_template_stmt(stmts->next->next->next->next->next->next, + "\n ", BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(stmts->next->next->next->next->next->next->next, + "multiple_sources", BLOGC_TEMPLATE_BLOCK_STMT); + b_slist_t *tmp = stmts->next->next->next->next->next->next->next->next; + blogc_assert_template_stmt(tmp, + "\n My cool blog - Main page\n ", + BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(tmp->next, NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT); + blogc_assert_template_stmt(tmp->next->next, + "\n \n \n

My cool blog

\n ", + BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(tmp->next->next->next, "single_source", + BLOGC_TEMPLATE_BLOCK_STMT); + blogc_assert_template_stmt(tmp->next->next->next->next, + "\n

", BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(tmp->next->next->next->next->next, + "TITLE", BLOGC_TEMPLATE_VARIABLE_STMT); + blogc_assert_template_stmt(tmp->next->next->next->next->next->next, + "

\n ", BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next, + "DATE", BLOGC_TEMPLATE_IF_STMT); + tmp = tmp->next->next->next->next->next->next->next->next; + blogc_assert_template_stmt(tmp, "

Published in: ", + BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(tmp->next, "DATE", BLOGC_TEMPLATE_VARIABLE_STMT); + blogc_assert_template_stmt(tmp->next->next, "

", + BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(tmp->next->next->next, NULL, + BLOGC_TEMPLATE_ENDIF_STMT); + blogc_assert_template_stmt(tmp->next->next->next->next, "\n
",
+        BLOGC_TEMPLATE_CONTENT_STMT);
+    blogc_assert_template_stmt(tmp->next->next->next->next->next,
+        "CONTENT", BLOGC_TEMPLATE_VARIABLE_STMT);
+    blogc_assert_template_stmt(tmp->next->next->next->next->next->next,
+        "
\n ", BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next, + NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT); + tmp = tmp->next->next->next->next->next->next->next->next; + blogc_assert_template_stmt(tmp, "\n ", BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(tmp->next, "multiple_sources_once", + BLOGC_TEMPLATE_BLOCK_STMT); + blogc_assert_template_stmt(tmp->next->next, "", + BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(tmp->next->next->next->next, NULL, + BLOGC_TEMPLATE_ENDBLOCK_STMT); + blogc_assert_template_stmt(tmp->next->next->next->next->next, + "\n \n\n", BLOGC_TEMPLATE_CONTENT_STMT); + assert_null(tmp->next->next->next->next->next->next); + blogc_template_free_stmts(stmts); +} + + +int +main(void) +{ + const UnitTest tests[] = { + unit_test(test_template_parse), + unit_test(test_template_parse_html), + }; + return run_tests(tests); +} -- cgit v1.2.3-18-g5258