Skip to content
Authors

File toml_parser.c

File List > source > toml_parser > src > toml_parser.c

Go to the documentation of this file

#include "toml_parser.h"
#include "stdio.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <pdgl_defs.h>
#include <prod_pure.h>
#include <prod_range.h>
#include <prod_janet.h>
#include <prod_weighted.h>
#include <production_store.h>
#include <tomlc17.h>

/*************************************************************************************************/
/************************** Defines **************************************************************/
/*************************************************************************************************/

/*************************************************************************************************/
/************************** Private Function Declarations ****************************************/
/*************************************************************************************************/
STATIC_INLINE prodstr_obj_t * tomlprsr_prod_pure_builder(toml_datum_t tbl);
STATIC_INLINE void tomlprsr_prod_pure_free(prodstr_obj_t *prd);
STATIC_INLINE char ** tomlprsr_prod_pure_builder_list(toml_datum_t ary);
STATIC_INLINE void tomlprsr_prod_range_free(prodstr_obj_t *prd);
STATIC_INLINE prodstr_obj_t * tomlprsr_prod_range_builder(toml_datum_t tbl);
STATIC_INLINE void tomlprsr_prod_janet_free(prodstr_obj_t *prd);
STATIC_INLINE prodstr_obj_t * tomlprsr_prod_janet_builder(toml_datum_t tbl);
STATIC_INLINE void tomlprsr_prod_weighted_free(prodstr_obj_t *prd);
STATIC_INLINE prodstr_obj_t * tomlprsr_prod_weighted_builder(toml_datum_t tbl);
STATIC_INLINE prod_weighted_pair_t * tomlprsr_prod_weighted_builder_list(toml_datum_t ary);


/*************************************************************************************************/
/************************** Local Variables ******************************************************/
/*************************************************************************************************/

typedef prodstr_obj_t * (*prod_builder_funptr_t)(toml_datum_t tbl);

typedef void (*prod_free_funptr_t)(prodstr_obj_t *prd);

typedef struct {
    char *                type;  
    prod_builder_funptr_t build; 
    prod_free_funptr_t    free;  
}prodstr_builder_set_t;


static prodstr_builder_set_t registed_prod_builders[] = {
    { PROD_PURE_NAME,     &tomlprsr_prod_pure_builder,     &tomlprsr_prod_pure_free     },
    { PROD_JANET_NAME,    &tomlprsr_prod_janet_builder,    &tomlprsr_prod_janet_free    },
    { PROD_RANGE_NAME,    &tomlprsr_prod_range_builder,    &tomlprsr_prod_range_free    },
    { PROD_WEIGHTED_NAME, &tomlprsr_prod_weighted_builder, &tomlprsr_prod_weighted_free },
    { NULL,               NULL,                            NULL                         }
    /* This list must be null terminated*/
};



