Просмотр исходного кода

ncd: extend AST with include directives

ambrop7 13 лет назад
Родитель
Сommit
bc17a671ed

+ 14 - 3
examples/ncd_parser_test.c

@@ -264,9 +264,20 @@ int main (int argc, char **argv)
     }
     
     // print
-    for (NCDProcess *p = NCDProgram_FirstProcess(&prog); p; p = NCDProgram_NextProcess(&prog, p)) {
-        printf("process name=%s is_template=%d\n", NCDProcess_Name(p), NCDProcess_IsTemplate(p));
-        print_block(NCDProcess_Block(p), 2);
+    for (NCDProgramElem *elem = NCDProgram_FirstElem(&prog); elem; elem = NCDProgram_NextElem(&prog, elem)) {
+        switch (NCDProgramElem_Type(elem)) {
+            case NCDPROGRAMELEM_PROCESS: {
+                NCDProcess *p = NCDProgramElem_Process(elem);
+                printf("process name=%s is_template=%d\n", NCDProcess_Name(p), NCDProcess_IsTemplate(p));
+                print_block(NCDProcess_Block(p), 2);
+            } break;
+            
+            case NCDPROGRAMELEM_INCLUDE: {
+                printf("include path=%s\n", NCDProgramElem_IncludePathData(elem));
+            } break;
+            
+            default: ASSERT(0);
+        }
     }
     
     res = 0;

+ 74 - 68
generated/NCDConfigParser_parse.c

@@ -914,10 +914,13 @@ static void yy_reduce(
     }
     yymsp[-1].minor.yy29.have = 0;
 
+    NCDProgramElem elem;
+    NCDProgramElem_InitProcess(&elem, proc);
+    
     NCDProgram prog;
     NCDProgram_Init(&prog);
 
-    if (!NCDProgram_PrependProcess(&prog, proc)) {
+    if (!NCDProgram_PrependElem(&prog, elem)) {
         goto failA1;
     }
 
@@ -927,7 +930,7 @@ static void yy_reduce(
 
 failA1:
     NCDProgram_Free(&prog);
-    NCDProcess_Free(&proc);
+    NCDProgramElem_Free(&elem);
 failA0:
     yygotominor.yy74.have = 0;
     parser_out->out_of_memory = 1;
@@ -937,10 +940,10 @@ doneA:
   yy_destructor(yypParser,2,&yymsp[-2].minor);
   yy_destructor(yypParser,3,&yymsp[0].minor);
 }
-#line 941 "NCDConfigParser_parse.c"
+#line 944 "NCDConfigParser_parse.c"
         break;
       case 2: /* processes ::= process_or_template NAME CURLY_OPEN statements CURLY_CLOSE processes */
-#line 179 "NCDConfigParser_parse.y"
+#line 182 "NCDConfigParser_parse.y"
 {
     ASSERT(yymsp[-4].minor.yy0.str)
     if (!yymsp[-2].minor.yy29.have || !yymsp[0].minor.yy74.have) {
@@ -952,8 +955,11 @@ doneA:
         goto failB0;
     }
     yymsp[-2].minor.yy29.have = 0;
+    
+    NCDProgramElem elem;
+    NCDProgramElem_InitProcess(&elem, proc);
 
-    if (!NCDProgram_PrependProcess(&yymsp[0].minor.yy74.v, proc)) {
+    if (!NCDProgram_PrependElem(&yymsp[0].minor.yy74.v, elem)) {
         goto failB1;
     }
 
@@ -963,7 +969,7 @@ doneA:
     goto doneB;
 
 failB1:
-    NCDProcess_Free(&proc);
+    NCDProgramElem_Free(&elem);
 failB0:
     yygotominor.yy74.have = 0;
     parser_out->out_of_memory = 1;
@@ -974,10 +980,10 @@ doneB:
   yy_destructor(yypParser,2,&yymsp[-3].minor);
   yy_destructor(yypParser,3,&yymsp[-1].minor);
 }
-#line 978 "NCDConfigParser_parse.c"
+#line 984 "NCDConfigParser_parse.c"
         break;
       case 3: /* statement ::= dotted_name ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON */
-#line 211 "NCDConfigParser_parse.y"
+#line 217 "NCDConfigParser_parse.y"
 {
     if (!yymsp[-5].minor.yy9 || !yymsp[-3].minor.yy27.have) {
         goto failC0;
@@ -1002,10 +1008,10 @@ doneC:
   yy_destructor(yypParser,5,&yymsp[-2].minor);
   yy_destructor(yypParser,6,&yymsp[0].minor);
 }
-#line 1006 "NCDConfigParser_parse.c"
+#line 1012 "NCDConfigParser_parse.c"
         break;
       case 4: /* statement ::= dotted_name ARROW dotted_name ROUND_OPEN statement_args_maybe ROUND_CLOSE name_maybe SEMICOLON */
-#line 233 "NCDConfigParser_parse.y"
+#line 239 "NCDConfigParser_parse.y"
 {
     if (!yymsp[-7].minor.yy9 || !yymsp[-5].minor.yy9 || !yymsp[-3].minor.yy27.have) {
         goto failD0;
@@ -1032,10 +1038,10 @@ doneD:
   yy_destructor(yypParser,5,&yymsp[-2].minor);
   yy_destructor(yypParser,6,&yymsp[0].minor);
 }
-#line 1036 "NCDConfigParser_parse.c"
+#line 1042 "NCDConfigParser_parse.c"
         break;
       case 5: /* statement ::= IF ROUND_OPEN value ROUND_CLOSE CURLY_OPEN statements CURLY_CLOSE elif_maybe else_maybe name_maybe SEMICOLON */
-#line 256 "NCDConfigParser_parse.y"
+#line 262 "NCDConfigParser_parse.y"
 {
     if (!yymsp[-8].minor.yy27.have || !yymsp[-5].minor.yy29.have || !yymsp[-3].minor.yy4.have) {
         goto failE0;
@@ -1080,10 +1086,10 @@ doneE:
   yy_destructor(yypParser,3,&yymsp[-4].minor);
   yy_destructor(yypParser,6,&yymsp[0].minor);
 }
-#line 1084 "NCDConfigParser_parse.c"
+#line 1090 "NCDConfigParser_parse.c"
         break;
       case 6: /* statement ::= FOREACH ROUND_OPEN value AS NAME ROUND_CLOSE CURLY_OPEN statements CURLY_CLOSE name_maybe SEMICOLON */
-#line 295 "NCDConfigParser_parse.y"
+#line 301 "NCDConfigParser_parse.y"
 {
     if (!yymsp[-8].minor.yy27.have || !yymsp[-6].minor.yy0.str || !yymsp[-3].minor.yy29.have) {
         goto failEA0;
@@ -1114,10 +1120,10 @@ doneEA0:
   yy_destructor(yypParser,3,&yymsp[-2].minor);
   yy_destructor(yypParser,6,&yymsp[0].minor);
 }
-#line 1118 "NCDConfigParser_parse.c"
+#line 1124 "NCDConfigParser_parse.c"
         break;
       case 7: /* statement ::= FOREACH ROUND_OPEN value AS NAME COLON NAME ROUND_CLOSE CURLY_OPEN statements CURLY_CLOSE name_maybe SEMICOLON */
-#line 319 "NCDConfigParser_parse.y"
+#line 325 "NCDConfigParser_parse.y"
 {
     if (!yymsp[-10].minor.yy27.have || !yymsp[-8].minor.yy0.str || !yymsp[-6].minor.yy0.str || !yymsp[-3].minor.yy29.have) {
         goto failEB0;
@@ -1150,25 +1156,25 @@ doneEB0:
   yy_destructor(yypParser,3,&yymsp[-2].minor);
   yy_destructor(yypParser,6,&yymsp[0].minor);
 }
-#line 1154 "NCDConfigParser_parse.c"
+#line 1160 "NCDConfigParser_parse.c"
         break;
       case 8: /* elif_maybe ::= */
-#line 344 "NCDConfigParser_parse.y"
+#line 350 "NCDConfigParser_parse.y"
 {
     NCDIfBlock_Init(&yygotominor.yy4.v);
     yygotominor.yy4.have = 1;
 }
-#line 1162 "NCDConfigParser_parse.c"
+#line 1168 "NCDConfigParser_parse.c"
         break;
       case 9: /* elif_maybe ::= elif */
-#line 349 "NCDConfigParser_parse.y"
+#line 355 "NCDConfigParser_parse.y"
 {
     yygotominor.yy4 = yymsp[0].minor.yy4;
 }
-#line 1169 "NCDConfigParser_parse.c"
+#line 1175 "NCDConfigParser_parse.c"
         break;
       case 10: /* elif ::= ELIF ROUND_OPEN value ROUND_CLOSE CURLY_OPEN statements CURLY_CLOSE */
-#line 353 "NCDConfigParser_parse.y"
+#line 359 "NCDConfigParser_parse.y"
 {
     if (!yymsp[-4].minor.yy27.have || !yymsp[-1].minor.yy29.have) {
         goto failF0;
@@ -1203,10 +1209,10 @@ doneF0:
   yy_destructor(yypParser,2,&yymsp[-2].minor);
   yy_destructor(yypParser,3,&yymsp[0].minor);
 }
-#line 1207 "NCDConfigParser_parse.c"
+#line 1213 "NCDConfigParser_parse.c"
         break;
       case 11: /* elif ::= ELIF ROUND_OPEN value ROUND_CLOSE CURLY_OPEN statements CURLY_CLOSE elif */
-#line 383 "NCDConfigParser_parse.y"
+#line 389 "NCDConfigParser_parse.y"
 {
     if (!yymsp[-5].minor.yy27.have || !yymsp[-2].minor.yy29.have || !yymsp[0].minor.yy4.have) {
         goto failG0;
@@ -1241,27 +1247,27 @@ doneG0:
   yy_destructor(yypParser,2,&yymsp[-3].minor);
   yy_destructor(yypParser,3,&yymsp[-1].minor);
 }
-#line 1245 "NCDConfigParser_parse.c"
+#line 1251 "NCDConfigParser_parse.c"
         break;
       case 12: /* else_maybe ::= */
-#line 413 "NCDConfigParser_parse.y"
+#line 419 "NCDConfigParser_parse.y"
 {
     yygotominor.yy29.have = 0;
 }
-#line 1252 "NCDConfigParser_parse.c"
+#line 1258 "NCDConfigParser_parse.c"
         break;
       case 13: /* else_maybe ::= ELSE CURLY_OPEN statements CURLY_CLOSE */
-#line 417 "NCDConfigParser_parse.y"
+#line 423 "NCDConfigParser_parse.y"
 {
     yygotominor.yy29 = yymsp[-1].minor.yy29;
   yy_destructor(yypParser,13,&yymsp[-3].minor);
   yy_destructor(yypParser,2,&yymsp[-2].minor);
   yy_destructor(yypParser,3,&yymsp[0].minor);
 }
-#line 1262 "NCDConfigParser_parse.c"
+#line 1268 "NCDConfigParser_parse.c"
         break;
       case 14: /* statements ::= statement */
-#line 421 "NCDConfigParser_parse.y"
+#line 427 "NCDConfigParser_parse.y"
 {
     if (!yymsp[0].minor.yy23.have) {
         goto failH0;
@@ -1285,10 +1291,10 @@ failH0:
 doneH:
     free_statement(yymsp[0].minor.yy23);
 }
-#line 1289 "NCDConfigParser_parse.c"
+#line 1295 "NCDConfigParser_parse.c"
         break;
       case 15: /* statements ::= statement statements */
-#line 445 "NCDConfigParser_parse.y"
+#line 451 "NCDConfigParser_parse.y"
 {
     if (!yymsp[-1].minor.yy23.have || !yymsp[0].minor.yy29.have) {
         goto failI0;
@@ -1313,20 +1319,20 @@ doneI:
     free_statement(yymsp[-1].minor.yy23);
     free_block(yymsp[0].minor.yy29);
 }
-#line 1317 "NCDConfigParser_parse.c"
+#line 1323 "NCDConfigParser_parse.c"
         break;
       case 16: /* dotted_name ::= NAME */
       case 33: /* name_maybe ::= NAME */ yytestcase(yyruleno==33);
-#line 470 "NCDConfigParser_parse.y"
+#line 476 "NCDConfigParser_parse.y"
 {
     ASSERT(yymsp[0].minor.yy0.str)
 
     yygotominor.yy9 = yymsp[0].minor.yy0.str;
 }
-#line 1327 "NCDConfigParser_parse.c"
+#line 1333 "NCDConfigParser_parse.c"
         break;
       case 17: /* dotted_name ::= NAME DOT dotted_name */
-#line 476 "NCDConfigParser_parse.y"
+#line 482 "NCDConfigParser_parse.y"
 {
     ASSERT(yymsp[-2].minor.yy0.str)
     if (!yymsp[0].minor.yy9) {
@@ -1347,27 +1353,27 @@ doneJ:
     free(yymsp[0].minor.yy9);
   yy_destructor(yypParser,14,&yymsp[-1].minor);
 }
-#line 1351 "NCDConfigParser_parse.c"
+#line 1357 "NCDConfigParser_parse.c"
         break;
       case 18: /* statement_args_maybe ::= */
-#line 496 "NCDConfigParser_parse.y"
+#line 502 "NCDConfigParser_parse.y"
 {
     yygotominor.yy27.have = 1;
     NCDValue_InitList(&yygotominor.yy27.v);
 }
-#line 1359 "NCDConfigParser_parse.c"
+#line 1365 "NCDConfigParser_parse.c"
         break;
       case 19: /* statement_args_maybe ::= list_contents */
       case 30: /* value ::= list */ yytestcase(yyruleno==30);
       case 31: /* value ::= map */ yytestcase(yyruleno==31);
-#line 501 "NCDConfigParser_parse.y"
+#line 507 "NCDConfigParser_parse.y"
 {
     yygotominor.yy27 = yymsp[0].minor.yy27;
 }
-#line 1368 "NCDConfigParser_parse.c"
+#line 1374 "NCDConfigParser_parse.c"
         break;
       case 20: /* list_contents ::= value */
-#line 505 "NCDConfigParser_parse.y"
+#line 511 "NCDConfigParser_parse.y"
 {
     if (!yymsp[0].minor.yy27.have) {
         goto failL0;
@@ -1391,10 +1397,10 @@ failL0:
 doneL:
     free_value(yymsp[0].minor.yy27);
 }
-#line 1395 "NCDConfigParser_parse.c"
+#line 1401 "NCDConfigParser_parse.c"
         break;
       case 21: /* list_contents ::= value COMMA list_contents */
-#line 529 "NCDConfigParser_parse.y"
+#line 535 "NCDConfigParser_parse.y"
 {
     if (!yymsp[-2].minor.yy27.have || !yymsp[0].minor.yy27.have) {
         goto failM0;
@@ -1418,29 +1424,29 @@ doneM:
     free_value(yymsp[0].minor.yy27);
   yy_destructor(yypParser,15,&yymsp[-1].minor);
 }
-#line 1422 "NCDConfigParser_parse.c"
+#line 1428 "NCDConfigParser_parse.c"
         break;
       case 22: /* list ::= CURLY_OPEN CURLY_CLOSE */
-#line 552 "NCDConfigParser_parse.y"
+#line 558 "NCDConfigParser_parse.y"
 {
     yygotominor.yy27.have = 1;
     NCDValue_InitList(&yygotominor.yy27.v);
   yy_destructor(yypParser,2,&yymsp[-1].minor);
   yy_destructor(yypParser,3,&yymsp[0].minor);
 }
-#line 1432 "NCDConfigParser_parse.c"
+#line 1438 "NCDConfigParser_parse.c"
         break;
       case 23: /* list ::= CURLY_OPEN list_contents CURLY_CLOSE */
-#line 557 "NCDConfigParser_parse.y"
+#line 563 "NCDConfigParser_parse.y"
 {
     yygotominor.yy27 = yymsp[-1].minor.yy27;
   yy_destructor(yypParser,2,&yymsp[-2].minor);
   yy_destructor(yypParser,3,&yymsp[0].minor);
 }
-#line 1441 "NCDConfigParser_parse.c"
+#line 1447 "NCDConfigParser_parse.c"
         break;
       case 24: /* map_contents ::= value COLON value */
-#line 561 "NCDConfigParser_parse.y"
+#line 567 "NCDConfigParser_parse.y"
 {
     if (!yymsp[-2].minor.yy27.have || !yymsp[0].minor.yy27.have) {
         goto failS0;
@@ -1467,10 +1473,10 @@ doneS:
     free_value(yymsp[0].minor.yy27);
   yy_destructor(yypParser,11,&yymsp[-1].minor);
 }
-#line 1471 "NCDConfigParser_parse.c"
+#line 1477 "NCDConfigParser_parse.c"
         break;
       case 25: /* map_contents ::= value COLON value COMMA map_contents */
-#line 587 "NCDConfigParser_parse.y"
+#line 593 "NCDConfigParser_parse.y"
 {
     if (!yymsp[-4].minor.yy27.have || !yymsp[-2].minor.yy27.have || !yymsp[0].minor.yy27.have) {
         goto failT0;
@@ -1497,29 +1503,29 @@ doneT:
   yy_destructor(yypParser,11,&yymsp[-3].minor);
   yy_destructor(yypParser,15,&yymsp[-1].minor);
 }
-#line 1501 "NCDConfigParser_parse.c"
+#line 1507 "NCDConfigParser_parse.c"
         break;
       case 26: /* map ::= BRACKET_OPEN BRACKET_CLOSE */
-#line 612 "NCDConfigParser_parse.y"
+#line 618 "NCDConfigParser_parse.y"
 {
     yygotominor.yy27.have = 1;
     NCDValue_InitMap(&yygotominor.yy27.v);
   yy_destructor(yypParser,16,&yymsp[-1].minor);
   yy_destructor(yypParser,17,&yymsp[0].minor);
 }
-#line 1511 "NCDConfigParser_parse.c"
+#line 1517 "NCDConfigParser_parse.c"
         break;
       case 27: /* map ::= BRACKET_OPEN map_contents BRACKET_CLOSE */
-#line 617 "NCDConfigParser_parse.y"
+#line 623 "NCDConfigParser_parse.y"
 {
     yygotominor.yy27 = yymsp[-1].minor.yy27;
   yy_destructor(yypParser,16,&yymsp[-2].minor);
   yy_destructor(yypParser,17,&yymsp[0].minor);
 }
-#line 1520 "NCDConfigParser_parse.c"
+#line 1526 "NCDConfigParser_parse.c"
         break;
       case 28: /* value ::= STRING */
-#line 621 "NCDConfigParser_parse.y"
+#line 627 "NCDConfigParser_parse.y"
 {
     ASSERT(yymsp[0].minor.yy0.str)
 
@@ -1536,10 +1542,10 @@ failU0:
 doneU:
     free_token(yymsp[0].minor.yy0);
 }
-#line 1540 "NCDConfigParser_parse.c"
+#line 1546 "NCDConfigParser_parse.c"
         break;
       case 29: /* value ::= dotted_name */
-#line 638 "NCDConfigParser_parse.y"
+#line 644 "NCDConfigParser_parse.y"
 {
     if (!yymsp[0].minor.yy9) {
         goto failV0;
@@ -1558,30 +1564,30 @@ failV0:
 doneV:
     free(yymsp[0].minor.yy9);
 }
-#line 1562 "NCDConfigParser_parse.c"
+#line 1568 "NCDConfigParser_parse.c"
         break;
       case 32: /* name_maybe ::= */
-#line 665 "NCDConfigParser_parse.y"
+#line 671 "NCDConfigParser_parse.y"
 {
     yygotominor.yy9 = NULL;
 }
-#line 1569 "NCDConfigParser_parse.c"
+#line 1575 "NCDConfigParser_parse.c"
         break;
       case 34: /* process_or_template ::= PROCESS */
-#line 675 "NCDConfigParser_parse.y"
+#line 681 "NCDConfigParser_parse.y"
 {
     yygotominor.yy8 = 0;
   yy_destructor(yypParser,19,&yymsp[0].minor);
 }
-#line 1577 "NCDConfigParser_parse.c"
+#line 1583 "NCDConfigParser_parse.c"
         break;
       case 35: /* process_or_template ::= TEMPLATE */
-#line 679 "NCDConfigParser_parse.y"
+#line 685 "NCDConfigParser_parse.y"
 {
     yygotominor.yy8 = 1;
   yy_destructor(yypParser,20,&yymsp[0].minor);
 }
-#line 1585 "NCDConfigParser_parse.c"
+#line 1591 "NCDConfigParser_parse.c"
         break;
       default:
         break;
@@ -1646,7 +1652,7 @@ static void yy_syntax_error(
 #line 125 "NCDConfigParser_parse.y"
 
     parser_out->syntax_error = 1;
-#line 1650 "NCDConfigParser_parse.c"
+#line 1656 "NCDConfigParser_parse.c"
   ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
 }
 

+ 10 - 4
generated/NCDConfigParser_parse.y

@@ -154,10 +154,13 @@ processes(R) ::= process_or_template(T) NAME(A) CURLY_OPEN statements(B) CURLY_C
     }
     B.have = 0;
 
+    NCDProgramElem elem;
+    NCDProgramElem_InitProcess(&elem, proc);
+    
     NCDProgram prog;
     NCDProgram_Init(&prog);
 
-    if (!NCDProgram_PrependProcess(&prog, proc)) {
+    if (!NCDProgram_PrependElem(&prog, elem)) {
         goto failA1;
     }
 
@@ -167,7 +170,7 @@ processes(R) ::= process_or_template(T) NAME(A) CURLY_OPEN statements(B) CURLY_C
 
 failA1:
     NCDProgram_Free(&prog);
-    NCDProcess_Free(&proc);
+    NCDProgramElem_Free(&elem);
 failA0:
     R.have = 0;
     parser_out->out_of_memory = 1;
@@ -187,8 +190,11 @@ processes(R) ::= process_or_template(T) NAME(A) CURLY_OPEN statements(B) CURLY_C
         goto failB0;
     }
     B.have = 0;
+    
+    NCDProgramElem elem;
+    NCDProgramElem_InitProcess(&elem, proc);
 
-    if (!NCDProgram_PrependProcess(&N.v, proc)) {
+    if (!NCDProgram_PrependElem(&N.v, elem)) {
         goto failB1;
     }
 
@@ -198,7 +204,7 @@ processes(R) ::= process_or_template(T) NAME(A) CURLY_OPEN statements(B) CURLY_C
     goto doneB;
 
 failB1:
-    NCDProcess_Free(&proc);
+    NCDProgramElem_Free(&elem);
 failB0:
     R.have = 0;
     parser_out->out_of_memory = 1;

+ 96 - 25
ncd/NCDAst.c

@@ -32,6 +32,7 @@
 #include <string.h>
 
 #include <misc/offset.h>
+#include <misc/strdup.h>
 
 #include "NCDAst.h"
 
@@ -354,71 +355,141 @@ const char * NCDValue_VarName (NCDValue *o)
 
 void NCDProgram_Init (NCDProgram *o)
 {
-    LinkedList1_Init(&o->processes_list);
-    o->num_processes = 0;
+    LinkedList1_Init(&o->elems_list);
+    o->num_elems = 0;
 }
 
 void NCDProgram_Free (NCDProgram *o)
 {
     LinkedList1Node *ln;
-    while (ln = LinkedList1_GetFirst(&o->processes_list)) {
-        struct ProgramProcess *e = UPPER_OBJECT(ln, struct ProgramProcess, processes_list_node);
-        NCDProcess_Free(&e->p);
-        LinkedList1_Remove(&o->processes_list, &e->processes_list_node);
+    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);
     }
 }
 
-NCDProcess * NCDProgram_PrependProcess (NCDProgram *o, NCDProcess p)
+NCDProgramElem * NCDProgram_PrependElem (NCDProgram *o, NCDProgramElem elem)
 {
-    if (o->num_processes == SIZE_MAX) {
+    if (o->num_elems == SIZE_MAX) {
         return NULL;
     }
     
-    struct ProgramProcess *e = malloc(sizeof(*e));
+    struct ProgramElem *e = malloc(sizeof(*e));
     if (!e) {
         return NULL;
     }
     
-    LinkedList1_Prepend(&o->processes_list, &e->processes_list_node);
-    e->p = p;
+    LinkedList1_Prepend(&o->elems_list, &e->elems_list_node);
+    e->elem = elem;
     
-    o->num_processes++;
+    o->num_elems++;
     
-    return &e->p;
+    return &e->elem;
 }
 
-NCDProcess * NCDProgram_FirstProcess (NCDProgram *o)
+NCDProgramElem * NCDProgram_FirstElem (NCDProgram *o)
 {
-    LinkedList1Node *ln = LinkedList1_GetFirst(&o->processes_list);
+    LinkedList1Node *ln = LinkedList1_GetFirst(&o->elems_list);
     if (!ln) {
         return NULL;
     }
     
-    struct ProgramProcess *e = UPPER_OBJECT(ln, struct ProgramProcess, processes_list_node);
+    struct ProgramElem *e = UPPER_OBJECT(ln, struct ProgramElem, elems_list_node);
     
-    return &e->p;
+    return &e->elem;
 }
 
-NCDProcess * NCDProgram_NextProcess (NCDProgram *o, NCDProcess *ep)
+NCDProgramElem * NCDProgram_NextElem (NCDProgram *o, NCDProgramElem *ee)
 {
-    ASSERT(ep)
+    ASSERT(ee)
     
-    struct ProgramProcess *cur_e = UPPER_OBJECT(ep, struct ProgramProcess, p);
+    struct ProgramElem *cur_e = UPPER_OBJECT(ee, struct ProgramElem, elem);
     
-    LinkedList1Node *ln = LinkedList1Node_Next(&cur_e->processes_list_node);
+    LinkedList1Node *ln = LinkedList1Node_Next(&cur_e->elems_list_node);
     if (!ln) {
         return NULL;
     }
     
-    struct ProgramProcess *e = UPPER_OBJECT(ln, struct ProgramProcess, processes_list_node);
+    struct ProgramElem *e = UPPER_OBJECT(ln, struct ProgramElem, elems_list_node);
     
-    return &e->p;
+    return &e->elem;
 }
 
-size_t NCDProgram_NumProcesses (NCDProgram *o)
+size_t NCDProgram_NumElems (NCDProgram *o)
 {
-    return o->num_processes;
+    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 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;
+}
+
+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;
+        
+        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;
 }
 
 int NCDProcess_Init (NCDProcess *o, int is_template, const char *name, NCDBlock block)

+ 33 - 9
ncd/NCDAst.h

@@ -38,6 +38,7 @@
 
 typedef struct NCDValue_s NCDValue;
 typedef struct NCDProgram_s NCDProgram;
+typedef struct NCDProgramElem_s NCDProgramElem;
 typedef struct NCDProcess_s NCDProcess;
 typedef struct NCDBlock_s NCDBlock;
 typedef struct NCDStatement_s NCDStatement;
@@ -66,8 +67,8 @@ struct NCDValue_s {
 };
 
 struct NCDProgram_s {
-    LinkedList1 processes_list;
-    size_t num_processes;
+    LinkedList1 elems_list;
+    size_t num_elems;
 };
 
 struct NCDBlock_s {
@@ -81,6 +82,17 @@ struct NCDProcess_s {
     NCDBlock block;
 };
 
+struct NCDProgramElem_s {
+    int type;
+    union {
+        NCDProcess process;
+        struct {
+            char *path_data;
+            size_t path_length;
+        } include;
+    };
+};
+
 struct NCDIfBlock_s {
     LinkedList1 ifs_list;
 };
@@ -114,9 +126,9 @@ struct NCDIf_s {
     NCDBlock block;
 };
 
-struct ProgramProcess {
-    LinkedList1Node processes_list_node;
-    NCDProcess p;
+struct ProgramElem {
+    LinkedList1Node elems_list_node;
+    NCDProgramElem elem;
 };
 
 struct BlockStatement {
@@ -136,6 +148,9 @@ struct IfBlockIf {
 #define NCDVALUE_MAP 3
 #define NCDVALUE_VAR 4
 
+#define NCDPROGRAMELEM_PROCESS 1
+#define NCDPROGRAMELEM_INCLUDE 2
+
 #define NCDSTATEMENT_REG 1
 #define NCDSTATEMENT_IF 2
 #define NCDSTATEMENT_FOREACH 3
@@ -163,10 +178,19 @@ const char * NCDValue_VarName (NCDValue *o);
 
 void NCDProgram_Init (NCDProgram *o);
 void NCDProgram_Free (NCDProgram *o);
-NCDProcess * NCDProgram_PrependProcess (NCDProgram *o, NCDProcess p) WARN_UNUSED;
-NCDProcess * NCDProgram_FirstProcess (NCDProgram *o);
-NCDProcess * NCDProgram_NextProcess (NCDProgram *o, NCDProcess *ep);
-size_t NCDProgram_NumProcesses (NCDProgram *o);
+NCDProgramElem * NCDProgram_PrependElem (NCDProgram *o, NCDProgramElem elem) WARN_UNUSED;
+NCDProgramElem * NCDProgram_FirstElem (NCDProgram *o);
+NCDProgramElem * NCDProgram_NextElem (NCDProgram *o, NCDProgramElem *ee);
+size_t NCDProgram_NumElems (NCDProgram *o);
+int NCDProgram_ContainsElemType (NCDProgram *o, int elem_type);
+
+void NCDProgramElem_InitProcess (NCDProgramElem *o, NCDProcess process);
+int NCDProgramElem_InitInclude (NCDProgramElem *o, const char *path_data, size_t path_length) WARN_UNUSED;
+void NCDProgramElem_Free (NCDProgramElem *o);
+int NCDProgramElem_Type (NCDProgramElem *o);
+NCDProcess * NCDProgramElem_Process (NCDProgramElem *o);
+const char * NCDProgramElem_IncludePathData (NCDProgramElem *o);
+size_t NCDProgramElem_IncludePathLength (NCDProgramElem *o);
 
 int NCDProcess_Init (NCDProcess *o, int is_template, const char *name, NCDBlock block) WARN_UNUSED;
 void NCDProcess_Free (NCDProcess *o);

+ 10 - 4
ncd/NCDConfigParser_parse.y

@@ -154,10 +154,13 @@ processes(R) ::= process_or_template(T) NAME(A) CURLY_OPEN statements(B) CURLY_C
     }
     B.have = 0;
 
+    NCDProgramElem elem;
+    NCDProgramElem_InitProcess(&elem, proc);
+    
     NCDProgram prog;
     NCDProgram_Init(&prog);
 
-    if (!NCDProgram_PrependProcess(&prog, proc)) {
+    if (!NCDProgram_PrependElem(&prog, elem)) {
         goto failA1;
     }
 
@@ -167,7 +170,7 @@ processes(R) ::= process_or_template(T) NAME(A) CURLY_OPEN statements(B) CURLY_C
 
 failA1:
     NCDProgram_Free(&prog);
-    NCDProcess_Free(&proc);
+    NCDProgramElem_Free(&elem);
 failA0:
     R.have = 0;
     parser_out->out_of_memory = 1;
@@ -187,8 +190,11 @@ processes(R) ::= process_or_template(T) NAME(A) CURLY_OPEN statements(B) CURLY_C
         goto failB0;
     }
     B.have = 0;
+    
+    NCDProgramElem elem;
+    NCDProgramElem_InitProcess(&elem, proc);
 
-    if (!NCDProgram_PrependProcess(&N.v, proc)) {
+    if (!NCDProgram_PrependElem(&N.v, elem)) {
         goto failB1;
     }
 
@@ -198,7 +204,7 @@ processes(R) ::= process_or_template(T) NAME(A) CURLY_OPEN statements(B) CURLY_C
     goto doneB;
 
 failB1:
-    NCDProcess_Free(&proc);
+    NCDProgramElem_Free(&elem);
 failB0:
     R.have = 0;
     parser_out->out_of_memory = 1;

+ 7 - 3
ncd/NCDInterpProg.c

@@ -44,16 +44,17 @@
 int NCDInterpProg_Init (NCDInterpProg *o, NCDProgram *prog, NCDStringIndex *string_index, NCDPlaceholderDb *pdb, NCDModuleIndex *module_index, NCDMethodIndex *method_index)
 {
     ASSERT(prog)
+    ASSERT(!NCDProgram_ContainsElemType(prog, NCDPROGRAMELEM_INCLUDE))
     ASSERT(string_index)
     ASSERT(pdb)
     ASSERT(module_index)
     ASSERT(method_index)
     
-    if (NCDProgram_NumProcesses(prog) > INT_MAX) {
+    if (NCDProgram_NumElems(prog) > INT_MAX) {
         BLog(BLOG_ERROR, "too many processes");
         goto fail0;
     }
-    int num_procs = NCDProgram_NumProcesses(prog);
+    int num_procs = NCDProgram_NumElems(prog);
     
     if (!(o->procs = BAllocArray(num_procs, sizeof(o->procs[0])))) {
         BLog(BLOG_ERROR, "BAllocArray failed");
@@ -67,7 +68,10 @@ int NCDInterpProg_Init (NCDInterpProg *o, NCDProgram *prog, NCDStringIndex *stri
     
     o->num_procs = 0;
     
-    for (NCDProcess *p = NCDProgram_FirstProcess(prog); p; p = NCDProgram_NextProcess(prog, p)) {
+    for (NCDProgramElem *elem = NCDProgram_FirstElem(prog); elem; elem = NCDProgram_NextElem(prog, elem)) {
+        ASSERT(NCDProgramElem_Type(elem) == NCDPROGRAMELEM_PROCESS)
+        NCDProcess *p = NCDProgramElem_Process(elem);
+        
         struct NCDInterpProg__process *e = &o->procs[o->num_procs];
         
         e->name = NCDStringIndex_Get(string_index, NCDProcess_Name(p));

+ 15 - 3
ncd/NCDInterpreter.c

@@ -181,6 +181,12 @@ int NCDInterpreter_Init (NCDInterpreter *o, const char *program, size_t program_
         goto fail3;
     }
     
+    // include commands are not implemented currently
+    if (NCDProgram_ContainsElemType(&o->program, NCDPROGRAMELEM_INCLUDE)) {
+        BLog(BLOG_ERROR, "TODO include not implemented");
+        goto fail4;
+    }
+    
     // desugar
     if (!NCDSugar_Desugar(&o->program)) {
         BLog(BLOG_ERROR, "NCDSugar_Desugar failed");
@@ -247,7 +253,10 @@ int NCDInterpreter_Init (NCDInterpreter *o, const char *program, size_t program_
     LinkedList1_Init(&o->processes);
     
     // init processes
-    for (NCDProcess *p = NCDProgram_FirstProcess(&o->program); p; p = NCDProgram_NextProcess(&o->program, p)) {
+    for (NCDProgramElem *elem = NCDProgram_FirstElem(&o->program); elem; elem = NCDProgram_NextElem(&o->program, elem)) {
+        ASSERT(NCDProgramElem_Type(elem) == NCDPROGRAMELEM_PROCESS)
+        NCDProcess *p = NCDProgramElem_Process(elem);
+        
         if (NCDProcess_IsTemplate(p)) {
             continue;
         }
@@ -439,8 +448,11 @@ int alloc_base_type_strings (NCDInterpreter *interp, const struct NCDModuleGroup
 
 void clear_process_cache (NCDInterpreter *interp)
 {
-    for (NCDProcess *p = NCDProgram_FirstProcess(&interp->program); p; p = NCDProgram_NextProcess(&interp->program, p)) {
-        NCD_string_id_t name_id = NCDStringIndex_Lookup(&interp->string_index, NCDProcess_Name(p));
+    for (NCDProgramElem *elem = NCDProgram_FirstElem(&interp->program); elem; elem = NCDProgram_NextElem(&interp->program, elem)) {
+        ASSERT(NCDProgramElem_Type(elem) == NCDPROGRAMELEM_PROCESS)
+        NCDProcess *ast_p = NCDProgramElem_Process(elem);
+        
+        NCD_string_id_t name_id = NCDStringIndex_Lookup(&interp->string_index, NCDProcess_Name(ast_p));
         NCDInterpProcess *iprocess = NCDInterpProg_FindProcess(&interp->iprogram, name_id);
         
         struct process *p;

+ 11 - 3
ncd/NCDSugar.c

@@ -60,8 +60,11 @@ static int add_template (struct desugar_state *state, NCDBlock block, NCDValue *
         return 0;
     }
     
-    if (!NCDProgram_PrependProcess(state->prog, proc_tmp)) {
-        NCDProcess_Free(&proc_tmp);
+    NCDProgramElem elem;
+    NCDProgramElem_InitProcess(&elem, proc_tmp);
+    
+    if (!NCDProgram_PrependElem(state->prog, elem)) {
+        NCDProgramElem_Free(&elem);
         return 0;
     }
     
@@ -230,11 +233,16 @@ fail:
 
 int NCDSugar_Desugar (NCDProgram *prog)
 {
+    ASSERT(!NCDProgram_ContainsElemType(prog, NCDPROGRAMELEM_INCLUDE))
+    
     struct desugar_state state;
     state.prog = prog;
     state.template_name_ctr = 0;
     
-    for (NCDProcess *proc = NCDProgram_FirstProcess(prog); proc; proc = NCDProgram_NextProcess(prog, proc)) {
+    for (NCDProgramElem *elem = NCDProgram_FirstElem(prog); elem; elem = NCDProgram_NextElem(prog, elem)) {
+        ASSERT(NCDProgramElem_Type(elem) == NCDPROGRAMELEM_PROCESS)
+        NCDProcess *proc = NCDProgramElem_Process(elem);
+        
         if (!desugar_block(&state, NCDProcess_Block(proc))) {
             return 0;
         }