xref: /Universal-ctags/parsers/json.c (revision 2ec6b03e1eb0c8a3535e89601f969899d7e854f8)
13ae02089SMasatake YAMATO /*
23ae02089SMasatake YAMATO  * Copyright (c) 2014, Colomban Wendling <colomban@geany.org>
33ae02089SMasatake YAMATO  *
43ae02089SMasatake YAMATO  * This source code is released for free distribution under the terms of the
50ce38835Sviccuad  * GNU General Public License version 2 or (at your option) any later version.
63ae02089SMasatake YAMATO  */
73ae02089SMasatake YAMATO /*
83ae02089SMasatake YAMATO  * This module contains functions for generating tags for JSON files.
93ae02089SMasatake YAMATO  *
103ae02089SMasatake YAMATO  * http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
113ae02089SMasatake YAMATO  *
123ae02089SMasatake YAMATO  * This implementation is forgiving and allows many constructs that are not
133ae02089SMasatake YAMATO  * actually valid but that don't conflict with the format.  This is intend to
143ae02089SMasatake YAMATO  * better support partly broken or unfinished files.
153ae02089SMasatake YAMATO  */
163ae02089SMasatake YAMATO 
173ae02089SMasatake YAMATO #include "general.h"
183ae02089SMasatake YAMATO 
193ae02089SMasatake YAMATO #include <string.h>
203ae02089SMasatake YAMATO #include "debug.h"
213ae02089SMasatake YAMATO #include "entry.h"
223ae02089SMasatake YAMATO #include "keyword.h"
23844ef580SMasatake YAMATO #include "options.h"
243ae02089SMasatake YAMATO #include "parse.h"
253ae02089SMasatake YAMATO #include "read.h"
263ae02089SMasatake YAMATO #include "routines.h"
273ae02089SMasatake YAMATO #include "vstring.h"
283ae02089SMasatake YAMATO 
292b28d0e0SJiří Techet #define isIdentChar(c) \
302b28d0e0SJiří Techet 	(isalnum (c) || (c) == '+' || (c) == '-' || (c) == '.')
312b28d0e0SJiří Techet 
323ae02089SMasatake YAMATO typedef enum {
333ae02089SMasatake YAMATO 	TOKEN_EOF,
343ae02089SMasatake YAMATO 	TOKEN_UNDEFINED,
353ae02089SMasatake YAMATO 	TOKEN_OPEN_SQUARE,
363ae02089SMasatake YAMATO 	TOKEN_CLOSE_SQUARE,
373ae02089SMasatake YAMATO 	TOKEN_OPEN_CURLY,
383ae02089SMasatake YAMATO 	TOKEN_CLOSE_CURLY,
393ae02089SMasatake YAMATO 	TOKEN_COLON,
403ae02089SMasatake YAMATO 	TOKEN_COMMA,
413ae02089SMasatake YAMATO 	TOKEN_TRUE,
423ae02089SMasatake YAMATO 	TOKEN_FALSE,
433ae02089SMasatake YAMATO 	TOKEN_NULL,
443ae02089SMasatake YAMATO 	TOKEN_NUMBER,
453ae02089SMasatake YAMATO 	TOKEN_STRING
463ae02089SMasatake YAMATO } tokenType;
473ae02089SMasatake YAMATO 
483ae02089SMasatake YAMATO typedef enum {
493ae02089SMasatake YAMATO 	TAG_NONE = -1,
503ae02089SMasatake YAMATO 	TAG_OBJECT,
513ae02089SMasatake YAMATO 	TAG_ARRAY,
523ae02089SMasatake YAMATO 	TAG_NUMBER,
533ae02089SMasatake YAMATO 	TAG_STRING,
543ae02089SMasatake YAMATO 	TAG_BOOLEAN,
553ae02089SMasatake YAMATO 	TAG_NULL,
563ae02089SMasatake YAMATO 	TAG_COUNT
573ae02089SMasatake YAMATO } jsonKind;
583ae02089SMasatake YAMATO 
593ae02089SMasatake YAMATO typedef struct {
603ae02089SMasatake YAMATO 	tokenType		type;
613ae02089SMasatake YAMATO 	jsonKind		scopeKind;
623ae02089SMasatake YAMATO 	vString			*string;
633ae02089SMasatake YAMATO 	vString			*scope;
643ae02089SMasatake YAMATO 	unsigned long	lineNumber;
65509a47dbSJiří Techet 	MIOPos			filePosition;
663ae02089SMasatake YAMATO } tokenInfo;
673ae02089SMasatake YAMATO 
683ae02089SMasatake YAMATO typedef enum {
693ae02089SMasatake YAMATO 	KEYWORD_true,
703ae02089SMasatake YAMATO 	KEYWORD_false,
713ae02089SMasatake YAMATO 	KEYWORD_null
723ae02089SMasatake YAMATO } keywordId;
733ae02089SMasatake YAMATO 
743ae02089SMasatake YAMATO static langType Lang_json;
753ae02089SMasatake YAMATO 
76e112e8abSMasatake YAMATO static kindDefinition JsonKinds [] = {
77ce990805SThomas Braun 	{ true,  'o', "object",		"objects"	},
78ce990805SThomas Braun 	{ true,  'a', "array",		"arrays"	},
79ce990805SThomas Braun 	{ true,  'n', "number",		"numbers"	},
80ce990805SThomas Braun 	{ true,  's', "string",		"strings"	},
8143630fd5SMasatake YAMATO 	{ true,  'b', "boolean",	"booleans"	},
82ce990805SThomas Braun 	{ true,  'z', "null",		"nulls"		}
833ae02089SMasatake YAMATO };
843ae02089SMasatake YAMATO 
8582c11d8cSRich Siegel static const keywordTable JsonKeywordTable [] = {
86c379c5d2SMasatake YAMATO 	{"true",  KEYWORD_true },
87c379c5d2SMasatake YAMATO 	{"false", KEYWORD_false},
88c379c5d2SMasatake YAMATO 	{"null", KEYWORD_null },
89c379c5d2SMasatake YAMATO };
90c379c5d2SMasatake YAMATO 
newToken(void)913ae02089SMasatake YAMATO static tokenInfo *newToken (void)
923ae02089SMasatake YAMATO {
933ae02089SMasatake YAMATO 	tokenInfo *const token = xMalloc (1, tokenInfo);
943ae02089SMasatake YAMATO 
953ae02089SMasatake YAMATO 	token->type			= TOKEN_UNDEFINED;
963ae02089SMasatake YAMATO 	token->scopeKind	= TAG_NONE;
973ae02089SMasatake YAMATO 	token->string		= vStringNew ();
983ae02089SMasatake YAMATO 	token->scope		= vStringNew ();
99a31b37dcSMasatake YAMATO 	token->lineNumber	= getInputLineNumber ();
1003ae02089SMasatake YAMATO 	token->filePosition	= getInputFilePosition ();
1013ae02089SMasatake YAMATO 
1023ae02089SMasatake YAMATO 	return token;
1033ae02089SMasatake YAMATO }
1043ae02089SMasatake YAMATO 
deleteToken(tokenInfo * const token)1053ae02089SMasatake YAMATO static void deleteToken (tokenInfo *const token)
1063ae02089SMasatake YAMATO {
1073ae02089SMasatake YAMATO 	vStringDelete (token->string);
1083ae02089SMasatake YAMATO 	vStringDelete (token->scope);
1093ae02089SMasatake YAMATO 	eFree (token);
1103ae02089SMasatake YAMATO }
1113ae02089SMasatake YAMATO 
copyToken(tokenInfo * const dest,tokenInfo * const src)1123ae02089SMasatake YAMATO static void copyToken (tokenInfo *const dest, tokenInfo *const src)
1133ae02089SMasatake YAMATO {
1143ae02089SMasatake YAMATO 	dest->type = src->type;
1153ae02089SMasatake YAMATO 	dest->scopeKind = src->scopeKind;
1163ae02089SMasatake YAMATO 	vStringCopy (dest->string, src->string);
1173ae02089SMasatake YAMATO 	vStringCopy (dest->scope, src->scope);
1183ae02089SMasatake YAMATO 	dest->lineNumber = src->lineNumber;
1193ae02089SMasatake YAMATO 	dest->filePosition = src->filePosition;
1203ae02089SMasatake YAMATO }
1213ae02089SMasatake YAMATO 
makeJsonTag(tokenInfo * const token,const jsonKind kind)1223ae02089SMasatake YAMATO static void makeJsonTag (tokenInfo *const token, const jsonKind kind)
1233ae02089SMasatake YAMATO {
1243ae02089SMasatake YAMATO 	tagEntryInfo e;
1253ae02089SMasatake YAMATO 
1263ae02089SMasatake YAMATO 	if (! JsonKinds[kind].enabled)
1273ae02089SMasatake YAMATO 		return;
1283ae02089SMasatake YAMATO 
12916a2541cSMasatake YAMATO 	initTagEntry (&e, vStringValue (token->string), kind);
1303ae02089SMasatake YAMATO 
1313ae02089SMasatake YAMATO 	e.lineNumber	= token->lineNumber;
1323ae02089SMasatake YAMATO 	e.filePosition	= token->filePosition;
1333ae02089SMasatake YAMATO 
1343ae02089SMasatake YAMATO 	if (vStringLength (token->scope) > 0)
1353ae02089SMasatake YAMATO 	{
1363ae02089SMasatake YAMATO 		Assert (token->scopeKind > TAG_NONE && token->scopeKind < TAG_COUNT);
1373ae02089SMasatake YAMATO 
138f92e6bf2SMasatake YAMATO 		e.extensionFields.scopeKindIndex = token->scopeKind;
139015ab54cSMasatake YAMATO 		e.extensionFields.scopeName = vStringValue (token->scope);
1403ae02089SMasatake YAMATO 	}
1413ae02089SMasatake YAMATO 
1423ae02089SMasatake YAMATO 	makeTagEntry (&e);
1433ae02089SMasatake YAMATO }
1443ae02089SMasatake YAMATO 
145844ef580SMasatake YAMATO #define DEPTH_LIMIT 512
146844ef580SMasatake YAMATO static int depth_counter;
147844ef580SMasatake YAMATO 
readTokenFull(tokenInfo * const token,bool includeStringRepr)1483ae02089SMasatake YAMATO static void readTokenFull (tokenInfo *const token,
149ce990805SThomas Braun 						   bool includeStringRepr)
1503ae02089SMasatake YAMATO {
1513ae02089SMasatake YAMATO 	int c;
1523ae02089SMasatake YAMATO 
153844ef580SMasatake YAMATO 	if (depth_counter > DEPTH_LIMIT)
154844ef580SMasatake YAMATO 	{
155844ef580SMasatake YAMATO 		token->type = TOKEN_EOF;
156844ef580SMasatake YAMATO 
157844ef580SMasatake YAMATO 		/* Not to repeat warnings. */
158844ef580SMasatake YAMATO 		if (depth_counter == (DEPTH_LIMIT + 1))
159844ef580SMasatake YAMATO 		{
160844ef580SMasatake YAMATO 			notice ("Terminate parsing: too deep brackets recursion in %s at %ld",
161844ef580SMasatake YAMATO 					getInputFileName(), getInputLineNumber());
162844ef580SMasatake YAMATO 			depth_counter++;
163844ef580SMasatake YAMATO 		}
164844ef580SMasatake YAMATO 		return;
165844ef580SMasatake YAMATO 	}
166844ef580SMasatake YAMATO 
1673ae02089SMasatake YAMATO 	token->type = TOKEN_UNDEFINED;
1683ae02089SMasatake YAMATO 	vStringClear (token->string);
1693ae02089SMasatake YAMATO 
1703ae02089SMasatake YAMATO 	do
171018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
1723ae02089SMasatake YAMATO 	while (c == '\t' || c == ' ' || c == '\r' || c == '\n');
1733ae02089SMasatake YAMATO 
174a31b37dcSMasatake YAMATO 	token->lineNumber   = getInputLineNumber ();
1753ae02089SMasatake YAMATO 	token->filePosition = getInputFilePosition ();
1763ae02089SMasatake YAMATO 
1773ae02089SMasatake YAMATO 	switch (c)
1783ae02089SMasatake YAMATO 	{
1793ae02089SMasatake YAMATO 		case EOF: token->type = TOKEN_EOF;			break;
180844ef580SMasatake YAMATO 		case '[':
181*2ec6b03eSMasatake YAMATO 			depth_counter++;
182844ef580SMasatake YAMATO 			token->type = TOKEN_OPEN_SQUARE;		break;
183844ef580SMasatake YAMATO 		case ']':
184*2ec6b03eSMasatake YAMATO 			depth_counter--;
185844ef580SMasatake YAMATO 			token->type = TOKEN_CLOSE_SQUARE;		break;
186844ef580SMasatake YAMATO 		case '{':
187*2ec6b03eSMasatake YAMATO 			depth_counter++;
188844ef580SMasatake YAMATO 			token->type = TOKEN_OPEN_CURLY;			break;
189844ef580SMasatake YAMATO 		case '}':
190*2ec6b03eSMasatake YAMATO 			depth_counter--;
191844ef580SMasatake YAMATO 			token->type = TOKEN_CLOSE_CURLY;		break;
1923ae02089SMasatake YAMATO 		case ':': token->type = TOKEN_COLON;		break;
1933ae02089SMasatake YAMATO 		case ',': token->type = TOKEN_COMMA;		break;
1943ae02089SMasatake YAMATO 
1953ae02089SMasatake YAMATO 		case '"':
1963ae02089SMasatake YAMATO 		{
197ce990805SThomas Braun 			bool escaped = false;
1983ae02089SMasatake YAMATO 			token->type = TOKEN_STRING;
199ce990805SThomas Braun 			while (true)
2003ae02089SMasatake YAMATO 			{
201018bce0bSMasatake YAMATO 				c = getcFromInputFile ();
2023ae02089SMasatake YAMATO 				/* we don't handle unicode escapes but they are safe */
2033ae02089SMasatake YAMATO 				if (escaped)
204ce990805SThomas Braun 					escaped = false;
2053ae02089SMasatake YAMATO 				else if (c == '\\')
206ce990805SThomas Braun 					escaped = true;
2073ae02089SMasatake YAMATO 				else if (c >= 0x00 && c <= 0x1F)
2083ae02089SMasatake YAMATO 					break; /* break on invalid, unescaped, control characters */
2093ae02089SMasatake YAMATO 				else if (c == '"' || c == EOF)
2103ae02089SMasatake YAMATO 					break;
2113ae02089SMasatake YAMATO 				if (includeStringRepr)
2123ae02089SMasatake YAMATO 					vStringPut (token->string, c);
2133ae02089SMasatake YAMATO 			}
2143ae02089SMasatake YAMATO 			break;
2153ae02089SMasatake YAMATO 		}
2163ae02089SMasatake YAMATO 
2173ae02089SMasatake YAMATO 		default:
2183ae02089SMasatake YAMATO 			if (! isIdentChar (c))
2193ae02089SMasatake YAMATO 				token->type = TOKEN_UNDEFINED;
2203ae02089SMasatake YAMATO 			else
2213ae02089SMasatake YAMATO 			{
2223ae02089SMasatake YAMATO 				do
2233ae02089SMasatake YAMATO 				{
2243ae02089SMasatake YAMATO 					vStringPut (token->string, c);
225018bce0bSMasatake YAMATO 					c = getcFromInputFile ();
2263ae02089SMasatake YAMATO 				}
2273ae02089SMasatake YAMATO 				while (c != EOF && isIdentChar (c));
22861f14fa5SMasatake YAMATO 				ungetcToInputFile (c);
2293ae02089SMasatake YAMATO 				switch (lookupKeyword (vStringValue (token->string), Lang_json))
2303ae02089SMasatake YAMATO 				{
2313ae02089SMasatake YAMATO 					case KEYWORD_true:	token->type = TOKEN_TRUE;	break;
2323ae02089SMasatake YAMATO 					case KEYWORD_false:	token->type = TOKEN_FALSE;	break;
2333ae02089SMasatake YAMATO 					case KEYWORD_null:	token->type = TOKEN_NULL;	break;
2343ae02089SMasatake YAMATO 					default:			token->type = TOKEN_NUMBER;	break;
2353ae02089SMasatake YAMATO 				}
2363ae02089SMasatake YAMATO 			}
2373ae02089SMasatake YAMATO 			break;
2383ae02089SMasatake YAMATO 	}
2393ae02089SMasatake YAMATO }
2403ae02089SMasatake YAMATO 
241ce990805SThomas Braun #define readToken(t) (readTokenFull ((t), false))
2423ae02089SMasatake YAMATO 
pushScope(tokenInfo * const token,const tokenInfo * const parent,const jsonKind parentKind)2433ae02089SMasatake YAMATO static void pushScope (tokenInfo *const token,
2443ae02089SMasatake YAMATO 					   const tokenInfo *const parent,
2453ae02089SMasatake YAMATO 					   const jsonKind parentKind)
2463ae02089SMasatake YAMATO {
2473ae02089SMasatake YAMATO 	if (vStringLength (token->scope) > 0)
2483ae02089SMasatake YAMATO 		vStringPut (token->scope, '.');
2493ae02089SMasatake YAMATO 	vStringCat (token->scope, parent->string);
2503ae02089SMasatake YAMATO 	token->scopeKind = parentKind;
2513ae02089SMasatake YAMATO }
2523ae02089SMasatake YAMATO 
popScope(tokenInfo * const token,const tokenInfo * const parent)2533ae02089SMasatake YAMATO static void popScope (tokenInfo *const token,
2543ae02089SMasatake YAMATO 					  const tokenInfo *const parent)
2553ae02089SMasatake YAMATO {
2567ae28a3dSColomban Wendling 	vStringTruncate (token->scope, vStringLength (parent->scope));
2573ae02089SMasatake YAMATO 	token->scopeKind = parent->scopeKind;
2583ae02089SMasatake YAMATO }
2593ae02089SMasatake YAMATO 
2603ae02089SMasatake YAMATO #define skipToOneOf2(token, type1, type2) \
2613ae02089SMasatake YAMATO 	(skipToOneOf3 (token, type1, type2, TOKEN_EOF /* dummy */))
2623ae02089SMasatake YAMATO 
2633ae02089SMasatake YAMATO #define skipTo(token, type) \
2643ae02089SMasatake YAMATO 	(skipToOneOf3 (token, type, /* dummies */ TOKEN_EOF, TOKEN_EOF))
2653ae02089SMasatake YAMATO 
skipToOneOf3(tokenInfo * const token,const tokenType type1,const tokenType type2,const tokenType type3)2663ae02089SMasatake YAMATO static void skipToOneOf3 (tokenInfo *const token,
2673ae02089SMasatake YAMATO 						  const tokenType type1,
2683ae02089SMasatake YAMATO 						  const tokenType type2,
2693ae02089SMasatake YAMATO 						  const tokenType type3)
2703ae02089SMasatake YAMATO {
2713ae02089SMasatake YAMATO 	while (token->type != TOKEN_EOF &&
2723ae02089SMasatake YAMATO 		   token->type != type1 &&
2733ae02089SMasatake YAMATO 		   token->type != type2 &&
2743ae02089SMasatake YAMATO 		   token->type != type3)
2753ae02089SMasatake YAMATO 	{
2763ae02089SMasatake YAMATO 		readToken (token);
2773ae02089SMasatake YAMATO 		if (token->type == TOKEN_OPEN_CURLY)
2783ae02089SMasatake YAMATO 		{
2793ae02089SMasatake YAMATO 			skipTo (token, TOKEN_CLOSE_CURLY);
2803ae02089SMasatake YAMATO 			readToken (token);
2813ae02089SMasatake YAMATO 		}
2823ae02089SMasatake YAMATO 		else if (token->type == TOKEN_OPEN_SQUARE)
2833ae02089SMasatake YAMATO 		{
2843ae02089SMasatake YAMATO 			skipTo (token, TOKEN_CLOSE_SQUARE);
2853ae02089SMasatake YAMATO 			readToken (token);
2863ae02089SMasatake YAMATO 		}
2873ae02089SMasatake YAMATO 	}
2883ae02089SMasatake YAMATO }
2893ae02089SMasatake YAMATO 
tokenToKind(const tokenType type)2903ae02089SMasatake YAMATO static jsonKind tokenToKind (const tokenType type)
2913ae02089SMasatake YAMATO {
2923ae02089SMasatake YAMATO 	switch (type)
2933ae02089SMasatake YAMATO 	{
2943ae02089SMasatake YAMATO 		case TOKEN_OPEN_CURLY:	return TAG_OBJECT;
2953ae02089SMasatake YAMATO 		case TOKEN_OPEN_SQUARE:	return TAG_ARRAY;
2963ae02089SMasatake YAMATO 		case TOKEN_STRING:		return TAG_STRING;
2973ae02089SMasatake YAMATO 		case TOKEN_TRUE:
2983ae02089SMasatake YAMATO 		case TOKEN_FALSE:		return TAG_BOOLEAN;
2993ae02089SMasatake YAMATO 		case TOKEN_NUMBER:		return TAG_NUMBER;
3003ae02089SMasatake YAMATO 		default:				return TAG_NULL;
3013ae02089SMasatake YAMATO 	}
3023ae02089SMasatake YAMATO }
3033ae02089SMasatake YAMATO 
parseValue(tokenInfo * const token)3043ae02089SMasatake YAMATO static void parseValue (tokenInfo *const token)
3053ae02089SMasatake YAMATO {
3063ae02089SMasatake YAMATO 	if (token->type == TOKEN_OPEN_CURLY)
3073ae02089SMasatake YAMATO 	{
3083ae02089SMasatake YAMATO 		tokenInfo *name = newToken ();
3093ae02089SMasatake YAMATO 
3103ae02089SMasatake YAMATO 		do
3113ae02089SMasatake YAMATO 		{
312ce990805SThomas Braun 			readTokenFull (token, true);
3133ae02089SMasatake YAMATO 			if (token->type == TOKEN_STRING)
3143ae02089SMasatake YAMATO 			{
3153ae02089SMasatake YAMATO 				jsonKind tagKind = TAG_NULL; /* default in case of invalid value */
3163ae02089SMasatake YAMATO 
3173ae02089SMasatake YAMATO 				copyToken (name, token);
3183ae02089SMasatake YAMATO 
3193ae02089SMasatake YAMATO 				/* skip any possible garbage before the value */
3203ae02089SMasatake YAMATO 				skipToOneOf3 (token, TOKEN_CLOSE_CURLY, TOKEN_COLON, TOKEN_COMMA);
3213ae02089SMasatake YAMATO 
3223ae02089SMasatake YAMATO 				if (token->type == TOKEN_COLON)
3233ae02089SMasatake YAMATO 				{
3243ae02089SMasatake YAMATO 					readToken (token);
3253ae02089SMasatake YAMATO 					tagKind = tokenToKind (token->type);
3263ae02089SMasatake YAMATO 
3273ae02089SMasatake YAMATO 					pushScope (token, name, tagKind);
3283ae02089SMasatake YAMATO 					parseValue (token);
3293ae02089SMasatake YAMATO 					popScope (token, name);
3303ae02089SMasatake YAMATO 				}
3313ae02089SMasatake YAMATO 
3323ae02089SMasatake YAMATO 				makeJsonTag (name, tagKind);
3333ae02089SMasatake YAMATO 			}
3343ae02089SMasatake YAMATO 			/* skip to the end of the construct */
3353ae02089SMasatake YAMATO 			skipToOneOf2 (token, TOKEN_CLOSE_CURLY, TOKEN_COMMA);
3363ae02089SMasatake YAMATO 		}
3373ae02089SMasatake YAMATO 		while (token->type != TOKEN_EOF &&
3383ae02089SMasatake YAMATO 			   token->type != TOKEN_CLOSE_CURLY);
3393ae02089SMasatake YAMATO 
3403ae02089SMasatake YAMATO 		if (token->type == TOKEN_CLOSE_CURLY)
3413ae02089SMasatake YAMATO 			readToken (token);
3423ae02089SMasatake YAMATO 
3433ae02089SMasatake YAMATO 		deleteToken (name);
3443ae02089SMasatake YAMATO 	}
3453ae02089SMasatake YAMATO 	else if (token->type == TOKEN_OPEN_SQUARE)
3463ae02089SMasatake YAMATO 	{
3473ae02089SMasatake YAMATO 		tokenInfo *name = newToken ();
3483ae02089SMasatake YAMATO 		char buf[32];
3493ae02089SMasatake YAMATO 		unsigned int nth = 0;
3503ae02089SMasatake YAMATO 
3513ae02089SMasatake YAMATO 		readToken (token);
3523ae02089SMasatake YAMATO 		while (token->type != TOKEN_EOF &&
3533ae02089SMasatake YAMATO 			   token->type != TOKEN_CLOSE_SQUARE)
3543ae02089SMasatake YAMATO 		{
3553ae02089SMasatake YAMATO 			jsonKind tagKind;
3563ae02089SMasatake YAMATO 
3573ae02089SMasatake YAMATO 			tagKind = tokenToKind (token->type);
3583ae02089SMasatake YAMATO 
3593ae02089SMasatake YAMATO 			copyToken (name, token);
3603ae02089SMasatake YAMATO 			snprintf (buf, sizeof buf, "%u", nth++);
3613ae02089SMasatake YAMATO 			vStringCopyS (name->string, buf);
3623ae02089SMasatake YAMATO 
3633ae02089SMasatake YAMATO 			makeJsonTag (name, tagKind);
3643ae02089SMasatake YAMATO 			pushScope (token, name, tagKind);
3653ae02089SMasatake YAMATO 			parseValue (token);
3663ae02089SMasatake YAMATO 			popScope (token, name);
3673ae02089SMasatake YAMATO 
3683ae02089SMasatake YAMATO 			/* skip to the end of the construct */
3693ae02089SMasatake YAMATO 			skipToOneOf2 (token, TOKEN_CLOSE_SQUARE, TOKEN_COMMA);
3703ae02089SMasatake YAMATO 			if (token->type != TOKEN_CLOSE_SQUARE)
3713ae02089SMasatake YAMATO 				readToken (token);
3723ae02089SMasatake YAMATO 		}
3733ae02089SMasatake YAMATO 
3743ae02089SMasatake YAMATO 		if (token->type == TOKEN_CLOSE_SQUARE)
3753ae02089SMasatake YAMATO 			readToken (token);
3763ae02089SMasatake YAMATO 
3773ae02089SMasatake YAMATO 		deleteToken (name);
3783ae02089SMasatake YAMATO 	}
3793ae02089SMasatake YAMATO }
3803ae02089SMasatake YAMATO 
findJsonTags(void)3813ae02089SMasatake YAMATO static void findJsonTags (void)
3823ae02089SMasatake YAMATO {
3833ae02089SMasatake YAMATO 	tokenInfo *const token = newToken ();
3843ae02089SMasatake YAMATO 
385*2ec6b03eSMasatake YAMATO 	depth_counter = 0;
386844ef580SMasatake YAMATO 
3873ae02089SMasatake YAMATO 	/* We allow multiple top-level elements, although it's not actually valid
3883ae02089SMasatake YAMATO 	 * JSON.  An interesting side effect of this is that we allow a leading
3893ae02089SMasatake YAMATO 	 * Unicode BOM mark -- even though ok, many JSON parsers will choke on it */
3903ae02089SMasatake YAMATO 	do
3913ae02089SMasatake YAMATO 	{
3923ae02089SMasatake YAMATO 		readToken (token);
3933ae02089SMasatake YAMATO 		parseValue (token);
3943ae02089SMasatake YAMATO 	}
3953ae02089SMasatake YAMATO 	while (token->type != TOKEN_EOF);
3963ae02089SMasatake YAMATO 
3973ae02089SMasatake YAMATO 	deleteToken (token);
3983ae02089SMasatake YAMATO }
3993ae02089SMasatake YAMATO 
initialize(const langType language)4003ae02089SMasatake YAMATO static void initialize (const langType language)
4013ae02089SMasatake YAMATO {
4023ae02089SMasatake YAMATO 	Lang_json = language;
4033ae02089SMasatake YAMATO }
4043ae02089SMasatake YAMATO 
405137eb990SK.Takata /* Create parser definition structure */
JsonParser(void)4063ae02089SMasatake YAMATO extern parserDefinition* JsonParser (void)
4073ae02089SMasatake YAMATO {
4083ae02089SMasatake YAMATO 	static const char *const extensions [] = { "json", NULL };
4093ae02089SMasatake YAMATO 	parserDefinition *const def = parserNew ("JSON");
4103ae02089SMasatake YAMATO 	def->extensions = extensions;
41109ae690fSMasatake YAMATO 	def->kindTable	= JsonKinds;
4123db72c21SMasatake YAMATO 	def->kindCount	= ARRAY_SIZE (JsonKinds);
4133ae02089SMasatake YAMATO 	def->parser		= findJsonTags;
4143ae02089SMasatake YAMATO 	def->initialize = initialize;
415c379c5d2SMasatake YAMATO 	def->keywordTable = JsonKeywordTable;
4163db72c21SMasatake YAMATO 	def->keywordCount = ARRAY_SIZE (JsonKeywordTable);
417ce990805SThomas Braun 	def->allowNullTag = true;
4183ae02089SMasatake YAMATO 
4193ae02089SMasatake YAMATO 	return def;
4203ae02089SMasatake YAMATO }
421