From: Michael Tremer Date: Wed, 24 Feb 2021 19:28:54 +0000 (+0000) Subject: parser: Add support for conditionals X-Git-Tag: 0.9.28~1285^2~703 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aff85bdb6685074eae41fadd06f25d1a813b5c28;p=pakfire.git parser: Add support for conditionals Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 9375199e5..3d4a7b324 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/src/libpakfire/parser/grammar.y b/src/libpakfire/parser/grammar.y index be342a8b8..7885ed07c 100644 --- a/src/libpakfire/parser/grammar.y +++ b/src/libpakfire/parser/grammar.y @@ -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 T_SUBPARSER %type grammar +%type subgrammar %type subparser +%type if_stmt +%type else_stmt %type key %type 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); diff --git a/src/libpakfire/parser/scanner.l b/src/libpakfire/parser/scanner.l index 5f55447c1..fe4f01478 100644 --- a/src/libpakfire/parser/scanner.l +++ b/src/libpakfire/parser/scanner.l @@ -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 index 000000000..f535094da --- /dev/null +++ b/tests/data/parser/test-conditionals.txt @@ -0,0 +1,8 @@ +a = 1 +b = 2 + +if "%{a}" == "%{b}" + result = true +else + result = false +end diff --git a/tests/libpakfire/parser.c b/tests/libpakfire/parser.c index 8961aa8a9..feea384a5 100644 --- a/tests/libpakfire/parser.c +++ b/tests/libpakfire/parser.c @@ -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,