/*************************************************************************************************/
/************************** Public Function Definitions ******************************************/
/*************************************************************************************************/
/* Docstring in header*/
prodstr_store_t *const tomlprsr_parse(const char *toml_data)
{
    prodstr_store_t *store = NULL;

    if (NULL != toml_data)
    {
        /* try to parse the input TOML*/
        toml_result_t tbl = toml_parse(toml_data, strlen(toml_data));

        if (true == tbl.ok)
        {
            toml_datum_t         arr;
            size_t               i        = 0;
            const prodstr_obj_t *entry    = NULL;
            prodstr_obj_t **     prd_buff = NULL;
            /* Allocate a new production store*/
            store = (prodstr_store_t *)malloc((sizeof(prodstr_store_t)));

            if (NULL == store)
            {
                toml_free(tbl);
                return NULL;
            }
            /* Initialize the store table*/
            store->count = 0;
            for (i = 0; i < PRODSTR_TABLE_SIZE; i++)
            {
                store->table[i] = NULL;
            }

            arr = toml_seek(tbl.toptab, "production");
            if (TOML_ARRAY != arr.type)
            {
                toml_free(tbl);
                free(store);
                return NULL;
            }

            /* Get a buffer of pointers to production object to make freeing easier if we find a
             * failure*/
            prd_buff = calloc(arr.u.arr.size, sizeof(prodstr_obj_t *));

            if (NULL == prd_buff)
            {
                toml_free(tbl);
                free(store);
                return NULL;
            }

            /* For each item in the TOML array */
            for (i = 0; i < arr.u.arr.size; i++)
            {
                toml_datum_t           prod    = arr.u.arr.elem[i];
                prodstr_builder_set_t *builder = registed_prod_builders;
                bool added = false;
                prd_buff[i] = NULL;
                /* For each configured production type*/
                while (NULL != builder->type)
                {
                    toml_datum_t type = toml_seek(prod, "type");
                    if (DEFS_PDGL_STRING_MATCH == strcmp(type.u.s, builder->type))
                    {
                        /* Try to parse the production as the jth type*/
                        prd_buff[i] = builder->build(prod);
                        if (NULL != prd_buff[i])
                        {
                            /* Parsed successfully add to store.*/
                            added = prodstr_add(store, prd_buff[i]);
                            break;
                        }
                    }
                    builder++;
                }
                /* If we failed to add a production on the last attempt */
                if (false == added)
                {
                    /* Free everything and report an error state */
                    size_t k;
                    for (k = 0; k < arr.u.arr.size; k++)
                    {
                        free(prd_buff[k]);
                    }
                    free(prd_buff);
                    free(store);
                    return NULL;
                }
            }

            /* Free the production temp buffer, and free the TOML table. */
            free(prd_buff);
            toml_free(tbl);

            /* We have exhausted all the productions in the array. Now ensure that there is a
             * production with the entry symbol.*/
            entry = prodstr_find(store, DEFS_PDGL_ENTRY_SYMBOL);
            if (NULL == entry)
            {
                tomlprsr_free(store);
                return NULL;
            }
        }
    }
    return store;
}

/* Docstring in header*/
void tomlprsr_free(prodstr_store_t *store)
{
    size_t i;

    /* For each table */
    for (i = 0; i < PRODSTR_TABLE_SIZE; i++)
    {
        prodstr_obj_t *obj = store->table[i];
        while (NULL != obj)
        {
            prodstr_builder_set_t *builder = registed_prod_builders;
            prodstr_obj_t *        nextobj = obj->next;

            /* For each configured production type*/
            while (NULL != builder->type)
            {
                if (DEFS_PDGL_STRING_MATCH == strcmp(obj->type, builder->type))
                {
                    builder->free(obj);
                    break;
                }
                builder++;
            }
            obj = nextobj;
        }
        store->table[i] = NULL;
    }
    free(store);
}

/*************************************************************************************************/
/************************** Private Function Definitions *****************************************/
/*************************************************************************************************/

/*************************************************************************************************/
/**************************   Pure Production Functions   *****************************************/
/*************************************************************************************************/

