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

+ 1 - 1
examples/CMakeLists.txt

@@ -32,7 +32,7 @@ if (BUILD_NCD)
     target_link_libraries(ncd_tokenizer_test ncdtokenizer)
 
     add_executable(ncd_parser_test ncd_parser_test.c)
-    target_link_libraries(ncd_parser_test ncdconfigparser ncdvaluegenerator)
+    target_link_libraries(ncd_parser_test ncdconfigparser ncdvaluegenerator ncdsugar)
 
     add_executable(ncd_value_parser_test ncd_value_parser_test.c)
     target_link_libraries(ncd_value_parser_test ncdvalueparser ncdvaluegenerator)

+ 34 - 10
examples/ncd_parser_test.c

@@ -36,6 +36,7 @@
 #include <base/BLog.h>
 #include <ncd/NCDConfigParser.h>
 #include <ncd/NCDValueGenerator.h>
+#include <ncd/NCDSugar.h>
 
 int error;
 
@@ -103,6 +104,16 @@ static void print_block (NCDBlock *block, unsigned int indent)
                 }
             } break;
             
+            case NCDSTATEMENT_FOREACH: {
+                const char *name1 = NCDStatement_ForeachName1(st);
+                const char *name2 = NCDStatement_ForeachName2(st) ? NCDStatement_ForeachName2(st) : "";
+                
+                print_indent(indent);
+                printf("foreach name=%s name1=%s name2=%s\n", name, name1, name2);
+                
+                print_block(NCDStatement_ForeachBlock(st), indent + 2);
+            } break;
+            
             default: ASSERT(0);
         }
     }
@@ -110,22 +121,31 @@ static void print_block (NCDBlock *block, unsigned int indent)
 
 int main (int argc, char **argv)
 {
-    if (argc < 1) {
-        return 1;
-    }
+    int res = 1;
     
-    if (argc != 2) {
-        printf("Usage: %s <string>\n", argv[0]);
-        return 1;
+    if (argc != 3) {
+        printf("Usage: %s <desugar=0/1> <string>\n", (argc > 0 ? argv[0] : ""));
+        goto fail0;
     }
     
+    int desugar = atoi(argv[1]);
+    char *text = argv[2];
+    
     BLog_InitStdout();
     
     // parse
     NCDProgram prog;
-    if (!NCDConfigParser_Parse(argv[1], strlen(argv[1]), &prog)) {
+    if (!NCDConfigParser_Parse(text, strlen(text), &prog)) {
         DEBUG("NCDConfigParser_Parse failed");
-        return 1;
+        goto fail1;
+    }
+    
+    // desugar
+    if (desugar) {
+        if (!NCDSugar_Desugar(&prog)) {
+            DEBUG("NCDSugar_Desugar failed");
+            goto fail2;
+        }
     }
     
     // print
@@ -134,7 +154,11 @@ int main (int argc, char **argv)
         print_block(NCDProcess_Block(p), 2);
     }
     
+    res = 0;
+fail2:
     NCDProgram_Free(&prog);
-    
-    return 0;
+fail1:
+    BLog_Free();
+fail0:
+    return res;
 }

Разница между файлами не показана из-за своего большого размера
+ 502 - 416
generated/NCDConfigParser_parse.c


+ 12 - 10
generated/NCDConfigParser_parse.h

@@ -6,13 +6,15 @@
 #define SEMICOLON                       6
 #define ARROW                           7
 #define IF                              8
-#define ELIF                            9
-#define ELSE                           10
-#define DOT                            11
-#define COMMA                          12
-#define COLON                          13
-#define BRACKET_OPEN                   14
-#define BRACKET_CLOSE                  15
-#define STRING                         16
-#define PROCESS                        17
-#define TEMPLATE                       18
+#define FOREACH                         9
+#define AS                             10
+#define COLON                          11
+#define ELIF                           12
+#define ELSE                           13
+#define DOT                            14
+#define COMMA                          15
+#define BRACKET_OPEN                   16
+#define BRACKET_CLOSE                  17
+#define STRING                         18
+#define PROCESS                        19
+#define TEMPLATE                       20

Разница между файлами не показана из-за своего большого размера
+ 427 - 258
generated/NCDConfigParser_parse.out


+ 49 - 0
generated/NCDConfigParser_parse.y

@@ -291,6 +291,55 @@ doneE:
     free(C);
 }
 
