LCOV - code coverage report
Current view: top level - src/parser - parser.c (source / functions) Hit Total Coverage
Test: passgen-test.info Lines: 262 268 97.8 %
Date: 2024-11-29 06:05:05 Functions: 22 23 95.7 %

          Line data    Source code
       1             : #include "passgen/parser/parser.h"
       2             : #include "passgen/config.h"
       3             : 
       4             : #include <stdbool.h>
       5             : #include <stddef.h>
       6             : #include <stdint.h>
       7             : #include <stdlib.h>
       8             : 
       9             : #include "passgen/container/stack.h"
      10             : #include "passgen/pattern/group.h"
      11             : #include "passgen/pattern/literal.h"
      12             : #include "passgen/pattern/pattern.h"
      13             : #include "passgen/pattern/range.h"
      14             : #include "passgen/pattern/repeat.h"
      15             : #include "passgen/pattern/segment.h"
      16             : #include "passgen/pattern/segment_item.h"
      17             : #include "passgen/pattern/set.h"
      18             : 
      19             : int passgen_parse_group(
      20             :     struct passgen_parser *parser,
      21             :     struct passgen_token *token,
      22             :     passgen_parser_state *state);
      23             : 
      24             : int passgen_parse_multiplier(
      25             :     struct passgen_parser *parser,
      26             :     struct passgen_token *token,
      27             :     passgen_parser_state *state);
      28             : 
      29             : int passgen_parse_set(
      30             :     struct passgen_parser *parser,
      31             :     struct passgen_token *token,
      32             :     passgen_parser_state *state);
      33             : 
      34             : int passgen_parse_set_range(
      35             :     struct passgen_parser *parser,
      36             :     struct passgen_token *token,
      37             :     passgen_parser_state *state);
      38             : 
      39             : int passgen_parse_repeat(
      40             :     struct passgen_parser *parser,
      41             :     struct passgen_token *token,
      42             :     passgen_parser_state *state);
      43             : 
      44             : int passgen_parse_repeat_range(
      45             :     struct passgen_parser *parser,
      46             :     struct passgen_token *token,
      47             :     passgen_parser_state *state);
      48             : 
      49             : int passgen_parse_special(
      50             :     struct passgen_parser *parser,
      51             :     struct passgen_token *token,
      52             :     passgen_parser_state *state);
      53             : 
      54             : int passgen_parse_special_name(
      55             :     struct passgen_parser *parser,
      56             :     struct passgen_token *token,
      57             :     passgen_parser_state *state);
      58             : 
      59       39896 : inline passgen_parser_state *passgen_parser_state_push(passgen_parser *parser) {
      60       39896 :     return passgen_stack_push(&parser->state, NULL);
      61             : }
      62             : 
      63       33428 : passgen_parser_state *passgen_parser_state_push_group(
      64             :     passgen_parser *parser,
      65             :     passgen_pattern_group *group,
      66             :     passgen_pattern_segment *segment) {
      67       33428 :     passgen_parser_state *state = passgen_parser_state_push(parser);
      68       33428 :     state->type = PASSGEN_PARSER_GROUP;
      69       33428 :     state->data.group.group = group;
      70       33428 :     state->data.group.segment = segment;
      71             : 
      72       33428 :     return state;
      73             : }
      74             : 
      75        3119 : passgen_parser_state *passgen_parser_state_push_set(
      76             :     passgen_parser *parser,
      77             :     passgen_pattern_set *set,
      78             :     passgen_pattern_range *range) {
      79        3119 :     passgen_parser_state *state = passgen_parser_state_push(parser);
      80        3119 :     state->type = PASSGEN_PARSER_SET;
      81        3119 :     state->data.set.set = set;
      82        3119 :     state->data.set.range = range;
      83             : 
      84        3119 :     return state;
      85             : }
      86             : 
      87        2660 : passgen_parser_state *passgen_parser_state_push_repeat(
      88             :     passgen_parser *parser,
      89             :     passgen_pattern_repeat *repeat) {
      90        2660 :     passgen_parser_state *state = passgen_parser_state_push(parser);
      91        2660 :     state->type = PASSGEN_PARSER_REPEAT;
      92        2660 :     repeat->min = 0;
      93        2660 :     repeat->max = 0;
      94        2660 :     state->data.repeat.repeat = repeat;
      95             : 
      96        2660 :     return state;
      97             : }
      98             : 
      99         552 : passgen_parser_state *passgen_parser_state_push_multiplier(
     100             :     passgen_parser *parser,
     101             :     size_t *multiplier,
     102             :     size_t *sum) {
     103         552 :     passgen_parser_state *state = passgen_parser_state_push(parser);
     104         552 :     state->type = PASSGEN_PARSER_MULTIPLIER;
     105         552 :     *multiplier = 0;
     106         552 :     state->data.multiplier.value = multiplier;
     107         552 :     state->data.multiplier.sum = sum;
     108         552 :     return state;
     109             : }
     110             : 
     111         137 : passgen_parser_state *passgen_parser_state_push_special(
     112             :     passgen_parser *parser,
     113             :     passgen_pattern_special *special) {
     114         137 :     passgen_parser_state *state = passgen_parser_state_push(parser);
     115         137 :     state->type = PASSGEN_PARSER_SPECIAL;
     116         137 :     state->data.special.special = special;
     117         137 :     return state;
     118             : }
     119             : 
     120       30154 : void passgen_parser_init(passgen_parser *parser, passgen_pattern *pattern) {
     121       30154 :     passgen_stack_init(&parser->state, sizeof(passgen_parser_state));
     122       30154 :     parser->limit = 0;
     123       30154 :     parser->pattern = pattern;
     124       30154 :     if(!pattern) {
     125           0 :         parser->pattern = malloc(sizeof(passgen_pattern));
     126             :     }
     127       30154 :     passgen_pattern_init(parser->pattern);
     128       60308 :     passgen_parser_state_push_group(
     129             :         parser,
     130       30154 :         &parser->pattern->group,
     131       30154 :         passgen_pattern_group_segment_append(&parser->pattern->group));
     132       30154 : }
     133             : 
     134       30154 : passgen_pattern *passgen_parser_free(passgen_parser *parser) {
     135       30154 :     passgen_stack_free(&parser->state);
     136       30154 :     passgen_pattern *pattern = parser->pattern;
     137       30154 :     parser->pattern = NULL;
     138             : 
     139       30154 :     PASSGEN_CLEAR(parser);
     140       30154 :     return pattern;
     141             : }
     142             : 
     143             : passgen_parser_state *
     144           0 : passgen_parser_state_get(passgen_parser *parser, size_t n) {
     145           0 :     return passgen_stack_get(&parser->state, n);
     146             : }
     147             : 
     148      352583 : passgen_parser_state *passgen_parser_state_last(passgen_parser *parser) {
     149      352583 :     return passgen_stack_top(&parser->state);
     150             : }
     151             : 
     152             : // get the last item, making sure that it's only a single character.
     153             : // in case of characters, mark it as tainted.
     154             : static inline passgen_pattern_item *
     155        5011 : last_single_item_taint(passgen_pattern_segment *segment) {
     156        5011 :     passgen_pattern_item *item = passgen_stack_top(&segment->items);
     157             : 
     158        5011 :     if(!item) {
     159         724 :         return NULL;
     160             :     }
     161             : 
     162        4287 :     if(item->kind == PASSGEN_PATTERN_LITERAL) {
     163        4263 :         if(item->data.literal.count > 1) {
     164             :             // save last codepoint
     165        3289 :             int32_t codepoint =
     166        3289 :                 item->data.literal.codepoints[item->data.literal.count - 1];
     167             : 
     168             :             // trim codepoints
     169        3289 :             item->data.literal.count -= 1;
     170             : 
     171             :             // create new item
     172        3289 :             item = passgen_pattern_segment_new_item(segment);
     173        3289 :             item->kind = PASSGEN_PATTERN_LITERAL;
     174        3289 :             passgen_pattern_literal_init(&item->data.literal);
     175        3289 :             passgen_pattern_literal_append(&item->data.literal, codepoint);
     176             :         }
     177             : 
     178             :         // characters are always marked as tainted.
     179        4263 :         passgen_pattern_literal_taint(&item->data.literal);
     180             :     }
     181             : 
     182        4287 :     return item;
     183             : }
     184             : 
     185      343064 : int passgen_parse_token(passgen_parser *parser, passgen_token *token) {
     186      343064 :     passgen_parser_state *state = passgen_parser_state_last(parser);
     187             : 
     188      343064 :     if(parser->limit && parser->state.len >= parser->limit) {
     189           1 :         return -1;
     190             :     }
     191             : 
     192      343063 :     switch(state->type) {
     193      319559 :         case PASSGEN_PARSER_GROUP:
     194      319559 :             return passgen_parse_group(parser, token, state);
     195         726 :         case PASSGEN_PARSER_MULTIPLIER:
     196         726 :             return passgen_parse_multiplier(parser, token, state);
     197       19473 :         case PASSGEN_PARSER_SET:
     198       19473 :             return passgen_parse_set(parser, token, state);
     199         100 :         case PASSGEN_PARSER_SET_RANGE:
     200         100 :             return passgen_parse_set_range(parser, token, state);
     201        2810 :         case PASSGEN_PARSER_REPEAT:
     202        2810 :             return passgen_parse_repeat(parser, token, state);
     203          63 :         case PASSGEN_PARSER_REPEAT_RANGE:
     204          63 :             return passgen_parse_repeat_range(parser, token, state);
     205         126 :         case PASSGEN_PARSER_SPECIAL:
     206         126 :             return passgen_parse_special(parser, token, state);
     207         206 :         case PASSGEN_PARSER_SPECIAL_NAME:
     208         206 :             return passgen_parse_special_name(parser, token, state);
     209           0 :         default:
     210           0 :             return -1;
     211             :     }
     212             : }
     213             : 
     214      329078 : static void passgen_pattern_segment_clean(passgen_pattern_segment *segment) {
     215      329078 :     if(segment->items.len > 0) {
     216             :         // get last item
     217      292635 :         passgen_pattern_item *last = passgen_stack_top(&segment->items);
     218             : 
     219      292635 :         if(last->kind == PASSGEN_PATTERN_GROUP &&
     220         354 :            last->data.group.multiplier_sum == 0) {
     221         153 :             passgen_pattern_group_free(&last->data.group);
     222         153 :             passgen_stack_pop(&segment->items, NULL);
     223             :         }
     224             :     }
     225      329078 : }
     226             : 
     227      319559 : int passgen_parse_group(
     228             :     passgen_parser *parser,
     229             :     passgen_token *token,
     230             :     passgen_parser_state *state) {
     231      319559 :     uint32_t codepoint = token->codepoint;
     232             :     passgen_pattern_group *group;
     233             :     passgen_pattern_special *special;
     234             :     passgen_pattern_item *item;
     235             : 
     236      319559 :     passgen_pattern_segment_clean(state->data.group.segment);
     237             : 
     238      319559 :     if(codepoint & PASSGEN_TOKEN_ESCAPED_BIT) {
     239        1912 :         codepoint &= ~PASSGEN_TOKEN_ESCAPED_BIT;
     240        1912 :         switch((char) codepoint) {
     241         251 :             case '|':
     242             :             case '(':
     243             :             case ')':
     244             :             case '{':
     245             :             case '}':
     246             :             case '[':
     247             :             case ']':
     248             :                 // escaped token which would normally do something but
     249             :                 // should be treated as text
     250         251 :                 break;
     251         137 :             case 'm':
     252             :             case 'p':
     253             :             case 'w':
     254             :                 // special token
     255         137 :                 special = passgen_pattern_segment_new_special(
     256             :                     state->data.group.segment);
     257         137 :                 passgen_pattern_special_init(special, (char) codepoint);
     258         137 :                 passgen_parser_state_push_special(parser, special);
     259         137 :                 return 0;
     260        1524 :             default:
     261             :                 // error
     262        1524 :                 return -1;
     263             :         }
     264             :     } else {
     265      317647 :         switch((char) codepoint) {
     266        3219 :             case '|':
     267        3219 :                 if(state->data.group.segment->multiplier > 0) {
     268             :                     // create new segment and parser state
     269        3117 :                     state->data.group.segment =
     270        3117 :                         passgen_pattern_group_segment_append(
     271             :                             state->data.group.group);
     272             :                 } else {
     273             :                     // if the previous segment had a zero multiplier, recycle it
     274         102 :                     passgen_pattern_segment_free(state->data.group.segment);
     275         102 :                     passgen_pattern_segment_init(state->data.group.segment);
     276             :                 }
     277        3219 :                 return 0;
     278        3140 :             case ')':
     279        3140 :                 if(state->data.group.segment->multiplier == 0) {
     280           2 :                     passgen_pattern_segment_free(state->data.group.segment);
     281           2 :                     passgen_stack_pop(&state->data.group.group->segments, NULL);
     282             :                 }
     283        3140 :                 if(parser->state.len <= 1) {
     284        2790 :                     return -1;
     285             :                 }
     286         350 :                 passgen_pattern_group_finish(state->data.group.group);
     287         350 :                 passgen_stack_pop(&parser->state, NULL);
     288         350 :                 return 0;
     289        3274 :             case '(':
     290             :                 // we're supposed to read something in.
     291        3274 :                 group = passgen_pattern_segment_new_group(
     292             :                     state->data.group.segment);
     293        3274 :                 passgen_parser_state_push_group(
     294             :                     parser,
     295             :                     group,
     296             :                     passgen_pattern_group_segment_append(group));
     297        3274 :                 return 0;
     298        3119 :             case '[':
     299        3119 :                 passgen_parser_state_push_set(
     300             :                     parser,
     301             :                     passgen_pattern_segment_new_set(state->data.group.segment),
     302             :                     NULL);
     303        3119 :                 return 0;
     304        3212 :             case '{':
     305        3212 :                 item = last_single_item_taint(state->data.group.segment);
     306             :                 // error, there was no item
     307        3212 :                 if(item) {
     308        2660 :                     passgen_parser_state_push_repeat(parser, &item->repeat);
     309        2660 :                     return 0;
     310             :                 } else {
     311         552 :                     state->data.group.segment->multiplier = 0;
     312         552 :                     state->data.group.group->multiplier_sum -= 1;
     313         552 :                     passgen_parser_state_push_multiplier(
     314             :                         parser,
     315         552 :                         &state->data.group.segment->multiplier,
     316         552 :                         &state->data.group.group->multiplier_sum);
     317         552 :                     return 0;
     318             :                 }
     319        1799 :             case '?':
     320        1799 :                 item = last_single_item_taint(state->data.group.segment);
     321        1799 :                 if(item) {
     322        1627 :                     item->maybe = true;
     323        1627 :                     return 0;
     324             :                 } else {
     325             :                     // error: maybe without a previous item
     326         172 :                     return -1;
     327             :                 }
     328      299884 :             default:
     329      299884 :                 break;
     330             :         }
     331             :     }
     332             : 
     333             :     // check if the last item was a character that we can add this one to
     334      300135 :     if(state->data.group.segment->items.len) {
     335             :         passgen_pattern_item *last =
     336      267489 :             passgen_stack_top(&state->data.group.segment->items);
     337             : 
     338      267489 :         if(last->kind == PASSGEN_PATTERN_LITERAL) {
     339      267196 :             if(0 ==
     340      267196 :                passgen_pattern_literal_append(&last->data.literal, codepoint)) {
     341      237688 :                 return 0;
     342             :             }
     343             :         }
     344             :     }
     345             : 
     346             :     passgen_pattern_literal *literal =
     347       62447 :         passgen_pattern_segment_new_char(state->data.group.segment);
     348       62447 :     passgen_pattern_literal_append(literal, codepoint);
     349             : 
     350       62447 :     return 0;
     351             : }
     352             : 
     353       19473 : int passgen_parse_set(
     354             :     passgen_parser *parser,
     355             :     passgen_token *token,
     356             :     passgen_parser_state *state) {
     357       19473 :     passgen_pattern_set *set = state->data.set.set;
     358             : 
     359             :     // this set's over
     360       19473 :     if(token->codepoint == ']') {
     361             :         // compute sum of choices and choices list for binary search.
     362         244 :         size_t choices = 0;
     363         244 :         set->choices_list = malloc(sizeof(size_t) * set->items.len);
     364        1128 :         for(size_t i = 0; i < set->items.len; i++) {
     365         884 :             passgen_pattern_range *range = passgen_stack_get(&set->items, i);
     366         884 :             choices += 1 + range->end - range->start;
     367         884 :             set->choices_list[i] = choices;
     368             :         }
     369             : 
     370         244 :         passgen_stack_pop(&parser->state, NULL);
     371         244 :         return 0;
     372             :     }
     373             : 
     374             :     // part of a range expression
     375       19229 :     if(state->data.set.range && token->codepoint == '-') {
     376         111 :         state->type = PASSGEN_PARSER_SET_RANGE;
     377         111 :         return 0;
     378             :     }
     379             : 
     380       19118 :     uint32_t codepoint = token->codepoint;
     381       19118 :     if(codepoint & PASSGEN_TOKEN_ESCAPED_BIT) {
     382             :         // no reason to expect an escaped token here unless it's a dash.
     383         167 :         switch(codepoint & ~PASSGEN_TOKEN_ESCAPED_BIT) {
     384           2 :             case '-':
     385           2 :                 codepoint &= ~PASSGEN_TOKEN_ESCAPED_BIT;
     386           2 :                 break;
     387         165 :             default:
     388         165 :                 return -1;
     389             :         }
     390       18951 :     }
     391             : 
     392       18953 :     passgen_pattern_range *range = passgen_pattern_set_range_append(set);
     393             : 
     394       18953 :     range->start = codepoint;
     395       18953 :     range->end = codepoint;
     396             : 
     397       18953 :     state->data.set.range = range;
     398             : 
     399       18953 :     return 0;
     400             : }
     401             : 
     402         100 : int passgen_parse_set_range(
     403             :     passgen_parser *parser,
     404             :     passgen_token *token,
     405             :     passgen_parser_state *state) {
     406             :     (void) parser;
     407         100 :     if(token->codepoint == ']') {
     408           2 :         return -1;
     409             :     }
     410             : 
     411          98 :     if(token->codepoint < state->data.set.range->start) {
     412          38 :         return -1;
     413             :     }
     414             : 
     415          60 :     state->data.set.range->end = token->codepoint;
     416          60 :     state->type = PASSGEN_PARSER_SET;
     417             : 
     418          60 :     return 0;
     419             : }
     420             : 
     421         726 : int passgen_parse_multiplier(
     422             :     passgen_parser *parser,
     423             :     passgen_token *token,
     424             :     passgen_parser_state *state) {
     425         726 :     if(token->codepoint == '}') {
     426         110 :         *state->data.multiplier.sum += *state->data.multiplier.value;
     427         110 :         passgen_stack_pop(&parser->state, NULL);
     428         110 :         return 0;
     429             :     }
     430             : 
     431         616 :     if(token->codepoint >= '0' && token->codepoint <= '9') {
     432         194 :         uint8_t digit = token->codepoint - '0';
     433             : 
     434         194 :         *state->data.multiplier.value *= 10;
     435         194 :         *state->data.multiplier.value += digit;
     436             : 
     437         194 :         return 0;
     438             :     }
     439             : 
     440         422 :     return -1;
     441             : }
     442             : 
     443        2810 : int passgen_parse_repeat(
     444             :     passgen_parser *parser,
     445             :     passgen_token *token,
     446             :     passgen_parser_state *state) {
     447             :     // this set's over
     448        2810 :     if(token->codepoint == '}') {
     449          57 :         state->data.repeat.repeat->max = state->data.repeat.repeat->min;
     450          57 :         passgen_stack_pop(&parser->state, NULL);
     451          57 :         return 0;
     452             :     }
     453             : 
     454        2753 :     if(token->codepoint == ',') {
     455          55 :         state->data.repeat.repeat->max = 0;
     456          55 :         state->type = PASSGEN_PARSER_REPEAT_RANGE;
     457          55 :         return 0;
     458             :     }
     459             : 
     460        2698 :     if(token->codepoint >= '0' && token->codepoint <= '9') {
     461         401 :         uint8_t digit = token->codepoint - '0';
     462             : 
     463         401 :         state->data.repeat.repeat->min *= 10;
     464         401 :         state->data.repeat.repeat->min += digit;
     465             : 
     466         401 :         return 0;
     467             :     }
     468             : 
     469        2297 :     return -1;
     470             : }
     471             : 
     472          63 : int passgen_parse_repeat_range(
     473             :     passgen_parser *parser,
     474             :     passgen_token *token,
     475             :     passgen_parser_state *state) {
     476          63 :     if(token->codepoint == '}') {
     477          10 :         passgen_stack_pop(&parser->state, NULL);
     478          10 :         return 0;
     479             :     }
     480             : 
     481          53 :     if(token->codepoint >= '0' && token->codepoint <= '9') {
     482          16 :         uint8_t digit = token->codepoint - '0';
     483             : 
     484          16 :         state->data.repeat.repeat->max *= 10;
     485          16 :         state->data.repeat.repeat->max += digit;
     486             : 
     487          16 :         return 0;
     488             :     }
     489             : 
     490          37 :     return -1;
     491             : }
     492             : 
     493         126 : int passgen_parse_special(
     494             :     passgen_parser *parser,
     495             :     passgen_token *token,
     496             :     passgen_parser_state *state) {
     497             :     (void) parser;
     498             : 
     499         126 :     if(token->codepoint == '{') {
     500          10 :         state->type = PASSGEN_PARSER_SPECIAL_NAME;
     501          10 :         return 0;
     502             :     }
     503             : 
     504         116 :     return -1;
     505             : }
     506             : 
     507         206 : int passgen_parse_special_name(
     508             :     passgen_parser *parser,
     509             :     passgen_token *token,
     510             :     passgen_parser_state *state) {
     511             :     (void) parser;
     512             : 
     513         206 :     if(token->codepoint == '}') {
     514           9 :         passgen_stack_pop(&parser->state, NULL);
     515             :     } else {
     516         197 :         passgen_pattern_special_push(
     517             :             state->data.special.special,
     518         197 :             token->codepoint & ~PASSGEN_TOKEN_ESCAPED_BIT);
     519             :     }
     520             : 
     521         206 :     return 0;
     522             : }
     523             : 
     524       13461 : int passgen_parse_finish(passgen_parser *parser) {
     525             :     // make sure we just have one state on the stack, the initial one.
     526       13461 :     if(parser->state.len != 1) {
     527        3942 :         return -1;
     528             :     }
     529             : 
     530             :     // make sure last state is a group
     531        9519 :     passgen_parser_state *state = passgen_parser_state_last(parser);
     532        9519 :     if(state->type != PASSGEN_PARSER_GROUP) {
     533           0 :         return -1;
     534             :     }
     535             : 
     536             :     // clean last state
     537        9519 :     passgen_pattern_segment_clean(state->data.group.segment);
     538             : 
     539        9519 :     return 0;
     540             : }
     541             : 
     542       10000 : int passgen_parser_unicode(
     543             :     passgen_parser *parser,
     544             :     uint32_t *data,
     545             :     size_t length) {
     546       10000 :     passgen_token_parser token_parser = {0};
     547       10000 :     passgen_token token = {0};
     548             :     int ret;
     549             : 
     550      160172 :     for(size_t pos = 0; pos < length; pos++) {
     551      151301 :         ret = passgen_token_parse(&token_parser, &token, 1, data[pos]);
     552             : 
     553      151301 :         if(ret == PASSGEN_TOKEN_INIT) {
     554      151301 :             ret = passgen_parse_token(parser, &token);
     555             : 
     556      151301 :             if(ret != 0) {
     557        1129 :                 return ret;
     558             :             }
     559             :         }
     560             :     }
     561             : 
     562        8871 :     return 0;
     563             : }

Generated by: LCOV version 1.14