/** * @file NCDAst.c * @author Ambroz Bizjak * * @section LICENSE * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "NCDAst.h" struct NCDValue__list_element { LinkedList1Node list_node; NCDValue v; }; struct NCDValue__map_element { LinkedList1Node list_node; NCDValue key; NCDValue val; }; struct ProgramElem { LinkedList1Node elems_list_node; NCDProgramElem elem; }; struct BlockStatement { LinkedList1Node statements_list_node; NCDStatement s; }; struct IfBlockIf { LinkedList1Node ifs_list_node; NCDIf ifc; }; static void value_assert (NCDValue *o) { switch (o->type) { case NCDVALUE_STRING: case NCDVALUE_LIST: case NCDVALUE_MAP: case NCDVALUE_VAR: return; default: ASSERT(0); } } void NCDValue_Free (NCDValue *o) { switch (o->type) { case NCDVALUE_STRING: { free(o->string); } break; case NCDVALUE_LIST: { LinkedList1Node *n; while (n = LinkedList1_GetFirst(&o->list)) { struct NCDValue__list_element *e = UPPER_OBJECT(n, struct NCDValue__list_element, list_node); NCDValue_Free(&e->v); LinkedList1_Remove(&o->list, &e->list_node); free(e); } } break; case NCDVALUE_MAP: { LinkedList1Node *n; while (n = LinkedList1_GetFirst(&o->map_list)) { struct NCDValue__map_element *e = UPPER_OBJECT(n, struct NCDValue__map_element, list_node); LinkedList1_Remove(&o->map_list, &e->list_node); NCDValue_Free(&e->key); NCDValue_Free(&e->val); free(e); } } break; case NCDVALUE_VAR: { free(o->var_name); } break; default: ASSERT(0); } } int NCDValue_Type (NCDValue *o) { value_assert(o); return o->type; } int NCDValue_InitString (NCDValue *o, const char *str) { return NCDValue_InitStringBin(o, (const uint8_t *)str, strlen(str)); } int NCDValue_InitStringBin (NCDValue *o, const uint8_t *str, size_t len) { if (len == SIZE_MAX) { return 0; } if (!(o->string = malloc(len + 1))) { return 0; } memcpy(o->string, str, len); o->string[len] = '\0'; o->string_len = len; o->type = NCDVALUE_STRING; return 1; } const char * NCDValue_StringValue (NCDValue *o) { ASSERT(o->type == NCDVALUE_STRING) return (char *)o->string; } size_t NCDValue_StringLength (NCDValue *o) { ASSERT(o->type == NCDVALUE_STRING) return o->string_len; } void NCDValue_InitList (NCDValue *o) { o->type = NCDVALUE_LIST; LinkedList1_Init(&o->list); o->list_count = 0; } size_t NCDValue_ListCount (NCDValue *o) { value_assert(o); ASSERT(o->type == NCDVALUE_LIST) return o->list_count; } int NCDValue_ListAppend (NCDValue *o, NCDValue v) { value_assert(o); ASSERT(o->type == NCDVALUE_LIST) value_assert(&v); if (o->list_count == SIZE_MAX) { return 0; } struct NCDValue__list_element *e = malloc(sizeof(*e)); if (!e) { return 0; } e->v = v; LinkedList1_Append(&o->list, &e->list_node); o->list_count++; return 1; } int NCDValue_ListPrepend (NCDValue *o, NCDValue v) { value_assert(o); ASSERT(o->type == NCDVALUE_LIST) value_assert(&v); if (o->list_count == SIZE_MAX) { return 0; } struct NCDValue__list_element *e = malloc(sizeof(*e)); if (!e) { return 0; } e->v = v; LinkedList1_Prepend(&o->list, &e->list_node); o->list_count++; return 1; } NCDValue * NCDValue_ListFirst (NCDValue *o) { value_assert(o); ASSERT(o->type == NCDVALUE_LIST) LinkedList1Node *ln = LinkedList1_GetFirst(&o->list); if (!ln) { return NULL; } struct NCDValue__list_element *e = UPPER_OBJECT(ln, struct NCDValue__list_element, list_node); return &e->v; } NCDValue * NCDValue_ListNext (NCDValue *o, NCDValue *ev) { value_assert(o); ASSERT(o->type == NCDVALUE_LIST) struct NCDValue__list_element *cur_e = UPPER_OBJECT(ev, struct NCDValue__list_element, v); LinkedList1Node *ln = LinkedList1Node_Next(&cur_e->list_node); if (!ln) { return NULL; } struct NCDValue__list_element *e = UPPER_OBJECT(ln, struct NCDValue__list_element, list_node); return &e->v; } void NCDValue_InitMap (NCDValue *o) { o->type = NCDVALUE_MAP; LinkedList1_Init(&o->map_list); o->map_count = 0; } size_t NCDValue_MapCount (NCDValue *o) { value_assert(o); ASSERT(o->type == NCDVALUE_MAP) return o->map_count; } int NCDValue_MapPrepend (NCDValue *o, NCDValue key, NCDValue val) { value_assert(o); ASSERT(o->type == NCDVALUE_MAP) value_assert(&key); value_assert(&val); if (o->map_count == SIZE_MAX) { return 0; } struct NCDValue__map_element *e = malloc(sizeof(*e)); if (!e) { return 0; } e->key = key; e->val = val; LinkedList1_Prepend(&o->map_list, &e->list_node); o->map_count++; return 1; } NCDValue * NCDValue_MapFirstKey (NCDValue *o) { value_assert(o); ASSERT(o->type == NCDVALUE_MAP) LinkedList1Node *ln = LinkedList1_GetFirst(&o->map_list); if (!ln) { return NULL; } struct NCDValue__map_element *e = UPPER_OBJECT(ln, struct NCDValue__map_element, list_node); value_assert(&e->key); value_assert(&e->val); return &e->key; } NCDValue * NCDValue_MapNextKey (NCDValue *o, NCDValue *ekey) { value_assert(o); ASSERT(o->type == NCDVALUE_MAP) struct NCDValue__map_element *e0 = UPPER_OBJECT(ekey, struct NCDValue__map_element, key); value_assert(&e0->key); value_assert(&e0->val); LinkedList1Node *ln = LinkedList1Node_Next(&e0->list_node); if (!ln) { return NULL; } struct NCDValue__map_element *e = UPPER_OBJECT(ln, struct NCDValue__map_element, list_node); value_assert(&e->key); value_assert(&e->val); return &e->key; } NCDValue * NCDValue_MapKeyValue (NCDValue *o, NCDValue *ekey) { value_assert(o); ASSERT(o->type == NCDVALUE_MAP) struct NCDValue__map_element *e = UPPER_OBJECT(ekey, struct NCDValue__map_element, key); value_assert(&e->key); value_assert(&e->val); return &e->val; } int NCDValue_InitVar (NCDValue *o, const char *var_name) { ASSERT(var_name) if (!(o->var_name = strdup(var_name))) { return 0; } o->type = NCDVALUE_VAR; return 1; } const char * NCDValue_VarName (NCDValue *o) { value_assert(o); ASSERT(o->type == NCDVALUE_VAR) return o->var_name; } void NCDProgram_Init (NCDProgram *o) { LinkedList1_Init(&o->elems_list); o->num_elems = 0; } void NCDProgram_Free (NCDProgram *o) { LinkedList1Node *ln; while (ln = LinkedList1_GetFirst(&o->elems_list)) { struct ProgramElem *e = UPPER_OBJECT(ln, struct ProgramElem, elems_list_node); NCDProgramElem_Free(&e->elem); LinkedList1_Remove(&o->elems_list, &e->elems_list_node); free(e); } } NCDProgramElem * NCDProgram_PrependElem (NCDProgram *o, NCDProgramElem elem) { if (o->num_elems == SIZE_MAX) { return NULL; } struct ProgramElem *e = malloc(sizeof(*e)); if (!e) { return NULL; } LinkedList1_Prepend(&o->elems_list, &e->elems_list_node); e->elem = elem; o->num_elems++; return &e->elem; } NCDProgramElem * NCDProgram_FirstElem (NCDProgram *o) { LinkedList1Node *ln = LinkedList1_GetFirst(&o->elems_list); if (!ln) { return NULL; } struct ProgramElem *e = UPPER_OBJECT(ln, struct ProgramElem, elems_list_node); return &e->elem; } NCDProgramElem * NCDProgram_NextElem (NCDProgram *o, NCDProgramElem *ee) { ASSERT(ee) struct ProgramElem *cur_e = UPPER_OBJECT(ee, struct ProgramElem, elem); LinkedList1Node *ln = LinkedList1Node_Next(&cur_e->elems_list_node); if (!ln) { return NULL; } struct ProgramElem *e = UPPER_OBJECT(ln, struct ProgramElem, elems_list_node); return &e->elem; } size_t NCDProgram_NumElems (NCDProgram *o) { return o->num_elems; } int NCDProgram_ContainsElemType (NCDProgram *o, int elem_type) { for (NCDProgramElem *elem = NCDProgram_FirstElem(o); elem; elem = NCDProgram_NextElem(o, elem)) { if (NCDProgramElem_Type(elem) == elem_type) { return 1; } } return 0; } void NCDProgram_RemoveElem (NCDProgram *o, NCDProgramElem *ee) { ASSERT(ee) struct ProgramElem *e = UPPER_OBJECT(ee, struct ProgramElem, elem); NCDProgramElem_Free(&e->elem); LinkedList1_Remove(&o->elems_list, &e->elems_list_node); free(e); ASSERT(o->num_elems > 0) o->num_elems--; } int NCDProgram_ReplaceElemWithProgram (NCDProgram *o, NCDProgramElem *ee, NCDProgram replace_prog) { ASSERT(ee) if (replace_prog.num_elems > SIZE_MAX - o->num_elems) { return 0; } struct ProgramElem *e = UPPER_OBJECT(ee, struct ProgramElem, elem); LinkedList1_InsertListAfter(&o->elems_list, replace_prog.elems_list, &e->elems_list_node); o->num_elems += replace_prog.num_elems; NCDProgram_RemoveElem(o, ee); return 1; } void NCDProgramElem_InitProcess (NCDProgramElem *o, NCDProcess process) { o->type = NCDPROGRAMELEM_PROCESS; o->process = process; } int NCDProgramElem_InitInclude (NCDProgramElem *o, const char *path_data, size_t path_length) { if (!(o->include.path_data = b_strdup_bin(path_data, path_length))) { return 0; } o->type = NCDPROGRAMELEM_INCLUDE; o->include.path_length = path_length; return 1; } int NCDProgramElem_InitIncludeGuard (NCDProgramElem *o, const char *id_data, size_t id_length) { if (!(o->include_guard.id_data = b_strdup_bin(id_data, id_length))) { return 0; } o->type = NCDPROGRAMELEM_INCLUDE_GUARD; o->include_guard.id_length = id_length; return 1; } void NCDProgramElem_Free (NCDProgramElem *o) { switch (o->type) { case NCDPROGRAMELEM_PROCESS: { NCDProcess_Free(&o->process); } break; case NCDPROGRAMELEM_INCLUDE: { free(o->include.path_data); } break; case NCDPROGRAMELEM_INCLUDE_GUARD: { free(o->include_guard.id_data); } break; default: ASSERT(0); } } int NCDProgramElem_Type (NCDProgramElem *o) { return o->type; } NCDProcess * NCDProgramElem_Process (NCDProgramElem *o) { ASSERT(o->type == NCDPROGRAMELEM_PROCESS) return &o->process; } const char * NCDProgramElem_IncludePathData (NCDProgramElem *o) { ASSERT(o->type == NCDPROGRAMELEM_INCLUDE) return o->include.path_data; } size_t NCDProgramElem_IncludePathLength (NCDProgramElem *o) { ASSERT(o->type == NCDPROGRAMELEM_INCLUDE) return o->include.path_length; } const char * NCDProgramElem_IncludeGuardIdData (NCDProgramElem *o) { ASSERT(o->type == NCDPROGRAMELEM_INCLUDE_GUARD) return o->include_guard.id_data; } size_t NCDProgramElem_IncludeGuardIdLength (NCDProgramElem *o) { ASSERT(o->type == NCDPROGRAMELEM_INCLUDE_GUARD) return o->include_guard.id_length; } int NCDProcess_Init (NCDProcess *o, int is_template, const char *name, NCDBlock block) { ASSERT(is_template == !!is_template) ASSERT(name) if (!(o->name = strdup(name))) { return 0; } o->is_template = is_template; o->block = block; return 1; } void NCDProcess_Free (NCDProcess *o) { NCDBlock_Free(&o->block); free(o->name); } int NCDProcess_IsTemplate (NCDProcess *o) { return o->is_template; } const char * NCDProcess_Name (NCDProcess *o) { return o->name; } NCDBlock * NCDProcess_Block (NCDProcess *o) { return &o->block; } void NCDBlock_Init (NCDBlock *o) { LinkedList1_Init(&o->statements_list); o->count = 0; } void NCDBlock_Free (NCDBlock *o) { LinkedList1Node *ln; while (ln = LinkedList1_GetFirst(&o->statements_list)) { struct BlockStatement *e = UPPER_OBJECT(ln, struct BlockStatement, statements_list_node); NCDStatement_Free(&e->s); LinkedList1_Remove(&o->statements_list, &e->statements_list_node); free(e); } } int NCDBlock_PrependStatement (NCDBlock *o, NCDStatement s) { return NCDBlock_InsertStatementAfter(o, NULL, s); } int NCDBlock_InsertStatementAfter (NCDBlock *o, NCDStatement *after, NCDStatement s) { struct BlockStatement *after_e = NULL; if (after) { after_e = UPPER_OBJECT(after, struct BlockStatement, s); } if (o->count == SIZE_MAX) { return 0; } struct BlockStatement *e = malloc(sizeof(*e)); if (!e) { return 0; } if (after_e) { LinkedList1_InsertAfter(&o->statements_list, &e->statements_list_node, &after_e->statements_list_node); } else { LinkedList1_Prepend(&o->statements_list, &e->statements_list_node); } e->s = s; o->count++; return 1; } NCDStatement * NCDBlock_ReplaceStatement (NCDBlock *o, NCDStatement *es, NCDStatement s) { ASSERT(es) struct BlockStatement *e = UPPER_OBJECT(es, struct BlockStatement, s); NCDStatement_Free(&e->s); e->s = s; return &e->s; } NCDStatement * NCDBlock_FirstStatement (NCDBlock *o) { LinkedList1Node *ln = LinkedList1_GetFirst(&o->statements_list); if (!ln) { return NULL; } struct BlockStatement *e = UPPER_OBJECT(ln, struct BlockStatement, statements_list_node); return &e->s; } NCDStatement * NCDBlock_NextStatement (NCDBlock *o, NCDStatement *es) { ASSERT(es) struct BlockStatement *cur_e = UPPER_OBJECT(es, struct BlockStatement, s); LinkedList1Node *ln = LinkedList1Node_Next(&cur_e->statements_list_node); if (!ln) { return NULL; } struct BlockStatement *e = UPPER_OBJECT(ln, struct BlockStatement, statements_list_node); return &e->s; } size_t NCDBlock_NumStatements (NCDBlock *o) { return o->count; } int NCDStatement_InitReg (NCDStatement *o, const char *name, const char *objname, const char *cmdname, NCDValue args) { ASSERT(cmdname) ASSERT(NCDValue_Type(&args) == NCDVALUE_LIST) o->name = NULL; o->reg.objname = NULL; o->reg.cmdname = NULL; if (name && !(o->name = strdup(name))) { goto fail; } if (objname && !(o->reg.objname = strdup(objname))) { goto fail; } if (!(o->reg.cmdname = strdup(cmdname))) { goto fail; } o->type = NCDSTATEMENT_REG; o->reg.args = args; return 1; fail: free(o->name); free(o->reg.objname); free(o->reg.cmdname); return 0; } int NCDStatement_InitIf (NCDStatement *o, const char *name, NCDIfBlock ifblock) { o->name = NULL; if (name && !(o->name = strdup(name))) { return 0; } o->type = NCDSTATEMENT_IF; o->ifc.ifblock = ifblock; o->ifc.have_else = 0; return 1; } int NCDStatement_InitForeach (NCDStatement *o, const char *name, NCDValue collection, const char *name1, const char *name2, NCDBlock block) { ASSERT(name1) o->name = NULL; o->foreach.name1 = NULL; o->foreach.name2 = NULL; if (name && !(o->name = strdup(name))) { goto fail; } if (!(o->foreach.name1 = strdup(name1))) { goto fail; } if (name2 && !(o->foreach.name2 = strdup(name2))) { goto fail; } o->type = NCDSTATEMENT_FOREACH; o->foreach.collection = collection; o->foreach.block = block; o->foreach.is_grabbed = 0; return 1; fail: free(o->name); free(o->foreach.name1); free(o->foreach.name2); return 0; } void NCDStatement_Free (NCDStatement *o) { switch (o->type) { case NCDSTATEMENT_REG: { NCDValue_Free(&o->reg.args); free(o->reg.cmdname); free(o->reg.objname); } break; case NCDSTATEMENT_IF: { if (o->ifc.have_else) { NCDBlock_Free(&o->ifc.else_block); } NCDIfBlock_Free(&o->ifc.ifblock); } break; case NCDSTATEMENT_FOREACH: { if (!o->foreach.is_grabbed) { NCDBlock_Free(&o->foreach.block); NCDValue_Free(&o->foreach.collection); } free(o->foreach.name2); free(o->foreach.name1); } break; default: ASSERT(0); } free(o->name); } int NCDStatement_Type (NCDStatement *o) { return o->type; } const char * NCDStatement_Name (NCDStatement *o) { return o->name; } const char * NCDStatement_RegObjName (NCDStatement *o) { ASSERT(o->type == NCDSTATEMENT_REG) return o->reg.objname; } const char * NCDStatement_RegCmdName (NCDStatement *o) { ASSERT(o->type == NCDSTATEMENT_REG) return o->reg.cmdname; } NCDValue * NCDStatement_RegArgs (NCDStatement *o) { ASSERT(o->type == NCDSTATEMENT_REG) return &o->reg.args; } NCDIfBlock * NCDStatement_IfBlock (NCDStatement *o) { ASSERT(o->type == NCDSTATEMENT_IF) return &o->ifc.ifblock; } void NCDStatement_IfAddElse (NCDStatement *o, NCDBlock else_block) { ASSERT(o->type == NCDSTATEMENT_IF) ASSERT(!o->ifc.have_else) o->ifc.have_else = 1; o->ifc.else_block = else_block; } NCDBlock * NCDStatement_IfElse (NCDStatement *o) { ASSERT(o->type == NCDSTATEMENT_IF) if (!o->ifc.have_else) { return NULL; } return &o->ifc.else_block; } NCDBlock NCDStatement_IfGrabElse (NCDStatement *o) { ASSERT(o->type == NCDSTATEMENT_IF) ASSERT(o->ifc.have_else) o->ifc.have_else = 0; return o->ifc.else_block; } NCDValue * NCDStatement_ForeachCollection (NCDStatement *o) { ASSERT(o->type == NCDSTATEMENT_FOREACH) ASSERT(!o->foreach.is_grabbed) return &o->foreach.collection; } const char * NCDStatement_ForeachName1 (NCDStatement *o) { ASSERT(o->type == NCDSTATEMENT_FOREACH) return o->foreach.name1; } const char * NCDStatement_ForeachName2 (NCDStatement *o) { ASSERT(o->type == NCDSTATEMENT_FOREACH) return o->foreach.name2; } NCDBlock * NCDStatement_ForeachBlock (NCDStatement *o) { ASSERT(o->type == NCDSTATEMENT_FOREACH) ASSERT(!o->foreach.is_grabbed) return &o->foreach.block; } void NCDStatement_ForeachGrab (NCDStatement *o, NCDValue *out_collection, NCDBlock *out_block) { ASSERT(o->type == NCDSTATEMENT_FOREACH) ASSERT(!o->foreach.is_grabbed) *out_collection = o->foreach.collection; *out_block = o->foreach.block; o->foreach.is_grabbed = 1; } void NCDIfBlock_Init (NCDIfBlock *o) { LinkedList1_Init(&o->ifs_list); } void NCDIfBlock_Free (NCDIfBlock *o) { LinkedList1Node *ln; while (ln = LinkedList1_GetFirst(&o->ifs_list)) { struct IfBlockIf *e = UPPER_OBJECT(ln, struct IfBlockIf, ifs_list_node); NCDIf_Free(&e->ifc); LinkedList1_Remove(&o->ifs_list, &e->ifs_list_node); free(e); } } int NCDIfBlock_PrependIf (NCDIfBlock *o, NCDIf ifc) { struct IfBlockIf *e = malloc(sizeof(*e)); if (!e) { return 0; } LinkedList1_Prepend(&o->ifs_list, &e->ifs_list_node); e->ifc = ifc; return 1; } NCDIf * NCDIfBlock_FirstIf (NCDIfBlock *o) { LinkedList1Node *ln = LinkedList1_GetFirst(&o->ifs_list); if (!ln) { return NULL; } struct IfBlockIf *e = UPPER_OBJECT(ln, struct IfBlockIf, ifs_list_node); return &e->ifc; } NCDIf * NCDIfBlock_NextIf (NCDIfBlock *o, NCDIf *ei) { ASSERT(ei) struct IfBlockIf *cur_e = UPPER_OBJECT(ei, struct IfBlockIf, ifc); LinkedList1Node *ln = LinkedList1Node_Next(&cur_e->ifs_list_node); if (!ln) { return NULL; } struct IfBlockIf *e = UPPER_OBJECT(ln, struct IfBlockIf, ifs_list_node); return &e->ifc; } NCDIf NCDIfBlock_GrabIf (NCDIfBlock *o, NCDIf *ei) { ASSERT(ei) struct IfBlockIf *e = UPPER_OBJECT(ei, struct IfBlockIf, ifc); NCDIf old_ifc = e->ifc; LinkedList1_Remove(&o->ifs_list, &e->ifs_list_node); free(e); return old_ifc; } void NCDIf_Init (NCDIf *o, NCDValue cond, NCDBlock block) { o->cond = cond; o->block = block; } void NCDIf_Free (NCDIf *o) { NCDValue_Free(&o->cond); NCDBlock_Free(&o->block); } void NCDIf_FreeGrab (NCDIf *o, NCDValue *out_cond, NCDBlock *out_block) { *out_cond = o->cond; *out_block = o->block; } NCDValue * NCDIf_Cond (NCDIf *o) { return &o->cond; } NCDBlock * NCDIf_Block (NCDIf *o) { return &o->block; }