+statement(R) ::= FOREACH ROUND_OPEN value(A) AS NAME(B) ROUND_CLOSE CURLY_OPEN statements(S) CURLY_CLOSE name_maybe(N) SEMICOLON. {
+    if (!A.have || !B.str || !S.have) {
+        goto failEA0;
+    }
+    
+    if (!NCDStatement_InitForeach(&R.v, N, A.v, B.str, NULL, S.v)) {
+        goto failEA0;
+    }
+    A.have = 0;
+    S.have = 0;
+    
+    R.have = 1;
+    goto doneEA0;
+    
+failEA0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneEA0:
+    free_value(A);
+    free_token(B);
+    free_block(S);
+    free(N);
+}
+
+statement(R) ::= FOREACH ROUND_OPEN value(A) AS NAME(B) COLON NAME(C) ROUND_CLOSE CURLY_OPEN statements(S) CURLY_CLOSE name_maybe(N) SEMICOLON. {
+    if (!A.have || !B.str || !C.str || !S.have) {
+        goto failEB0;
+    }
+    
+    if (!NCDStatement_InitForeach(&R.v, N, A.v, B.str, C.str, S.v)) {
+        goto failEB0;
+    }
+    A.have = 0;
+    S.have = 0;
+    
+    R.have = 1;
+    goto doneEB0;
+    
+failEB0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneEB0:
+    free_value(A);
+    free_token(B);
+    free_token(C);
+    free_block(S);
+    free(N);
+}
+
 elif_maybe(R) ::= . {
     NCDIfBlock_Init(&R.v);
     R.have = 1;

+ 6 - 2
ncd/CMakeLists.txt

@@ -59,6 +59,11 @@ add_library(ncdconfigparser
 )
 target_link_libraries(ncdconfigparser base ncdtokenizer ncdast)
 
+add_library(ncdsugar
+    NCDSugar.c
+)
+target_link_libraries(ncdsugar ncdast)
+
 add_library(ncdrequest
     NCDRequestClient.c
 )
@@ -75,7 +80,6 @@ add_executable(badvpn-ncd
     NCDModuleIndex.c
     NCDIfConfig.c
     NCDObject.c
-    NCDSugar.c
     NCDInterpBlock.c
     NCDInterpProg.c
     NCDInterpValue.c
@@ -145,7 +149,7 @@ add_executable(badvpn-ncd
     modules/explode.c
     ${NCD_ADDITIONAL_SOURCES}
 )
-target_link_libraries(badvpn-ncd system flow flowextra dhcpclient arpprobe ncdvalue ncdval ncdvalcompat ncdvaluegenerator ncdvalueparser ncdconfigparser udevmonitor ncdinterfacemonitor ncdrequest)
+target_link_libraries(badvpn-ncd system flow flowextra dhcpclient arpprobe ncdvalue ncdval ncdvalcompat ncdvaluegenerator ncdvalueparser ncdconfigparser ncdsugar udevmonitor ncdinterfacemonitor ncdrequest)
 
 if (BADVPN_USE_LINUX_INPUT)
     string(REPLACE " " ";" FLAGS_LIST "${CMAKE_C_FLAGS}")

+ 8 - 0
ncd/NCDConfigParser.c

@@ -142,6 +142,14 @@ static int tokenizer_output (void *user, int token, char *value, size_t value_le
             Parse(state->parser, ELSE, minor, &state->out);
         } break;
         
+        case NCD_TOKEN_FOREACH: {
+            Parse(state->parser, FOREACH, minor, &state->out);
+        } break;
+        
+        case NCD_TOKEN_AS: {
+            Parse(state->parser, AS, minor, &state->out);
+        } break;
+        
         default:
             BLog(BLOG_ERROR, "line %zu, character %zu: invalid token", line, line_char);
             free(minor.str);

+ 49 - 0
ncd/NCDConfigParser_parse.y

@@ -291,6 +291,55 @@ doneE:
     free(C);
 }
 
+statement(R) ::= FOREACH ROUND_OPEN value(A) AS NAME(B) ROUND_CLOSE CURLY_OPEN statements(S) CURLY_CLOSE name_maybe(N) SEMICOLON. {
+    if (!A.have || !B.str || !S.have) {
+        goto failEA0;
+    }
+    
+    if (!NCDStatement_InitForeach(&R.v, N, A.v, B.str, NULL, S.v)) {
+        goto failEA0;
+    }
+    A.have = 0;
+    S.have = 0;
+    
+    R.have = 1;
+    goto doneEA0;
+    
+failEA0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneEA0:
+    free_value(A);
+    free_token(B);
+    free_block(S);
+    free(N);
+}
+
+statement(R) ::= FOREACH ROUND_OPEN value(A) AS NAME(B) COLON NAME(C) ROUND_CLOSE CURLY_OPEN statements(S) CURLY_CLOSE name_maybe(N) SEMICOLON. {
+    if (!A.have || !B.str || !C.str || !S.have) {
+        goto failEB0;
+    }
+    
+    if (!NCDStatement_InitForeach(&R.v, N, A.v, B.str, C.str, S.v)) {
+        goto failEB0;
+    }
+    A.have = 0;
+    S.have = 0;
+    
+    R.have = 1;
+    goto doneEB0;
+    
+failEB0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneEB0:
+    free_value(A);
+    free_token(B);
+    free_token(C);
+    free_block(S);
+    free(N);
+}
+
 elif_maybe(R) ::= . {
     NCDIfBlock_Init(&R.v);
     R.have = 1;

+ 72 - 0
ncd/NCDSugar.c

@@ -41,6 +41,7 @@ struct desugar_state {
 static int add_template (struct desugar_state *state, NCDBlock block, NCDValue *out_name_val);
 static int desugar_block (struct desugar_state *state, NCDBlock *block);
 static int desugar_if (struct desugar_state *state, NCDBlock *block, NCDStatement *stmt, NCDStatement **out_next);
+static int desugar_foreach (struct desugar_state *state, NCDBlock *block, NCDStatement *stmt, NCDStatement **out_next);
 
 static int add_template (struct desugar_state *state, NCDBlock block, NCDValue *out_name_val)
 {
@@ -87,6 +88,12 @@ static int desugar_block (struct desugar_state *state, NCDBlock *block)
                 }
             } break;
             
+            case NCDSTATEMENT_FOREACH: {
+                if (!desugar_foreach(state, block, stmt, &stmt)) {
+                    return 0;
+                }
+            } break;
+            
             default: ASSERT(0);
         }
     }