STATIC_INLINE prodstr_obj_t * tomlprsr_prod_pure_builder(toml_datum_t tbl)
{
    toml_datum_t type         = toml_seek(tbl, "type");
    toml_datum_t name         = toml_seek(tbl, "name");
    toml_datum_t replacements = toml_seek(tbl, "replacements");
    toml_datum_t terminals    = toml_seek(tbl, "terminals");

    if ((TOML_STRING == name.type) &&
        (TOML_ARRAY == replacements.type) &&
        (TOML_ARRAY == terminals.type))
    {
        size_t cur_str_len         = 0;
        prod_pure_config_t *config = NULL;
        prodstr_obj_t *     prd    = NULL;
        char **repl_buff           = NULL;
        char **term_buff           = NULL;

        char *cur_str = NULL;


        config = (prod_pure_config_t *)malloc(sizeof(prod_pure_config_t));
        if (NULL == config)
        {
            return NULL;
        }

        config->repl_len  = replacements.u.arr.size;
        config->term_len  = terminals.u.arr.size;
        config->term_list = NULL;
        config->repl_list = NULL;


        prd = (prodstr_obj_t *)malloc(sizeof(prodstr_obj_t));
        if (NULL == prd)
        {
            free(config);
            return NULL;
        }

        prd->name   = NULL;
        prd->config = (void *)config;
        prd->next   = NULL;
        prd->res    = &prod_pure_resolve;
        prd->term   = &prod_pure_terminate;

        cur_str_len = strlen(name.u.s) + 1;
        cur_str     = (char *)calloc(cur_str_len, sizeof(char));
        if ((NULL == cur_str) || (cur_str_len > DEFS_PDGL_MAX_NAME_SIZE))
        {
            free(config);
            free(prd);
            return NULL;
        }

        strcpy(cur_str, name.u.s);
        prd->name = cur_str;
        cur_str   = NULL;

        cur_str_len = strlen(type.u.s) + 1;
        cur_str     = (char *)calloc(cur_str_len, sizeof(char));

        if ((NULL == cur_str) || (cur_str_len > DEFS_PDGL_MAX_NAME_SIZE))
        {
            free(prd->name);
            free(config);
            free(prd);
            return NULL;
        }
        strcpy(cur_str, type.u.s);
        prd->type = cur_str;
        cur_str   = NULL;


        repl_buff = tomlprsr_prod_pure_builder_list(replacements);
        if (NULL == repl_buff)
        {
            free(prd->name);
            free(prd->type);
            free(config);
            free(prd);
            return NULL;
        }
        config->repl_list = repl_buff;

        term_buff = tomlprsr_prod_pure_builder_list(terminals);
        if (NULL == term_buff)
        {
            size_t i;
            for (i = 0; i < config->repl_len; i++)
            {
                free(config->repl_list[i]);
            }
            free(config->repl_list);
            free(prd->name);
            free(prd->type);
            free(config);
            free(prd);
            return NULL;
        }
        config->term_list = term_buff;

        return prd;
    }

    return NULL;
}

STATIC_INLINE void tomlprsr_prod_pure_free(prodstr_obj_t *prd)
{
    if (NULL != prd)
    {
        size_t i;
        prod_pure_config_t *config = (prod_pure_config_t *)prd->config;
        for (i = 0; i < config->term_len; i++)
        {
            free(config->term_list[i]);
        }
        for (i = 0; i < config->repl_len; i++)
        {
            free(config->repl_list[i]);
        }

        free(config->repl_list);
        free(config->term_list);
        free(config);
        free(prd->name);
        free(prd->type);
        free(prd);
    }
}

STATIC_INLINE char ** tomlprsr_prod_pure_builder_list(toml_datum_t ary)
{
    size_t i = 0;

    char **buff = calloc(ary.u.arr.size, sizeof(char *));

    if (NULL == buff)
    {
        return NULL;
    }

    for (i = 0; i < ary.u.arr.size; i++)
    {
        toml_datum_t value = ary.u.arr.elem[i];
        buff[i] = NULL;
        if (TOML_STRING == value.type)
        {
            size_t str_len = strlen(value.u.s) + 1;
            if (str_len < DEFS_PDGL_MAX_STRING_SIZE)
            {
                char *str_config = (char *)calloc(str_len, sizeof(char));
                if (NULL != str_config)
                {
                    strcpy(str_config, value.u.s);
                    buff[i] = str_config;
                }
                else
                {
                    size_t j;
                    for (j = 0; j <= i; j++)
                    {
                        free(buff[i]);
                    }
                    free(buff);
                    return NULL;
                }
            }
            else
            {
                size_t j;
                for (j = 0; j <= i; j++)
                {
                    free(buff[i]);
                }
                free(buff);
                return NULL;
            }
        }
        else
        {
            size_t j;
            for (j = 0; j <= i; j++)
            {
                free(buff[i]);
            }
            free(buff);
            return NULL;
        }
    }
    return buff;
}

/*************************************************************************************************/
/**************************   Range Production Functions   ***************************************/
/*************************************************************************************************/


