#
# 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 "source-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_trie_t *config = NULL;
static const char *charbuf = NULL;
static char *key = NULL;
static char *content = NULL;


static void
blogc_source_config_key(const char *value)
{
    if (key != NULL) {
        fprintf(stderr, "Syntax error: configuration key already set: %s\n", key);
        exit(1);
    }
    key = b_strdup(value);
}


static void
blogc_source_config_value(const char *value)
{
    if (key == NULL) {
        fprintf(stderr, "Syntax error: configuration value without a key: %s\n", value);
        exit(1);
    }
    b_trie_insert(config, key, b_str_strip(b_strdup(value)));
    free(key);
    key = NULL;
}


static void
blogc_source_content(const char *value)
{
    if (content != NULL) {
        fprintf(stderr, "Syntax error: content set twice\n");
        exit(1);
    }
    content = b_strdup(value);
}

%}

page = ( ( - eol )* ( config ( - eol )* )+ '----' '-'* eol content eof ) | 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

# Configuration
config_key = < id >                     { blogc_source_config_key(yytext); }
config_value = < anything >             { blogc_source_config_value(yytext); }
config = config_key ':' ' '+ config_value

# Generic content
content = < ( !eof . )+ >               { blogc_source_content(yytext); }

%%


void
blogc_source_free(blogc_source_t *source)
{
    if (source == NULL)
        return;
    free(source->content);
    b_trie_free(source->config);
    free(source);
}


static void
blogc_source_config_free(void *ptr)
{
    free(ptr);
}


blogc_source_t*
blogc_source_parse(const char *tmpl)
{
    charbuf = tmpl;
    config = b_trie_new(blogc_source_config_free);
    key = NULL;
    content = NULL;
    while(yyparse());
    blogc_source_t *rv = malloc(sizeof(blogc_source_t));
    rv->content = content;
    rv->config = config;
    charbuf = NULL;
    return rv;
}