@@ -156,6 +163,71 @@ fail:
     return 0;
 }
 
+static int desugar_foreach (struct desugar_state *state, NCDBlock *block, NCDStatement *stmt, NCDStatement **out_next)
+{
+    ASSERT(NCDStatement_Type(stmt) == NCDSTATEMENT_FOREACH)
+    
+    NCDValue args;
+    NCDValue_InitList(&args);
+    
+    NCDValue collection;
+    NCDBlock foreach_block;
+    NCDStatement_ForeachGrab(stmt, &collection, &foreach_block);
+    
+    NCDValue template_arg;
+    if (!add_template(state, foreach_block, &template_arg)) {
+        NCDValue_Free(&collection);
+        goto fail;
+    }
+    
+    if (!NCDValue_ListAppend(&args, collection)) {
+        NCDValue_Free(&template_arg);
+        NCDValue_Free(&collection);
+        goto fail;
+    }
+    
+    if (!NCDValue_ListAppend(&args, template_arg)) {
+        NCDValue_Free(&template_arg);
+        goto fail;
+    }
+    
+    NCDValue name1_arg;
+    if (!NCDValue_InitString(&name1_arg, NCDStatement_ForeachName1(stmt))) {
+        goto fail;
+    }
+    
+    if (!NCDValue_ListAppend(&args, name1_arg)) {
+        NCDValue_Free(&name1_arg);
+        goto fail;
+    }
+    
+    if (NCDStatement_ForeachName2(stmt)) {
+        NCDValue name2_arg;
+        if (!NCDValue_InitString(&name2_arg, NCDStatement_ForeachName2(stmt))) {
+            goto fail;
+        }
+        
+        if (!NCDValue_ListAppend(&args, name2_arg)) {
+            NCDValue_Free(&name2_arg);
+            goto fail;
+        }
+    }
+    
+    NCDStatement new_stmt;
+    if (!NCDStatement_InitReg(&new_stmt, NCDStatement_Name(stmt), NULL, "foreach_emb", args)) {
+        goto fail;
+    }
+    
+    stmt = NCDBlock_ReplaceStatement(block, stmt, new_stmt);
+    
+    *out_next = NCDBlock_NextStatement(block, stmt);
+    return 1;
+    
+fail:
+    NCDValue_Free(&args);
+    return 0;
+}
+
 int NCDSugar_Desugar (NCDProgram *prog)
 {
     struct desugar_state state;

Некоторые файлы не были показаны из-за большого количества измененных файлов