STATIC_INLINE prodstr_obj_t * tomlprsr_prod_range_builder(toml_datum_t tbl)
{
    toml_datum_t type       = toml_seek(tbl, "type");
    toml_datum_t name       = toml_seek(tbl, "name");
    toml_datum_t lowerbound = toml_seek(tbl, "lower_bound");
    toml_datum_t upperbound = toml_seek(tbl, "upper_bound");

    if (
        (TOML_STRING == name.type) &&
        (TOML_INT64 == lowerbound.type) &&
        (TOML_INT64 == upperbound.type))
    {
        size_t cur_str_len          = 0;
        prod_range_config_t *config = NULL;
        prodstr_obj_t *      prd    = NULL;
        char *cur_str = NULL;

        config = (prod_range_config_t *)malloc(sizeof(prod_range_config_t));

        if (NULL == config)
        {
            return NULL;
        }

        config->lower_bound = lowerbound.u.int64;
        config->upper_bound = upperbound.u.int64;
        config->out_str     = NULL;
        config->out_str_len = DEFS_PDGL_MAX_STRING_SIZE;


        prd = (prodstr_obj_t *)malloc(sizeof(prodstr_obj_t));
        if (NULL == prd)
        {
            free(config);
            return NULL;
        }

        prd->name   = NULL;
        prd->config = (void *)config;
        prd->next   = NULL;
        prd->res    = &prod_range_resolve;
        prd->term   = &prod_range_terminate;

        cur_str_len = strlen(name.u.s) + 1;
        cur_str     = (char *)calloc(cur_str_len, sizeof(char));
        if ((NULL == cur_str) || (cur_str_len > DEFS_PDGL_MAX_NAME_SIZE))
        {
            free(config);
            free(prd);
            return NULL;
        }

        strcpy(cur_str, name.u.s);
        prd->name = cur_str;
        cur_str   = NULL;

        cur_str_len = strlen(type.u.s) + 1;
        cur_str     = (char *)calloc(cur_str_len, sizeof(char));

        if ((NULL == cur_str) || (cur_str_len > DEFS_PDGL_MAX_NAME_SIZE))
        {
            free(prd->name);
            free(config);
            free(prd);
            return NULL;
        }
        strcpy(cur_str, type.u.s);
        prd->type = cur_str;
        cur_str   = NULL;

        config->out_str = (char *)calloc(DEFS_PDGL_MAX_STRING_SIZE, sizeof(char));
        if (NULL == config->out_str)
        {
            free(prd->name);
            free(prd->type);
            free(config);
            free(prd);
            return NULL;
        }

        return prd;
    }

    return NULL;
}

STATIC_INLINE void tomlprsr_prod_range_free(prodstr_obj_t *prd)
{
    if (NULL != prd)
    {
        prod_range_config_t *config = (prod_range_config_t *)prd->config;
        free(config->out_str);
        free(config);
        free(prd->name);
        free(prd->type);
    }
    free(prd);
}

/*************************************************************************************************/
/**************************   Janet Production Functions   ***************************************/
/*************************************************************************************************/

