PostgreSQL Source Code  git master
jsonapi.c File Reference
#include "postgres.h"
#include "common/jsonapi.h"
#include "mb/pg_wchar.h"
#include "port/pg_lfind.h"
#include "miscadmin.h"
Include dependency graph for jsonapi.c:

Go to the source code of this file.

Macros

#define JSON_ALPHANUMERIC_CHAR(c)
 

Enumerations

enum  JsonParseContext {
  JSON_PARSE_VALUE , JSON_PARSE_STRING , JSON_PARSE_ARRAY_START , JSON_PARSE_ARRAY_NEXT ,
  JSON_PARSE_OBJECT_START , JSON_PARSE_OBJECT_LABEL , JSON_PARSE_OBJECT_NEXT , JSON_PARSE_OBJECT_COMMA ,
  JSON_PARSE_END
}
 

Functions

static JsonParseErrorType json_lex_string (JsonLexContext *lex)
 
static JsonParseErrorType json_lex_number (JsonLexContext *lex, char *s, bool *num_err, int *total_len)
 
static JsonParseErrorType parse_scalar (JsonLexContext *lex, JsonSemAction *sem)
 
static JsonParseErrorType parse_object_field (JsonLexContext *lex, JsonSemAction *sem)
 
static JsonParseErrorType parse_object (JsonLexContext *lex, JsonSemAction *sem)
 
static JsonParseErrorType parse_array_element (JsonLexContext *lex, JsonSemAction *sem)
 
static JsonParseErrorType parse_array (JsonLexContext *lex, JsonSemAction *sem)
 
static JsonParseErrorType report_parse_error (JsonParseContext ctx, JsonLexContext *lex)
 
static JsonTokenType lex_peek (JsonLexContext *lex)
 
