kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

desugar_test.c (3865B)


      1 /* Runtime check that front-end desugaring produces correct recognizers:
      2  * %def fragment inlining, `+` / `{n,m}` quantifier expansion, and ASCII
      3  * shorthand classes. Drives the generated byte-mode lexer from test/desugar.ebnf. */
      4 #include "generated_desugar.h"
      5 
      6 #include <stdio.h>
      7 #include <string.h>
      8 
      9 static int failures = 0;
     10 
     11 static void ck(const char *what, int ok) {
     12     printf("%s  %s\n", ok ? "ok  " : "FAIL", what);
     13     if (!ok) failures++;
     14 }
     15 
     16 typedef struct {
     17     KitGramTokenKind kind;
     18     const char *lexeme;
     19 } Want;
     20 
     21 static void check_stream(const char *src, const Want *want, size_t nwant) {
     22     KitGramLexInput in;
     23     kit_gram_lex_input_init(&in, &(KitGramLexInputConfig){0});
     24     KitGramLexer lx;
     25     KitGramLexConfig cfg = {0};
     26     desugar_lexer_init(&lx, &in, &cfg);
     27     KitGramLexInputSpan sp = { .bytes = (const unsigned char *)src, .len = strlen(src) };
     28     kit_gram_lex_input_push(&in, &sp);
     29     kit_gram_lex_input_finish(&in);
     30 
     31     size_t i = 0;
     32     char label[256];
     33     for (;;) {
     34         KitGramToken t;
     35         KitGramLexStatus st = kit_gram_lexer_next(&lx, &t);
     36         if (st == KIT_GRAM_LEX_TOKEN) {
     37             if (i >= nwant) {
     38                 ck("lexer emitted too many tokens", 0);
     39                 return;
     40             }
     41             int ok = t.kind == want[i].kind && t.len == strlen(want[i].lexeme) &&
     42                      strncmp(t.lexeme, want[i].lexeme, t.len) == 0;
     43             snprintf(label, sizeof label, "[%s] tok[%zu] kind=%u \"%.*s\" (want kind=%u \"%s\")",
     44                      src, i, (unsigned)t.kind, (int)t.len, t.lexeme,
     45                      (unsigned)want[i].kind, want[i].lexeme);
     46             ck(label, ok);
     47             i++;
     48             continue;
     49         }
     50         if (st == KIT_GRAM_LEX_EOF) {
     51             ck("stream fully consumed", i == nwant);
     52             return;
     53         }
     54         ck("unexpected lexer status", 0);
     55         return;
     56     }
     57 }
     58 
     59 /* Expect the first token at the start of `src` to be a lex error (no match). */
     60 static void check_reject(const char *src) {
     61     KitGramLexInput in;
     62     kit_gram_lex_input_init(&in, &(KitGramLexInputConfig){0});
     63     KitGramLexer lx;
     64     KitGramLexConfig cfg = {0};
     65     desugar_lexer_init(&lx, &in, &cfg);
     66     KitGramLexInputSpan sp = { .bytes = (const unsigned char *)src, .len = strlen(src) };
     67     kit_gram_lex_input_push(&in, &sp);
     68     kit_gram_lex_input_finish(&in);
     69     KitGramToken t;
     70     char label[128];
     71     snprintf(label, sizeof label, "rejects \"%s\"", src);
     72     ck(label, kit_gram_lexer_next(&lx, &t) == KIT_GRAM_LEX_ERROR);
     73 }
     74 
     75 int main(void) {
     76     printf("== desugaring: fragments, +, {n,m}, shorthands ==\n");
     77 
     78     { /* INT via fragment digit ("_"? digit)*, HEX via nested fragments */
     79         Want w[] = { { DESUGAR_TOK_INT, "12" }, { DESUGAR_TOK_INT, "3_456" },
     80                      { DESUGAR_TOK_HEX, "0x1f" }, { DESUGAR_TOK_HEX, "0xAB_CD" } };
     81         check_stream("12 3_456 0x1f 0xAB_CD", w, 4);
     82     }
     83     { /* FLOAT exercises digit+ and the optional exponent group */
     84         Want w[] = { { DESUGAR_TOK_FLOAT, "3.14" }, { DESUGAR_TOK_FLOAT, "1.0e-9" }, { DESUGAR_TOK_FLOAT, "2.5E+3" } };
     85         check_stream("3.14 1.0e-9 2.5E+3", w, 3);
     86     }
     87     { /* IDENT = [A-Za-z_] \w* : \w shorthand standalone */
     88         Want w[] = { { DESUGAR_TOK_IDENT, "foo" }, { DESUGAR_TOK_IDENT, "_bar9" }, { DESUGAR_TOK_IDENT, "Baz_Qux" } };
     89         check_stream("foo _bar9 Baz_Qux", w, 3);
     90     }
     91     { /* PERCENT = "%" digit{2} (exact count); OP is a 1-2 char operator (range count) */
     92         Want w[] = { { DESUGAR_TOK_PERCENT, "%50" }, { DESUGAR_TOK_OP, "+" }, { DESUGAR_TOK_OP, "--" }, { DESUGAR_TOK_OP, "*/" } };
     93         check_stream("%50 + -- */", w, 4);
     94     }
     95 
     96     /* {2} is exact: one digit after % is not a PERCENT. */
     97     check_reject("%5");
     98 
     99     printf(failures ? "\nDESUGAR FAILURES=%d\n" : "\nDESUGAR ALL OK\n", failures);
    100     return failures ? 1 : 0;
    101 }