STATIC_INLINE prodstr_obj_t * tomlprsr_prod_janet_builder(toml_datum_t tbl)
{
    /* #lizard forgives(cyclomatic_complexity) */
    toml_datum_t type        = toml_seek(tbl, "type");
    toml_datum_t name        = toml_seek(tbl, "name");
    toml_datum_t replacement = toml_seek(tbl, "replacement");
    toml_datum_t terminal    = toml_seek(tbl, "terminal");

    if ((TOML_STRING == name.type) &&
        (TOML_STRING == replacement.type) &&
        (TOML_STRING == terminal.type))
    {
        size_t cur_str_len          = 0;
        prod_janet_config_t *config = NULL;
        prodstr_obj_t *      prd    = NULL;
        char *cur_str = NULL;


        config = (prod_janet_config_t *)malloc(sizeof(prod_janet_config_t));
        if (NULL == config)
        {
            return NULL;
        }
        config->out_str     = NULL;
        config->out_str_len = DEFS_PDGL_MAX_STRING_SIZE;
        config->term_str    = NULL;
        config->repl_str    = NULL;


        prd = (prodstr_obj_t *)malloc(sizeof(prodstr_obj_t));
        if (NULL == prd)
        {
            free(config);
            return NULL;
        }

        prd->name   = NULL;
        prd->config = (void *)config;
        prd->next   = NULL;
        prd->res    = &prod_janet_resolve;
        prd->term   = &prod_janet_terminate;


        cur_str_len = strlen(name.u.s) + 1;
        cur_str     = (char *)calloc(cur_str_len, sizeof(char));
        if ((NULL == cur_str) || (cur_str_len > DEFS_PDGL_MAX_NAME_SIZE))
        {
            free(config);
            free(prd);
            return NULL;
        }

        strcpy(cur_str, name.u.s);
        prd->name = cur_str;
        cur_str   = NULL;

        cur_str_len = strlen(type.u.s) + 1;
        cur_str     = (char *)calloc(cur_str_len, sizeof(char));

        if ((NULL == cur_str) || (cur_str_len > DEFS_PDGL_MAX_NAME_SIZE))
        {
            free(prd->name);
            free(config);
            free(prd);
            return NULL;
        }
        strcpy(cur_str, type.u.s);
        prd->type = cur_str;
        cur_str   = NULL;

        config->out_str = (char *)calloc(DEFS_PDGL_MAX_STRING_SIZE, sizeof(char));
        if (NULL == config->out_str)
        {
            free(prd->name);
            free(prd->type);
            free(config);
            free(prd);
            return NULL;
        }

        *config->out_str = '\0';

        cur_str_len = strlen(replacement.u.s) + 1;
        cur_str     = (char *)calloc(cur_str_len, sizeof(char));

        if ((NULL == cur_str) || (cur_str_len > DEFS_PDGL_MAX_STRING_SIZE))
        {
            free(prd->name);
            free(prd->type);
            free(config->out_str);
            free(config);
            free(prd);
            return NULL;
        }
        strcpy(cur_str, replacement.u.s);
        config->repl_str = cur_str;
        cur_str          = NULL;

        cur_str_len = strlen(terminal.u.s) + 1;
        cur_str     = (char *)calloc(cur_str_len, sizeof(char));

        if ((NULL == cur_str) || (cur_str_len > DEFS_PDGL_MAX_STRING_SIZE))
        {
            free(prd->name);
            free(prd->type);
            free(config->out_str);
            free(config->repl_str);
            free(config);
            free(prd);
            return NULL;
        }
        strcpy(cur_str, terminal.u.s);
        config->term_str = cur_str;
        cur_str          = NULL;

        return prd;
    }
    return NULL;
}

STATIC_INLINE void tomlprsr_prod_janet_free(prodstr_obj_t *prd)
{
    if (NULL != prd)
    {
        prod_janet_config_t *config = (prod_janet_config_t *)prd->config;
        free(config->out_str);
        free(config->term_str);
        free(config->repl_str);
        free(config);
        free(prd->name);
        free(prd->type);
        free(prd);
    }
}

/*************************************************************************************************/
/**************************   Weighted Production Functions   ************************************/
/*************************************************************************************************/

