LCOV - code coverage report
Current view: top level - src/parser - token.c (source / functions) Hit Total Coverage
Test: passgen-test.info Lines: 94 94 100.0 %
Date: 2024-05-03 06:05:14 Functions: 9 9 100.0 %

          Line data    Source code
       1             : #include "passgen/parser/token.h"
       2             : 
       3          61 : void passgen_token_parser_init(struct passgen_token_parser *token_parser) {
       4          61 :     token_parser->state = PASSGEN_TOKEN_INIT;
       5          61 :     token_parser->offset = 0;
       6          61 :     token_parser->byte_offset = 0;
       7          61 : }
       8             : 
       9         287 : const char *passgen_token_state_string(enum passgen_token_state state) {
      10         287 :     switch(state) {
      11           1 :         case PASSGEN_TOKEN_INIT:
      12           1 :             return "ready for parsing";
      13         236 :         case PASSGEN_TOKEN_ESCAPED:
      14         236 :             return "parsing escaped token";
      15           4 :         case PASSGEN_TOKEN_UNICODE:
      16           4 :             return "parsing unicode token";
      17           3 :         case PASSGEN_TOKEN_UNICODE_PAYLOAD:
      18           3 :             return "parsing unicode token payload";
      19          37 :         case PASSGEN_TOKEN_ERROR_UNICODE_START:
      20          37 :             return "unexpected character while parsing unicode literal";
      21           1 :         case PASSGEN_TOKEN_ERROR_UNICODE_PAYLOAD:
      22           1 :             return "unexpected character while parsing unicode literal";
      23           3 :         case PASSGEN_TOKEN_ERROR_UNICODE_PAYLOAD_LEN:
      24           3 :             return "unicode literal payload too long";
      25           2 :         default:
      26           2 :             return NULL;
      27             :     }
      28             : }
      29             : 
      30     5566260 : static inline int8_t hex_decode(uint32_t c) {
      31     5566260 :     if('0' <= c && c <= '9') {
      32     3501844 :         return c - '0';
      33             :     }
      34             : 
      35     2064416 :     if('A' <= c && c <= 'F') {
      36           5 :         return 10 + c - 'A';
      37             :     }
      38             : 
      39     2064411 :     if('a' <= c && c <= 'f') {
      40     2064401 :         return 10 + c - 'a';
      41             :     }
      42             : 
      43          10 :     return -1;
      44             : }
      45             : 
      46     3685005 : static inline void token_parse_init(
      47             :     struct passgen_token_parser *parser,
      48             :     struct passgen_token *token,
      49             :     uint32_t codepoint) {
      50             :     // save position of initial token
      51     3685005 :     token->offset = parser->offset;
      52     3685005 :     token->byte_offset = parser->byte_offset;
      53             : 
      54     3685005 :     if(codepoint == '\\') {
      55     2231031 :         parser->state = PASSGEN_TOKEN_ESCAPED;
      56             :     } else {
      57     1453974 :         token->codepoint = codepoint;
      58     1453974 :         parser->state = PASSGEN_TOKEN_INIT;
      59             :     }
      60     3685005 : }
      61             : 
      62             : // Simple ASCII escape map. Don't use this for large (unicode) codepoints.
      63             : // Provides efficient O(1) lookup.
      64             : static const char simple_escaped[] = {
      65             :     0,
      66             :     ['a'] = '\a',
      67             :     ['b'] = '\b',
      68             :     ['e'] = '\033',
      69             :     ['f'] = '\f',
      70             :     ['n'] = '\n',
      71             :     ['r'] = '\r',
      72             :     ['t'] = '\t',
      73             :     ['v'] = '\v',
      74             :     ['\\'] = '\\'};
      75             : 
      76     2230796 : static inline void token_parse_escaped(
      77             :     struct passgen_token_parser *parser,
      78             :     struct passgen_token *token,
      79             :     uint32_t codepoint) {
      80             :     // simple_escaped only covers ASCII, whereas codepoint could be much
      81             :     // larger.
      82     2230796 :     if(codepoint < sizeof(simple_escaped) && simple_escaped[codepoint]) {
      83         402 :         token->codepoint = simple_escaped[codepoint];
      84         402 :         parser->state = PASSGEN_TOKEN_INIT;
      85             : 
      86         402 :         return;
      87             :     }
      88             : 
      89     2230394 :     switch(codepoint) {
      90     1114188 :         case 'u':
      91     1114188 :             parser->state = PASSGEN_TOKEN_UNICODE;
      92     1114188 :             break;
      93     1116206 :         default:
      94     1116206 :             token->codepoint = codepoint | PASSGEN_TOKEN_ESCAPED_BIT;
      95     1116206 :             parser->state = PASSGEN_TOKEN_INIT;
      96             :     }
      97             : }
      98             : 
      99             : static inline void
     100     1114185 : token_parse_unicode(struct passgen_token_parser *parser, uint32_t codepoint) {
     101     1114185 :     if(codepoint == '{') {
     102     1114138 :         parser->state = PASSGEN_TOKEN_UNICODE_PAYLOAD;
     103     1114138 :         parser->data.unicode_payload.length = 0;
     104     1114138 :         parser->data.unicode_payload.codepoint = 0;
     105             :     } else {
     106          47 :         parser->state = PASSGEN_TOKEN_ERROR_UNICODE_START;
     107             :     }
     108     1114185 : }
     109             : 
     110     6680386 : static inline void token_parse_unicode_payload(
     111             :     struct passgen_token_parser *parser,
     112             :     struct passgen_token *token,
     113             :     uint32_t codepoint) {
     114             :     // once we read the closing brace, the payload is over and we can emit the
     115             :     // token.
     116     6680386 :     if(codepoint == '}') {
     117     1114120 :         token->codepoint = parser->data.unicode_payload.codepoint;
     118     1114120 :         parser->state = PASSGEN_TOKEN_INIT;
     119             : 
     120     1114120 :         return;
     121             :     }
     122             : 
     123             :     // keep track of length, make sure it's not too long.
     124     5566266 :     parser->data.unicode_payload.length++;
     125     5566266 :     if(parser->data.unicode_payload.length > 6) {
     126           6 :         parser->state = PASSGEN_TOKEN_ERROR_UNICODE_PAYLOAD_LEN;
     127             : 
     128           6 :         return;
     129             :     }
     130             : 
     131             :     // try to decode the hex value.
     132     5566260 :     int8_t decoded = hex_decode(codepoint);
     133     5566260 :     if(decoded < 0) {
     134          10 :         parser->state = PASSGEN_TOKEN_ERROR_UNICODE_PAYLOAD;
     135             : 
     136          10 :         return;
     137             :     }
     138             : 
     139     5566250 :     parser->data.unicode_payload.codepoint *= 16;
     140     5566250 :     parser->data.unicode_payload.codepoint += decoded;
     141             : }
     142             : 
     143    13710375 : int passgen_token_parse(
     144             :     struct passgen_token_parser *parser,
     145             :     struct passgen_token *token,
     146             :     uint8_t width,
     147             :     uint32_t codepoint) {
     148    13710375 :     switch(parser->state) {
     149     3685005 :         case PASSGEN_TOKEN_INIT:
     150     3685005 :             token_parse_init(parser, token, codepoint);
     151     3685005 :             break;
     152     2230796 :         case PASSGEN_TOKEN_ESCAPED:
     153     2230796 :             token_parse_escaped(parser, token, codepoint);
     154     2230796 :             break;
     155     1114185 :         case PASSGEN_TOKEN_UNICODE:
     156     1114185 :             token_parse_unicode(parser, codepoint);
     157     1114185 :             break;
     158     6680386 :         case PASSGEN_TOKEN_UNICODE_PAYLOAD:
     159     6680386 :             token_parse_unicode_payload(parser, token, codepoint);
     160     6680386 :             break;
     161           3 :         default:
     162           3 :             return parser->state;
     163             :     }
     164             : 
     165             :     // update parser offsets
     166    13710372 :     parser->offset += 1;
     167    13710372 :     parser->byte_offset += width;
     168             : 
     169    13710372 :     return parser->state;
     170             : }
     171             : 
     172         278 : const char *passgen_token_parse_error_str(int ret) {
     173         278 :     return passgen_token_state_string(ret);
     174             : }

Generated by: LCOV version 1.14