]> git.ipfire.org Git - pakfire.git/commitdiff
parser: Add support for conditionals
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 24 Feb 2021 19:28:54 +0000 (19:28 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 24 Feb 2021 19:28:54 +0000 (19:28 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/libpakfire/parser/grammar.y
src/libpakfire/parser/scanner.l
tests/data/parser/test-conditionals.txt [new file with mode: 0644]
tests/libpakfire/parser.c

index 9375199e5fd46c64efd3a9fe0628dfacf786b038..3d4a7b3248d81c5343b029068a4efc6825cbdb32 100644 (file)
@@ -648,6 +648,7 @@ EXTRA_DIST += \
        tests/data/beep-1.3-2.ip3.x86_64.pfm \
        \
        tests/data/parser/test-comments.txt \
+       tests/data/parser/test-conditionals.txt \
        tests/data/parser/test-declarations.txt \
        tests/data/parser/test-subparsers.txt
 
index be342a8b89270397ab5a1f42b69407b72f5c2a9d..7885ed07ce493b30b29e913885796cba7c60cb4a 100644 (file)
@@ -57,6 +57,8 @@ enum operator {
        OP_EQUALS = 0,
 };
 
+static PakfireParser make_if_stmt(PakfireParser parser, const enum operator op,
+               const char* val1, const char* val2, PakfireParser if_block, PakfireParser else_block);
 static PakfireParser make_child(PakfireParser parent, const char* namespace);
 
 %}
@@ -70,14 +72,20 @@ static PakfireParser make_child(PakfireParser parent, const char* namespace);
 %token                                         T_EOL
 
 %token                                         T_END
+%token                                         T_IF
+%token                                         T_ELSE
 
+%token                                         T_EQUALS
 %token                                         T_ASSIGN
 %token                                         T_APPEND
 
 %token <string>                                T_SUBPARSER
 
 %type <parser>                         grammar
+%type <parser>                         subgrammar
 %type <parser>                         subparser
+%type <parser>                         if_stmt
+%type <parser>                         else_stmt
 
 %type <string>                         key
 %type <string>                         value
@@ -101,10 +109,28 @@ grammar                                           : %empty
                                                        | grammar declaration
                                                        | grammar subparser
                                                        {
-                                                               $$ = pakfire_parser_merge($1, $2);
-                                                               pakfire_parser_unref($2);
+                                                               if ($2) {
+                                                                       $$ = pakfire_parser_merge($1, $2);
+                                                                       //pakfire_parser_unref($2);
+                                                               }
+                                                       }
+                                                       | grammar if_stmt
+                                                       {
+                                                               if ($2) {
+                                                                       $$ = pakfire_parser_merge($1, $2);
+                                                                       //pakfire_parser_unref($2);
+                                                               }
                                                        }
                                                        | grammar empty
+                                                       {
+                                                               $$ = $1;
+                                                       }
+                                                       ;
+
+subgrammar                                     : T_INDENT grammar T_OUTDENT
+                                                       {
+                                                               $$ = $2;
+                                                       }
                                                        ;
 
 declaration                                    : key T_ASSIGN value T_EOL
@@ -164,7 +190,7 @@ subparser                                   : subparser_open T_INDENT grammar T_OUTDENT subparser_close
                                                                parser = pakfire_parser_get_parent(parser);
 
                                                                // Merge block into the parent parser
-                                                               pakfire_parser_merge(parser, $3);
+                                                               $$ = pakfire_parser_merge(parser, $3);
 
                                                                // Free block parser
                                                                pakfire_parser_unref($3);
@@ -178,7 +204,41 @@ subparser_open                             : T_SUBPARSER T_EOL
                                                        }
                                                        ;
 
-subparser_close                                : T_END;
+subparser_close                                : T_END T_EOL;
+
+if                                                     : T_IF
+                                                       {
+                                                               // Open a new block
+                                                               parser = make_child(parser, NULL);
+                                                       };
+
+else                                           : T_ELSE T_EOL
+                                                       {
+                                                               // Close the if block
+                                                               parser = pakfire_parser_get_parent(parser);
+
+                                                               // Open a new else block
+                                                               parser = make_child(parser, NULL);
+                                                       };
+
+if_stmt                                                : if T_STRING T_EQUALS T_STRING T_EOL subgrammar else_stmt T_END T_EOL
+                                                       {
+                                                               $$ = make_if_stmt(parser, OP_EQUALS, $2, $4, $6, $7);
+
+                                                               //pakfire_parser_unref($6);
+                                                               //pakfire_parser_unref($7);
+                                                       }
+                                                       ;
+
+else_stmt                                      : else subgrammar
+                                                       {
+                                                               $$ = $2;
+                                                       }
+                                                       | %empty
+                                                       {
+                                                               $$ = NULL;
+                                                       }
+                                                       ;
 
 %%
 
