From 530609aa4263bee5b5ca205d83f0dbad098d0465 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Fri, 17 Jan 2020 14:06:41 -0500 Subject: [PATCH] Remove jsonapi.c's lex_accept(). At first glance, this function seems useful, but it actually increases the amount of code required rather than decreasing it. Inline the logic into the callers instead; most callers don't use the 'lexeme' argument for anything and as a result considerable simplification is possible. Along the way, fix the header comment for the nearby function lex_expect(), which mislabeled it as lex_accept(). Patch by me, reviewed by David Steele, Mark Dilger, and Andrew Dunstan. Discussion: http://postgr.es/m/CA+TgmoYfOXhd27MUDGioVh6QtpD0C1K-f6ObSA10AWiHBAL5bA@mail.gmail.com --- src/backend/utils/adt/jsonapi.c | 124 +++++++++++++------------------- 1 file changed, 51 insertions(+), 73 deletions(-) diff --git a/src/backend/utils/adt/jsonapi.c b/src/backend/utils/adt/jsonapi.c index fc8af9f861..9e14306b6f 100644 --- a/src/backend/utils/adt/jsonapi.c +++ b/src/backend/utils/adt/jsonapi.c @@ -69,44 +69,7 @@ lex_peek(JsonLexContext *lex) } /* - * lex_accept - * - * accept the look_ahead token and move the lexer to the next token if the - * look_ahead token matches the token parameter. In that case, and if required, - * also hand back the de-escaped lexeme. - * - * returns true if the token matched, false otherwise. - */ -static inline bool -lex_accept(JsonLexContext *lex, JsonTokenType token, char **lexeme) -{ - if (lex->token_type == token) - { - if (lexeme != NULL) - { - if (lex->token_type == JSON_TOKEN_STRING) - { - if (lex->strval != NULL) - *lexeme = pstrdup(lex->strval->data); - } - else - { - int len = (lex->token_terminator - lex->token_start); - char *tokstr = palloc(len + 1); - - memcpy(tokstr, lex->token_start, len); - tokstr[len] = '\0'; - *lexeme = tokstr; - } - } - json_lex(lex); - return true; - } - return false; -} - -/* - * lex_accept + * lex_expect * * move the lexer to the next token if the current look_ahead token matches * the parameter token. Otherwise, report an error. @@ -114,7 +77,9 @@ lex_accept(JsonLexContext *lex, JsonTokenType token, char **lexeme) static inline void lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token) { - if (!lex_accept(lex, token, NULL)) + if (lex_peek(lex) == token) + json_lex(lex); + else report_parse_error(ctx, lex); } @@ -260,12 +225,14 @@ json_count_array_elements(JsonLexContext *lex) lex_expect(JSON_PARSE_ARRAY_START, ©lex, JSON_TOKEN_ARRAY_START); if (lex_peek(©lex) != JSON_TOKEN_ARRAY_END) { - do + while (1) { count++; parse_array_element(©lex, &nullSemAction); + if (copylex.token_type != JSON_TOKEN_COMMA) + break; + json_lex(©lex); } - while (lex_accept(©lex, JSON_TOKEN_COMMA, NULL)); } lex_expect(JSON_PARSE_ARRAY_NEXT, ©lex, JSON_TOKEN_ARRAY_END); @@ -286,35 +253,41 @@ parse_scalar(JsonLexContext *lex, JsonSemAction *sem) { char *val = NULL; json_scalar_action sfunc = sem->scalar; - char **valaddr; JsonTokenType tok = lex_peek(lex); - valaddr = sfunc == NULL ? NULL : &val; - /* a scalar must be a string, a number, true, false, or null */ - switch (tok) + if (tok != JSON_TOKEN_STRING && tok != JSON_TOKEN_NUMBER && + tok != JSON_TOKEN_TRUE && tok != JSON_TOKEN_FALSE && + tok != JSON_TOKEN_NULL) + report_parse_error(JSON_PARSE_VALUE, lex); + + /* if no semantic function, just consume the token */ + if (sfunc == NULL) { - case JSON_TOKEN_TRUE: - lex_accept(lex, JSON_TOKEN_TRUE, valaddr); - break; - case JSON_TOKEN_FALSE: - lex_accept(lex, JSON_TOKEN_FALSE, valaddr); - break; - case JSON_TOKEN_NULL: - lex_accept(lex, JSON_TOKEN_NULL, valaddr); - break; - case JSON_TOKEN_NUMBER: - lex_accept(lex, JSON_TOKEN_NUMBER, valaddr); - break; - case JSON_TOKEN_STRING: - lex_accept(lex, JSON_TOKEN_STRING, valaddr); - break; - default: - report_parse_error(JSON_PARSE_VALUE, lex); + json_lex(lex); + return; } - if (sfunc != NULL) - (*sfunc) (sem->semstate, val, tok); + /* extract the de-escaped string value, or the raw lexeme */ + if (lex_peek(lex) == JSON_TOKEN_STRING) + { + if (lex->strval != NULL) + val = pstrdup(lex->strval->data); + } + else + { + int len = (lex->token_terminator - lex->token_start); + + val = palloc(len + 1); + memcpy(val, lex->token_start, len); + val[len] = '\0'; + } + + /* consume the token */ + json_lex(lex); + + /* invoke the callback */ + (*sfunc) (sem->semstate, val, tok); } static void @@ -330,14 +303,13 @@ parse_object_field(JsonLexContext *lex, JsonSemAction *sem) json_ofield_action ostart = sem->object_field_start; json_ofield_action oend = sem->object_field_end; bool isnull; - char **fnameaddr = NULL; JsonTokenType tok; - if (ostart != NULL || oend != NULL) - fnameaddr = &fname; - - if (!lex_accept(lex, JSON_TOKEN_STRING, fnameaddr)) + if (lex_peek(lex) != JSON_TOKEN_STRING) report_parse_error(JSON_PARSE_STRING, lex); + if ((ostart != NULL || oend != NULL) && lex->strval != NULL) + fname = pstrdup(lex->strval->data); + json_lex(lex); lex_expect(JSON_PARSE_OBJECT_LABEL, lex, JSON_TOKEN_COLON); @@ -387,16 +359,19 @@ parse_object(JsonLexContext *lex, JsonSemAction *sem) */ lex->lex_level++; - /* we know this will succeed, just clearing the token */ - lex_expect(JSON_PARSE_OBJECT_START, lex, JSON_TOKEN_OBJECT_START); + Assert(lex_peek(lex) == JSON_TOKEN_OBJECT_START); + json_lex(lex); tok = lex_peek(lex); switch (tok) { case JSON_TOKEN_STRING: parse_object_field(lex, sem); - while (lex_accept(lex, JSON_TOKEN_COMMA, NULL)) + while (lex_peek(lex) == JSON_TOKEN_COMMA) + { + json_lex(lex); parse_object_field(lex, sem); + } break; case JSON_TOKEN_OBJECT_END: break; @@ -473,8 +448,11 @@ parse_array(JsonLexContext *lex, JsonSemAction *sem) parse_array_element(lex, sem); - while (lex_accept(lex, JSON_TOKEN_COMMA, NULL)) + while (lex_peek(lex) == JSON_TOKEN_COMMA) + { + json_lex(lex); parse_array_element(lex, sem); + } } lex_expect(JSON_PARSE_ARRAY_NEXT, lex, JSON_TOKEN_ARRAY_END);