]> git.ipfire.org Git - people/ms/pakfire.git/blame - src/libpakfire/parser/grammar.y
logging: Make the legacy logger configurable
[people/ms/pakfire.git] / src / libpakfire / parser / grammar.y
CommitLineData
f9a691ef
MT
1/*#############################################################################
2# #
3# Pakfire - The IPFire package management system #
4# Copyright (C) 2019 Pakfire development team #
5# #
6# This program is free software: you can redistribute it and/or modify #
7# it under the terms of the GNU General Public License as published by #
8# the Free Software Foundation, either version 3 of the License, or #
9# (at your option) any later version. #
10# #
11# This program is distributed in the hope that it will be useful, #
12# but WITHOUT ANY WARRANTY; without even the implied warranty of #
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14# GNU General Public License for more details. #
15# #
16# You should have received a copy of the GNU General Public License #
17# along with this program. If not, see <http://www.gnu.org/licenses/>. #
18# #
19#############################################################################*/
20
ffbcfe72
MT
21%lex-param {yyscan_t* scanner}
22
23%parse-param
24 {yyscan_t* scanner}
ac4c607b 25 {struct pakfire* pakfire}
657a5c72
MT
26 {struct pakfire_parser** parser}
27 {struct pakfire_parser* parent}
ffbcfe72
MT
28 {struct pakfire_parser_error** error}
29
30// Make the parser reentrant
31%define api.pure full
6d83a6d4 32
529de39f 33// Generate verbose error messages
acdc19a5 34%define parse.error verbose
529de39f 35
f9a691ef 36%{
79fd37b5
MT
37
38#include <errno.h>
4f2a7bce 39#include <stdio.h>
f0d6233d 40#include <stdlib.h>
df8aac92 41#include <time.h>
4f2a7bce 42
517708c8
MT
43// Enable legacy logging
44#define PAKFIRE_LEGACY_LOGGING
45
0ba52fbe 46#include <pakfire/constants.h>
a0258b56 47#include <pakfire/logging.h>
ac4c607b 48#include <pakfire/pakfire.h>
23188111 49#include <pakfire/parser.h>
d973a13d 50#include <pakfire/string.h>
23188111 51#include <pakfire/util.h>
35ebb186 52
f9a691ef
MT
53#define YYERROR_VERBOSE 1
54
a2e98734
MT
55// Enable to debug the grammar
56#define YYDEBUG 0
d5c4772d
MT
57#ifdef ENABLE_DEBUG
58 int yydebug = YYDEBUG;
529de39f
MT
59#endif
60
ffbcfe72 61typedef void* yyscan_t;
d91b495f 62extern int yylex_init_extra(struct pakfire_parser_state* state, yyscan_t* scanner);
ffbcfe72
MT
63int yylex_destroy(yyscan_t scanner);
64
f9a691ef 65typedef struct yy_buffer_state* YY_BUFFER_STATE;
4b39395b 66extern YY_BUFFER_STATE yy_scan_bytes(const char* buffer, int len, yyscan_t scanner);
ffbcfe72 67extern void yy_delete_buffer(YY_BUFFER_STATE buffer, yyscan_t scanner);
f9a691ef 68
d91b495f
MT
69#define YY_EXTRA_TYPE struct pakfire_parser_state*
70YY_EXTRA_TYPE yyget_extra(yyscan_t scanner);
71
ffbcfe72
MT
72#include "grammar.h"
73
74extern int yylex (YYSTYPE* yylval_param, yyscan_t yyscanner);
6ab14b96 75
01c2c202 76#define ABORT do { YYABORT; } while (0);
4f2a7bce 77
d310f14c
MT
78enum operator {
79 OP_EQUALS = 0,
80};
81
ac4c607b 82static void yyerror(yyscan_t* scanner, struct pakfire* pakfire, struct pakfire_parser** parser,
657a5c72 83 struct pakfire_parser* parent, struct pakfire_parser_error** error, const char* s) {
d91b495f
MT
84 const struct pakfire_parser_state* state = yyget_extra(scanner);
85
a8a41064 86 ERROR(pakfire, "Error (line %u): %s\n", state->lineno, s);
4b7699d9
MT
87
88 // Create a new error object
89 if (error) {
d91b495f 90 int r = pakfire_parser_error_create(error, *parser, NULL, state->lineno, s);
4b7699d9
MT
91 if (r) {
92 ERROR(pakfire, "Could not create error object: %s\n", strerror(errno));
93 }
94 }
95}
96
ac4c607b 97static struct pakfire_parser* make_if_stmt(struct pakfire* pakfire, const enum operator op,
657a5c72 98 const char* val1, const char* val2, struct pakfire_parser* if_block, struct pakfire_parser* else_block);
aed19891 99
20440ba7 100static int pakfire_parser_new_declaration(
5ba098cf 101 struct pakfire_parser_declaration** declaration, const char* name, const char* value, int flags) {
79fd37b5
MT
102 if (!name)
103 return EINVAL;
104
20440ba7 105 struct pakfire_parser_declaration* d = calloc(1, sizeof(*d));
79fd37b5
MT
106 if (!d)
107 return ENOMEM;
108
20440ba7
MT
109 // Set name
110 pakfire_string_set(d->name, name);
79fd37b5
MT
111
112 // Copy value
113 if (value)
114 d->value = strdup(value);
115 else
116 d->value = NULL;
117
5ba098cf
MT
118 // Copy flags
119 d->flags = flags;
120
79fd37b5
MT
121 *declaration = d;
122
123 return 0;
124}
125
126static void pakfire_parser_free_declaration(struct pakfire_parser_declaration* declaration) {
79fd37b5
MT
127 if (declaration->value)
128 free(declaration->value);
129
130 free(declaration);
131}
132
f37774cd 133%}
d310f14c 134
15746df5
MT
135%token T_INDENT
136%token T_OUTDENT
137
f37774cd
MT
138%token <string> T_KEY
139%token <string> T_STRING
ac98e979 140
f37774cd 141%token T_EOL
f9a691ef 142
15746df5 143%token T_END
aff85bdb
MT
144%token T_IF
145%token T_ELSE
5ba098cf 146%token T_EXPORT
15746df5 147
aff85bdb 148%token T_EQUALS
f37774cd 149%token T_ASSIGN
4784cd87 150%token T_APPEND
f37774cd 151
aed19891
MT
152%token <string> T_SUBPARSER
153
154%type <parser> grammar
0c184457 155%type <parser> block
aed19891 156%type <parser> subparser
69d27848 157%type <string> subparser_name
aff85bdb
MT
158%type <parser> if_stmt
159%type <parser> else_stmt
aed19891 160
f37774cd
MT
161%type <string> key
162%type <string> value
79fd37b5 163%type <declaration> declaration
d310f14c 164
15746df5
MT
165%type <string> lines
166%type <string> line
167
28afa9c2 168%union {
657a5c72 169 struct pakfire_parser* parser;
28afa9c2 170 char* string;
79fd37b5 171 struct pakfire_parser_declaration* declaration;
28afa9c2 172}
f9a691ef 173
f25d2019
MT
174%initial-action {
175 *parser = pakfire_parser_create(pakfire, parent, NULL, 0);
f25d2019
MT
176};
177
178%destructor { if ($$) pakfire_parser_unref($$); } <parser>
79fd37b5
MT
179%destructor { pakfire_parser_free_declaration($$); } <declaration>
180
f37774cd 181%start grammar
28afa9c2 182
f37774cd 183%%
05ce4b89 184
d54c1557 185grammar : %empty
aed19891 186 {
0c184457
MT
187 $$ = pakfire_parser_create(pakfire, *parser, NULL, 0);
188 if (!$$)
189 ABORT;
190
191 // This becomes the new top parser
192 if (*parser)
193 pakfire_parser_unref(*parser);
194 *parser = pakfire_parser_ref($$);
aed19891 195 }
d54c1557 196 | grammar declaration
79fd37b5 197 {
09b214b7
MT
198 $$ = $1;
199
79fd37b5
MT
200 int r = pakfire_parser_apply_declaration($1, $2);
201 if (r)
202 ABORT;
203
09b214b7 204 pakfire_parser_free_declaration($2);
79fd37b5 205 }
aed19891
MT
206 | grammar subparser
207 {
09b214b7
MT
208 $$ = $1;
209
122e45f5 210 int r = pakfire_parser_merge($1, $2);
c7577606 211 pakfire_parser_unref($2);
122e45f5
MT
212 if (r)
213 ABORT;
aff85bdb
MT
214 }
215 | grammar if_stmt
216 {
09b214b7
MT
217 $$ = $1;
218
122e45f5
MT
219 if ($2) {
220 int r = pakfire_parser_merge($1, $2);
09b214b7 221 pakfire_parser_unref($2);
122e45f5
MT
222 if (r)
223 ABORT;
224 }
aed19891 225 }
d54c1557 226 | grammar empty
aff85bdb 227 {
09b214b7 228 $$ = $1;
aff85bdb
MT
229 }
230 ;
231
0c184457 232block : T_INDENT grammar T_OUTDENT
f25d2019 233 {
0c184457 234 // Reset the top parser
657a5c72 235 struct pakfire_parser* p = pakfire_parser_get_parent(*parser);
0c184457
MT
236 pakfire_parser_unref(*parser);
237 *parser = p;
f25d2019 238
f25d2019 239 $$ = $2;
aff85bdb 240 }
28afa9c2
MT
241 ;
242
f37774cd 243declaration : key T_ASSIGN value T_EOL
28afa9c2 244 {
5ba098cf 245 int r = pakfire_parser_new_declaration(&$$, $1, $3, 0);
f37774cd 246 if (r)
4f2a7bce 247 ABORT;
4f2a7bce 248 }
4784cd87
MT
249 | key T_APPEND value T_EOL
250 {
ec0f0419
MT
251 int r = pakfire_parser_new_declaration(&$$, $1, $3,
252 PAKFIRE_PARSER_DECLARATION_APPEND);
4784cd87
MT
253 if (r)
254 ABORT;
255 }
36446af0 256 | key T_EOL empty_lines T_INDENT lines T_OUTDENT T_END T_EOL
15746df5 257 {
5ba098cf 258 int r = pakfire_parser_new_declaration(&$$, $1, $5, 0);
15746df5
MT
259 if (r)
260 ABORT;
5f17ac71 261 }
af7cb654
MT
262 | key T_EOL empty_lines T_END T_EOL
263 {
5ba098cf
MT
264 int r = pakfire_parser_new_declaration(&$$, $1, "", 0);
265 if (r)
266 ABORT;
267 }
268 | T_EXPORT key T_ASSIGN value T_EOL
269 {
270 int r = pakfire_parser_new_declaration(&$$, $key, $value,
271 PAKFIRE_PARSER_DECLARATION_EXPORT);
af7cb654
MT
272 if (r)
273 ABORT;
274 }
94e7baf6
MT
275 | T_EXPORT key T_APPEND value T_EOL
276 {
277 int r = pakfire_parser_new_declaration(&$$, $key, $value,
278 PAKFIRE_PARSER_DECLARATION_EXPORT|PAKFIRE_PARSER_DECLARATION_APPEND);
279 if (r)
280 ABORT;
281 }
6e5c9f26 282 ;
6b03e625 283
d54c1557
MT
284empty : T_EOL
285 ;
286
af7cb654
MT
287empty_lines : %empty
288 | empty_lines empty;
289
f37774cd 290key : T_KEY
79469dd9
MT
291 ;
292
f37774cd 293value : T_STRING
c2fcc7b5 294 {
f37774cd 295 $$ = $1;
79469dd9
MT
296 }
297 ;
c2fcc7b5 298
15746df5
MT
299lines : lines line
300 {
301 int r = asprintf(&$$, "%s\n%s", $1, $2);
302 if (r < 0)
303 ABORT;
147e59f0
MT
304
305 free($1);
306 free($2);
15746df5
MT
307 }
308 | line;
309
310line : T_STRING T_EOL
311 {
312 $$ = $1;
313 }
29cedba8
MT
314 | T_EOL
315 {
316 // Empty line
147e59f0 317 $$ = strdup("");
29cedba8 318 }
15746df5
MT
319 ;
320
0c184457 321subparser : subparser_name T_EOL block T_END T_EOL
aed19891 322 {
09b214b7 323 $$ = $3;
18281213
MT
324
325 pakfire_parser_set_namespace($$, $1);
326
6200facc
MT
327 char* key = NULL;
328 char* value = NULL;
18281213
MT
329
330 int r = pakfire_string_partition($1, ":", &key, &value);
331 if (r == 0) {
6200facc 332 if (key && strcmp("package", key) == 0) {
fea2e884 333 pakfire_parser_set($$, NULL, "name", value, 0);
18281213
MT
334 }
335
336 if (key)
337 free(key);
338 if (value)
339 free(value);
340 }
aed19891 341 }
5f17ac71
MT
342 | subparser_name T_EOL
343 {
6200facc
MT
344 char* key = NULL;
345 char* value = NULL;
5f17ac71
MT
346
347 // Create a new parser
0c184457 348 $$ = pakfire_parser_create(pakfire, *parser, NULL, 0);
5f17ac71
MT
349 if (!$$)
350 ABORT;
351
5837952f
MT
352 int r = pakfire_string_partition($1, ":", &key, &value);
353 if (r)
354 ABORT;
5f17ac71 355
570bec8a 356 // Handle packages
6200facc 357 if (key && strcmp("package", key) == 0) {
570bec8a
MT
358 pakfire_parser_set_namespace($$, $1);
359
360 // Set the name (because we cannot have empty parsers)
fea2e884 361 pakfire_parser_set($$, NULL, "name", value, 0);
570bec8a
MT
362
363 // Handle all other cases
364 } else {
fea2e884 365 pakfire_parser_set($$, NULL, key, value, 0);
570bec8a 366 }
5f17ac71
MT
367
368 if (key)
369 free(key);
370 if (value)
371 free(value);
372 }
aed19891
MT
373 ;
374
69d27848
MT
375subparser_name : T_SUBPARSER
376 | T_SUBPARSER T_STRING
377 {
378 int r = asprintf(&$$, "%s:%s", $1, $2);
379 if (r < 0)
380 ABORT;
147e59f0
MT
381
382 free($1);
383 free($2);
69d27848 384 }
5f17ac71 385 ;
69d27848 386
0c184457 387if_stmt : T_IF T_STRING T_EQUALS T_STRING T_EOL block else_stmt T_END T_EOL
aed19891 388 {
0ac3e9f3 389 $$ = make_if_stmt(pakfire, OP_EQUALS, $2, $4, $6, $7);
1a3bcdca
MT
390
391 if ($6)
392 pakfire_parser_unref($6);
393 if ($7)
394 pakfire_parser_unref($7);
aed19891
MT
395 }
396 ;
397
0c184457 398else_stmt : T_ELSE T_EOL block
aff85bdb 399 {
09b214b7 400 $$ = $3;
aff85bdb
MT
401 }
402 | %empty
403 {
404 $$ = NULL;
405 }
406 ;
aed19891 407
f9a691ef
MT
408%%
409
657a5c72 410int pakfire_parser_parse_data(struct pakfire_parser* parent, const char* data, size_t len,
4b7699d9 411 struct pakfire_parser_error** error) {
ac4c607b 412 struct pakfire* pakfire = pakfire_parser_get_pakfire(parent);
44ab277d 413 char* dump = NULL;
ffbcfe72 414 yyscan_t scanner;
23188111 415
d91b495f
MT
416 // Initialize the parser's state
417 struct pakfire_parser_state state = {
418 .lineno = 1,
419 .indent_level = 0,
420 .current_indent = 0,
421 .readline_indent = 0,
422 };
423
129176e5 424#ifdef ENABLE_DEBUG
0264c700
MT
425 DEBUG(pakfire, "Parsing the following data (%zu):\n%.*s\n",
426 len, (int)len, data);
a0258b56 427
df8aac92
MT
428 // Save start time
429 clock_t t_start = clock();
129176e5 430#endif
df8aac92 431
ffbcfe72 432 // Initialise scanner
d91b495f 433 yylex_init_extra(&state, &scanner);
ffbcfe72 434
abb9117f 435 // Create a new sub-parser
657a5c72 436 struct pakfire_parser* parser = NULL;
abb9117f 437
ffbcfe72 438 YY_BUFFER_STATE buffer = yy_scan_bytes(data, len, scanner);
c7577606 439 int r = yyparse(scanner, pakfire, &parser, parent, error);
ffbcfe72 440 yy_delete_buffer(buffer, scanner);
f9a691ef 441
abb9117f
MT
442 // If everything was parsed successfully, we merge the sub-parser into
443 // the parent parser. That way, it will be untouched if something could
444 // not be successfully parsed.
445 if (r == 0) {
c7577606
MT
446 if (parser)
447 pakfire_parser_merge(parent, parser);
abb9117f
MT
448 }
449
9405ba79 450 // Destroy the parser
c7577606 451 if (parser)
f25d2019 452 pakfire_parser_unref(parser);
9405ba79 453
129176e5 454#ifdef ENABLE_DEBUG
df8aac92
MT
455 // Save end time
456 clock_t t_end = clock();
457
dac3330d 458 // Log what we have in the parent parser now
44ab277d
MT
459 dump = pakfire_parser_dump(parent);
460 if (dump)
461 DEBUG(pakfire, "Status of the parser %p:\n%s\n", parent, dump);
dac3330d 462
df8aac92
MT
463 // Log time we needed to parse data
464 DEBUG(pakfire, "Parser finished in %.4fms\n",
465 (double)(t_end - t_start) * 1000 / CLOCKS_PER_SEC);
129176e5 466#endif
df8aac92 467
dac3330d 468 // Cleanup
44ab277d
MT
469 if (dump)
470 free(dump);
dac3330d 471 pakfire_unref(pakfire);
ffbcfe72 472 yylex_destroy(scanner);
dac3330d 473
fb077c4c 474 return r;
f9a691ef
MT
475}
476
ac4c607b 477static struct pakfire_parser* make_if_stmt(struct pakfire* pakfire, const enum operator op,
657a5c72 478 const char* val1, const char* val2, struct pakfire_parser* if_block, struct pakfire_parser* else_block) {
aff85bdb
MT
479 switch (op) {
480 case OP_EQUALS:
481 DEBUG(pakfire, "Evaluating if statement: %s == %s?\n", val1, val2);
482 break;
483 }
484
657a5c72 485 struct pakfire_parser* parent = pakfire_parser_get_parent(if_block);
0ac3e9f3
MT
486
487 DEBUG(pakfire, " parent = %p, if = %p, else = %p\n", parent, if_block, else_block);
aff85bdb
MT
488
489 // Expand values
0ac3e9f3
MT
490 char* v1 = pakfire_parser_expand(parent, NULL, val1);
491 char* v2 = pakfire_parser_expand(parent, NULL, val2);
aff85bdb 492
657a5c72 493 struct pakfire_parser* result = NULL;
aff85bdb
MT
494
495 switch (op) {
496 case OP_EQUALS:
497 DEBUG(pakfire, " '%s' == '%s'?\n", v1, v2);
498
499 if (strcmp(v1, v2) == 0)
500 result = if_block;
501 else
502 result = else_block;
503
504 break;
505 }
506
aff85bdb
MT
507 free(v1);
508 free(v2);
0ac3e9f3 509 pakfire_parser_unref(parent);
aff85bdb 510
7c22cb15
MT
511 if (result)
512 pakfire_parser_ref(result);
513
514 return result;
aff85bdb 515}