@@ -241,6 +301,43 @@ void yyerror(PakfireParser parser, const char* s) {
        pakfire_unref(pakfire);
 }
 
+static PakfireParser make_if_stmt(PakfireParser parser, const enum operator op,
+               const char* val1, const char* val2, PakfireParser if_block, PakfireParser else_block) {
+       Pakfire pakfire = pakfire_parser_get_pakfire(parser);
+
+       switch (op) {
+               case OP_EQUALS:
+                       DEBUG(pakfire, "Evaluating if statement: %s == %s?\n", val1, val2);
+                       break;
+       }
+
+       DEBUG(pakfire, "  parser = %p, if = %p, else = %p\n", parser, if_block, else_block);
+
+       // Expand values
+       char* v1 = pakfire_parser_expand(parser, val1);
+       char* v2 = pakfire_parser_expand(parser, val2);
+
+       PakfireParser result = NULL;
+
+       switch (op) {
+               case OP_EQUALS:
+                       DEBUG(pakfire, "  '%s' == '%s'?\n", v1, v2);
+
+                       if (strcmp(v1, v2) == 0)
+                               result = if_block;
+                       else
+                               result = else_block;
+
+                       break;
+       }
+
+       pakfire_unref(pakfire);
+       free(v1);
+       free(v2);
+
+       return pakfire_parser_ref(result);
+}
+
 static PakfireParser make_child(PakfireParser parent, const char* namespace) {
        PakfireParser parser = pakfire_parser_create_child(parent, namespace);
        pakfire_parser_unref(parent);
index 5f55447c1260bb3f04feceb1e14de1806b26ebd4..fe4f01478c7592e5091e60daebda22f62e28dcf5 100644 (file)
@@ -47,6 +47,29 @@ unsigned int indent_level = 0;
 unsigned int current_indent = 0;
 unsigned int readline_indent = 0;
 
+static char* unquote(const char* input) {
+       size_t length = strlen(input);
+
+       // Check whether the first character is "
+       if (*input != '"')
+               goto COPY;
+
+       // Check whether the last characters is "
+       if (input[length] != '"')
+               goto COPY;
+
+       char* output = malloc(length - 1);
+       if (!output)
+               return NULL;
+
+       // Copy everything except the first and last character
+       snprintf(output, length - 2, "%s", input + 1);
+
+       return output;
+COPY:
+       return strdup(input);
+}
+
 %}
 
 %x INDENT
@@ -58,6 +81,7 @@ letter                                        [A-Za-z]
 digit                                  [0-9]
 underscore                             _
 whitespace                             [ \t]+
+quoted_string                  \"([^\"])*\"
 
 key                                            ({letter}|{underscore})(({letter}|{digit}|{underscore})*({letter}|{digit}))?
 
@@ -124,6 +148,18 @@ keywords                           (build|dependencies|distribution|packages?|quality\-agent)
                                                        return T_SUBPARSER;
                                                }
 
+{quoted_string}                        {
+                                                       // Remove quotes
+                                                       yylval.string = unquote(yytext);
+
+                                                       return T_STRING;
+                                               }
+
+"if"                                   { return T_IF; }
+"else"                                 { return T_ELSE; }
+
+"=="                                   { return T_EQUALS; }
+
 "="                                            {
                                                        // Read everything after this
                                                        yy_push_state(READLINE);
diff --git a/tests/data/parser/test-conditionals.txt b/tests/data/parser/test-conditionals.txt
new file mode 100644 (file)
index 0000000..f535094
--- /dev/null
@@ -0,0 +1,8 @@
+a = 1
+b = 2
+
+if "%{a}" == "%{b}"
+       result = true
+else
+       result = false
+end
index 8961aa8a9128288884b089efcb137ca59e46eed1..feea384a5143e1e500f0d611ae03155c27fbb394 100644 (file)
@@ -105,6 +105,7 @@ static int test_parser(const struct test* t) {
 
 static const char* files[] = {
        "data/parser/test-comments.txt",
+       "data/parser/test-conditionals.txt",
        "data/parser/test-declarations.txt",
        "data/parser/test-subparsers.txt",
        NULL,