aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile.am29
-rw-r--r--src/main.c6
-rw-r--r--src/template-grammar.h32
-rw-r--r--src/template-grammar.leg200
-rw-r--r--tests/check_template_grammar.c98
6 files changed, 364 insertions, 4 deletions
diff --git a/.gitignore b/.gitignore
index 1d340aa..2751756 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,10 +40,11 @@ Makefile.in
/blogc
# tests
+/tests/check_template_grammar
/tests/check_utils
# leg generated source
-/src/template/parser-grammar.c
+/src/template-grammar.c
# tarballs
blogc-*.tar.*
diff --git a/Makefile.am b/Makefile.am
index 4e213e5..c0cbd6e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,12 +14,14 @@ AM_DISTCHECK_CONFIGURE_FLAGS = \
EXTRA_DIST = \
autogen.sh \
README.md \
+ src/template-grammar.leg \
$(NULL)
CLEANFILES = \
$(NULL)
noinst_HEADERS = \
+ src/template-grammar.h \
src/utils/utils.h \
$(NULL)
@@ -39,6 +41,7 @@ check_PROGRAMS = \
libblogc_la_SOURCES = \
+ src/template-grammar.c \
src/utils/slist.c \
src/utils/strings.c \
src/utils/trie.c \
@@ -53,6 +56,8 @@ libblogc_la_LIBADD = \
$(NULL)
if USE_LEG
+src/%-grammar.c: src/%-grammar.leg
+ $(AM_V_GEN)$(LEG) -o $@ $<
endif
blogc_SOURCES = \
@@ -84,9 +89,27 @@ endif
if USE_CMOCKA
check_PROGRAMS += \
+ tests/check_template_grammar \
tests/check_utils \
$(NULL)
+tests_check_template_grammar_SOURCES = \
+ tests/check_template_grammar.c \
+ $(NULL)
+
+tests_check_template_grammar_CFLAGS = \
+ $(CMOCKA_CFLAGS) \
+ $(NULL)
+
+tests_check_template_grammar_LDFLAGS = \
+ -no-install \
+ $(NULL)
+
+tests_check_template_grammar_LDADD = \
+ $(CMOCKA_LIBS) \
+ libblogc.la \
+ $(NULL)
+
tests_check_utils_SOURCES = \
tests/check_utils.c \
$(NULL)
@@ -96,7 +119,8 @@ tests_check_utils_CFLAGS = \
$(NULL)
tests_check_utils_LDFLAGS = \
- -no-install
+ -no-install \
+ $(NULL)
tests_check_utils_LDADD = \
$(CMOCKA_LIBS) \
@@ -119,7 +143,7 @@ valgrind: all
$(LIBTOOL) \
--mode=execute \
$(VALGRIND) \
- --tool=memcheck \
+ --tool=memcheck --leak-check=full --show-leak-kinds=all \
--leak-check=full \
--leak-resolution=high \
--num-callers=20 \
@@ -145,5 +169,4 @@ endif
# Helpers: Cleanup of helper files
clean-local:
- -rm -rf $(top_builddir)/doc/build/
-rm -rf $(top_builddir)/valgrind-*.xml
diff --git a/src/main.c b/src/main.c
index f989f62..65e45ee 100644
--- a/src/main.c
+++ b/src/main.c
@@ -12,10 +12,16 @@
#include <stdio.h>
+#include "template-grammar.h"
+
int
main(int argc, char **argv)
{
+ b_slist_t *t = blogc_template_parse(
+ "<html>{{ BOLA }}</html>\n"
+ "{% block single_source %}\n");
+ printf("%s\n", (char*) ((blogc_template_stmt_t*)t->next->next->next->data)->value);
printf("Hello, World!\n");
return 0;
}
diff --git a/src/template-grammar.h b/src/template-grammar.h
new file mode 100644
index 0000000..e95fa46
--- /dev/null
+++ b/src/template-grammar.h
@@ -0,0 +1,32 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2015 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the LGPL-2 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
new file mode 100644
index 0000000..63e2a69
--- /dev/null
+++ b/src/template-grammar.leg
@@ -0,0 +1,200 @@
+#
+# blogc: A balde compiler.
+# Copyright (C) 2015 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+#
+# This program can be distributed under the terms of the BSD License.
+# See the file COPYING.
+#
+
+%{
+
+#include <stdio.h>
+#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/tests/check_template_grammar.c b/tests/check_template_grammar.c
new file mode 100644
index 0000000..ffad8fb
--- /dev/null
+++ b/tests/check_template_grammar.c
@@ -0,0 +1,98 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2015 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#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);
+}
+
+
+int
+main(void)
+{
+ const UnitTest tests[] = {
+ unit_test(test_template_parse),
+ };
+ return run_tests(tests);
+}