1*8e33eff8Schristos #include "test/jemalloc_test.h" 2*8e33eff8Schristos 3*8e33eff8Schristos #include "jemalloc/internal/util.h" 4*8e33eff8Schristos 5*8e33eff8Schristos typedef enum { 6*8e33eff8Schristos TOKEN_TYPE_NONE, 7*8e33eff8Schristos TOKEN_TYPE_ERROR, 8*8e33eff8Schristos TOKEN_TYPE_EOI, 9*8e33eff8Schristos TOKEN_TYPE_NULL, 10*8e33eff8Schristos TOKEN_TYPE_FALSE, 11*8e33eff8Schristos TOKEN_TYPE_TRUE, 12*8e33eff8Schristos TOKEN_TYPE_LBRACKET, 13*8e33eff8Schristos TOKEN_TYPE_RBRACKET, 14*8e33eff8Schristos TOKEN_TYPE_LBRACE, 15*8e33eff8Schristos TOKEN_TYPE_RBRACE, 16*8e33eff8Schristos TOKEN_TYPE_COLON, 17*8e33eff8Schristos TOKEN_TYPE_COMMA, 18*8e33eff8Schristos TOKEN_TYPE_STRING, 19*8e33eff8Schristos TOKEN_TYPE_NUMBER 20*8e33eff8Schristos } token_type_t; 21*8e33eff8Schristos 22*8e33eff8Schristos typedef struct parser_s parser_t; 23*8e33eff8Schristos typedef struct { 24*8e33eff8Schristos parser_t *parser; 25*8e33eff8Schristos token_type_t token_type; 26*8e33eff8Schristos size_t pos; 27*8e33eff8Schristos size_t len; 28*8e33eff8Schristos size_t line; 29*8e33eff8Schristos size_t col; 30*8e33eff8Schristos } token_t; 31*8e33eff8Schristos 32*8e33eff8Schristos struct parser_s { 33*8e33eff8Schristos bool verbose; 34*8e33eff8Schristos char *buf; /* '\0'-terminated. */ 35*8e33eff8Schristos size_t len; /* Number of characters preceding '\0' in buf. */ 36*8e33eff8Schristos size_t pos; 37*8e33eff8Schristos size_t line; 38*8e33eff8Schristos size_t col; 39*8e33eff8Schristos token_t token; 40*8e33eff8Schristos }; 41*8e33eff8Schristos 42*8e33eff8Schristos static void 43*8e33eff8Schristos token_init(token_t *token, parser_t *parser, token_type_t token_type, 44*8e33eff8Schristos size_t pos, size_t len, size_t line, size_t col) { 45*8e33eff8Schristos token->parser = parser; 46*8e33eff8Schristos token->token_type = token_type; 47*8e33eff8Schristos token->pos = pos; 48*8e33eff8Schristos token->len = len; 49*8e33eff8Schristos token->line = line; 50*8e33eff8Schristos token->col = col; 51*8e33eff8Schristos } 52*8e33eff8Schristos 53*8e33eff8Schristos static void 54*8e33eff8Schristos token_error(token_t *token) { 55*8e33eff8Schristos if (!token->parser->verbose) { 56*8e33eff8Schristos return; 57*8e33eff8Schristos } 58*8e33eff8Schristos switch (token->token_type) { 59*8e33eff8Schristos case TOKEN_TYPE_NONE: 60*8e33eff8Schristos not_reached(); 61*8e33eff8Schristos case TOKEN_TYPE_ERROR: 62*8e33eff8Schristos malloc_printf("%zu:%zu: Unexpected character in token: ", 63*8e33eff8Schristos token->line, token->col); 64*8e33eff8Schristos break; 65*8e33eff8Schristos default: 66*8e33eff8Schristos malloc_printf("%zu:%zu: Unexpected token: ", token->line, 67*8e33eff8Schristos token->col); 68*8e33eff8Schristos break; 69*8e33eff8Schristos } 70*8e33eff8Schristos UNUSED ssize_t err = malloc_write_fd(STDERR_FILENO, 71*8e33eff8Schristos &token->parser->buf[token->pos], token->len); 72*8e33eff8Schristos malloc_printf("\n"); 73*8e33eff8Schristos } 74*8e33eff8Schristos 75*8e33eff8Schristos static void 76*8e33eff8Schristos parser_init(parser_t *parser, bool verbose) { 77*8e33eff8Schristos parser->verbose = verbose; 78*8e33eff8Schristos parser->buf = NULL; 79*8e33eff8Schristos parser->len = 0; 80*8e33eff8Schristos parser->pos = 0; 81*8e33eff8Schristos parser->line = 1; 82*8e33eff8Schristos parser->col = 0; 83*8e33eff8Schristos } 84*8e33eff8Schristos 85*8e33eff8Schristos static void 86*8e33eff8Schristos parser_fini(parser_t *parser) { 87*8e33eff8Schristos if (parser->buf != NULL) { 88*8e33eff8Schristos dallocx(parser->buf, MALLOCX_TCACHE_NONE); 89*8e33eff8Schristos } 90*8e33eff8Schristos } 91*8e33eff8Schristos 92*8e33eff8Schristos static bool 93*8e33eff8Schristos parser_append(parser_t *parser, const char *str) { 94*8e33eff8Schristos size_t len = strlen(str); 95*8e33eff8Schristos char *buf = (parser->buf == NULL) ? mallocx(len + 1, 96*8e33eff8Schristos MALLOCX_TCACHE_NONE) : rallocx(parser->buf, parser->len + len + 1, 97*8e33eff8Schristos MALLOCX_TCACHE_NONE); 98*8e33eff8Schristos if (buf == NULL) { 99*8e33eff8Schristos return true; 100*8e33eff8Schristos } 101*8e33eff8Schristos memcpy(&buf[parser->len], str, len + 1); 102*8e33eff8Schristos parser->buf = buf; 103*8e33eff8Schristos parser->len += len; 104*8e33eff8Schristos return false; 105*8e33eff8Schristos } 106*8e33eff8Schristos 107*8e33eff8Schristos static bool 108*8e33eff8Schristos parser_tokenize(parser_t *parser) { 109*8e33eff8Schristos enum { 110*8e33eff8Schristos STATE_START, 111*8e33eff8Schristos STATE_EOI, 112*8e33eff8Schristos STATE_N, STATE_NU, STATE_NUL, STATE_NULL, 113*8e33eff8Schristos STATE_F, STATE_FA, STATE_FAL, STATE_FALS, STATE_FALSE, 114*8e33eff8Schristos STATE_T, STATE_TR, STATE_TRU, STATE_TRUE, 115*8e33eff8Schristos STATE_LBRACKET, 116*8e33eff8Schristos STATE_RBRACKET, 117*8e33eff8Schristos STATE_LBRACE, 118*8e33eff8Schristos STATE_RBRACE, 119*8e33eff8Schristos STATE_COLON, 120*8e33eff8Schristos STATE_COMMA, 121*8e33eff8Schristos STATE_CHARS, 122*8e33eff8Schristos STATE_CHAR_ESCAPE, 123*8e33eff8Schristos STATE_CHAR_U, STATE_CHAR_UD, STATE_CHAR_UDD, STATE_CHAR_UDDD, 124*8e33eff8Schristos STATE_STRING, 125*8e33eff8Schristos STATE_MINUS, 126*8e33eff8Schristos STATE_LEADING_ZERO, 127*8e33eff8Schristos STATE_DIGITS, 128*8e33eff8Schristos STATE_DECIMAL, 129*8e33eff8Schristos STATE_FRAC_DIGITS, 130*8e33eff8Schristos STATE_EXP, 131*8e33eff8Schristos STATE_EXP_SIGN, 132*8e33eff8Schristos STATE_EXP_DIGITS, 133*8e33eff8Schristos STATE_ACCEPT 134*8e33eff8Schristos } state = STATE_START; 135*8e33eff8Schristos size_t token_pos JEMALLOC_CC_SILENCE_INIT(0); 136*8e33eff8Schristos size_t token_line JEMALLOC_CC_SILENCE_INIT(1); 137*8e33eff8Schristos size_t token_col JEMALLOC_CC_SILENCE_INIT(0); 138*8e33eff8Schristos 139*8e33eff8Schristos assert_zu_le(parser->pos, parser->len, 140*8e33eff8Schristos "Position is past end of buffer"); 141*8e33eff8Schristos 142*8e33eff8Schristos while (state != STATE_ACCEPT) { 143*8e33eff8Schristos char c = parser->buf[parser->pos]; 144*8e33eff8Schristos 145*8e33eff8Schristos switch (state) { 146*8e33eff8Schristos case STATE_START: 147*8e33eff8Schristos token_pos = parser->pos; 148*8e33eff8Schristos token_line = parser->line; 149*8e33eff8Schristos token_col = parser->col; 150*8e33eff8Schristos switch (c) { 151*8e33eff8Schristos case ' ': case '\b': case '\n': case '\r': case '\t': 152*8e33eff8Schristos break; 153*8e33eff8Schristos case '\0': 154*8e33eff8Schristos state = STATE_EOI; 155*8e33eff8Schristos break; 156*8e33eff8Schristos case 'n': 157*8e33eff8Schristos state = STATE_N; 158*8e33eff8Schristos break; 159*8e33eff8Schristos case 'f': 160*8e33eff8Schristos state = STATE_F; 161*8e33eff8Schristos break; 162*8e33eff8Schristos case 't': 163*8e33eff8Schristos state = STATE_T; 164*8e33eff8Schristos break; 165*8e33eff8Schristos case '[': 166*8e33eff8Schristos state = STATE_LBRACKET; 167*8e33eff8Schristos break; 168*8e33eff8Schristos case ']': 169*8e33eff8Schristos state = STATE_RBRACKET; 170*8e33eff8Schristos break; 171*8e33eff8Schristos case '{': 172*8e33eff8Schristos state = STATE_LBRACE; 173*8e33eff8Schristos break; 174*8e33eff8Schristos case '}': 175*8e33eff8Schristos state = STATE_RBRACE; 176*8e33eff8Schristos break; 177*8e33eff8Schristos case ':': 178*8e33eff8Schristos state = STATE_COLON; 179*8e33eff8Schristos break; 180*8e33eff8Schristos case ',': 181*8e33eff8Schristos state = STATE_COMMA; 182*8e33eff8Schristos break; 183*8e33eff8Schristos case '"': 184*8e33eff8Schristos state = STATE_CHARS; 185*8e33eff8Schristos break; 186*8e33eff8Schristos case '-': 187*8e33eff8Schristos state = STATE_MINUS; 188*8e33eff8Schristos break; 189*8e33eff8Schristos case '0': 190*8e33eff8Schristos state = STATE_LEADING_ZERO; 191*8e33eff8Schristos break; 192*8e33eff8Schristos case '1': case '2': case '3': case '4': 193*8e33eff8Schristos case '5': case '6': case '7': case '8': case '9': 194*8e33eff8Schristos state = STATE_DIGITS; 195*8e33eff8Schristos break; 196*8e33eff8Schristos default: 197*8e33eff8Schristos token_init(&parser->token, parser, 198*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 199*8e33eff8Schristos - token_pos, token_line, token_col); 200*8e33eff8Schristos return true; 201*8e33eff8Schristos } 202*8e33eff8Schristos break; 203*8e33eff8Schristos case STATE_EOI: 204*8e33eff8Schristos token_init(&parser->token, parser, 205*8e33eff8Schristos TOKEN_TYPE_EOI, token_pos, parser->pos - 206*8e33eff8Schristos token_pos, token_line, token_col); 207*8e33eff8Schristos state = STATE_ACCEPT; 208*8e33eff8Schristos break; 209*8e33eff8Schristos case STATE_N: 210*8e33eff8Schristos switch (c) { 211*8e33eff8Schristos case 'u': 212*8e33eff8Schristos state = STATE_NU; 213*8e33eff8Schristos break; 214*8e33eff8Schristos default: 215*8e33eff8Schristos token_init(&parser->token, parser, 216*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 217*8e33eff8Schristos - token_pos, token_line, token_col); 218*8e33eff8Schristos return true; 219*8e33eff8Schristos } 220*8e33eff8Schristos break; 221*8e33eff8Schristos case STATE_NU: 222*8e33eff8Schristos switch (c) { 223*8e33eff8Schristos case 'l': 224*8e33eff8Schristos state = STATE_NUL; 225*8e33eff8Schristos break; 226*8e33eff8Schristos default: 227*8e33eff8Schristos token_init(&parser->token, parser, 228*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 229*8e33eff8Schristos - token_pos, token_line, token_col); 230*8e33eff8Schristos return true; 231*8e33eff8Schristos } 232*8e33eff8Schristos break; 233*8e33eff8Schristos case STATE_NUL: 234*8e33eff8Schristos switch (c) { 235*8e33eff8Schristos case 'l': 236*8e33eff8Schristos state = STATE_NULL; 237*8e33eff8Schristos break; 238*8e33eff8Schristos default: 239*8e33eff8Schristos token_init(&parser->token, parser, 240*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 241*8e33eff8Schristos - token_pos, token_line, token_col); 242*8e33eff8Schristos return true; 243*8e33eff8Schristos } 244*8e33eff8Schristos break; 245*8e33eff8Schristos case STATE_NULL: 246*8e33eff8Schristos switch (c) { 247*8e33eff8Schristos case ' ': case '\b': case '\n': case '\r': case '\t': 248*8e33eff8Schristos case '\0': 249*8e33eff8Schristos case '[': case ']': case '{': case '}': case ':': 250*8e33eff8Schristos case ',': 251*8e33eff8Schristos break; 252*8e33eff8Schristos default: 253*8e33eff8Schristos token_init(&parser->token, parser, 254*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 255*8e33eff8Schristos - token_pos, token_line, token_col); 256*8e33eff8Schristos return true; 257*8e33eff8Schristos } 258*8e33eff8Schristos token_init(&parser->token, parser, TOKEN_TYPE_NULL, 259*8e33eff8Schristos token_pos, parser->pos - token_pos, token_line, 260*8e33eff8Schristos token_col); 261*8e33eff8Schristos state = STATE_ACCEPT; 262*8e33eff8Schristos break; 263*8e33eff8Schristos case STATE_F: 264*8e33eff8Schristos switch (c) { 265*8e33eff8Schristos case 'a': 266*8e33eff8Schristos state = STATE_FA; 267*8e33eff8Schristos break; 268*8e33eff8Schristos default: 269*8e33eff8Schristos token_init(&parser->token, parser, 270*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 271*8e33eff8Schristos - token_pos, token_line, token_col); 272*8e33eff8Schristos return true; 273*8e33eff8Schristos } 274*8e33eff8Schristos break; 275*8e33eff8Schristos case STATE_FA: 276*8e33eff8Schristos switch (c) { 277*8e33eff8Schristos case 'l': 278*8e33eff8Schristos state = STATE_FAL; 279*8e33eff8Schristos break; 280*8e33eff8Schristos default: 281*8e33eff8Schristos token_init(&parser->token, parser, 282*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 283*8e33eff8Schristos - token_pos, token_line, token_col); 284*8e33eff8Schristos return true; 285*8e33eff8Schristos } 286*8e33eff8Schristos break; 287*8e33eff8Schristos case STATE_FAL: 288*8e33eff8Schristos switch (c) { 289*8e33eff8Schristos case 's': 290*8e33eff8Schristos state = STATE_FALS; 291*8e33eff8Schristos break; 292*8e33eff8Schristos default: 293*8e33eff8Schristos token_init(&parser->token, parser, 294*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 295*8e33eff8Schristos - token_pos, token_line, token_col); 296*8e33eff8Schristos return true; 297*8e33eff8Schristos } 298*8e33eff8Schristos break; 299*8e33eff8Schristos case STATE_FALS: 300*8e33eff8Schristos switch (c) { 301*8e33eff8Schristos case 'e': 302*8e33eff8Schristos state = STATE_FALSE; 303*8e33eff8Schristos break; 304*8e33eff8Schristos default: 305*8e33eff8Schristos token_init(&parser->token, parser, 306*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 307*8e33eff8Schristos - token_pos, token_line, token_col); 308*8e33eff8Schristos return true; 309*8e33eff8Schristos } 310*8e33eff8Schristos break; 311*8e33eff8Schristos case STATE_FALSE: 312*8e33eff8Schristos switch (c) { 313*8e33eff8Schristos case ' ': case '\b': case '\n': case '\r': case '\t': 314*8e33eff8Schristos case '\0': 315*8e33eff8Schristos case '[': case ']': case '{': case '}': case ':': 316*8e33eff8Schristos case ',': 317*8e33eff8Schristos break; 318*8e33eff8Schristos default: 319*8e33eff8Schristos token_init(&parser->token, parser, 320*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 321*8e33eff8Schristos - token_pos, token_line, token_col); 322*8e33eff8Schristos return true; 323*8e33eff8Schristos } 324*8e33eff8Schristos token_init(&parser->token, parser, 325*8e33eff8Schristos TOKEN_TYPE_FALSE, token_pos, parser->pos - 326*8e33eff8Schristos token_pos, token_line, token_col); 327*8e33eff8Schristos state = STATE_ACCEPT; 328*8e33eff8Schristos break; 329*8e33eff8Schristos case STATE_T: 330*8e33eff8Schristos switch (c) { 331*8e33eff8Schristos case 'r': 332*8e33eff8Schristos state = STATE_TR; 333*8e33eff8Schristos break; 334*8e33eff8Schristos default: 335*8e33eff8Schristos token_init(&parser->token, parser, 336*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 337*8e33eff8Schristos - token_pos, token_line, token_col); 338*8e33eff8Schristos return true; 339*8e33eff8Schristos } 340*8e33eff8Schristos break; 341*8e33eff8Schristos case STATE_TR: 342*8e33eff8Schristos switch (c) { 343*8e33eff8Schristos case 'u': 344*8e33eff8Schristos state = STATE_TRU; 345*8e33eff8Schristos break; 346*8e33eff8Schristos default: 347*8e33eff8Schristos token_init(&parser->token, parser, 348*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 349*8e33eff8Schristos - token_pos, token_line, token_col); 350*8e33eff8Schristos return true; 351*8e33eff8Schristos } 352*8e33eff8Schristos break; 353*8e33eff8Schristos case STATE_TRU: 354*8e33eff8Schristos switch (c) { 355*8e33eff8Schristos case 'e': 356*8e33eff8Schristos state = STATE_TRUE; 357*8e33eff8Schristos break; 358*8e33eff8Schristos default: 359*8e33eff8Schristos token_init(&parser->token, parser, 360*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 361*8e33eff8Schristos - token_pos, token_line, token_col); 362*8e33eff8Schristos return true; 363*8e33eff8Schristos } 364*8e33eff8Schristos break; 365*8e33eff8Schristos case STATE_TRUE: 366*8e33eff8Schristos switch (c) { 367*8e33eff8Schristos case ' ': case '\b': case '\n': case '\r': case '\t': 368*8e33eff8Schristos case '\0': 369*8e33eff8Schristos case '[': case ']': case '{': case '}': case ':': 370*8e33eff8Schristos case ',': 371*8e33eff8Schristos break; 372*8e33eff8Schristos default: 373*8e33eff8Schristos token_init(&parser->token, parser, 374*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 375*8e33eff8Schristos - token_pos, token_line, token_col); 376*8e33eff8Schristos return true; 377*8e33eff8Schristos } 378*8e33eff8Schristos token_init(&parser->token, parser, TOKEN_TYPE_TRUE, 379*8e33eff8Schristos token_pos, parser->pos - token_pos, token_line, 380*8e33eff8Schristos token_col); 381*8e33eff8Schristos state = STATE_ACCEPT; 382*8e33eff8Schristos break; 383*8e33eff8Schristos case STATE_LBRACKET: 384*8e33eff8Schristos token_init(&parser->token, parser, TOKEN_TYPE_LBRACKET, 385*8e33eff8Schristos token_pos, parser->pos - token_pos, token_line, 386*8e33eff8Schristos token_col); 387*8e33eff8Schristos state = STATE_ACCEPT; 388*8e33eff8Schristos break; 389*8e33eff8Schristos case STATE_RBRACKET: 390*8e33eff8Schristos token_init(&parser->token, parser, TOKEN_TYPE_RBRACKET, 391*8e33eff8Schristos token_pos, parser->pos - token_pos, token_line, 392*8e33eff8Schristos token_col); 393*8e33eff8Schristos state = STATE_ACCEPT; 394*8e33eff8Schristos break; 395*8e33eff8Schristos case STATE_LBRACE: 396*8e33eff8Schristos token_init(&parser->token, parser, TOKEN_TYPE_LBRACE, 397*8e33eff8Schristos token_pos, parser->pos - token_pos, token_line, 398*8e33eff8Schristos token_col); 399*8e33eff8Schristos state = STATE_ACCEPT; 400*8e33eff8Schristos break; 401*8e33eff8Schristos case STATE_RBRACE: 402*8e33eff8Schristos token_init(&parser->token, parser, TOKEN_TYPE_RBRACE, 403*8e33eff8Schristos token_pos, parser->pos - token_pos, token_line, 404*8e33eff8Schristos token_col); 405*8e33eff8Schristos state = STATE_ACCEPT; 406*8e33eff8Schristos break; 407*8e33eff8Schristos case STATE_COLON: 408*8e33eff8Schristos token_init(&parser->token, parser, TOKEN_TYPE_COLON, 409*8e33eff8Schristos token_pos, parser->pos - token_pos, token_line, 410*8e33eff8Schristos token_col); 411*8e33eff8Schristos state = STATE_ACCEPT; 412*8e33eff8Schristos break; 413*8e33eff8Schristos case STATE_COMMA: 414*8e33eff8Schristos token_init(&parser->token, parser, TOKEN_TYPE_COMMA, 415*8e33eff8Schristos token_pos, parser->pos - token_pos, token_line, 416*8e33eff8Schristos token_col); 417*8e33eff8Schristos state = STATE_ACCEPT; 418*8e33eff8Schristos break; 419*8e33eff8Schristos case STATE_CHARS: 420*8e33eff8Schristos switch (c) { 421*8e33eff8Schristos case '\\': 422*8e33eff8Schristos state = STATE_CHAR_ESCAPE; 423*8e33eff8Schristos break; 424*8e33eff8Schristos case '"': 425*8e33eff8Schristos state = STATE_STRING; 426*8e33eff8Schristos break; 427*8e33eff8Schristos case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: 428*8e33eff8Schristos case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: 429*8e33eff8Schristos case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: 430*8e33eff8Schristos case 0x0f: case 0x10: case 0x11: case 0x12: case 0x13: 431*8e33eff8Schristos case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: 432*8e33eff8Schristos case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: 433*8e33eff8Schristos case 0x1e: case 0x1f: 434*8e33eff8Schristos token_init(&parser->token, parser, 435*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 436*8e33eff8Schristos - token_pos, token_line, token_col); 437*8e33eff8Schristos return true; 438*8e33eff8Schristos default: 439*8e33eff8Schristos break; 440*8e33eff8Schristos } 441*8e33eff8Schristos break; 442*8e33eff8Schristos case STATE_CHAR_ESCAPE: 443*8e33eff8Schristos switch (c) { 444*8e33eff8Schristos case '"': case '\\': case '/': case 'b': case 'n': 445*8e33eff8Schristos case 'r': case 't': 446*8e33eff8Schristos state = STATE_CHARS; 447*8e33eff8Schristos break; 448*8e33eff8Schristos case 'u': 449*8e33eff8Schristos state = STATE_CHAR_U; 450*8e33eff8Schristos break; 451*8e33eff8Schristos default: 452*8e33eff8Schristos token_init(&parser->token, parser, 453*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 454*8e33eff8Schristos - token_pos, token_line, token_col); 455*8e33eff8Schristos return true; 456*8e33eff8Schristos } 457*8e33eff8Schristos break; 458*8e33eff8Schristos case STATE_CHAR_U: 459*8e33eff8Schristos switch (c) { 460*8e33eff8Schristos case '0': case '1': case '2': case '3': case '4': 461*8e33eff8Schristos case '5': case '6': case '7': case '8': case '9': 462*8e33eff8Schristos case 'a': case 'b': case 'c': case 'd': case 'e': 463*8e33eff8Schristos case 'f': 464*8e33eff8Schristos case 'A': case 'B': case 'C': case 'D': case 'E': 465*8e33eff8Schristos case 'F': 466*8e33eff8Schristos state = STATE_CHAR_UD; 467*8e33eff8Schristos break; 468*8e33eff8Schristos default: 469*8e33eff8Schristos token_init(&parser->token, parser, 470*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 471*8e33eff8Schristos - token_pos, token_line, token_col); 472*8e33eff8Schristos return true; 473*8e33eff8Schristos } 474*8e33eff8Schristos break; 475*8e33eff8Schristos case STATE_CHAR_UD: 476*8e33eff8Schristos switch (c) { 477*8e33eff8Schristos case '0': case '1': case '2': case '3': case '4': 478*8e33eff8Schristos case '5': case '6': case '7': case '8': case '9': 479*8e33eff8Schristos case 'a': case 'b': case 'c': case 'd': case 'e': 480*8e33eff8Schristos case 'f': 481*8e33eff8Schristos case 'A': case 'B': case 'C': case 'D': case 'E': 482*8e33eff8Schristos case 'F': 483*8e33eff8Schristos state = STATE_CHAR_UDD; 484*8e33eff8Schristos break; 485*8e33eff8Schristos default: 486*8e33eff8Schristos token_init(&parser->token, parser, 487*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 488*8e33eff8Schristos - token_pos, token_line, token_col); 489*8e33eff8Schristos return true; 490*8e33eff8Schristos } 491*8e33eff8Schristos break; 492*8e33eff8Schristos case STATE_CHAR_UDD: 493*8e33eff8Schristos switch (c) { 494*8e33eff8Schristos case '0': case '1': case '2': case '3': case '4': 495*8e33eff8Schristos case '5': case '6': case '7': case '8': case '9': 496*8e33eff8Schristos case 'a': case 'b': case 'c': case 'd': case 'e': 497*8e33eff8Schristos case 'f': 498*8e33eff8Schristos case 'A': case 'B': case 'C': case 'D': case 'E': 499*8e33eff8Schristos case 'F': 500*8e33eff8Schristos state = STATE_CHAR_UDDD; 501*8e33eff8Schristos break; 502*8e33eff8Schristos default: 503*8e33eff8Schristos token_init(&parser->token, parser, 504*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 505*8e33eff8Schristos - token_pos, token_line, token_col); 506*8e33eff8Schristos return true; 507*8e33eff8Schristos } 508*8e33eff8Schristos break; 509*8e33eff8Schristos case STATE_CHAR_UDDD: 510*8e33eff8Schristos switch (c) { 511*8e33eff8Schristos case '0': case '1': case '2': case '3': case '4': 512*8e33eff8Schristos case '5': case '6': case '7': case '8': case '9': 513*8e33eff8Schristos case 'a': case 'b': case 'c': case 'd': case 'e': 514*8e33eff8Schristos case 'f': 515*8e33eff8Schristos case 'A': case 'B': case 'C': case 'D': case 'E': 516*8e33eff8Schristos case 'F': 517*8e33eff8Schristos state = STATE_CHARS; 518*8e33eff8Schristos break; 519*8e33eff8Schristos default: 520*8e33eff8Schristos token_init(&parser->token, parser, 521*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 522*8e33eff8Schristos - token_pos, token_line, token_col); 523*8e33eff8Schristos return true; 524*8e33eff8Schristos } 525*8e33eff8Schristos break; 526*8e33eff8Schristos case STATE_STRING: 527*8e33eff8Schristos token_init(&parser->token, parser, TOKEN_TYPE_STRING, 528*8e33eff8Schristos token_pos, parser->pos - token_pos, token_line, 529*8e33eff8Schristos token_col); 530*8e33eff8Schristos state = STATE_ACCEPT; 531*8e33eff8Schristos break; 532*8e33eff8Schristos case STATE_MINUS: 533*8e33eff8Schristos switch (c) { 534*8e33eff8Schristos case '0': 535*8e33eff8Schristos state = STATE_LEADING_ZERO; 536*8e33eff8Schristos break; 537*8e33eff8Schristos case '1': case '2': case '3': case '4': 538*8e33eff8Schristos case '5': case '6': case '7': case '8': case '9': 539*8e33eff8Schristos state = STATE_DIGITS; 540*8e33eff8Schristos break; 541*8e33eff8Schristos default: 542*8e33eff8Schristos token_init(&parser->token, parser, 543*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 544*8e33eff8Schristos - token_pos, token_line, token_col); 545*8e33eff8Schristos return true; 546*8e33eff8Schristos } 547*8e33eff8Schristos break; 548*8e33eff8Schristos case STATE_LEADING_ZERO: 549*8e33eff8Schristos switch (c) { 550*8e33eff8Schristos case '.': 551*8e33eff8Schristos state = STATE_DECIMAL; 552*8e33eff8Schristos break; 553*8e33eff8Schristos default: 554*8e33eff8Schristos token_init(&parser->token, parser, 555*8e33eff8Schristos TOKEN_TYPE_NUMBER, token_pos, parser->pos - 556*8e33eff8Schristos token_pos, token_line, token_col); 557*8e33eff8Schristos state = STATE_ACCEPT; 558*8e33eff8Schristos break; 559*8e33eff8Schristos } 560*8e33eff8Schristos break; 561*8e33eff8Schristos case STATE_DIGITS: 562*8e33eff8Schristos switch (c) { 563*8e33eff8Schristos case '0': case '1': case '2': case '3': case '4': 564*8e33eff8Schristos case '5': case '6': case '7': case '8': case '9': 565*8e33eff8Schristos break; 566*8e33eff8Schristos case '.': 567*8e33eff8Schristos state = STATE_DECIMAL; 568*8e33eff8Schristos break; 569*8e33eff8Schristos default: 570*8e33eff8Schristos token_init(&parser->token, parser, 571*8e33eff8Schristos TOKEN_TYPE_NUMBER, token_pos, parser->pos - 572*8e33eff8Schristos token_pos, token_line, token_col); 573*8e33eff8Schristos state = STATE_ACCEPT; 574*8e33eff8Schristos break; 575*8e33eff8Schristos } 576*8e33eff8Schristos break; 577*8e33eff8Schristos case STATE_DECIMAL: 578*8e33eff8Schristos switch (c) { 579*8e33eff8Schristos case '0': case '1': case '2': case '3': case '4': 580*8e33eff8Schristos case '5': case '6': case '7': case '8': case '9': 581*8e33eff8Schristos state = STATE_FRAC_DIGITS; 582*8e33eff8Schristos break; 583*8e33eff8Schristos default: 584*8e33eff8Schristos token_init(&parser->token, parser, 585*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 586*8e33eff8Schristos - token_pos, token_line, token_col); 587*8e33eff8Schristos return true; 588*8e33eff8Schristos } 589*8e33eff8Schristos break; 590*8e33eff8Schristos case STATE_FRAC_DIGITS: 591*8e33eff8Schristos switch (c) { 592*8e33eff8Schristos case '0': case '1': case '2': case '3': case '4': 593*8e33eff8Schristos case '5': case '6': case '7': case '8': case '9': 594*8e33eff8Schristos break; 595*8e33eff8Schristos case 'e': case 'E': 596*8e33eff8Schristos state = STATE_EXP; 597*8e33eff8Schristos break; 598*8e33eff8Schristos default: 599*8e33eff8Schristos token_init(&parser->token, parser, 600*8e33eff8Schristos TOKEN_TYPE_NUMBER, token_pos, parser->pos - 601*8e33eff8Schristos token_pos, token_line, token_col); 602*8e33eff8Schristos state = STATE_ACCEPT; 603*8e33eff8Schristos break; 604*8e33eff8Schristos } 605*8e33eff8Schristos break; 606*8e33eff8Schristos case STATE_EXP: 607*8e33eff8Schristos switch (c) { 608*8e33eff8Schristos case '-': case '+': 609*8e33eff8Schristos state = STATE_EXP_SIGN; 610*8e33eff8Schristos break; 611*8e33eff8Schristos case '0': case '1': case '2': case '3': case '4': 612*8e33eff8Schristos case '5': case '6': case '7': case '8': case '9': 613*8e33eff8Schristos state = STATE_EXP_DIGITS; 614*8e33eff8Schristos break; 615*8e33eff8Schristos default: 616*8e33eff8Schristos token_init(&parser->token, parser, 617*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 618*8e33eff8Schristos - token_pos, token_line, token_col); 619*8e33eff8Schristos return true; 620*8e33eff8Schristos } 621*8e33eff8Schristos break; 622*8e33eff8Schristos case STATE_EXP_SIGN: 623*8e33eff8Schristos switch (c) { 624*8e33eff8Schristos case '0': case '1': case '2': case '3': case '4': 625*8e33eff8Schristos case '5': case '6': case '7': case '8': case '9': 626*8e33eff8Schristos state = STATE_EXP_DIGITS; 627*8e33eff8Schristos break; 628*8e33eff8Schristos default: 629*8e33eff8Schristos token_init(&parser->token, parser, 630*8e33eff8Schristos TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 631*8e33eff8Schristos - token_pos, token_line, token_col); 632*8e33eff8Schristos return true; 633*8e33eff8Schristos } 634*8e33eff8Schristos break; 635*8e33eff8Schristos case STATE_EXP_DIGITS: 636*8e33eff8Schristos switch (c) { 637*8e33eff8Schristos case '0': case '1': case '2': case '3': case '4': 638*8e33eff8Schristos case '5': case '6': case '7': case '8': case '9': 639*8e33eff8Schristos break; 640*8e33eff8Schristos default: 641*8e33eff8Schristos token_init(&parser->token, parser, 642*8e33eff8Schristos TOKEN_TYPE_NUMBER, token_pos, parser->pos - 643*8e33eff8Schristos token_pos, token_line, token_col); 644*8e33eff8Schristos state = STATE_ACCEPT; 645*8e33eff8Schristos break; 646*8e33eff8Schristos } 647*8e33eff8Schristos break; 648*8e33eff8Schristos default: 649*8e33eff8Schristos not_reached(); 650*8e33eff8Schristos } 651*8e33eff8Schristos 652*8e33eff8Schristos if (state != STATE_ACCEPT) { 653*8e33eff8Schristos if (c == '\n') { 654*8e33eff8Schristos parser->line++; 655*8e33eff8Schristos parser->col = 0; 656*8e33eff8Schristos } else { 657*8e33eff8Schristos parser->col++; 658*8e33eff8Schristos } 659*8e33eff8Schristos parser->pos++; 660*8e33eff8Schristos } 661*8e33eff8Schristos } 662*8e33eff8Schristos return false; 663*8e33eff8Schristos } 664*8e33eff8Schristos 665*8e33eff8Schristos static bool parser_parse_array(parser_t *parser); 666*8e33eff8Schristos static bool parser_parse_object(parser_t *parser); 667*8e33eff8Schristos 668*8e33eff8Schristos static bool 669*8e33eff8Schristos parser_parse_value(parser_t *parser) { 670*8e33eff8Schristos switch (parser->token.token_type) { 671*8e33eff8Schristos case TOKEN_TYPE_NULL: 672*8e33eff8Schristos case TOKEN_TYPE_FALSE: 673*8e33eff8Schristos case TOKEN_TYPE_TRUE: 674*8e33eff8Schristos case TOKEN_TYPE_STRING: 675*8e33eff8Schristos case TOKEN_TYPE_NUMBER: 676*8e33eff8Schristos return false; 677*8e33eff8Schristos case TOKEN_TYPE_LBRACE: 678*8e33eff8Schristos return parser_parse_object(parser); 679*8e33eff8Schristos case TOKEN_TYPE_LBRACKET: 680*8e33eff8Schristos return parser_parse_array(parser); 681*8e33eff8Schristos default: 682*8e33eff8Schristos return true; 683*8e33eff8Schristos } 684*8e33eff8Schristos not_reached(); 685*8e33eff8Schristos } 686*8e33eff8Schristos 687*8e33eff8Schristos static bool 688*8e33eff8Schristos parser_parse_pair(parser_t *parser) { 689*8e33eff8Schristos assert_d_eq(parser->token.token_type, TOKEN_TYPE_STRING, 690*8e33eff8Schristos "Pair should start with string"); 691*8e33eff8Schristos if (parser_tokenize(parser)) { 692*8e33eff8Schristos return true; 693*8e33eff8Schristos } 694*8e33eff8Schristos switch (parser->token.token_type) { 695*8e33eff8Schristos case TOKEN_TYPE_COLON: 696*8e33eff8Schristos if (parser_tokenize(parser)) { 697*8e33eff8Schristos return true; 698*8e33eff8Schristos } 699*8e33eff8Schristos return parser_parse_value(parser); 700*8e33eff8Schristos default: 701*8e33eff8Schristos return true; 702*8e33eff8Schristos } 703*8e33eff8Schristos } 704*8e33eff8Schristos 705*8e33eff8Schristos static bool 706*8e33eff8Schristos parser_parse_values(parser_t *parser) { 707*8e33eff8Schristos if (parser_parse_value(parser)) { 708*8e33eff8Schristos return true; 709*8e33eff8Schristos } 710*8e33eff8Schristos 711*8e33eff8Schristos while (true) { 712*8e33eff8Schristos if (parser_tokenize(parser)) { 713*8e33eff8Schristos return true; 714*8e33eff8Schristos } 715*8e33eff8Schristos switch (parser->token.token_type) { 716*8e33eff8Schristos case TOKEN_TYPE_COMMA: 717*8e33eff8Schristos if (parser_tokenize(parser)) { 718*8e33eff8Schristos return true; 719*8e33eff8Schristos } 720*8e33eff8Schristos if (parser_parse_value(parser)) { 721*8e33eff8Schristos return true; 722*8e33eff8Schristos } 723*8e33eff8Schristos break; 724*8e33eff8Schristos case TOKEN_TYPE_RBRACKET: 725*8e33eff8Schristos return false; 726*8e33eff8Schristos default: 727*8e33eff8Schristos return true; 728*8e33eff8Schristos } 729*8e33eff8Schristos } 730*8e33eff8Schristos } 731*8e33eff8Schristos 732*8e33eff8Schristos static bool 733*8e33eff8Schristos parser_parse_array(parser_t *parser) { 734*8e33eff8Schristos assert_d_eq(parser->token.token_type, TOKEN_TYPE_LBRACKET, 735*8e33eff8Schristos "Array should start with ["); 736*8e33eff8Schristos if (parser_tokenize(parser)) { 737*8e33eff8Schristos return true; 738*8e33eff8Schristos } 739*8e33eff8Schristos switch (parser->token.token_type) { 740*8e33eff8Schristos case TOKEN_TYPE_RBRACKET: 741*8e33eff8Schristos return false; 742*8e33eff8Schristos default: 743*8e33eff8Schristos return parser_parse_values(parser); 744*8e33eff8Schristos } 745*8e33eff8Schristos not_reached(); 746*8e33eff8Schristos } 747*8e33eff8Schristos 748*8e33eff8Schristos static bool 749*8e33eff8Schristos parser_parse_pairs(parser_t *parser) { 750*8e33eff8Schristos assert_d_eq(parser->token.token_type, TOKEN_TYPE_STRING, 751*8e33eff8Schristos "Object should start with string"); 752*8e33eff8Schristos if (parser_parse_pair(parser)) { 753*8e33eff8Schristos return true; 754*8e33eff8Schristos } 755*8e33eff8Schristos 756*8e33eff8Schristos while (true) { 757*8e33eff8Schristos if (parser_tokenize(parser)) { 758*8e33eff8Schristos return true; 759*8e33eff8Schristos } 760*8e33eff8Schristos switch (parser->token.token_type) { 761*8e33eff8Schristos case TOKEN_TYPE_COMMA: 762*8e33eff8Schristos if (parser_tokenize(parser)) { 763*8e33eff8Schristos return true; 764*8e33eff8Schristos } 765*8e33eff8Schristos switch (parser->token.token_type) { 766*8e33eff8Schristos case TOKEN_TYPE_STRING: 767*8e33eff8Schristos if (parser_parse_pair(parser)) { 768*8e33eff8Schristos return true; 769*8e33eff8Schristos } 770*8e33eff8Schristos break; 771*8e33eff8Schristos default: 772*8e33eff8Schristos return true; 773*8e33eff8Schristos } 774*8e33eff8Schristos break; 775*8e33eff8Schristos case TOKEN_TYPE_RBRACE: 776*8e33eff8Schristos return false; 777*8e33eff8Schristos default: 778*8e33eff8Schristos return true; 779*8e33eff8Schristos } 780*8e33eff8Schristos } 781*8e33eff8Schristos } 782*8e33eff8Schristos 783*8e33eff8Schristos static bool 784*8e33eff8Schristos parser_parse_object(parser_t *parser) { 785*8e33eff8Schristos assert_d_eq(parser->token.token_type, TOKEN_TYPE_LBRACE, 786*8e33eff8Schristos "Object should start with {"); 787*8e33eff8Schristos if (parser_tokenize(parser)) { 788*8e33eff8Schristos return true; 789*8e33eff8Schristos } 790*8e33eff8Schristos switch (parser->token.token_type) { 791*8e33eff8Schristos case TOKEN_TYPE_STRING: 792*8e33eff8Schristos return parser_parse_pairs(parser); 793*8e33eff8Schristos case TOKEN_TYPE_RBRACE: 794*8e33eff8Schristos return false; 795*8e33eff8Schristos default: 796*8e33eff8Schristos return true; 797*8e33eff8Schristos } 798*8e33eff8Schristos not_reached(); 799*8e33eff8Schristos } 800*8e33eff8Schristos 801*8e33eff8Schristos static bool 802*8e33eff8Schristos parser_parse(parser_t *parser) { 803*8e33eff8Schristos if (parser_tokenize(parser)) { 804*8e33eff8Schristos goto label_error; 805*8e33eff8Schristos } 806*8e33eff8Schristos if (parser_parse_value(parser)) { 807*8e33eff8Schristos goto label_error; 808*8e33eff8Schristos } 809*8e33eff8Schristos 810*8e33eff8Schristos if (parser_tokenize(parser)) { 811*8e33eff8Schristos goto label_error; 812*8e33eff8Schristos } 813*8e33eff8Schristos switch (parser->token.token_type) { 814*8e33eff8Schristos case TOKEN_TYPE_EOI: 815*8e33eff8Schristos return false; 816*8e33eff8Schristos default: 817*8e33eff8Schristos goto label_error; 818*8e33eff8Schristos } 819*8e33eff8Schristos not_reached(); 820*8e33eff8Schristos 821*8e33eff8Schristos label_error: 822*8e33eff8Schristos token_error(&parser->token); 823*8e33eff8Schristos return true; 824*8e33eff8Schristos } 825*8e33eff8Schristos 826*8e33eff8Schristos TEST_BEGIN(test_json_parser) { 827*8e33eff8Schristos size_t i; 828*8e33eff8Schristos const char *invalid_inputs[] = { 829*8e33eff8Schristos /* Tokenizer error case tests. */ 830*8e33eff8Schristos "{ \"string\": X }", 831*8e33eff8Schristos "{ \"string\": nXll }", 832*8e33eff8Schristos "{ \"string\": nuXl }", 833*8e33eff8Schristos "{ \"string\": nulX }", 834*8e33eff8Schristos "{ \"string\": nullX }", 835*8e33eff8Schristos "{ \"string\": fXlse }", 836*8e33eff8Schristos "{ \"string\": faXse }", 837*8e33eff8Schristos "{ \"string\": falXe }", 838*8e33eff8Schristos "{ \"string\": falsX }", 839*8e33eff8Schristos "{ \"string\": falseX }", 840*8e33eff8Schristos "{ \"string\": tXue }", 841*8e33eff8Schristos "{ \"string\": trXe }", 842*8e33eff8Schristos "{ \"string\": truX }", 843*8e33eff8Schristos "{ \"string\": trueX }", 844*8e33eff8Schristos "{ \"string\": \"\n\" }", 845*8e33eff8Schristos "{ \"string\": \"\\z\" }", 846*8e33eff8Schristos "{ \"string\": \"\\uX000\" }", 847*8e33eff8Schristos "{ \"string\": \"\\u0X00\" }", 848*8e33eff8Schristos "{ \"string\": \"\\u00X0\" }", 849*8e33eff8Schristos "{ \"string\": \"\\u000X\" }", 850*8e33eff8Schristos "{ \"string\": -X }", 851*8e33eff8Schristos "{ \"string\": 0.X }", 852*8e33eff8Schristos "{ \"string\": 0.0eX }", 853*8e33eff8Schristos "{ \"string\": 0.0e+X }", 854*8e33eff8Schristos 855*8e33eff8Schristos /* Parser error test cases. */ 856*8e33eff8Schristos "{\"string\": }", 857*8e33eff8Schristos "{\"string\" }", 858*8e33eff8Schristos "{\"string\": [ 0 }", 859*8e33eff8Schristos "{\"string\": {\"a\":0, 1 } }", 860*8e33eff8Schristos "{\"string\": {\"a\":0: } }", 861*8e33eff8Schristos "{", 862*8e33eff8Schristos "{}{", 863*8e33eff8Schristos }; 864*8e33eff8Schristos const char *valid_inputs[] = { 865*8e33eff8Schristos /* Token tests. */ 866*8e33eff8Schristos "null", 867*8e33eff8Schristos "false", 868*8e33eff8Schristos "true", 869*8e33eff8Schristos "{}", 870*8e33eff8Schristos "{\"a\": 0}", 871*8e33eff8Schristos "[]", 872*8e33eff8Schristos "[0, 1]", 873*8e33eff8Schristos "0", 874*8e33eff8Schristos "1", 875*8e33eff8Schristos "10", 876*8e33eff8Schristos "-10", 877*8e33eff8Schristos "10.23", 878*8e33eff8Schristos "10.23e4", 879*8e33eff8Schristos "10.23e-4", 880*8e33eff8Schristos "10.23e+4", 881*8e33eff8Schristos "10.23E4", 882*8e33eff8Schristos "10.23E-4", 883*8e33eff8Schristos "10.23E+4", 884*8e33eff8Schristos "-10.23", 885*8e33eff8Schristos "-10.23e4", 886*8e33eff8Schristos "-10.23e-4", 887*8e33eff8Schristos "-10.23e+4", 888*8e33eff8Schristos "-10.23E4", 889*8e33eff8Schristos "-10.23E-4", 890*8e33eff8Schristos "-10.23E+4", 891*8e33eff8Schristos "\"value\"", 892*8e33eff8Schristos "\" \\\" \\/ \\b \\n \\r \\t \\u0abc \\u1DEF \"", 893*8e33eff8Schristos 894*8e33eff8Schristos /* Parser test with various nesting. */ 895*8e33eff8Schristos "{\"a\":null, \"b\":[1,[{\"c\":2},3]], \"d\":{\"e\":true}}", 896*8e33eff8Schristos }; 897*8e33eff8Schristos 898*8e33eff8Schristos for (i = 0; i < sizeof(invalid_inputs)/sizeof(const char *); i++) { 899*8e33eff8Schristos const char *input = invalid_inputs[i]; 900*8e33eff8Schristos parser_t parser; 901*8e33eff8Schristos parser_init(&parser, false); 902*8e33eff8Schristos assert_false(parser_append(&parser, input), 903*8e33eff8Schristos "Unexpected input appending failure"); 904*8e33eff8Schristos assert_true(parser_parse(&parser), 905*8e33eff8Schristos "Unexpected parse success for input: %s", input); 906*8e33eff8Schristos parser_fini(&parser); 907*8e33eff8Schristos } 908*8e33eff8Schristos 909*8e33eff8Schristos for (i = 0; i < sizeof(valid_inputs)/sizeof(const char *); i++) { 910*8e33eff8Schristos const char *input = valid_inputs[i]; 911*8e33eff8Schristos parser_t parser; 912*8e33eff8Schristos parser_init(&parser, true); 913*8e33eff8Schristos assert_false(parser_append(&parser, input), 914*8e33eff8Schristos "Unexpected input appending failure"); 915*8e33eff8Schristos assert_false(parser_parse(&parser), 916*8e33eff8Schristos "Unexpected parse error for input: %s", input); 917*8e33eff8Schristos parser_fini(&parser); 918*8e33eff8Schristos } 919*8e33eff8Schristos } 920*8e33eff8Schristos TEST_END 921*8e33eff8Schristos 922*8e33eff8Schristos void 923*8e33eff8Schristos write_cb(void *opaque, const char *str) { 924*8e33eff8Schristos parser_t *parser = (parser_t *)opaque; 925*8e33eff8Schristos if (parser_append(parser, str)) { 926*8e33eff8Schristos test_fail("Unexpected input appending failure"); 927*8e33eff8Schristos } 928*8e33eff8Schristos } 929*8e33eff8Schristos 930*8e33eff8Schristos TEST_BEGIN(test_stats_print_json) { 931*8e33eff8Schristos const char *opts[] = { 932*8e33eff8Schristos "J", 933*8e33eff8Schristos "Jg", 934*8e33eff8Schristos "Jm", 935*8e33eff8Schristos "Jd", 936*8e33eff8Schristos "Jmd", 937*8e33eff8Schristos "Jgd", 938*8e33eff8Schristos "Jgm", 939*8e33eff8Schristos "Jgmd", 940*8e33eff8Schristos "Ja", 941*8e33eff8Schristos "Jb", 942*8e33eff8Schristos "Jl", 943*8e33eff8Schristos "Jx", 944*8e33eff8Schristos "Jbl", 945*8e33eff8Schristos "Jal", 946*8e33eff8Schristos "Jab", 947*8e33eff8Schristos "Jabl", 948*8e33eff8Schristos "Jax", 949*8e33eff8Schristos "Jbx", 950*8e33eff8Schristos "Jlx", 951*8e33eff8Schristos "Jablx", 952*8e33eff8Schristos "Jgmdablx", 953*8e33eff8Schristos }; 954*8e33eff8Schristos unsigned arena_ind, i; 955*8e33eff8Schristos 956*8e33eff8Schristos for (i = 0; i < 3; i++) { 957*8e33eff8Schristos unsigned j; 958*8e33eff8Schristos 959*8e33eff8Schristos switch (i) { 960*8e33eff8Schristos case 0: 961*8e33eff8Schristos break; 962*8e33eff8Schristos case 1: { 963*8e33eff8Schristos size_t sz = sizeof(arena_ind); 964*8e33eff8Schristos assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, 965*8e33eff8Schristos &sz, NULL, 0), 0, "Unexpected mallctl failure"); 966*8e33eff8Schristos break; 967*8e33eff8Schristos } case 2: { 968*8e33eff8Schristos size_t mib[3]; 969*8e33eff8Schristos size_t miblen = sizeof(mib)/sizeof(size_t); 970*8e33eff8Schristos assert_d_eq(mallctlnametomib("arena.0.destroy", 971*8e33eff8Schristos mib, &miblen), 0, 972*8e33eff8Schristos "Unexpected mallctlnametomib failure"); 973*8e33eff8Schristos mib[1] = arena_ind; 974*8e33eff8Schristos assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 975*8e33eff8Schristos 0), 0, "Unexpected mallctlbymib failure"); 976*8e33eff8Schristos break; 977*8e33eff8Schristos } default: 978*8e33eff8Schristos not_reached(); 979*8e33eff8Schristos } 980*8e33eff8Schristos 981*8e33eff8Schristos for (j = 0; j < sizeof(opts)/sizeof(const char *); j++) { 982*8e33eff8Schristos parser_t parser; 983*8e33eff8Schristos 984*8e33eff8Schristos parser_init(&parser, true); 985*8e33eff8Schristos malloc_stats_print(write_cb, (void *)&parser, opts[j]); 986*8e33eff8Schristos assert_false(parser_parse(&parser), 987*8e33eff8Schristos "Unexpected parse error, opts=\"%s\"", opts[j]); 988*8e33eff8Schristos parser_fini(&parser); 989*8e33eff8Schristos } 990*8e33eff8Schristos } 991*8e33eff8Schristos } 992*8e33eff8Schristos TEST_END 993*8e33eff8Schristos 994*8e33eff8Schristos int 995*8e33eff8Schristos main(void) { 996*8e33eff8Schristos return test( 997*8e33eff8Schristos test_json_parser, 998*8e33eff8Schristos test_stats_print_json); 999*8e33eff8Schristos } 1000