STATIC_INLINE prodstr_obj_t * tomlprsr_prod_weighted_builder(toml_datum_t tbl)
{
    /* #lizard forgives(cyclomatic_complexity) */
    toml_datum_t type         = toml_seek(tbl, "type");
    toml_datum_t name         = toml_seek(tbl, "name");
    toml_datum_t replacements = toml_seek(tbl, "replacements");
    toml_datum_t terminals    = toml_seek(tbl, "terminals");

    if ((TOML_STRING == name.type) &&
        (TOML_ARRAY == replacements.type) &&
        (TOML_ARRAY == terminals.type))
    {
        size_t cur_str_len             = 0;
        prod_weighted_config_t *config = NULL;
        prodstr_obj_t *         prd    = NULL;
        char *cur_str = NULL;
        prod_weighted_pair_t *repl_buff = NULL;
        prod_weighted_pair_t *term_buff = NULL;


        config = (prod_weighted_config_t *)malloc(sizeof(prod_weighted_config_t));
        if (NULL == config)
        {
            return NULL;
        }

        config->repl_list = NULL;
        config->repl_len  = replacements.u.arr.size;
        config->term_list = NULL;
        config->term_len  = terminals.u.arr.size;


        prd = (prodstr_obj_t *)malloc(sizeof(prodstr_obj_t));
        if (NULL == prd)
        {
            free(config);
            return NULL;
        }

        prd->name   = NULL;
        prd->config = (void *)config;
        prd->next   = NULL;
        prd->res    = &prod_weighted_resolve;
        prd->term   = &prod_weighted_terminate;


        cur_str_len = strlen(name.u.s) + 1;
        cur_str     = (char *)calloc(cur_str_len, sizeof(char));
        if ((NULL == cur_str) || (cur_str_len > DEFS_PDGL_MAX_NAME_SIZE))
        {
            free(config);
            free(prd);
            return NULL;
        }

        strcpy(cur_str, name.u.s);
        prd->name = cur_str;
        cur_str   = NULL;

        cur_str_len = strlen(type.u.s) + 1;
        cur_str     = (char *)calloc(cur_str_len, sizeof(char));

        if ((NULL == cur_str) || (cur_str_len > DEFS_PDGL_MAX_NAME_SIZE))
        {
            free(prd->name);
            free(config);
            free(prd);
            return NULL;
        }
        strcpy(cur_str, type.u.s);
        prd->type = cur_str;
        cur_str   = NULL;

        repl_buff = tomlprsr_prod_weighted_builder_list(replacements);
        if (NULL == repl_buff)
        {
            free(prd->name);
            free(prd->type);
            free(config);
            free(prd);
            return NULL;
        }
        config->repl_list = repl_buff;

        term_buff = tomlprsr_prod_weighted_builder_list(terminals);
        if (NULL == term_buff)
        {
            volatile size_t i;
            for (i = 0; i < config->repl_len; i++)
            {
                free(config->repl_list[i].string);
            }
            free(config->repl_list);
            free(prd->name);
            free(prd->type);
            free(config);
            free(prd);
            return NULL;
        }
        config->term_list = term_buff;



        return prd;
    }
    return NULL;
}

STATIC_INLINE void tomlprsr_prod_weighted_free(prodstr_obj_t *prd)
{
    if (NULL != prd)
    {
        size_t i;
        prod_weighted_config_t *config = (prod_weighted_config_t *)prd->config;
        for (i = 0; i < config->repl_len; i++)
        {
            free(config->repl_list[i].string);
        }
        for (i = 0; i < config->term_len; i++)
        {
            free(config->term_list[i].string);
        }

        free(config->repl_list);
        free(config->term_list);
        free(config);

        free(prd->name);
        free(prd->type);
        free(prd);
    }
}

STATIC_INLINE prod_weighted_pair_t * tomlprsr_prod_weighted_builder_list(toml_datum_t ary)
{
    size_t i;

    prod_weighted_pair_t *buff = calloc(ary.u.arr.size, sizeof(prod_weighted_pair_t));

    if (NULL == buff)
    {
        return NULL;
    }

    for (i = 0; i < ary.u.arr.size; i++)
    {
        toml_datum_t value  = ary.u.arr.elem[i];
        toml_datum_t string = toml_seek(value, "string");
        toml_datum_t weight = toml_seek(value, "weight");

        if ((TOML_STRING == string.type) && (TOML_INT64 == weight.type))
        {
            buff[i].string = NULL;
            buff[i].weight = 0;
            size_t str_len = strlen(string.u.s) + 1;
            if (str_len < DEFS_PDGL_MAX_STRING_SIZE)
            {
                char *str_config = (char *)calloc(str_len, sizeof(char));

                if (NULL != str_config)
                {
                    strcpy(str_config, string.u.s);
                    buff[i].string = str_config;
                    buff[i].weight = weight.u.int64;
                }
                else
                {
                    size_t j;
                    for (j = 0; j <= i; j++)
                    {
                        free(buff[i].string);
                    }
                    free(buff);
                    return NULL;
                }
            }
            else
            {
                size_t j;
                for (j = 0; j <= i; j++)
                {
                    free(buff[i].string);
                }
                free(buff);
                return NULL;
            }
        }
        else
        {
            size_t j;
            for (j = 0; j <= i; j++)
            {
                free(buff[i].string);
            }
            free(buff);
            return NULL;
        }
    }
    return buff;
}