123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999 |
- #include "test/jemalloc_test.h"
- #include "jemalloc/internal/util.h"
- typedef enum {
- TOKEN_TYPE_NONE,
- TOKEN_TYPE_ERROR,
- TOKEN_TYPE_EOI,
- TOKEN_TYPE_NULL,
- TOKEN_TYPE_FALSE,
- TOKEN_TYPE_TRUE,
- TOKEN_TYPE_LBRACKET,
- TOKEN_TYPE_RBRACKET,
- TOKEN_TYPE_LBRACE,
- TOKEN_TYPE_RBRACE,
- TOKEN_TYPE_COLON,
- TOKEN_TYPE_COMMA,
- TOKEN_TYPE_STRING,
- TOKEN_TYPE_NUMBER
- } token_type_t;
- typedef struct parser_s parser_t;
- typedef struct {
- parser_t *parser;
- token_type_t token_type;
- size_t pos;
- size_t len;
- size_t line;
- size_t col;
- } token_t;
- struct parser_s {
- bool verbose;
- char *buf; /* '\0'-terminated. */
- size_t len; /* Number of characters preceding '\0' in buf. */
- size_t pos;
- size_t line;
- size_t col;
- token_t token;
- };
- static void
- token_init(token_t *token, parser_t *parser, token_type_t token_type,
- size_t pos, size_t len, size_t line, size_t col) {
- token->parser = parser;
- token->token_type = token_type;
- token->pos = pos;
- token->len = len;
- token->line = line;
- token->col = col;
- }
- static void
- token_error(token_t *token) {
- if (!token->parser->verbose) {
- return;
- }
- switch (token->token_type) {
- case TOKEN_TYPE_NONE:
- not_reached();
- case TOKEN_TYPE_ERROR:
- malloc_printf("%zu:%zu: Unexpected character in token: ",
- token->line, token->col);
- break;
- default:
- malloc_printf("%zu:%zu: Unexpected token: ", token->line,
- token->col);
- break;
- }
- UNUSED ssize_t err = malloc_write_fd(STDERR_FILENO,
- &token->parser->buf[token->pos], token->len);
- malloc_printf("\n");
- }
- static void
- parser_init(parser_t *parser, bool verbose) {
- parser->verbose = verbose;
- parser->buf = NULL;
- parser->len = 0;
- parser->pos = 0;
- parser->line = 1;
- parser->col = 0;
- }
- static void
- parser_fini(parser_t *parser) {
- if (parser->buf != NULL) {
- dallocx(parser->buf, MALLOCX_TCACHE_NONE);
- }
- }
- static bool
- parser_append(parser_t *parser, const char *str) {
- size_t len = strlen(str);
- char *buf = (parser->buf == NULL) ? mallocx(len + 1,
- MALLOCX_TCACHE_NONE) : rallocx(parser->buf, parser->len + len + 1,
- MALLOCX_TCACHE_NONE);
- if (buf == NULL) {
- return true;
- }
- memcpy(&buf[parser->len], str, len + 1);
- parser->buf = buf;
- parser->len += len;
- return false;
- }
- static bool
- parser_tokenize(parser_t *parser) {
- enum {
- STATE_START,
- STATE_EOI,
- STATE_N, STATE_NU, STATE_NUL, STATE_NULL,
- STATE_F, STATE_FA, STATE_FAL, STATE_FALS, STATE_FALSE,
- STATE_T, STATE_TR, STATE_TRU, STATE_TRUE,
- STATE_LBRACKET,
- STATE_RBRACKET,
- STATE_LBRACE,
- STATE_RBRACE,
- STATE_COLON,
- STATE_COMMA,
- STATE_CHARS,
- STATE_CHAR_ESCAPE,
- STATE_CHAR_U, STATE_CHAR_UD, STATE_CHAR_UDD, STATE_CHAR_UDDD,
- STATE_STRING,
- STATE_MINUS,
- STATE_LEADING_ZERO,
- STATE_DIGITS,
- STATE_DECIMAL,
- STATE_FRAC_DIGITS,
- STATE_EXP,
- STATE_EXP_SIGN,
- STATE_EXP_DIGITS,
- STATE_ACCEPT
- } state = STATE_START;
- size_t token_pos JEMALLOC_CC_SILENCE_INIT(0);
- size_t token_line JEMALLOC_CC_SILENCE_INIT(1);
- size_t token_col JEMALLOC_CC_SILENCE_INIT(0);
- assert_zu_le(parser->pos, parser->len,
- "Position is past end of buffer");
- while (state != STATE_ACCEPT) {
- char c = parser->buf[parser->pos];
- switch (state) {
- case STATE_START:
- token_pos = parser->pos;
- token_line = parser->line;
- token_col = parser->col;
- switch (c) {
- case ' ': case '\b': case '\n': case '\r': case '\t':
- break;
- case '\0':
- state = STATE_EOI;
- break;
- case 'n':
- state = STATE_N;
- break;
- case 'f':
- state = STATE_F;
- break;
- case 't':
- state = STATE_T;
- break;
- case '[':
- state = STATE_LBRACKET;
- break;
- case ']':
- state = STATE_RBRACKET;
- break;
- case '{':
- state = STATE_LBRACE;
- break;
- case '}':
- state = STATE_RBRACE;
- break;
- case ':':
- state = STATE_COLON;
- break;
- case ',':
- state = STATE_COMMA;
- break;
- case '"':
- state = STATE_CHARS;
- break;
- case '-':
- state = STATE_MINUS;
- break;
- case '0':
- state = STATE_LEADING_ZERO;
- break;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- state = STATE_DIGITS;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_EOI:
- token_init(&parser->token, parser,
- TOKEN_TYPE_EOI, token_pos, parser->pos -
- token_pos, token_line, token_col);
- state = STATE_ACCEPT;
- break;
- case STATE_N:
- switch (c) {
- case 'u':
- state = STATE_NU;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_NU:
- switch (c) {
- case 'l':
- state = STATE_NUL;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_NUL:
- switch (c) {
- case 'l':
- state = STATE_NULL;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_NULL:
- switch (c) {
- case ' ': case '\b': case '\n': case '\r': case '\t':
- case '\0':
- case '[': case ']': case '{': case '}': case ':':
- case ',':
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- token_init(&parser->token, parser, TOKEN_TYPE_NULL,
- token_pos, parser->pos - token_pos, token_line,
- token_col);
- state = STATE_ACCEPT;
- break;
- case STATE_F:
- switch (c) {
- case 'a':
- state = STATE_FA;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_FA:
- switch (c) {
- case 'l':
- state = STATE_FAL;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_FAL:
- switch (c) {
- case 's':
- state = STATE_FALS;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_FALS:
- switch (c) {
- case 'e':
- state = STATE_FALSE;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_FALSE:
- switch (c) {
- case ' ': case '\b': case '\n': case '\r': case '\t':
- case '\0':
- case '[': case ']': case '{': case '}': case ':':
- case ',':
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- token_init(&parser->token, parser,
- TOKEN_TYPE_FALSE, token_pos, parser->pos -
- token_pos, token_line, token_col);
- state = STATE_ACCEPT;
- break;
- case STATE_T:
- switch (c) {
- case 'r':
- state = STATE_TR;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_TR:
- switch (c) {
- case 'u':
- state = STATE_TRU;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_TRU:
- switch (c) {
- case 'e':
- state = STATE_TRUE;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_TRUE:
- switch (c) {
- case ' ': case '\b': case '\n': case '\r': case '\t':
- case '\0':
- case '[': case ']': case '{': case '}': case ':':
- case ',':
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- token_init(&parser->token, parser, TOKEN_TYPE_TRUE,
- token_pos, parser->pos - token_pos, token_line,
- token_col);
- state = STATE_ACCEPT;
- break;
- case STATE_LBRACKET:
- token_init(&parser->token, parser, TOKEN_TYPE_LBRACKET,
- token_pos, parser->pos - token_pos, token_line,
- token_col);
- state = STATE_ACCEPT;
- break;
- case STATE_RBRACKET:
- token_init(&parser->token, parser, TOKEN_TYPE_RBRACKET,
- token_pos, parser->pos - token_pos, token_line,
- token_col);
- state = STATE_ACCEPT;
- break;
- case STATE_LBRACE:
- token_init(&parser->token, parser, TOKEN_TYPE_LBRACE,
- token_pos, parser->pos - token_pos, token_line,
- token_col);
- state = STATE_ACCEPT;
- break;
- case STATE_RBRACE:
- token_init(&parser->token, parser, TOKEN_TYPE_RBRACE,
- token_pos, parser->pos - token_pos, token_line,
- token_col);
- state = STATE_ACCEPT;
- break;
- case STATE_COLON:
- token_init(&parser->token, parser, TOKEN_TYPE_COLON,
- token_pos, parser->pos - token_pos, token_line,
- token_col);
- state = STATE_ACCEPT;
- break;
- case STATE_COMMA:
- token_init(&parser->token, parser, TOKEN_TYPE_COMMA,
- token_pos, parser->pos - token_pos, token_line,
- token_col);
- state = STATE_ACCEPT;
- break;
- case STATE_CHARS:
- switch (c) {
- case '\\':
- state = STATE_CHAR_ESCAPE;
- break;
- case '"':
- state = STATE_STRING;
- break;
- case 0x00: case 0x01: case 0x02: case 0x03: case 0x04:
- case 0x05: case 0x06: case 0x07: case 0x08: case 0x09:
- case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e:
- case 0x0f: case 0x10: case 0x11: case 0x12: case 0x13:
- case 0x14: case 0x15: case 0x16: case 0x17: case 0x18:
- case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d:
- case 0x1e: case 0x1f:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- default:
- break;
- }
- break;
- case STATE_CHAR_ESCAPE:
- switch (c) {
- case '"': case '\\': case '/': case 'b': case 'n':
- case 'r': case 't':
- state = STATE_CHARS;
- break;
- case 'u':
- state = STATE_CHAR_U;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_CHAR_U:
- switch (c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case 'a': case 'b': case 'c': case 'd': case 'e':
- case 'f':
- case 'A': case 'B': case 'C': case 'D': case 'E':
- case 'F':
- state = STATE_CHAR_UD;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_CHAR_UD:
- switch (c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case 'a': case 'b': case 'c': case 'd': case 'e':
- case 'f':
- case 'A': case 'B': case 'C': case 'D': case 'E':
- case 'F':
- state = STATE_CHAR_UDD;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_CHAR_UDD:
- switch (c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case 'a': case 'b': case 'c': case 'd': case 'e':
- case 'f':
- case 'A': case 'B': case 'C': case 'D': case 'E':
- case 'F':
- state = STATE_CHAR_UDDD;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_CHAR_UDDD:
- switch (c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case 'a': case 'b': case 'c': case 'd': case 'e':
- case 'f':
- case 'A': case 'B': case 'C': case 'D': case 'E':
- case 'F':
- state = STATE_CHARS;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_STRING:
- token_init(&parser->token, parser, TOKEN_TYPE_STRING,
- token_pos, parser->pos - token_pos, token_line,
- token_col);
- state = STATE_ACCEPT;
- break;
- case STATE_MINUS:
- switch (c) {
- case '0':
- state = STATE_LEADING_ZERO;
- break;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- state = STATE_DIGITS;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_LEADING_ZERO:
- switch (c) {
- case '.':
- state = STATE_DECIMAL;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_NUMBER, token_pos, parser->pos -
- token_pos, token_line, token_col);
- state = STATE_ACCEPT;
- break;
- }
- break;
- case STATE_DIGITS:
- switch (c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- break;
- case '.':
- state = STATE_DECIMAL;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_NUMBER, token_pos, parser->pos -
- token_pos, token_line, token_col);
- state = STATE_ACCEPT;
- break;
- }
- break;
- case STATE_DECIMAL:
- switch (c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- state = STATE_FRAC_DIGITS;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_FRAC_DIGITS:
- switch (c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- break;
- case 'e': case 'E':
- state = STATE_EXP;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_NUMBER, token_pos, parser->pos -
- token_pos, token_line, token_col);
- state = STATE_ACCEPT;
- break;
- }
- break;
- case STATE_EXP:
- switch (c) {
- case '-': case '+':
- state = STATE_EXP_SIGN;
- break;
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- state = STATE_EXP_DIGITS;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_EXP_SIGN:
- switch (c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- state = STATE_EXP_DIGITS;
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_ERROR, token_pos, parser->pos + 1
- - token_pos, token_line, token_col);
- return true;
- }
- break;
- case STATE_EXP_DIGITS:
- switch (c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- break;
- default:
- token_init(&parser->token, parser,
- TOKEN_TYPE_NUMBER, token_pos, parser->pos -
- token_pos, token_line, token_col);
- state = STATE_ACCEPT;
- break;
- }
- break;
- default:
- not_reached();
- }
- if (state != STATE_ACCEPT) {
- if (c == '\n') {
- parser->line++;
- parser->col = 0;
- } else {
- parser->col++;
- }
- parser->pos++;
- }
- }
- return false;
- }
- static bool parser_parse_array(parser_t *parser);
- static bool parser_parse_object(parser_t *parser);
- static bool
- parser_parse_value(parser_t *parser) {
- switch (parser->token.token_type) {
- case TOKEN_TYPE_NULL:
- case TOKEN_TYPE_FALSE:
- case TOKEN_TYPE_TRUE:
- case TOKEN_TYPE_STRING:
- case TOKEN_TYPE_NUMBER:
- return false;
- case TOKEN_TYPE_LBRACE:
- return parser_parse_object(parser);
- case TOKEN_TYPE_LBRACKET:
- return parser_parse_array(parser);
- default:
- return true;
- }
- not_reached();
- }
- static bool
- parser_parse_pair(parser_t *parser) {
- assert_d_eq(parser->token.token_type, TOKEN_TYPE_STRING,
- "Pair should start with string");
- if (parser_tokenize(parser)) {
- return true;
- }
- switch (parser->token.token_type) {
- case TOKEN_TYPE_COLON:
- if (parser_tokenize(parser)) {
- return true;
- }
- return parser_parse_value(parser);
- default:
- return true;
- }
- }
- static bool
- parser_parse_values(parser_t *parser) {
- if (parser_parse_value(parser)) {
- return true;
- }
- while (true) {
- if (parser_tokenize(parser)) {
- return true;
- }
- switch (parser->token.token_type) {
- case TOKEN_TYPE_COMMA:
- if (parser_tokenize(parser)) {
- return true;
- }
- if (parser_parse_value(parser)) {
- return true;
- }
- break;
- case TOKEN_TYPE_RBRACKET:
- return false;
- default:
- return true;
- }
- }
- }
- static bool
- parser_parse_array(parser_t *parser) {
- assert_d_eq(parser->token.token_type, TOKEN_TYPE_LBRACKET,
- "Array should start with [");
- if (parser_tokenize(parser)) {
- return true;
- }
- switch (parser->token.token_type) {
- case TOKEN_TYPE_RBRACKET:
- return false;
- default:
- return parser_parse_values(parser);
- }
- not_reached();
- }
- static bool
- parser_parse_pairs(parser_t *parser) {
- assert_d_eq(parser->token.token_type, TOKEN_TYPE_STRING,
- "Object should start with string");
- if (parser_parse_pair(parser)) {
- return true;
- }
- while (true) {
- if (parser_tokenize(parser)) {
- return true;
- }
- switch (parser->token.token_type) {
- case TOKEN_TYPE_COMMA:
- if (parser_tokenize(parser)) {
- return true;
- }
- switch (parser->token.token_type) {
- case TOKEN_TYPE_STRING:
- if (parser_parse_pair(parser)) {
- return true;
- }
- break;
- default:
- return true;
- }
- break;
- case TOKEN_TYPE_RBRACE:
- return false;
- default:
- return true;
- }
- }
- }
- static bool
- parser_parse_object(parser_t *parser) {
- assert_d_eq(parser->token.token_type, TOKEN_TYPE_LBRACE,
- "Object should start with {");
- if (parser_tokenize(parser)) {
- return true;
- }
- switch (parser->token.token_type) {
- case TOKEN_TYPE_STRING:
- return parser_parse_pairs(parser);
- case TOKEN_TYPE_RBRACE:
- return false;
- default:
- return true;
- }
- not_reached();
- }
- static bool
- parser_parse(parser_t *parser) {
- if (parser_tokenize(parser)) {
- goto label_error;
- }
- if (parser_parse_value(parser)) {
- goto label_error;
- }
- if (parser_tokenize(parser)) {
- goto label_error;
- }
- switch (parser->token.token_type) {
- case TOKEN_TYPE_EOI:
- return false;
- default:
- goto label_error;
- }
- not_reached();
- label_error:
- token_error(&parser->token);
- return true;
- }
- TEST_BEGIN(test_json_parser) {
- size_t i;
- const char *invalid_inputs[] = {
- /* Tokenizer error case tests. */
- "{ \"string\": X }",
- "{ \"string\": nXll }",
- "{ \"string\": nuXl }",
- "{ \"string\": nulX }",
- "{ \"string\": nullX }",
- "{ \"string\": fXlse }",
- "{ \"string\": faXse }",
- "{ \"string\": falXe }",
- "{ \"string\": falsX }",
- "{ \"string\": falseX }",
- "{ \"string\": tXue }",
- "{ \"string\": trXe }",
- "{ \"string\": truX }",
- "{ \"string\": trueX }",
- "{ \"string\": \"\n\" }",
- "{ \"string\": \"\\z\" }",
- "{ \"string\": \"\\uX000\" }",
- "{ \"string\": \"\\u0X00\" }",
- "{ \"string\": \"\\u00X0\" }",
- "{ \"string\": \"\\u000X\" }",
- "{ \"string\": -X }",
- "{ \"string\": 0.X }",
- "{ \"string\": 0.0eX }",
- "{ \"string\": 0.0e+X }",
- /* Parser error test cases. */
- "{\"string\": }",
- "{\"string\" }",
- "{\"string\": [ 0 }",
- "{\"string\": {\"a\":0, 1 } }",
- "{\"string\": {\"a\":0: } }",
- "{",
- "{}{",
- };
- const char *valid_inputs[] = {
- /* Token tests. */
- "null",
- "false",
- "true",
- "{}",
- "{\"a\": 0}",
- "[]",
- "[0, 1]",
- "0",
- "1",
- "10",
- "-10",
- "10.23",
- "10.23e4",
- "10.23e-4",
- "10.23e+4",
- "10.23E4",
- "10.23E-4",
- "10.23E+4",
- "-10.23",
- "-10.23e4",
- "-10.23e-4",
- "-10.23e+4",
- "-10.23E4",
- "-10.23E-4",
- "-10.23E+4",
- "\"value\"",
- "\" \\\" \\/ \\b \\n \\r \\t \\u0abc \\u1DEF \"",
- /* Parser test with various nesting. */
- "{\"a\":null, \"b\":[1,[{\"c\":2},3]], \"d\":{\"e\":true}}",
- };
- for (i = 0; i < sizeof(invalid_inputs)/sizeof(const char *); i++) {
- const char *input = invalid_inputs[i];
- parser_t parser;
- parser_init(&parser, false);
- assert_false(parser_append(&parser, input),
- "Unexpected input appending failure");
- assert_true(parser_parse(&parser),
- "Unexpected parse success for input: %s", input);
- parser_fini(&parser);
- }
- for (i = 0; i < sizeof(valid_inputs)/sizeof(const char *); i++) {
- const char *input = valid_inputs[i];
- parser_t parser;
- parser_init(&parser, true);
- assert_false(parser_append(&parser, input),
- "Unexpected input appending failure");
- assert_false(parser_parse(&parser),
- "Unexpected parse error for input: %s", input);
- parser_fini(&parser);
- }
- }
- TEST_END
- void
- write_cb(void *opaque, const char *str) {
- parser_t *parser = (parser_t *)opaque;
- if (parser_append(parser, str)) {
- test_fail("Unexpected input appending failure");
- }
- }
- TEST_BEGIN(test_stats_print_json) {
- const char *opts[] = {
- "J",
- "Jg",
- "Jm",
- "Jd",
- "Jmd",
- "Jgd",
- "Jgm",
- "Jgmd",
- "Ja",
- "Jb",
- "Jl",
- "Jx",
- "Jbl",
- "Jal",
- "Jab",
- "Jabl",
- "Jax",
- "Jbx",
- "Jlx",
- "Jablx",
- "Jgmdablx",
- };
- unsigned arena_ind, i;
- for (i = 0; i < 3; i++) {
- unsigned j;
- switch (i) {
- case 0:
- break;
- case 1: {
- size_t sz = sizeof(arena_ind);
- assert_d_eq(mallctl("arenas.create", (void *)&arena_ind,
- &sz, NULL, 0), 0, "Unexpected mallctl failure");
- break;
- } case 2: {
- size_t mib[3];
- size_t miblen = sizeof(mib)/sizeof(size_t);
- assert_d_eq(mallctlnametomib("arena.0.destroy",
- mib, &miblen), 0,
- "Unexpected mallctlnametomib failure");
- mib[1] = arena_ind;
- assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL,
- 0), 0, "Unexpected mallctlbymib failure");
- break;
- } default:
- not_reached();
- }
- for (j = 0; j < sizeof(opts)/sizeof(const char *); j++) {
- parser_t parser;
- parser_init(&parser, true);
- malloc_stats_print(write_cb, (void *)&parser, opts[j]);
- assert_false(parser_parse(&parser),
- "Unexpected parse error, opts=\"%s\"", opts[j]);
- parser_fini(&parser);
- }
- }
- }
- TEST_END
- int
- main(void) {
- return test(
- test_json_parser,
- test_stats_print_json);
- }
|