static JsonParseErrorType lex_expect (JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
 
bool IsValidJsonNumber (const char *str, int len)
 
JsonLexContextmakeJsonLexContextCstringLen (char *json, int len, int encoding, bool need_escapes)
 
JsonParseErrorType pg_parse_json (JsonLexContext *lex, JsonSemAction *sem)
 
JsonParseErrorType json_count_array_elements (JsonLexContext *lex, int *elements)
 
JsonParseErrorType json_lex (JsonLexContext *lex)
 
static char * extract_token (JsonLexContext *lex)
 
char * json_errdetail (JsonParseErrorType error, JsonLexContext *lex)
 

Variables

JsonSemAction nullSemAction
 

Macro Definition Documentation

◆ JSON_ALPHANUMERIC_CHAR

#define JSON_ALPHANUMERIC_CHAR (   c)
Value:
(((c) >= 'a' && (c) <= 'z') || \
((c) >= 'A' && (c) <= 'Z') || \
((c) >= '0' && (c) <= '9') || \
(c) == '_' || \
IS_HIGHBIT_SET(c))
char * c

Definition at line 92 of file jsonapi.c.

Enumeration Type Documentation

◆ JsonParseContext

Enumerator
JSON_PARSE_VALUE 
JSON_PARSE_STRING 
JSON_PARSE_ARRAY_START 
JSON_PARSE_ARRAY_NEXT 
JSON_PARSE_OBJECT_START 
JSON_PARSE_OBJECT_LABEL 
JSON_PARSE_OBJECT_NEXT 
JSON_PARSE_OBJECT_COMMA 
JSON_PARSE_END 

Definition at line 33 of file jsonapi.c.

34 {
35  JSON_PARSE_VALUE, /* expecting a value */
36  JSON_PARSE_STRING, /* expecting a string (for a field name) */
37  JSON_PARSE_ARRAY_START, /* saw '[', expecting value or ']' */
38  JSON_PARSE_ARRAY_NEXT, /* saw array element, expecting ',' or ']' */
39  JSON_PARSE_OBJECT_START, /* saw '{', expecting label or '}' */
40  JSON_PARSE_OBJECT_LABEL, /* saw object label, expecting ':' */
41  JSON_PARSE_OBJECT_NEXT, /* saw object value, expecting ',' or '}' */
42  JSON_PARSE_OBJECT_COMMA, /* saw object ',', expecting next label */
43  JSON_PARSE_END /* saw the end of a document, expect nothing */
JsonParseContext
Definition: jsonapi.c:34
@ JSON_PARSE_OBJECT_LABEL
Definition: jsonapi.c:40
@ JSON_PARSE_VALUE
Definition: jsonapi.c:35
@ JSON_PARSE_OBJECT_START
Definition: jsonapi.c:39
@ JSON_PARSE_ARRAY_START
Definition: jsonapi.c:37
@ JSON_PARSE_END
Definition: jsonapi.c:43
@ JSON_PARSE_OBJECT_NEXT
Definition: jsonapi.c:41
@ JSON_PARSE_ARRAY_NEXT
Definition: jsonapi.c:38
@ JSON_PARSE_OBJECT_COMMA
Definition: jsonapi.c:42
@ JSON_PARSE_STRING
Definition: jsonapi.c:36

Function Documentation

◆ extract_token()

static char* extract_token ( JsonLexContext lex)
static

Definition at line 1100 of file jsonapi.c.

1101 {
1102  int toklen = lex->token_terminator - lex->token_start;
1103  char *token = palloc(toklen + 1);
1104 
1105  memcpy(token, lex->token_start, toklen);
1106  token[toklen] = '\0';
1107  return token;
1108 }
void * palloc(Size size)
Definition: mcxt.c:1210
char * token_start
Definition: jsonapi.h:79
char * token_terminator
Definition: jsonapi.h:80

References palloc(), JsonLexContext::token_start, and JsonLexContext::token_terminator.

Referenced by json_errdetail().

◆ IsValidJsonNumber()

bool IsValidJsonNumber ( const char *  str,
int  len 
)

Definition at line 105 of file jsonapi.c.

106 {
107  bool numeric_error;
108  int total_len;
109  JsonLexContext dummy_lex;
110 
111  if (len <= 0)
112  return false;
113 
114  /*
115  * json_lex_number expects a leading '-' to have been eaten already.
116  *
117  * having to cast away the constness of str is ugly, but there's not much
118  * easy alternative.
119  */
120  if (*str == '-')
121  {
122  dummy_lex.input = unconstify(char *, str) + 1;
123  dummy_lex.input_length = len - 1;
124  }
125  else
126  {
127  dummy_lex.input = unconstify(char *, str);
128  dummy_lex.input_length = len;
129  }
130 
131  json_lex_number(&dummy_lex, dummy_lex.input, &numeric_error, &total_len);
132 
133  return (!numeric_error) && (total_len == dummy_lex.input_length);
134 }
#define unconstify(underlying_type, expr)
Definition: c.h:1232
static JsonParseErrorType json_lex_number(JsonLexContext *lex, char *s, bool *num_err, int *total_len)
Definition: jsonapi.c:957
const void size_t len
char * input
Definition: jsonapi.h:76
int input_length
Definition: jsonapi.h:77

References JsonLexContext::input, JsonLexContext::input_length, json_lex_number(), len, generate_unaccent_rules::str, and unconstify.

Referenced by datum_to_json(), hstore_to_json_loose(), and hstore_to_jsonb_loose().

◆ json_count_array_elements()

JsonParseErrorType json_count_array_elements ( JsonLexContext lex,
int *  elements 
)

Definition at line 209 of file jsonapi.c.

210 {
211  JsonLexContext copylex;
212  int count;
213  JsonParseErrorType result;
214 
215  /*
216  * It's safe to do this with a shallow copy because the lexical routines
217  * don't scribble on the input. They do scribble on the other pointers
218  * etc, so doing this with a copy makes that safe.
219  */
220  memcpy(&copylex, lex, sizeof(JsonLexContext));
221  copylex.strval = NULL; /* not interested in values here */
222  copylex.lex_level++;
223 
224  count = 0;
225  result = lex_expect(JSON_PARSE_ARRAY_START, &copylex,
227  if (result != JSON_SUCCESS)
228  return result;
229  if (lex_peek(&copylex) != JSON_TOKEN_ARRAY_END)
230  {
231  while (1)
232  {
233  count++;
234  result = parse_array_element(&copylex, &nullSemAction);
235  if (result != JSON_SUCCESS)
236  return result;
237  if (copylex.token_type != JSON_TOKEN_COMMA)
238  break;
239  result = json_lex(&copylex);
240  if (result != JSON_SUCCESS)
241  return result;
242  }
243  }
244  result = lex_expect(JSON_PARSE_ARRAY_NEXT, &copylex,
246  if (result != JSON_SUCCESS)
247  return result;
248 
249  *elements = count;
250  return JSON_SUCCESS;
251 }
static JsonParseErrorType parse_array_element(JsonLexContext *lex, JsonSemAction *sem)
Definition: jsonapi.c:443
static JsonTokenType lex_peek(JsonLexContext *lex)
Definition: jsonapi.c:71
JsonSemAction nullSemAction
Definition: jsonapi.c:57
static JsonParseErrorType lex_expect(JsonParseContext ctx, JsonLexContext *lex, JsonTokenType token)
Definition: jsonapi.c:83
JsonParseErrorType json_lex(JsonLexContext *lex)
Definition: jsonapi.c:552
JsonParseErrorType
Definition: jsonapi.h:37
@ JSON_SUCCESS
Definition: jsonapi.h:38
@ JSON_TOKEN_COMMA
Definition: jsonapi.h:28
@ JSON_TOKEN_ARRAY_END
Definition: jsonapi.h:27
@ JSON_TOKEN_ARRAY_START
Definition: jsonapi.h:26
StringInfo strval
Definition: jsonapi.h:86
int lex_level
Definition: jsonapi.h:83
JsonTokenType token_type
Definition: jsonapi.h:82

References json_lex(), JSON_PARSE_ARRAY_NEXT, JSON_PARSE_ARRAY_START, JSON_SUCCESS, JSON_TOKEN_ARRAY_END, JSON_TOKEN_ARRAY_START, JSON_TOKEN_COMMA, lex_expect(), JsonLexContext::lex_level, lex_peek(), nullSemAction, parse_array_element(), JsonLexContext::strval, and JsonLexContext::token_type.

Referenced by get_array_start().

◆ json_errdetail()

char* json_errdetail ( JsonParseErrorType  error,
JsonLexContext lex 
)

Definition at line 1118 of file jsonapi.c.

1119 {
1120  switch (error)
1121  {
1122  case JSON_SUCCESS:
1123  /* fall through to the error code after switch */
1124  break;
1125  case JSON_ESCAPING_INVALID:
1126  return psprintf(_("Escape sequence \"\\%s\" is invalid."),
1127  extract_token(lex));
1129  return psprintf(_("Character with value 0x%02x must be escaped."),
1130  (unsigned char) *(lex->token_terminator));
1131  case JSON_EXPECTED_END:
1132  return psprintf(_("Expected end of input, but found \"%s\"."),
1133  extract_token(lex));
1135  return psprintf(_("Expected array element or \"]\", but found \"%s\"."),
1136  extract_token(lex));
1138  return psprintf(_("Expected \",\" or \"]\", but found \"%s\"."),
1139  extract_token(lex));
1140  case JSON_EXPECTED_COLON:
1141  return psprintf(_("Expected \":\", but found \"%s\"."),
1142  extract_token(lex));
1143  case JSON_EXPECTED_JSON:
1144  return psprintf(_("Expected JSON value, but found \"%s\"."),
1145  extract_token(lex));
1146  case JSON_EXPECTED_MORE:
1147  return _("The input string ended unexpectedly.");
1149  return psprintf(_("Expected string or \"}\", but found \"%s\"."),
1150  extract_token(lex));
1152  return psprintf(_("Expected \",\" or \"}\", but found \"%s\"."),
1153  extract_token(lex));
1154  case JSON_EXPECTED_STRING:
1155  return psprintf(_("Expected string, but found \"%s\"."),
1156  extract_token(lex));
1157  case JSON_INVALID_TOKEN:
1158  return psprintf(_("Token \"%s\" is invalid."),
1159  extract_token(lex));
1161  return _("\\u0000 cannot be converted to text.");
1163  return _("\"\\u\" must be followed by four hexadecimal digits.");
1165  /* note: this case is only reachable in frontend not backend */
1166  return _("Unicode escape values cannot be used for code point values above 007F when the encoding is not UTF8.");
1168  /* note: this case is only reachable in backend not frontend */
1169  return psprintf(_("Unicode escape value could not be translated to the server's encoding %s."),
1172  return _("Unicode high surrogate must not follow a high surrogate.");
1174  return _("Unicode low surrogate must follow a high surrogate.");
1176  /* fall through to the error code after switch */
1177  break;
1178  }
1179 
1180  /*
1181  * We don't use a default: case, so that the compiler will warn about
1182  * unhandled enum values. But this needs to be here anyway to cover the
1183  * possibility of an incorrect input.
1184  */
1185  elog(ERROR, "unexpected json parse error type: %d", (int) error);
1186  return NULL;
1187 }
#define _(x)
Definition: elog.c:91
#define ERROR
Definition: elog.h:39
static char * extract_token(JsonLexContext *lex)
Definition: jsonapi.c:1100
@ JSON_SEM_ACTION_FAILED
Definition: jsonapi.h:57
@ JSON_EXPECTED_ARRAY_FIRST
Definition: jsonapi.h:41
@ JSON_EXPECTED_MORE
Definition: jsonapi.h:46
@ JSON_UNICODE_HIGH_SURROGATE
Definition: jsonapi.h:55
@ JSON_EXPECTED_COLON
Definition: jsonapi.h:43
@ JSON_EXPECTED_OBJECT_FIRST
Definition: jsonapi.h:47
@ JSON_UNICODE_CODE_POINT_ZERO
Definition: jsonapi.h:51
@ JSON_EXPECTED_STRING
Definition: jsonapi.h:49
@ JSON_UNICODE_ESCAPE_FORMAT
Definition: jsonapi.h:52
@ JSON_UNICODE_UNTRANSLATABLE
Definition: jsonapi.h:54
@ JSON_EXPECTED_OBJECT_NEXT
Definition: jsonapi.h:48
@ JSON_ESCAPING_REQUIRED
Definition: jsonapi.h:40
@ JSON_EXPECTED_JSON
Definition: jsonapi.h:45
@ JSON_INVALID_TOKEN
Definition: jsonapi.h:50
@ JSON_ESCAPING_INVALID
Definition: jsonapi.h:39
@ JSON_EXPECTED_END
Definition: jsonapi.h:44
@ JSON_EXPECTED_ARRAY_NEXT
Definition: jsonapi.h:42
@ JSON_UNICODE_HIGH_ESCAPE
Definition: jsonapi.h:53
@ JSON_UNICODE_LOW_SURROGATE
Definition: jsonapi.h:56
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1274
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static void error(void)
Definition: sql-dyntest.c:147

References _, elog(), ERROR, error(), extract_token(), GetDatabaseEncodingName(), JSON_ESCAPING_INVALID, JSON_ESCAPING_REQUIRED, JSON_EXPECTED_ARRAY_FIRST, JSON_EXPECTED_ARRAY_NEXT, JSON_EXPECTED_COLON, JSON_EXPECTED_END, JSON_EXPECTED_JSON, JSON_EXPECTED_MORE, JSON_EXPECTED_OBJECT_FIRST, JSON_EXPECTED_OBJECT_NEXT, JSON_EXPECTED_STRING, JSON_INVALID_TOKEN, JSON_SEM_ACTION_FAILED, JSON_SUCCESS, JSON_UNICODE_CODE_POINT_ZERO, JSON_UNICODE_ESCAPE_FORMAT, JSON_UNICODE_HIGH_ESCAPE, JSON_UNICODE_HIGH_SURROGATE, JSON_UNICODE_LOW_SURROGATE, JSON_UNICODE_UNTRANSLATABLE, psprintf(), and JsonLexContext::token_terminator.

Referenced by json_errsave_error().

◆ json_lex()

JsonParseErrorType json_lex ( JsonLexContext lex)

Definition at line 552 of file jsonapi.c.

553 {
554  char *s;
555  char *const end = lex->input + lex->input_length;
556  JsonParseErrorType result;
557 
558  /* Skip leading whitespace. */
559  s = lex->token_terminator;
560  while (s < end && (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'))
561  {
562  if (*s++ == '\n')
563  {
564  ++lex->line_number;
565  lex->line_start = s;
566  }
567  }
568  lex->token_start = s;
569 
570  /* Determine token type. */
571  if (s >= end)
572  {
573  lex->token_start = NULL;
575  lex->token_terminator = s;
576  lex->token_type = JSON_TOKEN_END;
577  }
578  else
579  {
580  switch (*s)
581  {
582  /* Single-character token, some kind of punctuation mark. */
583  case '{':
585  lex->token_terminator = s + 1;
587  break;
588  case '}':
590  lex->token_terminator = s + 1;
592  break;
593  case '[':
595  lex->token_terminator = s + 1;
597  break;
598  case ']':
600  lex->token_terminator = s + 1;
602  break;
603  case ',':
605  lex->token_terminator = s + 1;
607  break;
608  case ':':
610  lex->token_terminator = s + 1;
612  break;
613  case '"':
614  /* string */
615  result = json_lex_string(lex);
616  if (result != JSON_SUCCESS)
617  return result;
619  break;
620  case '-':
621  /* Negative number. */
622  result = json_lex_number(lex, s + 1, NULL, NULL);
623  if (result != JSON_SUCCESS)
624  return result;
626  break;
627  case '0':
628  case '1':
629  case '2':
630  case '3':
631  case '4':
632  case '5':
633  case '6':
634  case '7':
635  case '8':
636  case '9':
637  /* Positive number. */
638  result = json_lex_number(lex, s, NULL, NULL);
639  if (result != JSON_SUCCESS)
640  return result;
642  break;
643  default:
644  {
645  char *p;
646 
647  /*
648  * We're not dealing with a string, number, legal
649  * punctuation mark, or end of string. The only legal
650  * tokens we might find here are true, false, and null,
651  * but for error reporting purposes we scan until we see a
652  * non-alphanumeric character. That way, we can report
653  * the whole word as an unexpected token, rather than just
654  * some unintuitive prefix thereof.
655  */
656  for (p = s; p < end && JSON_ALPHANUMERIC_CHAR(*p); p++)
657  /* skip */ ;
658 
659  /*
660  * We got some sort of unexpected punctuation or an
661  * otherwise unexpected character, so just complain about
662  * that one character.
663  */
664  if (p == s)
665  {
667  lex->token_terminator = s + 1;
668  return JSON_INVALID_TOKEN;
669  }
670 
671  /*
672  * We've got a real alphanumeric token here. If it
673  * happens to be true, false, or null, all is well. If
674  * not, error out.
675  */
677  lex->token_terminator = p;
678  if (p - s == 4)
679  {
680  if (memcmp(s, "true", 4) == 0)
682  else if (memcmp(s, "null", 4) == 0)
684  else
685  return JSON_INVALID_TOKEN;
686  }
687  else if (p - s == 5 && memcmp(s, "false", 5) == 0)
689  else
690  return JSON_INVALID_TOKEN;
691  }
692  } /* end of switch */
693  }
694 
695  return JSON_SUCCESS;
696 }
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
static JsonParseErrorType json_lex_string(JsonLexContext *lex)
Definition: jsonapi.c:702
#define JSON_ALPHANUMERIC_CHAR(c)
Definition: jsonapi.c:92
@ JSON_TOKEN_FALSE
Definition: jsonapi.h:31
@ JSON_TOKEN_END
Definition: jsonapi.h:33
@ JSON_TOKEN_TRUE
Definition: jsonapi.h:30
@ JSON_TOKEN_OBJECT_END
Definition: jsonapi.h:25
@ JSON_TOKEN_NULL
Definition: jsonapi.h:32
@ JSON_TOKEN_OBJECT_START
Definition: jsonapi.h:24
@ JSON_TOKEN_NUMBER
Definition: jsonapi.h:23
@ JSON_TOKEN_STRING
Definition: jsonapi.h:22
@ JSON_TOKEN_COLON
Definition: jsonapi.h:29
char * prev_token_terminator
Definition: jsonapi.h:81
char * line_start
Definition: jsonapi.h:85
int line_number
Definition: jsonapi.h:84

References if(), JsonLexContext::input, JsonLexContext::input_length, JSON_ALPHANUMERIC_CHAR, JSON_INVALID_TOKEN, json_lex_number(), json_lex_string(), JSON_SUCCESS, JSON_TOKEN_ARRAY_END, JSON_TOKEN_ARRAY_START, JSON_TOKEN_COLON, JSON_TOKEN_COMMA, JSON_TOKEN_END, JSON_TOKEN_FALSE, JSON_TOKEN_NULL, JSON_TOKEN_NUMBER, JSON_TOKEN_OBJECT_END, JSON_TOKEN_OBJECT_START, JSON_TOKEN_STRING, JSON_TOKEN_TRUE, JsonLexContext::line_number, JsonLexContext::line_start, JsonLexContext::prev_token_terminator, JsonLexContext::token_start, JsonLexContext::token_terminator, and JsonLexContext::token_type.

Referenced by json_count_array_elements(), json_typeof(), lex_expect(), parse_array(), parse_object(), parse_object_field(), parse_scalar(), and pg_parse_json().

◆ json_lex_number()

static JsonParseErrorType json_lex_number ( JsonLexContext lex,
char *  s,
bool num_err,
int *  total_len 
)
inlinestatic

Definition at line 957 of file jsonapi.c.

959 {
960  bool error = false;
961  int len = s - lex->input;
962 
963  /* Part (1): leading sign indicator. */
964  /* Caller already did this for us; so do nothing. */
965 
966  /* Part (2): parse main digit string. */
967  if (len < lex->input_length && *s == '0')
968  {
969  s++;
970  len++;
971  }
972  else if (len < lex->input_length && *s >= '1' && *s <= '9')
973  {
974  do
975  {
976  s++;
977  len++;
978  } while (len < lex->input_length && *s >= '0' && *s <= '9');
979  }
980  else
981  error = true;
982 
983  /* Part (3): parse optional decimal portion. */
984  if (len < lex->input_length && *s == '.')
985  {
986  s++;
987  len++;
988  if (len == lex->input_length || *s < '0' || *s > '9')
989  error = true;
990  else
991  {
992  do
993  {
994  s++;
995  len++;
996  } while (len < lex->input_length && *s >= '0' && *s <= '9');
997  }
998  }
999 
1000  /* Part (4): parse optional exponent. */
1001  if (len < lex->input_length && (*s == 'e' || *s == 'E'))
1002  {
1003  s++;
1004  len++;
1005  if (len < lex->input_length && (*s == '+' || *s == '-'))
1006  {
1007  s++;
1008  len++;
1009  }
1010  if (len == lex->input_length || *s < '0' || *s > '9')
1011  error = true;
1012  else
1013  {
1014  do
1015  {
1016  s++;
1017  len++;
1018  } while (len < lex->input_length && *s >= '0' && *s <= '9');
1019  }
1020  }
1021 
1022  /*
1023  * Check for trailing garbage. As in json_lex(), any alphanumeric stuff
1024  * here should be considered part of the token for error-reporting
1025  * purposes.
1026  */
1027  for (; len < lex->input_length && JSON_ALPHANUMERIC_CHAR(*s); s++, len++)
1028  error = true;
1029 
1030  if (total_len != NULL)
1031  *total_len = len;
1032 
1033  if (num_err != NULL)
1034  {
1035  /* let the caller handle any error */
1036  *num_err = error;
1037  }
1038  else
1039  {
1040  /* return token endpoint */
1042  lex->token_terminator = s;
1043  /* handle error if any */
1044  if (error)
1045  return JSON_INVALID_TOKEN;
1046  }
1047 
1048  return JSON_SUCCESS;
1049 }

References error(), JsonLexContext::input, JsonLexContext::input_length, JSON_ALPHANUMERIC_CHAR, JSON_INVALID_TOKEN, JSON_SUCCESS, len, JsonLexContext::prev_token_terminator, and JsonLexContext::token_terminator.

Referenced by IsValidJsonNumber(), and json_lex().

◆ json_lex_string()

static JsonParseErrorType json_lex_string ( JsonLexContext lex)
inlinestatic

Definition at line 702 of file jsonapi.c.

703 {
704  char *s;
705  char *const end = lex->input + lex->input_length;
706  int hi_surrogate = -1;
707 
708  if (lex->strval != NULL)
709  resetStringInfo(lex->strval);
710 
711  Assert(lex->input_length > 0);
712  s = lex->token_start;
713  for (;;)
714  {
715  s++;
716  /* Premature end of the string. */
717  if (s >= end)
718  {
719  lex->token_terminator = s;
720  return JSON_INVALID_TOKEN;
721  }
722  else if (*s == '"')
723  break;
724  else if (*s == '\\')
725  {
726  /* OK, we have an escape character. */
727  s++;
728  if (s >= end)
729  {
730  lex->token_terminator = s;
731  return JSON_INVALID_TOKEN;
732  }
733  else if (*s == 'u')
734  {
735  int i;
736  int ch = 0;
737 
738  for (i = 1; i <= 4; i++)
739  {
740  s++;
741  if (s >= end)
742  {
743  lex->token_terminator = s;
744  return JSON_INVALID_TOKEN;
745  }
746  else if (*s >= '0' && *s <= '9')
747  ch = (ch * 16) + (*s - '0');
748  else if (*s >= 'a' && *s <= 'f')
749  ch = (ch * 16) + (*s - 'a') + 10;
750  else if (*s >= 'A' && *s <= 'F')
751  ch = (ch * 16) + (*s - 'A') + 10;
752  else
753  {
756  }
757  }
758  if (lex->strval != NULL)
759  {
760  /*
761  * Combine surrogate pairs.
762  */
763  if (is_utf16_surrogate_first(ch))
764  {
765  if (hi_surrogate != -1)
767  hi_surrogate = ch;
768  continue;
769  }
770  else if (is_utf16_surrogate_second(ch))
771  {
772  if (hi_surrogate == -1)
774  ch = surrogate_pair_to_codepoint(hi_surrogate, ch);
775  hi_surrogate = -1;
776  }
777 
778  if (hi_surrogate != -1)
780 
781  /*
782  * Reject invalid cases. We can't have a value above
783  * 0xFFFF here (since we only accepted 4 hex digits
784  * above), so no need to test for out-of-range chars.
785  */
786  if (ch == 0)
787  {
788  /* We can't allow this, since our TEXT type doesn't */
790  }
791 
792  /*
793  * Add the represented character to lex->strval. In the
794  * backend, we can let pg_unicode_to_server_noerror()
795  * handle any required character set conversion; in
796  * frontend, we can only deal with trivial conversions.
797  */
798 #ifndef FRONTEND
799  {
800  char cbuf[MAX_UNICODE_EQUIVALENT_STRING + 1];
801 
802  if (!pg_unicode_to_server_noerror(ch, (unsigned char *) cbuf))
804  appendStringInfoString(lex->strval, cbuf);
805  }
806 #else
807  if (lex->input_encoding == PG_UTF8)
808  {
809  /* OK, we can map the code point to UTF8 easily */
810  char utf8str[5];
811  int utf8len;
812 
813  unicode_to_utf8(ch, (unsigned char *) utf8str);
814  utf8len = pg_utf_mblen((unsigned char *) utf8str);
815  appendBinaryStringInfo(lex->strval, utf8str, utf8len);
816  }
817  else if (ch <= 0x007f)
818  {
819  /* The ASCII range is the same in all encodings */
820  appendStringInfoChar(lex->strval, (char) ch);
821  }
822  else
824 #endif /* FRONTEND */
825  }
826  }
827  else if (lex->strval != NULL)
828  {
829  if (hi_surrogate != -1)
831 
832  switch (*s)
833  {
834  case '"':
835  case '\\':
836  case '/':
837  appendStringInfoChar(lex->strval, *s);
838  break;
839  case 'b':
840  appendStringInfoChar(lex->strval, '\b');
841  break;
842  case 'f':
843  appendStringInfoChar(lex->strval, '\f');
844  break;
845  case 'n':
846  appendStringInfoChar(lex->strval, '\n');
847  break;
848  case 'r':
849  appendStringInfoChar(lex->strval, '\r');
850  break;
851  case 't':
852  appendStringInfoChar(lex->strval, '\t');
853  break;
854  default:
855  /* Not a valid string escape, so signal error. */
856  lex->token_start = s;
858  return JSON_ESCAPING_INVALID;
859  }
860  }
861  else if (strchr("\"\\/bfnrt", *s) == NULL)
862  {
863  /*
864  * Simpler processing if we're not bothered about de-escaping
865  *
866  * It's very tempting to remove the strchr() call here and
867  * replace it with a switch statement, but testing so far has
868  * shown it's not a performance win.
869  */
870  lex->token_start = s;
872  return JSON_ESCAPING_INVALID;
873  }
874  }
875  else
876  {
877  char *p = s;
878 
879  if (hi_surrogate != -1)
881 
882  /*
883  * Skip to the first byte that requires special handling, so we
884  * can batch calls to appendBinaryStringInfo.
885  */
886  while (p < end - sizeof(Vector8) &&
887  !pg_lfind8('\\', (uint8 *) p, sizeof(Vector8)) &&
888  !pg_lfind8('"', (uint8 *) p, sizeof(Vector8)) &&
889  !pg_lfind8_le(31, (uint8 *) p, sizeof(Vector8)))
890  p += sizeof(Vector8);
891 
892  for (; p < end; p++)
893  {
894  if (*p == '\\' || *p == '"')
895  break;
896  else if ((unsigned char) *p <= 31)
897  {
898  /* Per RFC4627, these characters MUST be escaped. */
899  /*
900  * Since *p isn't printable, exclude it from the context
901  * string
902  */
903  lex->token_terminator = p;
904  return JSON_ESCAPING_REQUIRED;
905  }
906  }
907 
908  if (lex->strval != NULL)
909  appendBinaryStringInfo(lex->strval, s, p - s);
910 
911  /*
912  * s will be incremented at the top of the loop, so set it to just
913  * behind our lookahead position
914  */
915  s = p - 1;
916  }
917  }
918 
919  if (hi_surrogate != -1)
921 
922  /* Hooray, we found the end of the string! */
924  lex->token_terminator = s + 1;
925  return JSON_SUCCESS;
926 }
unsigned char uint8
Definition: c.h:488
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
bool pg_unicode_to_server_noerror(pg_wchar c, unsigned char *s)
Definition: mbutils.c:927
static bool pg_lfind8_le(uint8 key, uint8 *base, uint32 nelem)
Definition: pg_lfind.h:58
static bool pg_lfind8(uint8 key, uint8 *base, uint32 nelem)
Definition: pg_lfind.h:26
@ PG_UTF8
Definition: pg_wchar.h:232
#define MAX_UNICODE_EQUIVALENT_STRING
Definition: pg_wchar.h:329
static pg_wchar surrogate_pair_to_codepoint(pg_wchar first, pg_wchar second)
Definition: pg_wchar.h:543
static bool is_utf16_surrogate_first(pg_wchar c)
Definition: pg_wchar.h:531
static bool is_utf16_surrogate_second(pg_wchar c)
Definition: pg_wchar.h:537
uint64 Vector8
Definition: simd.h:60
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:75
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:227
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
int input_encoding
Definition: jsonapi.h:78
int pg_encoding_mblen_bounded(int encoding, const char *mbstr)
Definition: wchar.c:2142
unsigned char * unicode_to_utf8(pg_wchar c, unsigned char *utf8string)
Definition: wchar.c:483
int pg_utf_mblen(const unsigned char *s)
Definition: wchar.c:549

References appendBinaryStringInfo(), appendStringInfoChar(), appendStringInfoString(), Assert(), i, JsonLexContext::input, JsonLexContext::input_encoding, JsonLexContext::input_length, is_utf16_surrogate_first(), is_utf16_surrogate_second(), JSON_ESCAPING_INVALID, JSON_ESCAPING_REQUIRED, JSON_INVALID_TOKEN, JSON_SUCCESS, JSON_UNICODE_CODE_POINT_ZERO, JSON_UNICODE_ESCAPE_FORMAT, JSON_UNICODE_HIGH_ESCAPE, JSON_UNICODE_HIGH_SURROGATE, JSON_UNICODE_LOW_SURROGATE, JSON_UNICODE_UNTRANSLATABLE, MAX_UNICODE_EQUIVALENT_STRING, pg_encoding_mblen_bounded(), pg_lfind8(), pg_lfind8_le(), pg_unicode_to_server_noerror(), PG_UTF8, pg_utf_mblen(), JsonLexContext::prev_token_terminator, resetStringInfo(), JsonLexContext::strval, surrogate_pair_to_codepoint(), JsonLexContext::token_start, JsonLexContext::token_terminator, and unicode_to_utf8().

Referenced by json_lex().

◆ lex_expect()

static JsonParseErrorType lex_expect ( JsonParseContext  ctx,
JsonLexContext lex,
JsonTokenType  token 
)
inlinestatic

Definition at line 83 of file jsonapi.c.

84 {
85  if (lex_peek(lex) == token)
86  return json_lex(lex);
87  else
88  return report_parse_error(ctx, lex);
89 }
static JsonParseErrorType report_parse_error(JsonParseContext ctx, JsonLexContext *lex)
Definition: jsonapi.c:1057

References json_lex(), lex_peek(), and report_parse_error().

Referenced by json_count_array_elements(), parse_array(), parse_object(), parse_object_field(), and pg_parse_json().

◆ lex_peek()

static JsonTokenType lex_peek ( JsonLexContext lex)
inlinestatic

◆ makeJsonLexContextCstringLen()

JsonLexContext* makeJsonLexContextCstringLen ( char *  json,
int  len,
int  encoding,
bool  need_escapes 
)

Definition at line 145 of file jsonapi.c.

146 {
147  JsonLexContext *lex = palloc0(sizeof(JsonLexContext));
148 
149  lex->input = lex->token_terminator = lex->line_start = json;
150  lex->line_number = 1;
151  lex->input_length = len;
152  lex->input_encoding = encoding;
153  if (need_escapes)
154  lex->strval = makeStringInfo();
155  return lex;
156 }
void * palloc0(Size size)
Definition: mcxt.c:1241
int32 encoding
Definition: pg_database.h:41
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41

References encoding, JsonLexContext::input, JsonLexContext::input_encoding, JsonLexContext::input_length, len, JsonLexContext::line_number, JsonLexContext::line_start, makeStringInfo(), palloc0(), JsonLexContext::strval, and JsonLexContext::token_terminator.

Referenced by get_json_object_as_hash(), json_parse_manifest(), json_recv(), jsonb_from_cstring(), makeJsonLexContext(), and populate_array_json().

◆ parse_array()

static JsonParseErrorType parse_array ( JsonLexContext lex,
JsonSemAction sem 
)
static

Definition at line 487 of file jsonapi.c.

488 {
489  /*
490  * an array is a possibly empty sequence of array elements, separated by
491  * commas and surrounded by square brackets.
492  */
493  json_struct_action astart = sem->array_start;
494  json_struct_action aend = sem->array_end;
495  JsonParseErrorType result;
496 
497 #ifndef FRONTEND
499 #endif
500 
501  if (astart != NULL)
502  {
503  result = (*astart) (sem->semstate);
504  if (result != JSON_SUCCESS)
505  return result;
506  }
507 
508  /*
509  * Data inside an array is at a higher nesting level than the array
510  * itself. Note that we increment this after we call the semantic routine
511  * for the array start and restore it before we call the routine for the
512  * array end.
513  */
514  lex->lex_level++;
515 
517  if (result == JSON_SUCCESS && lex_peek(lex) != JSON_TOKEN_ARRAY_END)
518  {
519  result = parse_array_element(lex, sem);
520 
521  while (result == JSON_SUCCESS && lex_peek(lex) == JSON_TOKEN_COMMA)
522  {
523  result = json_lex(lex);
524  if (result != JSON_SUCCESS)
525  break;
526  result = parse_array_element(lex, sem);
527  }
528  }
529  if (result != JSON_SUCCESS)
530  return result;
531 
533  if (result != JSON_SUCCESS)
534  return result;
535 
536  lex->lex_level--;
537 
538  if (aend != NULL)
539  {
540  result = (*aend) (sem->semstate);
541  if (result != JSON_SUCCESS)
542  return result;
543  }
544 
545  return JSON_SUCCESS;
546 }
JsonParseErrorType(* json_struct_action)(void *state)
Definition: jsonapi.h:89
void check_stack_depth(void)
Definition: postgres.c:3454
json_struct_action array_end
Definition: jsonapi.h:118
void * semstate
Definition: jsonapi.h:114
json_struct_action array_start
Definition: jsonapi.h:117

References JsonSemAction::array_end, JsonSemAction::array_start, check_stack_depth(), json_lex(), JSON_PARSE_ARRAY_NEXT, JSON_PARSE_ARRAY_START, JSON_SUCCESS, JSON_TOKEN_ARRAY_END, JSON_TOKEN_ARRAY_START, JSON_TOKEN_COMMA, lex_expect(), JsonLexContext::lex_level, lex_peek(), parse_array_element(), and JsonSemAction::semstate.

Referenced by parse_array_element(), parse_object_field(), and pg_parse_json().

◆ parse_array_element()

static JsonParseErrorType parse_array_element ( JsonLexContext lex,
JsonSemAction sem 
)
static

Definition at line 443 of file jsonapi.c.

444 {
447  JsonTokenType tok = lex_peek(lex);
448  JsonParseErrorType result;
449  bool isnull;
450 
451  isnull = tok == JSON_TOKEN_NULL;
452 
453  if (astart != NULL)
454  {
455  result = (*astart) (sem->semstate, isnull);
456  if (result != JSON_SUCCESS)
457  return result;
458  }
459 
460  /* an array element is any object, array or scalar */
461  switch (tok)
462  {
464  result = parse_object(lex, sem);
465  break;
467  result = parse_array(lex, sem);
468  break;
469  default:
470  result = parse_scalar(lex, sem);
471  }
472 
473  if (result != JSON_SUCCESS)
474  return result;
475 
476  if (aend != NULL)
477  {
478  result = (*aend) (sem->semstate, isnull);
479  if (result != JSON_SUCCESS)
480  return result;
481  }
482 
483  return JSON_SUCCESS;
484 }
static JsonParseErrorType parse_object(JsonLexContext *lex, JsonSemAction *sem)
Definition: jsonapi.c:369
static JsonParseErrorType parse_array(JsonLexContext *lex, JsonSemAction *sem)
Definition: jsonapi.c:487
static JsonParseErrorType parse_scalar(JsonLexContext *lex, JsonSemAction *sem)
Definition: jsonapi.c:263
JsonParseErrorType(* json_aelem_action)(void *state, bool isnull)
Definition: jsonapi.h:91
JsonTokenType
Definition: jsonapi.h:20
json_aelem_action array_element_start
Definition: jsonapi.h:121
json_aelem_action array_element_end
Definition: jsonapi.h:122

References JsonSemAction::array_element_end, JsonSemAction::array_element_start, JSON_SUCCESS, JSON_TOKEN_ARRAY_START, JSON_TOKEN_NULL, JSON_TOKEN_OBJECT_START, lex_peek(), parse_array(), parse_object(), parse_scalar(), and JsonSemAction::semstate.

Referenced by json_count_array_elements(), and parse_array().

◆ parse_object()

static JsonParseErrorType parse_object ( JsonLexContext lex,
JsonSemAction sem 
)
static

Definition at line 369 of file jsonapi.c.

370 {
371  /*
372  * an object is a possibly empty sequence of object fields, separated by
373  * commas and surrounded by curly braces.
374  */
375  json_struct_action ostart = sem->object_start;
376  json_struct_action oend = sem->object_end;
377  JsonTokenType tok;
378  JsonParseErrorType result;
379 
380 #ifndef FRONTEND
382 #endif
383 
384  if (ostart != NULL)
385  {
386  result = (*ostart) (sem->semstate);
387  if (result != JSON_SUCCESS)
388  return result;
389  }
390 
391  /*
392  * Data inside an object is at a higher nesting level than the object
393  * itself. Note that we increment this after we call the semantic routine
394  * for the object start and restore it before we call the routine for the
395  * object end.
396  */
397  lex->lex_level++;
398 
400  result = json_lex(lex);
401  if (result != JSON_SUCCESS)
402  return result;
403 
404  tok = lex_peek(lex);
405  switch (tok)
406  {
407  case JSON_TOKEN_STRING:
408  result = parse_object_field(lex, sem);
409  while (result == JSON_SUCCESS && lex_peek(lex) == JSON_TOKEN_COMMA)
410  {
411  result = json_lex(lex);
412  if (result != JSON_SUCCESS)
413  break;
414  result = parse_object_field(lex, sem);
415  }
416  break;
418  break;
419  default:
420  /* case of an invalid initial token inside the object */
422  }
423  if (result != JSON_SUCCESS)
424  return result;
425 
427  if (result != JSON_SUCCESS)
428  return result;
429 
430  lex->lex_level--;
431 
432  if (oend != NULL)
433  {
434  result = (*oend) (sem->semstate);
435  if (result != JSON_SUCCESS)
436  return result;
437  }
438 
439  return JSON_SUCCESS;
440 }
static JsonParseErrorType parse_object_field(JsonLexContext *lex, JsonSemAction *sem)
Definition: jsonapi.c:307
json_struct_action object_start
Definition: jsonapi.h:115
json_struct_action object_end
Definition: jsonapi.h:116

References Assert(), check_stack_depth(), json_lex(), JSON_PARSE_OBJECT_NEXT, JSON_PARSE_OBJECT_START, JSON_SUCCESS, JSON_TOKEN_COMMA, JSON_TOKEN_OBJECT_END, JSON_TOKEN_OBJECT_START, JSON_TOKEN_STRING, lex_expect(), JsonLexContext::lex_level, lex_peek(), JsonSemAction::object_end, JsonSemAction::object_start, parse_object_field(), report_parse_error(), and JsonSemAction::semstate.

Referenced by parse_array_element(), parse_object_field(), and pg_parse_json().

◆ parse_object_field()

static JsonParseErrorType parse_object_field ( JsonLexContext lex,
JsonSemAction sem 
)
static

Definition at line 307 of file jsonapi.c.

308 {
309  /*
310  * An object field is "fieldname" : value where value can be a scalar,
311  * object or array. Note: in user-facing docs and error messages, we
312  * generally call a field name a "key".
313  */
314 
315  char *fname = NULL; /* keep compiler quiet */
318  bool isnull;
319  JsonTokenType tok;
320  JsonParseErrorType result;
321 
322  if (lex_peek(lex) != JSON_TOKEN_STRING)
324  if ((ostart != NULL || oend != NULL) && lex->strval != NULL)
325  fname = pstrdup(lex->strval->data);
326  result = json_lex(lex);
327  if (result != JSON_SUCCESS)
328  return result;
329 
331  if (result != JSON_SUCCESS)
332  return result;
333 
334  tok = lex_peek(lex);
335  isnull = tok == JSON_TOKEN_NULL;
336 
337  if (ostart != NULL)
338  {
339  result = (*ostart) (sem->semstate, fname, isnull);
340  if (result != JSON_SUCCESS)
341  return result;
342  }
343 
344  switch (tok)
345  {
347  result = parse_object(lex, sem);
348  break;
350  result = parse_array(lex, sem);
351  break;
352  default:
353  result = parse_scalar(lex, sem);
354  }
355  if (result != JSON_SUCCESS)
356  return result;
357 
358  if (oend != NULL)
359  {
360  result = (*oend) (sem->semstate, fname, isnull);
361  if (result != JSON_SUCCESS)
362  return result;
363  }
364 
365  return JSON_SUCCESS;
366 }
JsonParseErrorType(* json_ofield_action)(void *state, char *fname, bool isnull)
Definition: jsonapi.h:90
char * pstrdup(const char *in)
Definition: mcxt.c:1624
json_ofield_action object_field_start
Definition: jsonapi.h:119
json_ofield_action object_field_end
Definition: jsonapi.h:120

References StringInfoData::data, json_lex(), JSON_PARSE_OBJECT_LABEL, JSON_PARSE_STRING, JSON_SUCCESS, JSON_TOKEN_ARRAY_START, JSON_TOKEN_COLON, JSON_TOKEN_NULL, JSON_TOKEN_OBJECT_START, JSON_TOKEN_STRING, lex_expect(), lex_peek(), JsonSemAction::object_field_end, JsonSemAction::object_field_start, parse_array(), parse_object(), parse_scalar(), pstrdup(), report_parse_error(), JsonSemAction::semstate, and JsonLexContext::strval.

Referenced by parse_object().

◆ parse_scalar()

static JsonParseErrorType parse_scalar ( JsonLexContext lex,
JsonSemAction sem 
)
inlinestatic

Definition at line 263 of file jsonapi.c.

264 {
265  char *val = NULL;
266  json_scalar_action sfunc = sem->scalar;
267  JsonTokenType tok = lex_peek(lex);
268  JsonParseErrorType result;
269 
270  /* a scalar must be a string, a number, true, false, or null */
271  if (tok != JSON_TOKEN_STRING && tok != JSON_TOKEN_NUMBER &&
272  tok != JSON_TOKEN_TRUE && tok != JSON_TOKEN_FALSE &&
273  tok != JSON_TOKEN_NULL)
275 
276  /* if no semantic function, just consume the token */
277  if (sfunc == NULL)
278  return json_lex(lex);
279 
280  /* extract the de-escaped string value, or the raw lexeme */
281  if (lex_peek(lex) == JSON_TOKEN_STRING)
282  {
283  if (lex->strval != NULL)
284  val = pstrdup(lex->strval->data);
285  }
286  else
287  {
288  int len = (lex->token_terminator - lex->token_start);
289 
290  val = palloc(len + 1);
291  memcpy(val, lex->token_start, len);
292  val[len] = '\0';
293  }
294 
295  /* consume the token */
296  result = json_lex(lex);
297  if (result != JSON_SUCCESS)
298  return result;
299 
300  /* invoke the callback */
301  result = (*sfunc) (sem->semstate, val, tok);
302 
303  return result;
304 }
long val
Definition: informix.c:664
JsonParseErrorType(* json_scalar_action)(void *state, char *token, JsonTokenType tokentype)
Definition: jsonapi.h:92
json_scalar_action scalar
Definition: jsonapi.h:123

References StringInfoData::data, json_lex(), JSON_PARSE_VALUE, JSON_SUCCESS, JSON_TOKEN_FALSE, JSON_TOKEN_NULL, JSON_TOKEN_NUMBER, JSON_TOKEN_STRING, JSON_TOKEN_TRUE, len, lex_peek(), palloc(), pstrdup(), report_parse_error(), JsonSemAction::scalar, JsonSemAction::semstate, JsonLexContext::strval, JsonLexContext::token_start, JsonLexContext::token_terminator, and val.

Referenced by parse_array_element(), parse_object_field(), and pg_parse_json().

◆ pg_parse_json()

JsonParseErrorType pg_parse_json ( JsonLexContext lex,
JsonSemAction sem 
)

Definition at line 169 of file jsonapi.c.

170 {
171  JsonTokenType tok;
172  JsonParseErrorType result;
173 
174  /* get the initial token */
175  result = json_lex(lex);
176  if (result != JSON_SUCCESS)
177  return result;
178 
179  tok = lex_peek(lex);
180 
181  /* parse by recursive descent */
182  switch (tok)
183  {
185  result = parse_object(lex, sem);
186  break;
188  result = parse_array(lex, sem);
189  break;
190  default:
191  result = parse_scalar(lex, sem); /* json can be a bare scalar */
192  }
193 
194  if (result == JSON_SUCCESS)
195  result = lex_expect(JSON_PARSE_END, lex, JSON_TOKEN_END);
196 
197  return result;
198 }

References json_lex(), JSON_PARSE_END, JSON_SUCCESS, JSON_TOKEN_ARRAY_START, JSON_TOKEN_END, JSON_TOKEN_OBJECT_START, lex_expect(), lex_peek(), parse_array(), parse_object(), and parse_scalar().

Referenced by json_parse_manifest(), and pg_parse_json_or_errsave().

◆ report_parse_error()

static JsonParseErrorType report_parse_error ( JsonParseContext  ctx,
JsonLexContext lex 
)
static

Definition at line 1057 of file jsonapi.c.

1058 {
1059  /* Handle case where the input ended prematurely. */
1060  if (lex->token_start == NULL || lex->token_type == JSON_TOKEN_END)
1061  return JSON_EXPECTED_MORE;
1062 
1063  /* Otherwise choose the error type based on the parsing context. */
1064  switch (ctx)
1065  {
1066  case JSON_PARSE_END:
1067  return JSON_EXPECTED_END;
1068  case JSON_PARSE_VALUE:
1069  return JSON_EXPECTED_JSON;
1070  case JSON_PARSE_STRING:
1071  return JSON_EXPECTED_STRING;
1074  case JSON_PARSE_ARRAY_NEXT:
1075  return JSON_EXPECTED_ARRAY_NEXT;
1079  return JSON_EXPECTED_COLON;
1083  return JSON_EXPECTED_STRING;
1084  }
1085 
1086  /*
1087  * We don't use a default: case, so that the compiler will warn about
1088  * unhandled enum values.
1089  */
1090  Assert(false);
1091  return JSON_SUCCESS; /* silence stupider compilers */
1092 }

References Assert(), JSON_EXPECTED_ARRAY_FIRST, JSON_EXPECTED_ARRAY_NEXT, JSON_EXPECTED_COLON, JSON_EXPECTED_END, JSON_EXPECTED_JSON, JSON_EXPECTED_MORE, JSON_EXPECTED_OBJECT_FIRST, JSON_EXPECTED_OBJECT_NEXT, JSON_EXPECTED_STRING, JSON_PARSE_ARRAY_NEXT, JSON_PARSE_ARRAY_START, JSON_PARSE_END, JSON_PARSE_OBJECT_COMMA, JSON_PARSE_OBJECT_LABEL, JSON_PARSE_OBJECT_NEXT, JSON_PARSE_OBJECT_START, JSON_PARSE_STRING, JSON_PARSE_VALUE, JSON_SUCCESS, JSON_TOKEN_END, JsonLexContext::token_start, and JsonLexContext::token_type.

Referenced by lex_expect(), parse_object(), parse_object_field(), and parse_scalar().

Variable Documentation

◆ nullSemAction

JsonSemAction nullSemAction
Initial value:
=
{
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL
}

Definition at line 57 of file jsonapi.c.

Referenced by json_count_array_elements(), json_in(), and json_recv().