xref: /Universal-ctags/parsers/jscript.c (revision 6f5dd0b16afc44f8acb7f7c0561de3aaa16909cc)
13ae02089SMasatake YAMATO /*
23ae02089SMasatake YAMATO  *	 Copyright (c) 2003, Darren Hiebert
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  *	 This module contains functions for generating tags for JavaScript language
83ae02089SMasatake YAMATO  *	 files.
93ae02089SMasatake YAMATO  *
104241b144SColomban Wendling  *	 Reference: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
114241b144SColomban Wendling  *
123ae02089SMasatake YAMATO  *	 This is a good reference for different forms of the function statement:
133ae02089SMasatake YAMATO  *		 http://www.permadi.com/tutorial/jsFunc/
143ae02089SMasatake YAMATO  *   Another good reference:
153ae02089SMasatake YAMATO  *       http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide
163ae02089SMasatake YAMATO  */
173ae02089SMasatake YAMATO 
183ae02089SMasatake YAMATO /*
193ae02089SMasatake YAMATO  *	 INCLUDE FILES
203ae02089SMasatake YAMATO  */
213ae02089SMasatake YAMATO #include "general.h"	/* must always come first */
223ae02089SMasatake YAMATO #include <ctype.h>	/* to define isalpha () */
233ae02089SMasatake YAMATO #ifdef DEBUG
243ae02089SMasatake YAMATO #include <stdio.h>
253ae02089SMasatake YAMATO #endif
263ae02089SMasatake YAMATO 
274d985ad2SColomban Wendling #ifdef HAVE_ICONV
284d985ad2SColomban Wendling #include <iconv.h>
294d985ad2SColomban Wendling #include <errno.h>
303addc312SColomban Wendling #	ifdef WORDS_BIGENDIAN
313addc312SColomban Wendling #		define INTERNAL_ENCODING "UTF-32BE"
323addc312SColomban Wendling #	else
333addc312SColomban Wendling #		define INTERNAL_ENCODING "UTF-32LE"
343addc312SColomban Wendling #	endif /* WORDS_BIGENDIAN */
354d985ad2SColomban Wendling #endif
364d985ad2SColomban Wendling 
373ae02089SMasatake YAMATO #include <string.h>
383ae02089SMasatake YAMATO #include "debug.h"
393ae02089SMasatake YAMATO #include "entry.h"
403ae02089SMasatake YAMATO #include "keyword.h"
413ae02089SMasatake YAMATO #include "parse.h"
423ae02089SMasatake YAMATO #include "read.h"
433ae02089SMasatake YAMATO #include "routines.h"
443ae02089SMasatake YAMATO #include "vstring.h"
453815cb18SJiří Techet #include "objpool.h"
464d985ad2SColomban Wendling #include "options.h"
474d985ad2SColomban Wendling #include "mbcs.h"
4885bb93f2SSzymon Tomasz Stefanek #include "trace.h"
490d502ef0SMasatake YAMATO #include "strlist.h"
503ae02089SMasatake YAMATO 
513ae02089SMasatake YAMATO /*
523ae02089SMasatake YAMATO  *	 MACROS
533ae02089SMasatake YAMATO  */
54ce990805SThomas Braun #define isType(token,t)		(bool) ((token)->type == (t))
55ce990805SThomas Braun #define isKeyword(token,k)	(bool) ((token)->keyword == (k))
562b28d0e0SJiří Techet #define isIdentChar(c) \
572b28d0e0SJiří Techet 	(isalpha (c) || isdigit (c) || (c) == '$' || \
584d985ad2SColomban Wendling 		(c) == '@' || (c) == '_' || (c) == '#' || \
594d985ad2SColomban Wendling 		(c) >= 0x80)
603815cb18SJiří Techet #define newToken() (objPoolGet (TokenPool))
613815cb18SJiří Techet #define deleteToken(t) (objPoolPut (TokenPool, (t)))
623ae02089SMasatake YAMATO 
633ae02089SMasatake YAMATO /*
643ae02089SMasatake YAMATO  *	 DATA DECLARATIONS
653ae02089SMasatake YAMATO  */
663ae02089SMasatake YAMATO 
673ae02089SMasatake YAMATO /*
683ae02089SMasatake YAMATO  * Tracks class and function names already created
693ae02089SMasatake YAMATO  */
703ae02089SMasatake YAMATO static stringList *ClassNames;
713ae02089SMasatake YAMATO static stringList *FunctionNames;
723ae02089SMasatake YAMATO 
733ae02089SMasatake YAMATO /*	Used to specify type of keyword.
743ae02089SMasatake YAMATO */
754faa2076SColomban Wendling enum eKeywordId {
763ae02089SMasatake YAMATO 	KEYWORD_function,
773ae02089SMasatake YAMATO 	KEYWORD_capital_function,
783ae02089SMasatake YAMATO 	KEYWORD_capital_object,
793ae02089SMasatake YAMATO 	KEYWORD_prototype,
803ae02089SMasatake YAMATO 	KEYWORD_var,
813ae02089SMasatake YAMATO 	KEYWORD_let,
823ae02089SMasatake YAMATO 	KEYWORD_const,
833ae02089SMasatake YAMATO 	KEYWORD_new,
843ae02089SMasatake YAMATO 	KEYWORD_this,
853ae02089SMasatake YAMATO 	KEYWORD_for,
863ae02089SMasatake YAMATO 	KEYWORD_while,
873ae02089SMasatake YAMATO 	KEYWORD_do,
883ae02089SMasatake YAMATO 	KEYWORD_if,
893ae02089SMasatake YAMATO 	KEYWORD_else,
903ae02089SMasatake YAMATO 	KEYWORD_switch,
913ae02089SMasatake YAMATO 	KEYWORD_try,
923ae02089SMasatake YAMATO 	KEYWORD_catch,
933ae02089SMasatake YAMATO 	KEYWORD_finally,
943ae02089SMasatake YAMATO 	KEYWORD_sap,
9588ec5491SSzymon Tomasz Stefanek 	KEYWORD_return,
9688ec5491SSzymon Tomasz Stefanek 	KEYWORD_class,
9788ec5491SSzymon Tomasz Stefanek 	KEYWORD_extends,
98e76668e3SSzymon Tomasz Stefanek 	KEYWORD_static,
991917d23dSColomban Wendling 	KEYWORD_default,
1001917d23dSColomban Wendling 	KEYWORD_export,
10141c2c77eSColomban Wendling 	KEYWORD_async,
1028d0d236fSMasatake YAMATO 	KEYWORD_get,
1038d0d236fSMasatake YAMATO 	KEYWORD_set,
1044faa2076SColomban Wendling };
1054faa2076SColomban Wendling typedef int keywordId; /* to allow KEYWORD_NONE */
1063ae02089SMasatake YAMATO 
1073ae02089SMasatake YAMATO typedef enum eTokenType {
1083ae02089SMasatake YAMATO 	TOKEN_UNDEFINED,
1093ae02089SMasatake YAMATO 	TOKEN_EOF,
1103ae02089SMasatake YAMATO 	TOKEN_CHARACTER,
1113ae02089SMasatake YAMATO 	TOKEN_CLOSE_PAREN,
1123ae02089SMasatake YAMATO 	TOKEN_SEMICOLON,
1133ae02089SMasatake YAMATO 	TOKEN_COLON,
1143ae02089SMasatake YAMATO 	TOKEN_COMMA,
1153ae02089SMasatake YAMATO 	TOKEN_KEYWORD,
1163ae02089SMasatake YAMATO 	TOKEN_OPEN_PAREN,
1173ae02089SMasatake YAMATO 	TOKEN_IDENTIFIER,
1183ae02089SMasatake YAMATO 	TOKEN_STRING,
1195869a275SColomban Wendling 	TOKEN_TEMPLATE_STRING,
1203ae02089SMasatake YAMATO 	TOKEN_PERIOD,
1213ae02089SMasatake YAMATO 	TOKEN_OPEN_CURLY,
1223ae02089SMasatake YAMATO 	TOKEN_CLOSE_CURLY,
1233ae02089SMasatake YAMATO 	TOKEN_EQUAL_SIGN,
1243ae02089SMasatake YAMATO 	TOKEN_OPEN_SQUARE,
1253ae02089SMasatake YAMATO 	TOKEN_CLOSE_SQUARE,
1263ae02089SMasatake YAMATO 	TOKEN_REGEXP,
1273ae02089SMasatake YAMATO 	TOKEN_POSTFIX_OPERATOR,
128d01b4a7cSColomban Wendling 	TOKEN_STAR,
129f2e65b39SMasatake YAMATO 	/* To handle Babel's decorators.
130f2e65b39SMasatake YAMATO 	 * Used only in readTokenFull or lower functions. */
131f2e65b39SMasatake YAMATO 	TOKEN_ATMARK,
13250eb5201SJohn Lindal 	TOKEN_BINARY_OPERATOR,
13350eb5201SJohn Lindal 	TOKEN_ARROW
1343ae02089SMasatake YAMATO } tokenType;
1353ae02089SMasatake YAMATO 
1363ae02089SMasatake YAMATO typedef struct sTokenInfo {
1373ae02089SMasatake YAMATO 	tokenType		type;
1383ae02089SMasatake YAMATO 	keywordId		keyword;
1393ae02089SMasatake YAMATO 	vString *		string;
1403ae02089SMasatake YAMATO 	vString *		scope;
1413ae02089SMasatake YAMATO 	unsigned long 	lineNumber;
142509a47dbSJiří Techet 	MIOPos 			filePosition;
1433ae02089SMasatake YAMATO 	int				nestLevel;
144c3f80c4aSMasatake YAMATO 	bool			dynamicProp;
1453ae02089SMasatake YAMATO } tokenInfo;
1463ae02089SMasatake YAMATO 
1473ae02089SMasatake YAMATO /*
1483ae02089SMasatake YAMATO  *	DATA DEFINITIONS
1493ae02089SMasatake YAMATO  */
1503ae02089SMasatake YAMATO 
1513ae02089SMasatake YAMATO static tokenType LastTokenType;
152fc4ca4b7SColomban Wendling static tokenInfo *NextToken;
1533ae02089SMasatake YAMATO 
1543ae02089SMasatake YAMATO static langType Lang_js;
1553ae02089SMasatake YAMATO 
1563815cb18SJiří Techet static objPool *TokenPool = NULL;
1573815cb18SJiří Techet 
1584d985ad2SColomban Wendling #ifdef HAVE_ICONV
1594d985ad2SColomban Wendling static iconv_t JSUnicodeConverter = (iconv_t) -2;
1604d985ad2SColomban Wendling #endif
1614d985ad2SColomban Wendling 
1623ae02089SMasatake YAMATO typedef enum {
1633ae02089SMasatake YAMATO 	JSTAG_FUNCTION,
1643ae02089SMasatake YAMATO 	JSTAG_CLASS,
1653ae02089SMasatake YAMATO 	JSTAG_METHOD,
1663ae02089SMasatake YAMATO 	JSTAG_PROPERTY,
1673ae02089SMasatake YAMATO 	JSTAG_CONSTANT,
1683ae02089SMasatake YAMATO 	JSTAG_VARIABLE,
169d01b4a7cSColomban Wendling 	JSTAG_GENERATOR,
1708d0d236fSMasatake YAMATO 	JSTAG_GETTER,
1718d0d236fSMasatake YAMATO 	JSTAG_SETTER,
17223d2f194SMasatake YAMATO 	JSTAG_FIELD,
1733ae02089SMasatake YAMATO 	JSTAG_COUNT
1743ae02089SMasatake YAMATO } jsKind;
1753ae02089SMasatake YAMATO 
176e112e8abSMasatake YAMATO static kindDefinition JsKinds [] = {
177ce990805SThomas Braun 	{ true,  'f', "function",	  "functions"		   },
178ce990805SThomas Braun 	{ true,  'c', "class",		  "classes"			   },
179ce990805SThomas Braun 	{ true,  'm', "method",		  "methods"			   },
180ce990805SThomas Braun 	{ true,  'p', "property",	  "properties"		   },
181ce990805SThomas Braun 	{ true,  'C', "constant",	  "constants"		   },
182d01b4a7cSColomban Wendling 	{ true,  'v', "variable",	  "global variables"   },
1838d0d236fSMasatake YAMATO 	{ true,  'g', "generator",	  "generators"		   },
1848d0d236fSMasatake YAMATO 	{ true,  'G', "getter",		  "getters"			   },
1858d0d236fSMasatake YAMATO 	{ true,  'S', "setter",		  "setters"			   },
18623d2f194SMasatake YAMATO 	{ true,  'M', "field",		  "fields"			   },
1873ae02089SMasatake YAMATO };
1883ae02089SMasatake YAMATO 
18982c11d8cSRich Siegel static const keywordTable JsKeywordTable [] = {
1903ae02089SMasatake YAMATO 	/* keyword		keyword ID */
1913ae02089SMasatake YAMATO 	{ "function",	KEYWORD_function			},
1923ae02089SMasatake YAMATO 	{ "Function",	KEYWORD_capital_function	},
1933ae02089SMasatake YAMATO 	{ "Object",		KEYWORD_capital_object		},
1943ae02089SMasatake YAMATO 	{ "prototype",	KEYWORD_prototype			},
1953ae02089SMasatake YAMATO 	{ "var",		KEYWORD_var					},
1963ae02089SMasatake YAMATO 	{ "let",		KEYWORD_let					},
1973ae02089SMasatake YAMATO 	{ "const",		KEYWORD_const				},
1983ae02089SMasatake YAMATO 	{ "new",		KEYWORD_new					},
1993ae02089SMasatake YAMATO 	{ "this",		KEYWORD_this				},
2003ae02089SMasatake YAMATO 	{ "for",		KEYWORD_for					},
2013ae02089SMasatake YAMATO 	{ "while",		KEYWORD_while				},
2023ae02089SMasatake YAMATO 	{ "do",			KEYWORD_do					},
2033ae02089SMasatake YAMATO 	{ "if",			KEYWORD_if					},
2043ae02089SMasatake YAMATO 	{ "else",		KEYWORD_else				},
2053ae02089SMasatake YAMATO 	{ "switch",		KEYWORD_switch				},
2063ae02089SMasatake YAMATO 	{ "try",		KEYWORD_try					},
2073ae02089SMasatake YAMATO 	{ "catch",		KEYWORD_catch				},
2083ae02089SMasatake YAMATO 	{ "finally",	KEYWORD_finally				},
2093ae02089SMasatake YAMATO 	{ "sap",	    KEYWORD_sap    				},
21088ec5491SSzymon Tomasz Stefanek 	{ "return",		KEYWORD_return				},
21188ec5491SSzymon Tomasz Stefanek 	{ "class",		KEYWORD_class				},
21288ec5491SSzymon Tomasz Stefanek 	{ "extends",	KEYWORD_extends				},
213e76668e3SSzymon Tomasz Stefanek 	{ "static",		KEYWORD_static				},
2141917d23dSColomban Wendling 	{ "default",	KEYWORD_default				},
2151917d23dSColomban Wendling 	{ "export",		KEYWORD_export				},
21641c2c77eSColomban Wendling 	{ "async",		KEYWORD_async				},
2178d0d236fSMasatake YAMATO 	{ "get",		KEYWORD_get					},
2188d0d236fSMasatake YAMATO 	{ "set",		KEYWORD_set					},
2193ae02089SMasatake YAMATO };
2203ae02089SMasatake YAMATO 
2213ae02089SMasatake YAMATO /*
2223ae02089SMasatake YAMATO  *	 FUNCTION DEFINITIONS
2233ae02089SMasatake YAMATO  */
2243ae02089SMasatake YAMATO 
2253ae02089SMasatake YAMATO /* Recursive functions */
226ce990805SThomas Braun static void readTokenFull (tokenInfo *const token, bool include_newlines, vString *const repr);
227f2e65b39SMasatake YAMATO static void skipArgumentList (tokenInfo *const token, bool include_newlines, vString *const repr);
2283ae02089SMasatake YAMATO static void parseFunction (tokenInfo *const token);
2294fd7a374SColomban Wendling static bool parseBlock (tokenInfo *const token, const vString *const parentScope);
23050eb5201SJohn Lindal static bool parseMethods (tokenInfo *const token, const tokenInfo *const class, const bool is_es6_class);
2314fd7a374SColomban Wendling static bool parseLine (tokenInfo *const token, bool is_inside_class);
2323ae02089SMasatake YAMATO static void parseUI5 (tokenInfo *const token);
2333ae02089SMasatake YAMATO 
2340b62aad1SMasatake YAMATO #ifdef DO_TRACING
2350b62aad1SMasatake YAMATO static const char *tokenTypeName(enum eTokenType e);
236*6f5dd0b1SMasatake YAMATO // #define DO_TRACING_USE_DUMP_TOKEN
237*6f5dd0b1SMasatake YAMATO #ifdef DO_TRACING_USE_DUMP_TOKEN
238*6f5dd0b1SMasatake YAMATO static void dumpToken (const tokenInfo *const token);
239*6f5dd0b1SMasatake YAMATO static const char *keywordName(enum eKeywordId e);
240*6f5dd0b1SMasatake YAMATO #endif
2410b62aad1SMasatake YAMATO #endif
2420b62aad1SMasatake YAMATO 
newPoolToken(void * createArg CTAGS_ATTR_UNUSED)243e013efc1SMasatake YAMATO static void *newPoolToken (void *createArg CTAGS_ATTR_UNUSED)
2443ae02089SMasatake YAMATO {
2453815cb18SJiří Techet 	tokenInfo *token = xMalloc (1, tokenInfo);
2463ae02089SMasatake YAMATO 
2473ae02089SMasatake YAMATO 	token->string		= vStringNew ();
2483ae02089SMasatake YAMATO 	token->scope		= vStringNew ();
2493ae02089SMasatake YAMATO 
2503ae02089SMasatake YAMATO 	return token;
2513ae02089SMasatake YAMATO }
2523ae02089SMasatake YAMATO 
clearPoolToken(void * data)2533815cb18SJiří Techet static void clearPoolToken (void *data)
2543ae02089SMasatake YAMATO {
2553815cb18SJiří Techet 	tokenInfo *token = data;
2563815cb18SJiří Techet 
2573815cb18SJiří Techet 	token->type			= TOKEN_UNDEFINED;
2583815cb18SJiří Techet 	token->keyword		= KEYWORD_NONE;
2593815cb18SJiří Techet 	token->nestLevel	= 0;
260c3f80c4aSMasatake YAMATO 	token->dynamicProp  = false;
2613815cb18SJiří Techet 	token->lineNumber   = getInputLineNumber ();
2623815cb18SJiří Techet 	token->filePosition = getInputFilePosition ();
2633815cb18SJiří Techet 	vStringClear (token->string);
2643815cb18SJiří Techet 	vStringClear (token->scope);
2653815cb18SJiří Techet }
2663815cb18SJiří Techet 
deletePoolToken(void * data)2673815cb18SJiří Techet static void deletePoolToken (void *data)
2683815cb18SJiří Techet {
2693815cb18SJiří Techet 	tokenInfo *token = data;
2703ae02089SMasatake YAMATO 	vStringDelete (token->string);
2713ae02089SMasatake YAMATO 	vStringDelete (token->scope);
2723ae02089SMasatake YAMATO 	eFree (token);
2733ae02089SMasatake YAMATO }
2743ae02089SMasatake YAMATO 
copyToken(tokenInfo * const dest,const tokenInfo * const src,bool const include_non_read_info)275fc4ca4b7SColomban Wendling static void copyToken (tokenInfo *const dest, const tokenInfo *const src,
276ce990805SThomas Braun                        bool const include_non_read_info)
277fc4ca4b7SColomban Wendling {
278fc4ca4b7SColomban Wendling 	dest->lineNumber = src->lineNumber;
279fc4ca4b7SColomban Wendling 	dest->filePosition = src->filePosition;
280fc4ca4b7SColomban Wendling 	dest->type = src->type;
281fc4ca4b7SColomban Wendling 	dest->keyword = src->keyword;
282c3f80c4aSMasatake YAMATO 	dest->dynamicProp = src->dynamicProp;
283fc4ca4b7SColomban Wendling 	vStringCopy(dest->string, src->string);
284fc4ca4b7SColomban Wendling 	if (include_non_read_info)
285fc4ca4b7SColomban Wendling 	{
286fc4ca4b7SColomban Wendling 		dest->nestLevel = src->nestLevel;
287fc4ca4b7SColomban Wendling 		vStringCopy(dest->scope, src->scope);
288fc4ca4b7SColomban Wendling 	}
289fc4ca4b7SColomban Wendling }
290fc4ca4b7SColomban Wendling 
injectDynamicName(tokenInfo * const token,vString * newName)291c3f80c4aSMasatake YAMATO static void injectDynamicName (tokenInfo *const token, vString *newName)
292c3f80c4aSMasatake YAMATO {
293c3f80c4aSMasatake YAMATO 	token->dynamicProp = true;
294c3f80c4aSMasatake YAMATO 	vStringDelete (token->string);
295c3f80c4aSMasatake YAMATO 	token->string = newName;
296c3f80c4aSMasatake YAMATO }
297c3f80c4aSMasatake YAMATO 
2983ae02089SMasatake YAMATO /*
2993ae02089SMasatake YAMATO  *	 Tag generation functions
3003ae02089SMasatake YAMATO  */
3013ae02089SMasatake YAMATO 
makeJsTagCommon(const tokenInfo * const token,const jsKind kind,vString * const signature,vString * const inheritance,bool anonymous)3020e4c5d4aSMasatake YAMATO static void makeJsTagCommon (const tokenInfo *const token, const jsKind kind,
3030e4c5d4aSMasatake YAMATO 							 vString *const signature, vString *const inheritance,
3040e4c5d4aSMasatake YAMATO 							 bool anonymous)
3053ae02089SMasatake YAMATO {
30650c63a4eSMasatake YAMATO 	if (JsKinds [kind].enabled )
3073ae02089SMasatake YAMATO 	{
3083ae02089SMasatake YAMATO 		const char *name = vStringValue (token->string);
3093ae02089SMasatake YAMATO 		vString *fullscope = vStringNewCopy (token->scope);
3103ae02089SMasatake YAMATO 		const char *p;
3113ae02089SMasatake YAMATO 		tagEntryInfo e;
3123ae02089SMasatake YAMATO 
313c3f80c4aSMasatake YAMATO 		if (!token->dynamicProp && kind != JSTAG_PROPERTY &&  (p = strrchr (name, '.')) != NULL )
3143ae02089SMasatake YAMATO 		{
3153ae02089SMasatake YAMATO 			if (vStringLength (fullscope) > 0)
3163ae02089SMasatake YAMATO 				vStringPut (fullscope, '.');
3173ae02089SMasatake YAMATO 			vStringNCatS (fullscope, name, (size_t) (p - name));
3183ae02089SMasatake YAMATO 			name = p + 1;
3193ae02089SMasatake YAMATO 		}
3203ae02089SMasatake YAMATO 
32116a2541cSMasatake YAMATO 		initTagEntry (&e, name, kind);
3223ae02089SMasatake YAMATO 
323c93e1170SMasatake YAMATO 		TRACE_PRINT("Emitting tag for symbol '%s' of kind %02x with scope '%s'",name,kind,vStringValue(fullscope));
32485bb93f2SSzymon Tomasz Stefanek 
3253ae02089SMasatake YAMATO 		e.lineNumber   = token->lineNumber;
3263ae02089SMasatake YAMATO 		e.filePosition = token->filePosition;
3273ae02089SMasatake YAMATO 
3283ae02089SMasatake YAMATO 		if ( vStringLength(fullscope) > 0 )
3293ae02089SMasatake YAMATO 		{
330e81a1060SColomban Wendling 			/* FIXME: proper parent type */
3313ae02089SMasatake YAMATO 			jsKind parent_kind = JSTAG_CLASS;
3323ae02089SMasatake YAMATO 
3333ae02089SMasatake YAMATO 			/*
3343ae02089SMasatake YAMATO 			 * If we're creating a function (and not a method),
3353ae02089SMasatake YAMATO 			 * guess we're inside another function
3363ae02089SMasatake YAMATO 			 */
3373ae02089SMasatake YAMATO 			if (kind == JSTAG_FUNCTION)
3383ae02089SMasatake YAMATO 				parent_kind = JSTAG_FUNCTION;
3393ae02089SMasatake YAMATO 
340f92e6bf2SMasatake YAMATO 			e.extensionFields.scopeKindIndex = parent_kind;
341015ab54cSMasatake YAMATO 			e.extensionFields.scopeName = vStringValue (fullscope);
3423ae02089SMasatake YAMATO 		}
3433ae02089SMasatake YAMATO 
3443ae02089SMasatake YAMATO 		if (signature && vStringLength(signature))
3453ae02089SMasatake YAMATO 		{
3463ae02089SMasatake YAMATO 			size_t i;
3473ae02089SMasatake YAMATO 			/* sanitize signature by replacing all control characters with a
3483ae02089SMasatake YAMATO 			 * space (because it's simple).
3493ae02089SMasatake YAMATO 			 * there should never be any junk in a valid signature, but who
3503ae02089SMasatake YAMATO 			 * knows what the user wrote and CTags doesn't cope well with weird
3513ae02089SMasatake YAMATO 			 * characters. */
3523ae02089SMasatake YAMATO 			for (i = 0; i < signature->length; i++)
3533ae02089SMasatake YAMATO 			{
354e852ee0eSMasatake YAMATO 				unsigned char c = (unsigned char) vStringChar (signature, i);
3553ae02089SMasatake YAMATO 				if (c < 0x20 /* below space */ || c == 0x7F /* DEL */)
356e852ee0eSMasatake YAMATO 					vStringChar (signature, i) = ' ';
3573ae02089SMasatake YAMATO 			}
3583ae02089SMasatake YAMATO 			e.extensionFields.signature = vStringValue(signature);
3593ae02089SMasatake YAMATO 		}
3603ae02089SMasatake YAMATO 
361a53a76deSColomban Wendling 		if (inheritance)
362a53a76deSColomban Wendling 			e.extensionFields.inheritance = vStringValue(inheritance);
363a53a76deSColomban Wendling 
3640e4c5d4aSMasatake YAMATO 		if (anonymous)
3650e4c5d4aSMasatake YAMATO 			markTagExtraBit (&e, XTAG_ANONYMOUS);
3660e4c5d4aSMasatake YAMATO 
3673ae02089SMasatake YAMATO 		makeTagEntry (&e);
3683ae02089SMasatake YAMATO 		vStringDelete (fullscope);
3693ae02089SMasatake YAMATO 	}
3703ae02089SMasatake YAMATO }
3713ae02089SMasatake YAMATO 
makeJsTag(const tokenInfo * const token,const jsKind kind,vString * const signature,vString * const inheritance)3720e4c5d4aSMasatake YAMATO static void makeJsTag (const tokenInfo *const token, const jsKind kind,
3730e4c5d4aSMasatake YAMATO 					   vString *const signature, vString *const inheritance)
3740e4c5d4aSMasatake YAMATO {
3750e4c5d4aSMasatake YAMATO 	makeJsTagCommon (token, kind, signature, inheritance, false);
3760e4c5d4aSMasatake YAMATO }
3770e4c5d4aSMasatake YAMATO 
makeClassTagCommon(tokenInfo * const token,vString * const signature,vString * const inheritance,bool anonymous)3780e4c5d4aSMasatake YAMATO static void makeClassTagCommon (tokenInfo *const token, vString *const signature,
3790e4c5d4aSMasatake YAMATO                           vString *const inheritance, bool anonymous)
3803ae02089SMasatake YAMATO {
38150c63a4eSMasatake YAMATO 	vString *	fulltag = vStringNew ();
3823ae02089SMasatake YAMATO 	if (vStringLength (token->scope) > 0)
3833ae02089SMasatake YAMATO 	{
3843ae02089SMasatake YAMATO 		vStringCopy(fulltag, token->scope);
3851da6e7e4SMasatake YAMATO 		vStringPut (fulltag, '.');
3864e6bcb7bSColomban Wendling 		vStringCat (fulltag, token->string);
3873ae02089SMasatake YAMATO 	}
3883ae02089SMasatake YAMATO 	else
3893ae02089SMasatake YAMATO 	{
3903ae02089SMasatake YAMATO 		vStringCopy(fulltag, token->string);
3913ae02089SMasatake YAMATO 	}
3923ae02089SMasatake YAMATO 	if ( ! stringListHas(ClassNames, vStringValue (fulltag)) )
3933ae02089SMasatake YAMATO 	{
3943ae02089SMasatake YAMATO 		stringListAdd (ClassNames, vStringNewCopy (fulltag));
3950e4c5d4aSMasatake YAMATO 		makeJsTagCommon (token, JSTAG_CLASS, signature, inheritance,
3960e4c5d4aSMasatake YAMATO 						 anonymous);
3973ae02089SMasatake YAMATO 	}
3983ae02089SMasatake YAMATO 	vStringDelete (fulltag);
3993ae02089SMasatake YAMATO }
4003ae02089SMasatake YAMATO 
makeClassTag(tokenInfo * const token,vString * const signature,vString * const inheritance)4010e4c5d4aSMasatake YAMATO static void makeClassTag (tokenInfo *const token, vString *const signature,
4020e4c5d4aSMasatake YAMATO 						  vString *const inheritance)
4030e4c5d4aSMasatake YAMATO {
4040e4c5d4aSMasatake YAMATO 	makeClassTagCommon (token, signature, inheritance, false);
4050e4c5d4aSMasatake YAMATO }
4060e4c5d4aSMasatake YAMATO 
makeFunctionTagCommon(tokenInfo * const token,vString * const signature,bool generator,bool anonymous)4070e4c5d4aSMasatake YAMATO static void makeFunctionTagCommon (tokenInfo *const token, vString *const signature, bool generator,
4080e4c5d4aSMasatake YAMATO 								   bool anonymous)
4093ae02089SMasatake YAMATO {
41050c63a4eSMasatake YAMATO 	vString *	fulltag = vStringNew ();
4113ae02089SMasatake YAMATO 	if (vStringLength (token->scope) > 0)
4123ae02089SMasatake YAMATO 	{
4133ae02089SMasatake YAMATO 		vStringCopy(fulltag, token->scope);
4141da6e7e4SMasatake YAMATO 		vStringPut (fulltag, '.');
4154e6bcb7bSColomban Wendling 		vStringCat (fulltag, token->string);
4163ae02089SMasatake YAMATO 	}
4173ae02089SMasatake YAMATO 	else
4183ae02089SMasatake YAMATO 	{
4193ae02089SMasatake YAMATO 		vStringCopy(fulltag, token->string);
4203ae02089SMasatake YAMATO 	}
4213ae02089SMasatake YAMATO 	if ( ! stringListHas(FunctionNames, vStringValue (fulltag)) )
4223ae02089SMasatake YAMATO 	{
4233ae02089SMasatake YAMATO 		stringListAdd (FunctionNames, vStringNewCopy (fulltag));
4240e4c5d4aSMasatake YAMATO 		makeJsTagCommon (token, generator ? JSTAG_GENERATOR : JSTAG_FUNCTION, signature, NULL,
4250e4c5d4aSMasatake YAMATO 						 anonymous);
4263ae02089SMasatake YAMATO 	}
4273ae02089SMasatake YAMATO 	vStringDelete (fulltag);
4283ae02089SMasatake YAMATO }
4293ae02089SMasatake YAMATO 
makeFunctionTag(tokenInfo * const token,vString * const signature,bool generator)4300e4c5d4aSMasatake YAMATO static void makeFunctionTag (tokenInfo *const token, vString *const signature, bool generator)
4310e4c5d4aSMasatake YAMATO {
4320e4c5d4aSMasatake YAMATO 	makeFunctionTagCommon (token, signature, generator, false);
4330e4c5d4aSMasatake YAMATO }
4340e4c5d4aSMasatake YAMATO 
4353ae02089SMasatake YAMATO /*
4363ae02089SMasatake YAMATO  *	 Parsing functions
4373ae02089SMasatake YAMATO  */
4383ae02089SMasatake YAMATO 
4394d985ad2SColomban Wendling /* given @p point, returns the first byte of the encoded output sequence, and
4404d985ad2SColomban Wendling  * make sure the next ones will be returned by calls to getcFromInputFile()
4414d985ad2SColomban Wendling  * as if the code point was simply written in the input file. */
handleUnicodeCodePoint(uint32_t point)4424d985ad2SColomban Wendling static int handleUnicodeCodePoint (uint32_t point)
4434d985ad2SColomban Wendling {
4444d985ad2SColomban Wendling 	int c = (int) point;
4454d985ad2SColomban Wendling 
4464d985ad2SColomban Wendling 	Assert (point < 0x110000);
4474d985ad2SColomban Wendling 
4484d985ad2SColomban Wendling #ifdef HAVE_ICONV
4494d985ad2SColomban Wendling 	/* if we do have iconv and the encodings are specified, use this */
4504d985ad2SColomban Wendling 	if (isConverting () && JSUnicodeConverter == (iconv_t) -2)
4514d985ad2SColomban Wendling 	{
4524d985ad2SColomban Wendling 		/* if we didn't try creating the converter yet, try and do so */
4533addc312SColomban Wendling 		JSUnicodeConverter = iconv_open (getLanguageEncoding (Lang_js), INTERNAL_ENCODING);
4544d985ad2SColomban Wendling 	}
4554d985ad2SColomban Wendling 	if (isConverting () && JSUnicodeConverter != (iconv_t) -1)
4564d985ad2SColomban Wendling 	{
4574d985ad2SColomban Wendling 		char *input_ptr = (char *) &point;
4584d985ad2SColomban Wendling 		size_t input_left = sizeof point;
4594d985ad2SColomban Wendling 		/* 4 bytes should be enough for any encoding (it's how much UTF-32
4604d985ad2SColomban Wendling 		 * would need). */
4614d985ad2SColomban Wendling 		/* FIXME: actually iconv has a tendency to output a BOM for Unicode
462ebdbd8e2SK.Takata 		 * encodings where it matters when the endianness is not specified in
4634d985ad2SColomban Wendling 		 * the target encoding name.  E.g., if the target encoding is "UTF-32"
4644d985ad2SColomban Wendling 		 * or "UTF-16" it will output 2 code points, the BOM (U+FEFF) and the
465ebdbd8e2SK.Takata 		 * one we expect. This does not happen if the endianness is specified
4664d985ad2SColomban Wendling 		 * explicitly, e.g. with "UTF-32LE", or "UTF-16BE".
4674d985ad2SColomban Wendling 		 * However, it's not very relevant for the moment as nothing in CTags
4684d985ad2SColomban Wendling 		 * cope well (if at all) with non-ASCII-compatible encodings like
4694d985ad2SColomban Wendling 		 * UTF-32 or UTF-16 anyway. */
4704d985ad2SColomban Wendling 		char output[4] = { 0 };
4714d985ad2SColomban Wendling 		char *output_ptr = output;
4724d985ad2SColomban Wendling 		size_t output_left = ARRAY_SIZE (output);
4734d985ad2SColomban Wendling 
4744d985ad2SColomban Wendling 		if (iconv (JSUnicodeConverter, &input_ptr, &input_left, &output_ptr, &output_left) == (size_t) -1)
4754d985ad2SColomban Wendling 		{
4764d985ad2SColomban Wendling 			/* something went wrong, which probably means the output encoding
4774d985ad2SColomban Wendling 			 * cannot represent the character.  Use a placeholder likely to be
4784d985ad2SColomban Wendling 			 * supported instead, that's also valid in an identifier */
4794d985ad2SColomban Wendling 			verbose ("JavaScript: Encoding: %s\n", strerror (errno));
4804d985ad2SColomban Wendling 			c = '_';
4814d985ad2SColomban Wendling 		}
4824d985ad2SColomban Wendling 		else
4834d985ad2SColomban Wendling 		{
4844d985ad2SColomban Wendling 			const size_t output_len = ARRAY_SIZE (output) - output_left;
4854d985ad2SColomban Wendling 
4864d985ad2SColomban Wendling 			/* put all but the first byte back so that getcFromInputFile() will
4874d985ad2SColomban Wendling 			 * return them in the right order */
4884d985ad2SColomban Wendling 			for (unsigned int i = 1; i < output_len; i++)
4894d985ad2SColomban Wendling 				ungetcToInputFile ((unsigned char) output[output_len - i]);
4904d985ad2SColomban Wendling 			c = (unsigned char) output[0];
4914d985ad2SColomban Wendling 		}
4924d985ad2SColomban Wendling 
4934d985ad2SColomban Wendling 		iconv (JSUnicodeConverter, NULL, NULL, NULL, NULL);
4944d985ad2SColomban Wendling 	}
4954d985ad2SColomban Wendling 	else
4964d985ad2SColomban Wendling #endif
4974d985ad2SColomban Wendling 	{
498bde9f60aSColomban Wendling 		/* when no encoding is specified (or no iconv), assume UTF-8 is good.
4994d985ad2SColomban Wendling 		 * Why UTF-8?  Because it's an ASCII-compatible common Unicode encoding. */
5004d985ad2SColomban Wendling 		if (point < 0x80)
5014d985ad2SColomban Wendling 			c = (unsigned char) point;
5024d985ad2SColomban Wendling 		else if (point < 0x800)
5034d985ad2SColomban Wendling 		{
5044d985ad2SColomban Wendling 			c = (unsigned char) (0xc0 | ((point >> 6) & 0x1f));
5054d985ad2SColomban Wendling 			ungetcToInputFile ((unsigned char) (0x80 | (point & 0x3f)));
5064d985ad2SColomban Wendling 		}
5074d985ad2SColomban Wendling 		else if (point < 0x10000)
5084d985ad2SColomban Wendling 		{
5094d985ad2SColomban Wendling 			c = (unsigned char) (0xe0 | ((point >> 12) & 0x0f));
5104d985ad2SColomban Wendling 			ungetcToInputFile ((unsigned char) (0x80 | ((point >>  0) & 0x3f)));
5114d985ad2SColomban Wendling 			ungetcToInputFile ((unsigned char) (0x80 | ((point >>  6) & 0x3f)));
5124d985ad2SColomban Wendling 		}
5134d985ad2SColomban Wendling 		else if (point < 0x110000)
5144d985ad2SColomban Wendling 		{
5154d985ad2SColomban Wendling 			c = (unsigned char) (0xf0 | ((point >> 18) & 0x07));
5164d985ad2SColomban Wendling 			ungetcToInputFile ((unsigned char) (0x80 | ((point >>  0) & 0x3f)));
5174d985ad2SColomban Wendling 			ungetcToInputFile ((unsigned char) (0x80 | ((point >>  6) & 0x3f)));
5184d985ad2SColomban Wendling 			ungetcToInputFile ((unsigned char) (0x80 | ((point >> 12) & 0x3f)));
5194d985ad2SColomban Wendling 		}
5204d985ad2SColomban Wendling 	}
5214d985ad2SColomban Wendling 
5224d985ad2SColomban Wendling 	return c;
5234d985ad2SColomban Wendling }
5244d985ad2SColomban Wendling 
5254d985ad2SColomban Wendling /* reads a Unicode escape sequence after the "\" prefix.
5264d985ad2SColomban Wendling  * @param value Location to store the escape sequence value.
5274d985ad2SColomban Wendling  * @param isUTF16 Location to store whether @param value is an UTF-16 word.
5284d985ad2SColomban Wendling  * @returns Whether a valid sequence was read. */
readUnicodeEscapeSequenceValue(uint32_t * const value,bool * const isUTF16)5294d985ad2SColomban Wendling static bool readUnicodeEscapeSequenceValue (uint32_t *const value,
5304d985ad2SColomban Wendling                                             bool *const isUTF16)
5314d985ad2SColomban Wendling {
5324d985ad2SColomban Wendling 	bool valid = false;
5334d985ad2SColomban Wendling 	int d = getcFromInputFile ();
5344d985ad2SColomban Wendling 
5354d985ad2SColomban Wendling 	if (d != 'u')
5364d985ad2SColomban Wendling 		ungetcToInputFile (d);
5374d985ad2SColomban Wendling 	else
5384d985ad2SColomban Wendling 	{
5394d985ad2SColomban Wendling 		int e = getcFromInputFile ();
5404d985ad2SColomban Wendling 		char cp[6 + 1]; /* up to 6 hex + possible closing '}' or invalid char */
5414d985ad2SColomban Wendling 		unsigned int cp_len = 0;
5424d985ad2SColomban Wendling 
5434d985ad2SColomban Wendling 		*isUTF16 = (e != '{');
5444d985ad2SColomban Wendling 		if (e == '{')
5454d985ad2SColomban Wendling 		{	/* Handles Unicode code point escapes: \u{ HexDigits }
5464d985ad2SColomban Wendling 			 * We skip the leading 0s because there can be any number of them
5474d985ad2SColomban Wendling 			 * and they don't change any meaning. */
5484d985ad2SColomban Wendling 			bool has_leading_zero = false;
5494d985ad2SColomban Wendling 
5504d985ad2SColomban Wendling 			while ((cp[cp_len] = (char) getcFromInputFile ()) == '0')
5514d985ad2SColomban Wendling 				has_leading_zero = true;
5524d985ad2SColomban Wendling 
5534d985ad2SColomban Wendling 			while (isxdigit (cp[cp_len]) && ++cp_len < ARRAY_SIZE (cp))
5544d985ad2SColomban Wendling 				cp[cp_len] = (char) getcFromInputFile ();
5554d985ad2SColomban Wendling 			valid = ((cp_len > 0 || has_leading_zero) &&
5564d985ad2SColomban Wendling 					 cp_len < ARRAY_SIZE (cp) && cp[cp_len] == '}' &&
5574d985ad2SColomban Wendling 					 /* also check if it's a valid Unicode code point */
5584d985ad2SColomban Wendling 					 (cp_len < 6 ||
5594d985ad2SColomban Wendling 					  (cp_len == 6 && strncmp (cp, "110000", 6) < 0)));
5604d985ad2SColomban Wendling 			if (! valid) /* put back the last (likely invalid) character */
5614d985ad2SColomban Wendling 				ungetcToInputFile (cp[cp_len]);
5624d985ad2SColomban Wendling 		}
5634d985ad2SColomban Wendling 		else
5644d985ad2SColomban Wendling 		{	/* Handles Unicode escape sequences: \u Hex4Digits */
5654d985ad2SColomban Wendling 			do
5664d985ad2SColomban Wendling 				cp[cp_len] = (char) ((cp_len == 0) ? e : getcFromInputFile ());
5674d985ad2SColomban Wendling 			while (isxdigit (cp[cp_len]) && ++cp_len < 4);
5684d985ad2SColomban Wendling 			valid = (cp_len == 4);
5694d985ad2SColomban Wendling 		}
5704d985ad2SColomban Wendling 
5714d985ad2SColomban Wendling 		if (! valid)
5724d985ad2SColomban Wendling 		{
5734d985ad2SColomban Wendling 			/* we don't get every character back, but it would require to
5744d985ad2SColomban Wendling 			 * be able to put up to 9 characters back (in the worst case
5754d985ad2SColomban Wendling 			 * for handling invalid \u{10FFFFx}), and here we're recovering
5764d985ad2SColomban Wendling 			 * from invalid syntax anyway. */
5774d985ad2SColomban Wendling 			ungetcToInputFile (e);
5784d985ad2SColomban Wendling 			ungetcToInputFile (d);
5794d985ad2SColomban Wendling 		}
5804d985ad2SColomban Wendling 		else
5814d985ad2SColomban Wendling 		{
5824d985ad2SColomban Wendling 			*value = 0;
5834d985ad2SColomban Wendling 			for (unsigned int i = 0; i < cp_len; i++)
5844d985ad2SColomban Wendling 			{
5854d985ad2SColomban Wendling 				*value *= 16;
5864d985ad2SColomban Wendling 
5874d985ad2SColomban Wendling 				/* we know it's a hex digit, no need to double check */
5884d985ad2SColomban Wendling 				if (cp[i] < 'A')
5894d985ad2SColomban Wendling 					*value += (unsigned int) cp[i] - '0';
5904d985ad2SColomban Wendling 				else if (cp[i] < 'a')
5914d985ad2SColomban Wendling 					*value += 10 + (unsigned int) cp[i] - 'A';
5924d985ad2SColomban Wendling 				else
5934d985ad2SColomban Wendling 					*value += 10 + (unsigned int) cp[i] - 'a';
5944d985ad2SColomban Wendling 			}
5954d985ad2SColomban Wendling 		}
5964d985ad2SColomban Wendling 	}
5974d985ad2SColomban Wendling 
5984d985ad2SColomban Wendling 	return valid;
5994d985ad2SColomban Wendling }
6004d985ad2SColomban Wendling 
valueToXDigit(unsigned char v)60184c69486SColomban Wendling static int valueToXDigit (unsigned char v)
60284c69486SColomban Wendling {
60384c69486SColomban Wendling 	Assert (v <= 0xF);
60484c69486SColomban Wendling 
60584c69486SColomban Wendling 	if (v >= 0xA)
60684c69486SColomban Wendling 		return 'A' + (v - 0xA);
60784c69486SColomban Wendling 	else
60884c69486SColomban Wendling 		return '0' + v;
60984c69486SColomban Wendling }
61084c69486SColomban Wendling 
6114d985ad2SColomban Wendling /* Reads and expands a Unicode escape sequence after the "\" prefix.  If the
6124d985ad2SColomban Wendling  * escape sequence is a UTF16 high surrogate, also try and read the low
6134d985ad2SColomban Wendling  * surrogate to emit the proper code point.
6144d985ad2SColomban Wendling  * @param fallback The character to return if the sequence is invalid. Usually
6154d985ad2SColomban Wendling  *                 this would be the '\' character starting the sequence.
6164d985ad2SColomban Wendling  * @returns The first byte of the sequence, or @param fallback if the sequence
6174d985ad2SColomban Wendling  *          is invalid. On success, next calls to getcFromInputFile() will
6184d985ad2SColomban Wendling  *          return subsequent bytes (if any). */
readUnicodeEscapeSequence(const int fallback)6194d985ad2SColomban Wendling static int readUnicodeEscapeSequence (const int fallback)
6204d985ad2SColomban Wendling {
6214d985ad2SColomban Wendling 	int c;
6224d985ad2SColomban Wendling 	uint32_t value;
6234d985ad2SColomban Wendling 	bool isUTF16;
6244d985ad2SColomban Wendling 
6254d985ad2SColomban Wendling 	if (! readUnicodeEscapeSequenceValue (&value, &isUTF16))
6264d985ad2SColomban Wendling 		c = fallback;
6274d985ad2SColomban Wendling 	else
6284d985ad2SColomban Wendling 	{
6294d985ad2SColomban Wendling 		if (isUTF16 && (value & 0xfc00) == 0xd800)
6304d985ad2SColomban Wendling 		{	/* this is a high surrogate, try and read its low surrogate and
6314d985ad2SColomban Wendling 			 * emit the resulting code point */
6324d985ad2SColomban Wendling 			uint32_t low;
6334d985ad2SColomban Wendling 			int d = getcFromInputFile ();
6344d985ad2SColomban Wendling 
6354d985ad2SColomban Wendling 			if (d != '\\' || ! readUnicodeEscapeSequenceValue (&low, &isUTF16))
6364d985ad2SColomban Wendling 				ungetcToInputFile (d);
63784c69486SColomban Wendling 			else if (! isUTF16)
63884c69486SColomban Wendling 			{	/* not UTF-16 low surrogate but a plain code point */
6394d985ad2SColomban Wendling 				d = handleUnicodeCodePoint (low);
6404d985ad2SColomban Wendling 				ungetcToInputFile (d);
6414d985ad2SColomban Wendling 			}
64284c69486SColomban Wendling 			else if ((low & 0xfc00) != 0xdc00)
64384c69486SColomban Wendling 			{	/* not a low surrogate, so put back the escaped representation
64484c69486SColomban Wendling 				 * in case it was another high surrogate we should read as part
64584c69486SColomban Wendling 				 * of another pair. */
64684c69486SColomban Wendling 				ungetcToInputFile (valueToXDigit ((unsigned char) ((low & 0x000f) >>  0)));
64784c69486SColomban Wendling 				ungetcToInputFile (valueToXDigit ((unsigned char) ((low & 0x00f0) >>  4)));
64884c69486SColomban Wendling 				ungetcToInputFile (valueToXDigit ((unsigned char) ((low & 0x0f00) >>  8)));
64984c69486SColomban Wendling 				ungetcToInputFile (valueToXDigit ((unsigned char) ((low & 0xf000) >> 12)));
65084c69486SColomban Wendling 				ungetcToInputFile ('u');
65184c69486SColomban Wendling 				ungetcToInputFile ('\\');
65284c69486SColomban Wendling 			}
6534d985ad2SColomban Wendling 			else
6544d985ad2SColomban Wendling 				value = 0x010000 + ((value & 0x03ff) << 10) + (low & 0x03ff);
6554d985ad2SColomban Wendling 		}
6564d985ad2SColomban Wendling 		c = handleUnicodeCodePoint (value);
6574d985ad2SColomban Wendling 	}
6584d985ad2SColomban Wendling 
6594d985ad2SColomban Wendling 	return c;
6604d985ad2SColomban Wendling }
6614d985ad2SColomban Wendling 
parseString(vString * const string,const int delimiter)6623ae02089SMasatake YAMATO static void parseString (vString *const string, const int delimiter)
6633ae02089SMasatake YAMATO {
664ce990805SThomas Braun 	bool end = false;
6653ae02089SMasatake YAMATO 	while (! end)
6663ae02089SMasatake YAMATO 	{
667018bce0bSMasatake YAMATO 		int c = getcFromInputFile ();
6683ae02089SMasatake YAMATO 		if (c == EOF)
669ce990805SThomas Braun 			end = true;
6703ae02089SMasatake YAMATO 		else if (c == '\\')
6713ae02089SMasatake YAMATO 		{
6723ae02089SMasatake YAMATO 			/* Eat the escape sequence (\", \', etc).  We properly handle
6733ae02089SMasatake YAMATO 			 * <LineContinuation> by eating a whole \<CR><LF> not to see <LF>
6743ae02089SMasatake YAMATO 			 * as an unescaped character, which is invalid and handled below.
6753ae02089SMasatake YAMATO 			 * Also, handle the fact that <LineContinuation> produces an empty
6763ae02089SMasatake YAMATO 			 * sequence.
6773ae02089SMasatake YAMATO 			 * See ECMA-262 7.8.4 */
678018bce0bSMasatake YAMATO 			c = getcFromInputFile ();
6794d985ad2SColomban Wendling 			if (c == 'u')
6804d985ad2SColomban Wendling 			{
6814d985ad2SColomban Wendling 				ungetcToInputFile (c);
6824d985ad2SColomban Wendling 				c = readUnicodeEscapeSequence ('\\');
6834d985ad2SColomban Wendling 				vStringPut (string, c);
6844d985ad2SColomban Wendling 			}
6854d985ad2SColomban Wendling 			else if (c != '\r' && c != '\n')
6863ae02089SMasatake YAMATO 				vStringPut(string, c);
6873ae02089SMasatake YAMATO 			else if (c == '\r')
6883ae02089SMasatake YAMATO 			{
689018bce0bSMasatake YAMATO 				c = getcFromInputFile();
6903ae02089SMasatake YAMATO 				if (c != '\n')
69161f14fa5SMasatake YAMATO 					ungetcToInputFile (c);
6923ae02089SMasatake YAMATO 			}
6933ae02089SMasatake YAMATO 		}
6943ae02089SMasatake YAMATO 		else if (c == delimiter)
695ce990805SThomas Braun 			end = true;
6963ae02089SMasatake YAMATO 		else if (c == '\r' || c == '\n')
6973ae02089SMasatake YAMATO 		{
6983ae02089SMasatake YAMATO 			/* those are invalid when not escaped */
699ce990805SThomas Braun 			end = true;
7003ae02089SMasatake YAMATO 			/* we don't want to eat the newline itself to let the automatic
7013ae02089SMasatake YAMATO 			 * semicolon insertion code kick in */
70261f14fa5SMasatake YAMATO 			ungetcToInputFile (c);
7033ae02089SMasatake YAMATO 		}
7043ae02089SMasatake YAMATO 		else
7053ae02089SMasatake YAMATO 			vStringPut (string, c);
7063ae02089SMasatake YAMATO 	}
7073ae02089SMasatake YAMATO }
7083ae02089SMasatake YAMATO 
parseRegExp(void)7093ae02089SMasatake YAMATO static void parseRegExp (void)
7103ae02089SMasatake YAMATO {
7113ae02089SMasatake YAMATO 	int c;
712ce990805SThomas Braun 	bool in_range = false;
7133ae02089SMasatake YAMATO 
7143ae02089SMasatake YAMATO 	do
7153ae02089SMasatake YAMATO 	{
716018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
7173ae02089SMasatake YAMATO 		if (! in_range && c == '/')
7183ae02089SMasatake YAMATO 		{
7193ae02089SMasatake YAMATO 			do /* skip flags */
7203ae02089SMasatake YAMATO 			{
721018bce0bSMasatake YAMATO 				c = getcFromInputFile ();
7223ae02089SMasatake YAMATO 			} while (isalpha (c));
72361f14fa5SMasatake YAMATO 			ungetcToInputFile (c);
7243ae02089SMasatake YAMATO 			break;
7253ae02089SMasatake YAMATO 		}
726f716a6e1SColomban Wendling 		else if (c == '\n' || c == '\r')
727f716a6e1SColomban Wendling 		{
728f716a6e1SColomban Wendling 			/* invalid in a regex */
729f716a6e1SColomban Wendling 			ungetcToInputFile (c);
730f716a6e1SColomban Wendling 			break;
731f716a6e1SColomban Wendling 		}
7323ae02089SMasatake YAMATO 		else if (c == '\\')
733018bce0bSMasatake YAMATO 			c = getcFromInputFile (); /* skip next character */
7343ae02089SMasatake YAMATO 		else if (c == '[')
735ce990805SThomas Braun 			in_range = true;
7363ae02089SMasatake YAMATO 		else if (c == ']')
737ce990805SThomas Braun 			in_range = false;
7383ae02089SMasatake YAMATO 	} while (c != EOF);
7393ae02089SMasatake YAMATO }
7403ae02089SMasatake YAMATO 
7413ae02089SMasatake YAMATO /*	Read a C identifier beginning with "firstChar" and places it into
7423ae02089SMasatake YAMATO  *	"name".
7433ae02089SMasatake YAMATO  */
parseIdentifier(vString * const string,const int firstChar)7443ae02089SMasatake YAMATO static void parseIdentifier (vString *const string, const int firstChar)
7453ae02089SMasatake YAMATO {
7463ae02089SMasatake YAMATO 	int c = firstChar;
7473ae02089SMasatake YAMATO 	Assert (isIdentChar (c));
7483ae02089SMasatake YAMATO 	do
7493ae02089SMasatake YAMATO 	{
7503ae02089SMasatake YAMATO 		vStringPut (string, c);
751018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
7524d985ad2SColomban Wendling 		if (c == '\\')
7534d985ad2SColomban Wendling 			c = readUnicodeEscapeSequence (c);
7543ae02089SMasatake YAMATO 	} while (isIdentChar (c));
7554d985ad2SColomban Wendling 	/* if readUnicodeEscapeSequence() read an escape sequence this is incorrect,
7564d985ad2SColomban Wendling 	 * as we should actually put back the whole escape sequence and not the
7574d985ad2SColomban Wendling 	 * decoded character.  However, it's not really worth the hassle as it can
7584d985ad2SColomban Wendling 	 * only happen if the input has an invalid escape sequence. */
75961f14fa5SMasatake YAMATO 	ungetcToInputFile (c);		/* unget non-identifier character */
7603ae02089SMasatake YAMATO }
7613ae02089SMasatake YAMATO 
parseTemplateString(vString * const string)7625869a275SColomban Wendling static void parseTemplateString (vString *const string)
7635869a275SColomban Wendling {
7645869a275SColomban Wendling 	int c;
7655869a275SColomban Wendling 	do
7665869a275SColomban Wendling 	{
767018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
768fe7e03a1SMasatake YAMATO 		if (c == '`' || c == EOF)
7695869a275SColomban Wendling 			break;
770fe7e03a1SMasatake YAMATO 
7715869a275SColomban Wendling 		vStringPut (string, c);
772fe7e03a1SMasatake YAMATO 
7735869a275SColomban Wendling 		if (c == '\\')
7745869a275SColomban Wendling 		{
775018bce0bSMasatake YAMATO 			c = getcFromInputFile();
776fe7e03a1SMasatake YAMATO 			if (c != EOF)
7775869a275SColomban Wendling 				vStringPut(string, c);
7785869a275SColomban Wendling 		}
7795869a275SColomban Wendling 		else if (c == '$')
7805869a275SColomban Wendling 		{
781018bce0bSMasatake YAMATO 			c = getcFromInputFile ();
7825869a275SColomban Wendling 			if (c != '{')
78361f14fa5SMasatake YAMATO 				ungetcToInputFile (c);
7845869a275SColomban Wendling 			else
7855869a275SColomban Wendling 			{
7865869a275SColomban Wendling 				int depth = 1;
7875869a275SColomban Wendling 				/* we need to use the real token machinery to handle strings,
7885869a275SColomban Wendling 				 * comments, regexes and whatnot */
7895869a275SColomban Wendling 				tokenInfo *token = newToken ();
7905869a275SColomban Wendling 				LastTokenType = TOKEN_UNDEFINED;
7915869a275SColomban Wendling 				vStringPut(string, c);
7925869a275SColomban Wendling 				do
7935869a275SColomban Wendling 				{
794ce990805SThomas Braun 					readTokenFull (token, false, string);
7955869a275SColomban Wendling 					if (isType (token, TOKEN_OPEN_CURLY))
7965869a275SColomban Wendling 						depth++;
7975869a275SColomban Wendling 					else if (isType (token, TOKEN_CLOSE_CURLY))
7985869a275SColomban Wendling 						depth--;
7995869a275SColomban Wendling 				}
8005869a275SColomban Wendling 				while (! isType (token, TOKEN_EOF) && depth > 0);
8015869a275SColomban Wendling 				deleteToken (token);
8025869a275SColomban Wendling 			}
8035869a275SColomban Wendling 		}
8045869a275SColomban Wendling 	}
8055869a275SColomban Wendling 	while (c != EOF);
8065869a275SColomban Wendling }
8075869a275SColomban Wendling 
readTokenFullRaw(tokenInfo * const token,bool include_newlines,vString * const repr)808f2e65b39SMasatake YAMATO static void readTokenFullRaw (tokenInfo *const token, bool include_newlines, vString *const repr)
8093ae02089SMasatake YAMATO {
8103ae02089SMasatake YAMATO 	int c;
8113ae02089SMasatake YAMATO 	int i;
812ce990805SThomas Braun 	bool newline_encountered = false;
813fc4ca4b7SColomban Wendling 
814fc4ca4b7SColomban Wendling 	/* if we've got a token held back, emit it */
815fc4ca4b7SColomban Wendling 	if (NextToken)
816fc4ca4b7SColomban Wendling 	{
817ce990805SThomas Braun 		copyToken (token, NextToken, false);
818fc4ca4b7SColomban Wendling 		deleteToken (NextToken);
819fc4ca4b7SColomban Wendling 		NextToken = NULL;
820fc4ca4b7SColomban Wendling 		return;
821fc4ca4b7SColomban Wendling 	}
8223ae02089SMasatake YAMATO 
8233ae02089SMasatake YAMATO 	token->type			= TOKEN_UNDEFINED;
8243ae02089SMasatake YAMATO 	token->keyword		= KEYWORD_NONE;
8253ae02089SMasatake YAMATO 	vStringClear (token->string);
8263ae02089SMasatake YAMATO 
8273ae02089SMasatake YAMATO getNextChar:
8283ae02089SMasatake YAMATO 	i = 0;
8293ae02089SMasatake YAMATO 	do
8303ae02089SMasatake YAMATO 	{
831018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
832fc4ca4b7SColomban Wendling 		if (include_newlines && (c == '\r' || c == '\n'))
833ce990805SThomas Braun 			newline_encountered = true;
8343ae02089SMasatake YAMATO 		i++;
8353ae02089SMasatake YAMATO 	}
836fc4ca4b7SColomban Wendling 	while (c == '\t' || c == ' ' || c == '\r' || c == '\n');
8373ae02089SMasatake YAMATO 
838a31b37dcSMasatake YAMATO 	token->lineNumber   = getInputLineNumber ();
8393ae02089SMasatake YAMATO 	token->filePosition = getInputFilePosition ();
8403ae02089SMasatake YAMATO 
841fe7e03a1SMasatake YAMATO 	if (repr && c != EOF)
8423ae02089SMasatake YAMATO 	{
8433ae02089SMasatake YAMATO 		if (i > 1)
8443ae02089SMasatake YAMATO 			vStringPut (repr, ' ');
8453ae02089SMasatake YAMATO 		vStringPut (repr, c);
8463ae02089SMasatake YAMATO 	}
8473ae02089SMasatake YAMATO 
8483ae02089SMasatake YAMATO 	switch (c)
8493ae02089SMasatake YAMATO 	{
8503ae02089SMasatake YAMATO 		case EOF: token->type = TOKEN_EOF;					break;
8513ae02089SMasatake YAMATO 		case '(': token->type = TOKEN_OPEN_PAREN;			break;
8523ae02089SMasatake YAMATO 		case ')': token->type = TOKEN_CLOSE_PAREN;			break;
8533ae02089SMasatake YAMATO 		case ';': token->type = TOKEN_SEMICOLON;			break;
8543ae02089SMasatake YAMATO 		case ',': token->type = TOKEN_COMMA;				break;
8553ae02089SMasatake YAMATO 		case '.': token->type = TOKEN_PERIOD;				break;
8563ae02089SMasatake YAMATO 		case ':': token->type = TOKEN_COLON;				break;
8573ae02089SMasatake YAMATO 		case '{': token->type = TOKEN_OPEN_CURLY;			break;
8583ae02089SMasatake YAMATO 		case '}': token->type = TOKEN_CLOSE_CURLY;			break;
8593ae02089SMasatake YAMATO 		case '[': token->type = TOKEN_OPEN_SQUARE;			break;
8603ae02089SMasatake YAMATO 		case ']': token->type = TOKEN_CLOSE_SQUARE;			break;
8613ae02089SMasatake YAMATO 
86250eb5201SJohn Lindal 		case '=':
86350eb5201SJohn Lindal 			{
86450eb5201SJohn Lindal 				int d = getcFromInputFile ();
86550eb5201SJohn Lindal 				if (d == '>')
86650eb5201SJohn Lindal 					token->type = TOKEN_ARROW;
86750eb5201SJohn Lindal 				else
86850eb5201SJohn Lindal 				{
86950eb5201SJohn Lindal 					ungetcToInputFile (d);
87050eb5201SJohn Lindal 					token->type = TOKEN_EQUAL_SIGN;
87150eb5201SJohn Lindal 				}
87250eb5201SJohn Lindal 				break;
87350eb5201SJohn Lindal 			}
87450eb5201SJohn Lindal 
8753ae02089SMasatake YAMATO 		case '+':
8763ae02089SMasatake YAMATO 		case '-':
8773ae02089SMasatake YAMATO 			{
878018bce0bSMasatake YAMATO 				int d = getcFromInputFile ();
8793ae02089SMasatake YAMATO 				if (d == c) /* ++ or -- */
8803ae02089SMasatake YAMATO 					token->type = TOKEN_POSTFIX_OPERATOR;
8813ae02089SMasatake YAMATO 				else
8823ae02089SMasatake YAMATO 				{
88361f14fa5SMasatake YAMATO 					ungetcToInputFile (d);
8843ae02089SMasatake YAMATO 					token->type = TOKEN_BINARY_OPERATOR;
8853ae02089SMasatake YAMATO 				}
8863ae02089SMasatake YAMATO 				break;
8873ae02089SMasatake YAMATO 			}
8883ae02089SMasatake YAMATO 
8893ae02089SMasatake YAMATO 		case '*':
890d01b4a7cSColomban Wendling 			token->type = TOKEN_STAR;
891d01b4a7cSColomban Wendling 			break;
8923ae02089SMasatake YAMATO 		case '%':
8933ae02089SMasatake YAMATO 		case '?':
8943ae02089SMasatake YAMATO 		case '>':
8953ae02089SMasatake YAMATO 		case '<':
8963ae02089SMasatake YAMATO 		case '^':
8973ae02089SMasatake YAMATO 		case '|':
8983ae02089SMasatake YAMATO 		case '&':
8993ae02089SMasatake YAMATO 			token->type = TOKEN_BINARY_OPERATOR;
9003ae02089SMasatake YAMATO 			break;
9013ae02089SMasatake YAMATO 
9023ae02089SMasatake YAMATO 		case '\'':
9033ae02089SMasatake YAMATO 		case '"':
9043ae02089SMasatake YAMATO 				  token->type = TOKEN_STRING;
9053ae02089SMasatake YAMATO 				  parseString (token->string, c);
906a31b37dcSMasatake YAMATO 				  token->lineNumber = getInputLineNumber ();
9073ae02089SMasatake YAMATO 				  token->filePosition = getInputFilePosition ();
9083ae02089SMasatake YAMATO 				  if (repr)
9093ae02089SMasatake YAMATO 				  {
9103ae02089SMasatake YAMATO 					  vStringCat (repr, token->string);
9113ae02089SMasatake YAMATO 					  vStringPut (repr, c);
9123ae02089SMasatake YAMATO 				  }
9133ae02089SMasatake YAMATO 				  break;
9143ae02089SMasatake YAMATO 
9155869a275SColomban Wendling 		case '`':
9165869a275SColomban Wendling 				  token->type = TOKEN_TEMPLATE_STRING;
9175869a275SColomban Wendling 				  parseTemplateString (token->string);
918a31b37dcSMasatake YAMATO 				  token->lineNumber = getInputLineNumber ();
9195869a275SColomban Wendling 				  token->filePosition = getInputFilePosition ();
9205869a275SColomban Wendling 				  if (repr)
9215869a275SColomban Wendling 				  {
9225869a275SColomban Wendling 					  vStringCat (repr, token->string);
9235869a275SColomban Wendling 					  vStringPut (repr, c);
9245869a275SColomban Wendling 				  }
9255869a275SColomban Wendling 				  break;
9265869a275SColomban Wendling 
9273ae02089SMasatake YAMATO 		case '/':
9283ae02089SMasatake YAMATO 				  {
929018bce0bSMasatake YAMATO 					  int d = getcFromInputFile ();
9303ae02089SMasatake YAMATO 					  if ( (d != '*') &&		/* is this the start of a comment? */
9313ae02089SMasatake YAMATO 							  (d != '/') )		/* is a one line comment? */
9323ae02089SMasatake YAMATO 					  {
93361f14fa5SMasatake YAMATO 						  ungetcToInputFile (d);
9343ae02089SMasatake YAMATO 						  switch (LastTokenType)
9353ae02089SMasatake YAMATO 						  {
9363ae02089SMasatake YAMATO 							  case TOKEN_CHARACTER:
9373ae02089SMasatake YAMATO 							  case TOKEN_IDENTIFIER:
9383ae02089SMasatake YAMATO 							  case TOKEN_STRING:
9395869a275SColomban Wendling 							  case TOKEN_TEMPLATE_STRING:
9403ae02089SMasatake YAMATO 							  case TOKEN_CLOSE_CURLY:
9413ae02089SMasatake YAMATO 							  case TOKEN_CLOSE_PAREN:
9423ae02089SMasatake YAMATO 							  case TOKEN_CLOSE_SQUARE:
94302278201SColomban Wendling 								  token->type = TOKEN_BINARY_OPERATOR;
9443ae02089SMasatake YAMATO 								  break;
9453ae02089SMasatake YAMATO 
9463ae02089SMasatake YAMATO 							  default:
9473ae02089SMasatake YAMATO 								  token->type = TOKEN_REGEXP;
9483ae02089SMasatake YAMATO 								  parseRegExp ();
949a31b37dcSMasatake YAMATO 								  token->lineNumber = getInputLineNumber ();
9503ae02089SMasatake YAMATO 								  token->filePosition = getInputFilePosition ();
9513ae02089SMasatake YAMATO 								  break;
9523ae02089SMasatake YAMATO 						  }
9533ae02089SMasatake YAMATO 					  }
9543ae02089SMasatake YAMATO 					  else
9553ae02089SMasatake YAMATO 					  {
9563ae02089SMasatake YAMATO 						  if (repr) /* remove the / we added */
957e852ee0eSMasatake YAMATO 							  vStringChop(repr);
9583ae02089SMasatake YAMATO 						  if (d == '*')
9593ae02089SMasatake YAMATO 						  {
96064a05963SMasatake YAMATO 							  skipToCharacterInInputFile2('*', '/');
9613ae02089SMasatake YAMATO 							  goto getNextChar;
9623ae02089SMasatake YAMATO 						  }
9633ae02089SMasatake YAMATO 						  else if (d == '/')	/* is this the start of a comment?  */
9643ae02089SMasatake YAMATO 						  {
9654fffc5afSMasatake YAMATO 							  skipToCharacterInInputFile ('\n');
9663ae02089SMasatake YAMATO 							  /* if we care about newlines, put it back so it is seen */
9673ae02089SMasatake YAMATO 							  if (include_newlines)
96861f14fa5SMasatake YAMATO 								  ungetcToInputFile ('\n');
9693ae02089SMasatake YAMATO 							  goto getNextChar;
9703ae02089SMasatake YAMATO 						  }
9713ae02089SMasatake YAMATO 					  }
9723ae02089SMasatake YAMATO 					  break;
9733ae02089SMasatake YAMATO 				  }
9743ae02089SMasatake YAMATO 
9753ae02089SMasatake YAMATO 		case '#':
9763ae02089SMasatake YAMATO 				  /* skip shebang in case of e.g. Node.js scripts */
9773ae02089SMasatake YAMATO 				  if (token->lineNumber > 1)
9783ae02089SMasatake YAMATO 					  token->type = TOKEN_UNDEFINED;
979018bce0bSMasatake YAMATO 				  else if ((c = getcFromInputFile ()) != '!')
9803ae02089SMasatake YAMATO 				  {
98161f14fa5SMasatake YAMATO 					  ungetcToInputFile (c);
9823ae02089SMasatake YAMATO 					  token->type = TOKEN_UNDEFINED;
9833ae02089SMasatake YAMATO 				  }
9843ae02089SMasatake YAMATO 				  else
9853ae02089SMasatake YAMATO 				  {
9864fffc5afSMasatake YAMATO 					  skipToCharacterInInputFile ('\n');
9873ae02089SMasatake YAMATO 					  goto getNextChar;
9883ae02089SMasatake YAMATO 				  }
9893ae02089SMasatake YAMATO 				  break;
9903ae02089SMasatake YAMATO 
991f2e65b39SMasatake YAMATO 		case '@':
992f2e65b39SMasatake YAMATO 				  token->type = TOKEN_ATMARK;
993f2e65b39SMasatake YAMATO 				  break;
994f2e65b39SMasatake YAMATO 
9954d985ad2SColomban Wendling 		case '\\':
9964d985ad2SColomban Wendling 				  c = readUnicodeEscapeSequence (c);
9974d985ad2SColomban Wendling 				  /* fallthrough */
9983ae02089SMasatake YAMATO 		default:
9993ae02089SMasatake YAMATO 				  if (! isIdentChar (c))
10003ae02089SMasatake YAMATO 					  token->type = TOKEN_UNDEFINED;
10013ae02089SMasatake YAMATO 				  else
10023ae02089SMasatake YAMATO 				  {
10033ae02089SMasatake YAMATO 					  parseIdentifier (token->string, c);
1004a31b37dcSMasatake YAMATO 					  token->lineNumber = getInputLineNumber ();
10053ae02089SMasatake YAMATO 					  token->filePosition = getInputFilePosition ();
10068f29d6c9SJiří Techet 					  token->keyword = lookupKeyword (vStringValue (token->string), Lang_js);
10073ae02089SMasatake YAMATO 					  if (isKeyword (token, KEYWORD_NONE))
10083ae02089SMasatake YAMATO 						  token->type = TOKEN_IDENTIFIER;
10093ae02089SMasatake YAMATO 					  else
10103ae02089SMasatake YAMATO 						  token->type = TOKEN_KEYWORD;
10113ae02089SMasatake YAMATO 					  if (repr && vStringLength (token->string) > 1)
10123ae02089SMasatake YAMATO 						  vStringCatS (repr, vStringValue (token->string) + 1);
10133ae02089SMasatake YAMATO 				  }
10143ae02089SMasatake YAMATO 				  break;
10153ae02089SMasatake YAMATO 	}
10163ae02089SMasatake YAMATO 
1017fc4ca4b7SColomban Wendling 	if (include_newlines && newline_encountered)
1018fc4ca4b7SColomban Wendling 	{
1019fc4ca4b7SColomban Wendling 		/* This isn't strictly correct per the standard, but following the
1020fc4ca4b7SColomban Wendling 		 * real rules means understanding all statements, and that's not
1021fc4ca4b7SColomban Wendling 		 * what the parser currently does.  What we do here is a guess, by
1022fc4ca4b7SColomban Wendling 		 * avoiding inserting semicolons that would make the statement on
1023fc4ca4b7SColomban Wendling 		 * the left or right obviously invalid.  Hopefully this should not
1024fc4ca4b7SColomban Wendling 		 * have false negatives (e.g. should not miss insertion of a semicolon)
1025fc4ca4b7SColomban Wendling 		 * but might have false positives (e.g. it will wrongfully emit a
1026fc4ca4b7SColomban Wendling 		 * semicolon sometimes, i.e. for the newline in "foo\n(bar)").
1027fc4ca4b7SColomban Wendling 		 * This should however be mostly harmless as we only deal with
1028fc4ca4b7SColomban Wendling 		 * newlines in specific situations where we know a false positive
1029fc4ca4b7SColomban Wendling 		 * wouldn't hurt too bad. */
1030fc4ca4b7SColomban Wendling 
1031fc4ca4b7SColomban Wendling 		/* these already end a statement, so no need to duplicate it */
1032fc4ca4b7SColomban Wendling 		#define IS_STMT_SEPARATOR(t) ((t) == TOKEN_SEMICOLON    || \
1033fc4ca4b7SColomban Wendling 		                              (t) == TOKEN_EOF          || \
1034fc4ca4b7SColomban Wendling 		                              (t) == TOKEN_COMMA        || \
1035fc4ca4b7SColomban Wendling 		                              (t) == TOKEN_OPEN_CURLY)
1036fc4ca4b7SColomban Wendling 		/* these cannot be the start or end of a statement */
1037fc4ca4b7SColomban Wendling 		#define IS_BINARY_OPERATOR(t) ((t) == TOKEN_EQUAL_SIGN      || \
103850eb5201SJohn Lindal 		                               (t) == TOKEN_ARROW           || \
1039fc4ca4b7SColomban Wendling 		                               (t) == TOKEN_COLON           || \
1040fc4ca4b7SColomban Wendling 		                               (t) == TOKEN_PERIOD          || \
1041d01b4a7cSColomban Wendling 		                               (t) == TOKEN_STAR            || \
1042fc4ca4b7SColomban Wendling 		                               (t) == TOKEN_BINARY_OPERATOR)
1043fc4ca4b7SColomban Wendling 
1044fc4ca4b7SColomban Wendling 		if (! IS_STMT_SEPARATOR(LastTokenType) &&
1045fc4ca4b7SColomban Wendling 		    ! IS_STMT_SEPARATOR(token->type) &&
1046fc4ca4b7SColomban Wendling 		    ! IS_BINARY_OPERATOR(LastTokenType) &&
1047fc4ca4b7SColomban Wendling 		    ! IS_BINARY_OPERATOR(token->type) &&
1048fc4ca4b7SColomban Wendling 		    /* these cannot be followed by a semicolon */
1049fc4ca4b7SColomban Wendling 		    ! (LastTokenType == TOKEN_OPEN_PAREN ||
1050fc4ca4b7SColomban Wendling 		       LastTokenType == TOKEN_OPEN_SQUARE))
1051fc4ca4b7SColomban Wendling 		{
1052137eb990SK.Takata 			/* hold the token... */
1053fc4ca4b7SColomban Wendling 			Assert (NextToken == NULL);
1054fc4ca4b7SColomban Wendling 			NextToken = newToken ();
1055ce990805SThomas Braun 			copyToken (NextToken, token, false);
1056fc4ca4b7SColomban Wendling 
1057fc4ca4b7SColomban Wendling 			/* ...and emit a semicolon instead */
1058fc4ca4b7SColomban Wendling 			token->type		= TOKEN_SEMICOLON;
1059fc4ca4b7SColomban Wendling 			token->keyword	= KEYWORD_NONE;
1060fc4ca4b7SColomban Wendling 			vStringClear (token->string);
1061fc4ca4b7SColomban Wendling 			if (repr)
1062fc4ca4b7SColomban Wendling 				vStringPut (token->string, '\n');
1063fc4ca4b7SColomban Wendling 		}
1064fc4ca4b7SColomban Wendling 
1065fc4ca4b7SColomban Wendling 		#undef IS_STMT_SEPARATOR
1066fc4ca4b7SColomban Wendling 		#undef IS_BINARY_OPERATOR
1067fc4ca4b7SColomban Wendling 	}
1068fc4ca4b7SColomban Wendling 
10693ae02089SMasatake YAMATO 	LastTokenType = token->type;
10703ae02089SMasatake YAMATO }
10713ae02089SMasatake YAMATO 
1072f2e65b39SMasatake YAMATO /* See https://babeljs.io/blog/2018/09/17/decorators */
skipBabelDecorator(tokenInfo * token,bool include_newlines,vString * const repr)1073f2e65b39SMasatake YAMATO static void skipBabelDecorator (tokenInfo *token, bool include_newlines, vString *const repr)
1074f2e65b39SMasatake YAMATO {
1075f2e65b39SMasatake YAMATO 	readTokenFullRaw (token, include_newlines, repr);
1076f2e65b39SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_PAREN))
1077f2e65b39SMasatake YAMATO 	{
1078f2e65b39SMasatake YAMATO 		/*  @(complex ? dec1 : dec2) */
1079f2e65b39SMasatake YAMATO 		skipArgumentList (token, include_newlines, repr);
1080f2e65b39SMasatake YAMATO 		TRACE_PRINT ("found @(...) style decorator");
1081f2e65b39SMasatake YAMATO 	}
1082f2e65b39SMasatake YAMATO 	else if (isType (token, TOKEN_IDENTIFIER))
1083f2e65b39SMasatake YAMATO 	{
1084f2e65b39SMasatake YAMATO 		/*  @namespace.foo (...) */
1085f2e65b39SMasatake YAMATO 		bool found_period = false;
1086f2e65b39SMasatake YAMATO 		while (1)
1087f2e65b39SMasatake YAMATO 		{
1088f2e65b39SMasatake YAMATO 			readTokenFullRaw (token, include_newlines, repr);
1089f2e65b39SMasatake YAMATO 			if (isType (token, TOKEN_IDENTIFIER))
1090f2e65b39SMasatake YAMATO 			{
1091f2e65b39SMasatake YAMATO 				if (!found_period)
1092f2e65b39SMasatake YAMATO 				{
1093f2e65b39SMasatake YAMATO 					TRACE_PRINT("found @namespace.bar style decorator");
1094f2e65b39SMasatake YAMATO 					break;
1095f2e65b39SMasatake YAMATO 				}
1096f2e65b39SMasatake YAMATO 				found_period = false;
1097f2e65b39SMasatake YAMATO 			}
1098f2e65b39SMasatake YAMATO 			else if (isType (token, TOKEN_PERIOD))
1099f2e65b39SMasatake YAMATO 				found_period = true;
1100f2e65b39SMasatake YAMATO 			else if (isType (token, TOKEN_OPEN_PAREN))
1101f2e65b39SMasatake YAMATO 			{
1102f2e65b39SMasatake YAMATO 				skipArgumentList (token, include_newlines, repr);
1103f2e65b39SMasatake YAMATO 				TRACE_PRINT("found @foo(...) style decorator");
1104f2e65b39SMasatake YAMATO 				break;
1105f2e65b39SMasatake YAMATO 			}
1106f2e65b39SMasatake YAMATO 			else
1107f2e65b39SMasatake YAMATO 			{
1108f2e65b39SMasatake YAMATO 				TRACE_PRINT("found @foo style decorator");
1109f2e65b39SMasatake YAMATO 				break;
1110f2e65b39SMasatake YAMATO 			}
1111f2e65b39SMasatake YAMATO 		}
1112f2e65b39SMasatake YAMATO 	}
1113f2e65b39SMasatake YAMATO 	else
1114f2e65b39SMasatake YAMATO 		/* Unexpected token after @ */
1115f2e65b39SMasatake YAMATO 		TRACE_PRINT("found unexpected token during skipping a decorator");
1116f2e65b39SMasatake YAMATO }
1117f2e65b39SMasatake YAMATO 
readTokenFull(tokenInfo * const token,bool include_newlines,vString * const repr)1118f2e65b39SMasatake YAMATO static void readTokenFull (tokenInfo *const token, bool include_newlines, vString *const repr)
1119f2e65b39SMasatake YAMATO {
1120f2e65b39SMasatake YAMATO 	readTokenFullRaw (token, include_newlines, repr);
1121f2e65b39SMasatake YAMATO 
1122f2e65b39SMasatake YAMATO 	while (1)
1123f2e65b39SMasatake YAMATO 	{
1124f2e65b39SMasatake YAMATO 		if (!isType (token, TOKEN_ATMARK))
1125f2e65b39SMasatake YAMATO 			break;
1126f2e65b39SMasatake YAMATO 		skipBabelDecorator (token, include_newlines, repr);
1127f2e65b39SMasatake YAMATO 		/* @decorator0 @decorator1 ... There can be more than one decorator. */
1128f2e65b39SMasatake YAMATO 	}
1129f2e65b39SMasatake YAMATO }
1130f2e65b39SMasatake YAMATO 
113135c54da9SColomban Wendling #ifdef JSCRIPT_DO_DEBUGGING
113235c54da9SColomban Wendling /* trace readTokenFull() */
readTokenFullDebug(tokenInfo * const token,bool include_newlines,vString * const repr)113335c54da9SColomban Wendling static void readTokenFullDebug (tokenInfo *const token, bool include_newlines, vString *const repr)
113435c54da9SColomban Wendling {
113535c54da9SColomban Wendling 	readTokenFull (token, include_newlines, repr);
1136c93e1170SMasatake YAMATO 	TRACE_PRINT("token '%s' of type %02x with scope '%s'",vStringValue(token->string),token->type, vStringValue(token->scope));
113735c54da9SColomban Wendling }
113835c54da9SColomban Wendling # define readTokenFull readTokenFullDebug
113935c54da9SColomban Wendling #endif
114035c54da9SColomban Wendling 
readToken(tokenInfo * const token)11413ae02089SMasatake YAMATO static void readToken (tokenInfo *const token)
11423ae02089SMasatake YAMATO {
1143ce990805SThomas Braun 	readTokenFull (token, false, NULL);
11443ae02089SMasatake YAMATO }
11453ae02089SMasatake YAMATO 
11463ae02089SMasatake YAMATO /*
11473ae02089SMasatake YAMATO  *	 Token parsing functions
11483ae02089SMasatake YAMATO  */
11493ae02089SMasatake YAMATO 
parseMethodsInAnonymousClass(tokenInfo * const token)115050eb5201SJohn Lindal static void parseMethodsInAnonymousClass (tokenInfo *const token)
115150eb5201SJohn Lindal {
115250eb5201SJohn Lindal 	tokenInfo *const anon_class = newToken ();
115350eb5201SJohn Lindal 	copyToken (anon_class, token, true);
115450eb5201SJohn Lindal 	anonGenerate (anon_class->string, "AnonymousClass", JSTAG_CLASS);
115550eb5201SJohn Lindal 	anon_class->type = TOKEN_IDENTIFIER;
115650eb5201SJohn Lindal 
115750eb5201SJohn Lindal 	bool has_methods = parseMethods (token, anon_class, false);
115850eb5201SJohn Lindal 
115950eb5201SJohn Lindal 	if (has_methods)
116050eb5201SJohn Lindal 		makeJsTagCommon (anon_class, JSTAG_CLASS, NULL, NULL, true);
116150eb5201SJohn Lindal 
116250eb5201SJohn Lindal 	deleteToken (anon_class);
116350eb5201SJohn Lindal }
116450eb5201SJohn Lindal 
skipArgumentList(tokenInfo * const token,bool include_newlines,vString * const repr)1165ce990805SThomas Braun static void skipArgumentList (tokenInfo *const token, bool include_newlines, vString *const repr)
11663ae02089SMasatake YAMATO {
11673ae02089SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_PAREN))	/* arguments? */
11683ae02089SMasatake YAMATO 	{
116950eb5201SJohn Lindal 		int nest_level = 1;
11703ae02089SMasatake YAMATO 		if (repr)
11713ae02089SMasatake YAMATO 			vStringPut (repr, '(');
117250eb5201SJohn Lindal 
117350eb5201SJohn Lindal 		tokenType prev_token_type = token->type;
11743ae02089SMasatake YAMATO 		while (nest_level > 0 && ! isType (token, TOKEN_EOF))
11753ae02089SMasatake YAMATO 		{
1176ce990805SThomas Braun 			readTokenFull (token, false, repr);
11773ae02089SMasatake YAMATO 			if (isType (token, TOKEN_OPEN_PAREN))
11783ae02089SMasatake YAMATO 				nest_level++;
11793ae02089SMasatake YAMATO 			else if (isType (token, TOKEN_CLOSE_PAREN))
11803ae02089SMasatake YAMATO 				nest_level--;
118150eb5201SJohn Lindal 			else if (isType (token, TOKEN_OPEN_CURLY))
118250eb5201SJohn Lindal 			{
118350eb5201SJohn Lindal 				if (prev_token_type == TOKEN_ARROW)
118450eb5201SJohn Lindal 					parseBlock (token, NULL);
118550eb5201SJohn Lindal 				else
118650eb5201SJohn Lindal 					parseMethodsInAnonymousClass (token);
118750eb5201SJohn Lindal 			}
118878a90f03SMasatake YAMATO 			else if (isKeyword (token, KEYWORD_function))
118978a90f03SMasatake YAMATO 				parseFunction (token);
119050eb5201SJohn Lindal 
119150eb5201SJohn Lindal 			prev_token_type = token->type;
11923ae02089SMasatake YAMATO 		}
11933ae02089SMasatake YAMATO 		readTokenFull (token, include_newlines, NULL);
11943ae02089SMasatake YAMATO 	}
11953ae02089SMasatake YAMATO }
11963ae02089SMasatake YAMATO 
skipArrayList(tokenInfo * const token,bool include_newlines)1197ce990805SThomas Braun static void skipArrayList (tokenInfo *const token, bool include_newlines)
11983ae02089SMasatake YAMATO {
11993ae02089SMasatake YAMATO 	/*
12003ae02089SMasatake YAMATO 	 * Handle square brackets
12013ae02089SMasatake YAMATO 	 *	 var name[1]
12023ae02089SMasatake YAMATO 	 * So we must check for nested open and closing square brackets
12033ae02089SMasatake YAMATO 	 */
12043ae02089SMasatake YAMATO 
12053ae02089SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_SQUARE))	/* arguments? */
12063ae02089SMasatake YAMATO 	{
120750eb5201SJohn Lindal 		int nest_level = 1;
120850eb5201SJohn Lindal 		tokenType prev_token_type = token->type;
12093ae02089SMasatake YAMATO 		while (nest_level > 0 && ! isType (token, TOKEN_EOF))
12103ae02089SMasatake YAMATO 		{
12113ae02089SMasatake YAMATO 			readToken (token);
12123ae02089SMasatake YAMATO 			if (isType (token, TOKEN_OPEN_SQUARE))
12133ae02089SMasatake YAMATO 				nest_level++;
12143ae02089SMasatake YAMATO 			else if (isType (token, TOKEN_CLOSE_SQUARE))
12153ae02089SMasatake YAMATO 				nest_level--;
121650eb5201SJohn Lindal 			else if (isType (token, TOKEN_OPEN_CURLY))
121750eb5201SJohn Lindal 			{
121850eb5201SJohn Lindal 				if (prev_token_type == TOKEN_ARROW)
121950eb5201SJohn Lindal 					parseBlock (token, NULL);
122050eb5201SJohn Lindal 				else
122150eb5201SJohn Lindal 					parseMethodsInAnonymousClass (token);
122250eb5201SJohn Lindal 			}
122350eb5201SJohn Lindal 
122450eb5201SJohn Lindal 			prev_token_type = token->type;
12253ae02089SMasatake YAMATO 		}
12263ae02089SMasatake YAMATO 		readTokenFull (token, include_newlines, NULL);
12273ae02089SMasatake YAMATO 	}
12283ae02089SMasatake YAMATO }
12293ae02089SMasatake YAMATO 
skipQualifiedIdentifier(tokenInfo * const token)1230d1a0367eSMasatake YAMATO static void skipQualifiedIdentifier (tokenInfo *const token)
1231d1a0367eSMasatake YAMATO {
1232d1a0367eSMasatake YAMATO 	/* Skip foo.bar.baz */
1233d1a0367eSMasatake YAMATO 	while (isType (token, TOKEN_IDENTIFIER))
1234d1a0367eSMasatake YAMATO 	{
1235d1a0367eSMasatake YAMATO 		readToken (token);
1236d1a0367eSMasatake YAMATO 		if (isType (token, TOKEN_PERIOD))
1237d1a0367eSMasatake YAMATO 			readToken (token);
1238d1a0367eSMasatake YAMATO 		else
1239d1a0367eSMasatake YAMATO 			break;
1240d1a0367eSMasatake YAMATO 	}
1241d1a0367eSMasatake YAMATO }
1242d1a0367eSMasatake YAMATO 
addContext(tokenInfo * const parent,const tokenInfo * const child)12433ae02089SMasatake YAMATO static void addContext (tokenInfo* const parent, const tokenInfo* const child)
12443ae02089SMasatake YAMATO {
12453ae02089SMasatake YAMATO 	if (vStringLength (parent->string) > 0)
12463ae02089SMasatake YAMATO 	{
12471da6e7e4SMasatake YAMATO 		vStringPut (parent->string, '.');
12483ae02089SMasatake YAMATO 	}
12494e6bcb7bSColomban Wendling 	vStringCat (parent->string, child->string);
12503ae02089SMasatake YAMATO }
12513ae02089SMasatake YAMATO 
addToScope(tokenInfo * const token,const vString * const extra)12524fd7a374SColomban Wendling static void addToScope (tokenInfo* const token, const vString* const extra)
12533ae02089SMasatake YAMATO {
12543ae02089SMasatake YAMATO 	if (vStringLength (token->scope) > 0)
12553ae02089SMasatake YAMATO 	{
12561da6e7e4SMasatake YAMATO 		vStringPut (token->scope, '.');
12573ae02089SMasatake YAMATO 	}
12584e6bcb7bSColomban Wendling 	vStringCat (token->scope, extra);
12593ae02089SMasatake YAMATO }
12603ae02089SMasatake YAMATO 
12613ae02089SMasatake YAMATO /*
12623ae02089SMasatake YAMATO  *	 Scanning functions
12633ae02089SMasatake YAMATO  */
12643ae02089SMasatake YAMATO 
findCmdTerm(tokenInfo * const token,bool include_newlines,bool include_commas)1265ce990805SThomas Braun static bool findCmdTerm (tokenInfo *const token, bool include_newlines,
1266ce990805SThomas Braun                             bool include_commas)
12673ae02089SMasatake YAMATO {
12683ae02089SMasatake YAMATO 	/*
12693ae02089SMasatake YAMATO 	 * Read until we find either a semicolon or closing brace.
12703ae02089SMasatake YAMATO 	 * Any nested braces will be handled within.
12713ae02089SMasatake YAMATO 	 */
12723ae02089SMasatake YAMATO 	while (! isType (token, TOKEN_SEMICOLON) &&
12733ae02089SMasatake YAMATO 		   ! isType (token, TOKEN_CLOSE_CURLY) &&
12744aa0017cSColomban Wendling 		   ! (include_commas && isType (token, TOKEN_COMMA)) &&
12753ae02089SMasatake YAMATO 		   ! isType (token, TOKEN_EOF))
12763ae02089SMasatake YAMATO 	{
12773ae02089SMasatake YAMATO 		/* Handle nested blocks */
12783ae02089SMasatake YAMATO 		if ( isType (token, TOKEN_OPEN_CURLY))
12793ae02089SMasatake YAMATO 		{
12804fd7a374SColomban Wendling 			parseBlock (token, NULL);
12813ae02089SMasatake YAMATO 			readTokenFull (token, include_newlines, NULL);
12823ae02089SMasatake YAMATO 		}
12833ae02089SMasatake YAMATO 		else if ( isType (token, TOKEN_OPEN_PAREN) )
12843ae02089SMasatake YAMATO 		{
12853ae02089SMasatake YAMATO 			skipArgumentList(token, include_newlines, NULL);
12863ae02089SMasatake YAMATO 		}
12873ae02089SMasatake YAMATO 		else if ( isType (token, TOKEN_OPEN_SQUARE) )
12883ae02089SMasatake YAMATO 		{
12893ae02089SMasatake YAMATO 			skipArrayList(token, include_newlines);
12903ae02089SMasatake YAMATO 		}
12913ae02089SMasatake YAMATO 		else
12923ae02089SMasatake YAMATO 		{
12933ae02089SMasatake YAMATO 			readTokenFull (token, include_newlines, NULL);
12943ae02089SMasatake YAMATO 		}
12953ae02089SMasatake YAMATO 	}
12963ae02089SMasatake YAMATO 
12973ae02089SMasatake YAMATO 	return isType (token, TOKEN_SEMICOLON);
12983ae02089SMasatake YAMATO }
12993ae02089SMasatake YAMATO 
parseSwitch(tokenInfo * const token)13003ae02089SMasatake YAMATO static void parseSwitch (tokenInfo *const token)
13013ae02089SMasatake YAMATO {
13023ae02089SMasatake YAMATO 	/*
13033ae02089SMasatake YAMATO 	 * switch (expression) {
13043ae02089SMasatake YAMATO 	 * case value1:
13053ae02089SMasatake YAMATO 	 *	   statement;
13063ae02089SMasatake YAMATO 	 *	   break;
13073ae02089SMasatake YAMATO 	 * case value2:
13083ae02089SMasatake YAMATO 	 *	   statement;
13093ae02089SMasatake YAMATO 	 *	   break;
13103ae02089SMasatake YAMATO 	 * default : statement;
13113ae02089SMasatake YAMATO 	 * }
13123ae02089SMasatake YAMATO 	 */
13133ae02089SMasatake YAMATO 
13143ae02089SMasatake YAMATO 	readToken (token);
13153ae02089SMasatake YAMATO 
13163ae02089SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_PAREN))
13173ae02089SMasatake YAMATO 	{
1318ce990805SThomas Braun 		skipArgumentList(token, false, NULL);
13193ae02089SMasatake YAMATO 	}
13203ae02089SMasatake YAMATO 
13213ae02089SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_CURLY))
13223ae02089SMasatake YAMATO 	{
13234fd7a374SColomban Wendling 		parseBlock (token, NULL);
13243ae02089SMasatake YAMATO 	}
13253ae02089SMasatake YAMATO }
13263ae02089SMasatake YAMATO 
parseLoop(tokenInfo * const token)13274fd7a374SColomban Wendling static bool parseLoop (tokenInfo *const token)
13283ae02089SMasatake YAMATO {
13293ae02089SMasatake YAMATO 	/*
13303ae02089SMasatake YAMATO 	 * Handles these statements
13313ae02089SMasatake YAMATO 	 *	   for (x=0; x<3; x++)
13323ae02089SMasatake YAMATO 	 *		   document.write("This text is repeated three times<br>");
13333ae02089SMasatake YAMATO 	 *
13343ae02089SMasatake YAMATO 	 *	   for (x=0; x<3; x++)
13353ae02089SMasatake YAMATO 	 *	   {
13363ae02089SMasatake YAMATO 	 *		   document.write("This text is repeated three times<br>");
13373ae02089SMasatake YAMATO 	 *	   }
13383ae02089SMasatake YAMATO 	 *
13393ae02089SMasatake YAMATO 	 *	   while (number<5){
13403ae02089SMasatake YAMATO 	 *		   document.write(number+"<br>");
13413ae02089SMasatake YAMATO 	 *		   number++;
13423ae02089SMasatake YAMATO 	 *	   }
13433ae02089SMasatake YAMATO 	 *
13443ae02089SMasatake YAMATO 	 *	   do{
13453ae02089SMasatake YAMATO 	 *		   document.write(number+"<br>");
13463ae02089SMasatake YAMATO 	 *		   number++;
13473ae02089SMasatake YAMATO 	 *	   }
13483ae02089SMasatake YAMATO 	 *	   while (number<5);
13493ae02089SMasatake YAMATO 	 */
1350ce990805SThomas Braun 	bool is_terminated = true;
13513ae02089SMasatake YAMATO 
13523ae02089SMasatake YAMATO 	if (isKeyword (token, KEYWORD_for) || isKeyword (token, KEYWORD_while))
13533ae02089SMasatake YAMATO 	{
13543ae02089SMasatake YAMATO 		readToken(token);
13553ae02089SMasatake YAMATO 
13563ae02089SMasatake YAMATO 		if (isType (token, TOKEN_OPEN_PAREN))
13573ae02089SMasatake YAMATO 		{
1358ce990805SThomas Braun 			skipArgumentList(token, false, NULL);
13593ae02089SMasatake YAMATO 		}
13603ae02089SMasatake YAMATO 
13613ae02089SMasatake YAMATO 		if (isType (token, TOKEN_OPEN_CURLY))
13623ae02089SMasatake YAMATO 		{
13634fd7a374SColomban Wendling 			parseBlock (token, NULL);
13643ae02089SMasatake YAMATO 		}
13653ae02089SMasatake YAMATO 		else
13663ae02089SMasatake YAMATO 		{
13674fd7a374SColomban Wendling 			is_terminated = parseLine(token, false);
13683ae02089SMasatake YAMATO 		}
13693ae02089SMasatake YAMATO 	}
13703ae02089SMasatake YAMATO 	else if (isKeyword (token, KEYWORD_do))
13713ae02089SMasatake YAMATO 	{
13723ae02089SMasatake YAMATO 		readToken(token);
13733ae02089SMasatake YAMATO 
13743ae02089SMasatake YAMATO 		if (isType (token, TOKEN_OPEN_CURLY))
13753ae02089SMasatake YAMATO 		{
13764fd7a374SColomban Wendling 			parseBlock (token, NULL);
13773ae02089SMasatake YAMATO 		}
13783ae02089SMasatake YAMATO 		else
13793ae02089SMasatake YAMATO 		{
13804fd7a374SColomban Wendling 			is_terminated = parseLine(token, false);
13813ae02089SMasatake YAMATO 		}
13823ae02089SMasatake YAMATO 
13833ae02089SMasatake YAMATO 		if (is_terminated)
13843ae02089SMasatake YAMATO 			readToken(token);
13853ae02089SMasatake YAMATO 
13863ae02089SMasatake YAMATO 		if (isKeyword (token, KEYWORD_while))
13873ae02089SMasatake YAMATO 		{
13883ae02089SMasatake YAMATO 			readToken(token);
13893ae02089SMasatake YAMATO 
13903ae02089SMasatake YAMATO 			if (isType (token, TOKEN_OPEN_PAREN))
13913ae02089SMasatake YAMATO 			{
1392ce990805SThomas Braun 				skipArgumentList(token, true, NULL);
13933ae02089SMasatake YAMATO 			}
13943ae02089SMasatake YAMATO 			if (! isType (token, TOKEN_SEMICOLON))
13954c698bd1SColomban Wendling 			{
13964c698bd1SColomban Wendling 				/* oddly enough, `do {} while (0) var foo = 42` is perfectly
13974c698bd1SColomban Wendling 				 * valid JS, so explicitly handle the remaining of the line
13984c698bd1SColomban Wendling 				 * for the sake of the root scope handling (as parseJsFile()
13994c698bd1SColomban Wendling 				 * always advances a token not to ever get stuck) */
14004c698bd1SColomban Wendling 				is_terminated = parseLine(token, false);
14014c698bd1SColomban Wendling 			}
14023ae02089SMasatake YAMATO 		}
14033ae02089SMasatake YAMATO 	}
14043ae02089SMasatake YAMATO 
14053ae02089SMasatake YAMATO 	return is_terminated;
14063ae02089SMasatake YAMATO }
14073ae02089SMasatake YAMATO 
parseIf(tokenInfo * const token)14084fd7a374SColomban Wendling static bool parseIf (tokenInfo *const token)
14093ae02089SMasatake YAMATO {
1410ce990805SThomas Braun 	bool read_next_token = true;
14113ae02089SMasatake YAMATO 	/*
14123ae02089SMasatake YAMATO 	 * If statements have two forms
14133ae02089SMasatake YAMATO 	 *	   if ( ... )
14143ae02089SMasatake YAMATO 	 *		   one line;
14153ae02089SMasatake YAMATO 	 *
14163ae02089SMasatake YAMATO 	 *	   if ( ... )
14173ae02089SMasatake YAMATO 	 *		  statement;
14183ae02089SMasatake YAMATO 	 *	   else
14193ae02089SMasatake YAMATO 	 *		  statement
14203ae02089SMasatake YAMATO 	 *
14213ae02089SMasatake YAMATO 	 *	   if ( ... ) {
14223ae02089SMasatake YAMATO 	 *		  multiple;
14233ae02089SMasatake YAMATO 	 *		  statements;
14243ae02089SMasatake YAMATO 	 *	   }
14253ae02089SMasatake YAMATO 	 *
14263ae02089SMasatake YAMATO 	 *
14273ae02089SMasatake YAMATO 	 *	   if ( ... ) {
14283ae02089SMasatake YAMATO 	 *		  return elem
14293ae02089SMasatake YAMATO 	 *	   }
14303ae02089SMasatake YAMATO 	 *
14313ae02089SMasatake YAMATO 	 *     This example if correctly written, but the
14323ae02089SMasatake YAMATO 	 *     else contains only 1 statement without a terminator
14333ae02089SMasatake YAMATO 	 *     since the function finishes with the closing brace.
14343ae02089SMasatake YAMATO 	 *
14353ae02089SMasatake YAMATO      *     function a(flag){
14363ae02089SMasatake YAMATO      *         if(flag)
14373ae02089SMasatake YAMATO      *             test(1);
14383ae02089SMasatake YAMATO      *         else
14393ae02089SMasatake YAMATO      *             test(2)
14403ae02089SMasatake YAMATO      *     }
14413ae02089SMasatake YAMATO 	 *
14423ae02089SMasatake YAMATO 	 * TODO:  Deal with statements that can optional end
14433ae02089SMasatake YAMATO 	 *		  without a semi-colon.  Currently this messes up
14443ae02089SMasatake YAMATO 	 *		  the parsing of blocks.
14453ae02089SMasatake YAMATO 	 *		  Need to somehow detect this has happened, and either
14463ae02089SMasatake YAMATO 	 *		  backup a token, or skip reading the next token if
14473ae02089SMasatake YAMATO 	 *		  that is possible from all code locations.
14483ae02089SMasatake YAMATO 	 *
14493ae02089SMasatake YAMATO 	 */
14503ae02089SMasatake YAMATO 
14513ae02089SMasatake YAMATO 	readToken (token);
14523ae02089SMasatake YAMATO 
14533ae02089SMasatake YAMATO 	if (isKeyword (token, KEYWORD_if))
14543ae02089SMasatake YAMATO 	{
14553ae02089SMasatake YAMATO 		/*
14563ae02089SMasatake YAMATO 		 * Check for an "else if" and consume the "if"
14573ae02089SMasatake YAMATO 		 */
14583ae02089SMasatake YAMATO 		readToken (token);
14593ae02089SMasatake YAMATO 	}
14603ae02089SMasatake YAMATO 
14613ae02089SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_PAREN))
14623ae02089SMasatake YAMATO 	{
1463ce990805SThomas Braun 		skipArgumentList(token, false, NULL);
14643ae02089SMasatake YAMATO 	}
14653ae02089SMasatake YAMATO 
14663ae02089SMasatake YAMATO 	if (isType (token, TOKEN_OPEN_CURLY))
14673ae02089SMasatake YAMATO 	{
14684fd7a374SColomban Wendling 		parseBlock (token, NULL);
14693ae02089SMasatake YAMATO 	}
14703ae02089SMasatake YAMATO 	else
14713ae02089SMasatake YAMATO 	{
14723ae02089SMasatake YAMATO 		/* The next token should only be read if this statement had its own
14733ae02089SMasatake YAMATO 		 * terminator */
1474ce990805SThomas Braun 		read_next_token = findCmdTerm (token, true, false);
14753ae02089SMasatake YAMATO 	}
14763ae02089SMasatake YAMATO 	return read_next_token;
14773ae02089SMasatake YAMATO }
14783ae02089SMasatake YAMATO 
parseFunction(tokenInfo * const token)14793ae02089SMasatake YAMATO static void parseFunction (tokenInfo *const token)
14803ae02089SMasatake YAMATO {
1481c93e1170SMasatake YAMATO 	TRACE_ENTER();
1482c93e1170SMasatake YAMATO 
14833ae02089SMasatake YAMATO 	tokenInfo *const name = newToken ();
14843ae02089SMasatake YAMATO 	vString *const signature = vStringNew ();
1485ce990805SThomas Braun 	bool is_class = false;
1486d01b4a7cSColomban Wendling 	bool is_generator = false;
14870e4c5d4aSMasatake YAMATO 	bool is_anonymous = false;
14883ae02089SMasatake YAMATO 	/*
14893ae02089SMasatake YAMATO 	 * This deals with these formats
14903ae02089SMasatake YAMATO 	 *	   function validFunctionTwo(a,b) {}
1491d01b4a7cSColomban Wendling 	 *	   function * generator(a,b) {}
14923ae02089SMasatake YAMATO 	 */
14933ae02089SMasatake YAMATO 
14944fd7a374SColomban Wendling 	copyToken (name, token, true);
14953ae02089SMasatake YAMATO 	readToken (name);
1496d01b4a7cSColomban Wendling 	if (isType (name, TOKEN_STAR))
1497d01b4a7cSColomban Wendling 	{
1498d01b4a7cSColomban Wendling 		is_generator = true;
1499d01b4a7cSColomban Wendling 		readToken (name);
1500d01b4a7cSColomban Wendling 	}
1501cc1a1875SColomban Wendling 	if (isType (name, TOKEN_OPEN_PAREN))
1502cc1a1875SColomban Wendling 	{
1503cc1a1875SColomban Wendling 		/* anonymous function */
1504cc1a1875SColomban Wendling 		copyToken (token, name, false);
1505cc1a1875SColomban Wendling 		anonGenerate (name->string, "AnonymousFunction", JSTAG_FUNCTION);
15060e4c5d4aSMasatake YAMATO 		is_anonymous = true;
1507cc1a1875SColomban Wendling 	}
1508cc1a1875SColomban Wendling 	else if (!isType (name, TOKEN_IDENTIFIER))
150992ee531aSMasatake YAMATO 		goto cleanUp;
1510cc1a1875SColomban Wendling 	else
1511cc1a1875SColomban Wendling 		readToken (token);
15124f11ded2SMasatake YAMATO 
15133ae02089SMasatake YAMATO 	while (isType (token, TOKEN_PERIOD))
15143ae02089SMasatake YAMATO 	{
15153ae02089SMasatake YAMATO 		readToken (token);
151651d7d471SColomban Wendling 		if (! isType(token, TOKEN_KEYWORD))
15173ae02089SMasatake YAMATO 		{
15183ae02089SMasatake YAMATO 			addContext (name, token);
15193ae02089SMasatake YAMATO 			readToken (token);
15203ae02089SMasatake YAMATO 		}
15213ae02089SMasatake YAMATO 	}
15223ae02089SMasatake YAMATO 
15233ae02089SMasatake YAMATO 	if ( isType (token, TOKEN_OPEN_PAREN) )
1524ce990805SThomas Braun 		skipArgumentList(token, false, signature);
15253ae02089SMasatake YAMATO 
15263ae02089SMasatake YAMATO 	if ( isType (token, TOKEN_OPEN_CURLY) )
15273ae02089SMasatake YAMATO 	{
15284fd7a374SColomban Wendling 		is_class = parseBlock (token, name->string);
15293ae02089SMasatake YAMATO 		if ( is_class )
15300e4c5d4aSMasatake YAMATO 			makeClassTagCommon (name, signature, NULL, is_anonymous);
15313ae02089SMasatake YAMATO 		else
15320e4c5d4aSMasatake YAMATO 			makeFunctionTagCommon (name, signature, is_generator, is_anonymous);
15333ae02089SMasatake YAMATO 	}
15343ae02089SMasatake YAMATO 
1535ce990805SThomas Braun 	findCmdTerm (token, false, false);
15363ae02089SMasatake YAMATO 
153792ee531aSMasatake YAMATO  cleanUp:
15383ae02089SMasatake YAMATO 	vStringDelete (signature);
15393ae02089SMasatake YAMATO 	deleteToken (name);
1540c93e1170SMasatake YAMATO 
1541c93e1170SMasatake YAMATO 	TRACE_LEAVE();
15423ae02089SMasatake YAMATO }
15433ae02089SMasatake YAMATO 
15444fd7a374SColomban Wendling /* Parses a block surrounded by curly braces.
15454fd7a374SColomban Wendling  * @p parentScope is the scope name for this block, or NULL for unnamed scopes */
parseBlock(tokenInfo * const token,const vString * const parentScope)15464fd7a374SColomban Wendling static bool parseBlock (tokenInfo *const token, const vString *const parentScope)
15473ae02089SMasatake YAMATO {
1548c93e1170SMasatake YAMATO 	TRACE_ENTER();
154985bb93f2SSzymon Tomasz Stefanek 
1550ce990805SThomas Braun 	bool is_class = false;
1551ce990805SThomas Braun 	bool read_next_token = true;
15523ae02089SMasatake YAMATO 	vString * saveScope = vStringNew ();
15533ae02089SMasatake YAMATO 
15544fd7a374SColomban Wendling 	vStringCopy(saveScope, token->scope);
15554fd7a374SColomban Wendling 	if (parentScope)
1556f5e0c35dSColomban Wendling 	{
15574fd7a374SColomban Wendling 		addToScope (token, parentScope);
15583ae02089SMasatake YAMATO 		token->nestLevel++;
1559f5e0c35dSColomban Wendling 	}
1560f5e0c35dSColomban Wendling 
15613ae02089SMasatake YAMATO 	/*
15623ae02089SMasatake YAMATO 	 * Make this routine a bit more forgiving.
15633ae02089SMasatake YAMATO 	 * If called on an open_curly advance it
15643ae02089SMasatake YAMATO 	 */
156551d7d471SColomban Wendling 	if (isType (token, TOKEN_OPEN_CURLY))
15663ae02089SMasatake YAMATO 		readToken(token);
15673ae02089SMasatake YAMATO 
15683ae02089SMasatake YAMATO 	if (! isType (token, TOKEN_CLOSE_CURLY))
15693ae02089SMasatake YAMATO 	{
15703ae02089SMasatake YAMATO 		/*
15713ae02089SMasatake YAMATO 		 * Read until we find the closing brace,
15723ae02089SMasatake YAMATO 		 * any nested braces will be handled within
15733ae02089SMasatake YAMATO 		 */
15743ae02089SMasatake YAMATO 		do
15753ae02089SMasatake YAMATO 		{
1576ce990805SThomas Braun 			read_next_token = true;
15773ae02089SMasatake YAMATO 			if (isKeyword (token, KEYWORD_this))
15783ae02089SMasatake YAMATO 			{
15793ae02089SMasatake YAMATO 				/*
15803ae02089SMasatake YAMATO 				 * Means we are inside a class and have found
15813ae02089SMasatake YAMATO 				 * a class, not a function
15823ae02089SMasatake YAMATO 				 */
1583ce990805SThomas Braun 				is_class = true;
15843ae02089SMasatake YAMATO 
15853ae02089SMasatake YAMATO 				/*
15863ae02089SMasatake YAMATO 				 * Ignore the remainder of the line
15873ae02089SMasatake YAMATO 				 * findCmdTerm(token);
15883ae02089SMasatake YAMATO 				 */
15894fd7a374SColomban Wendling 				read_next_token = parseLine (token, is_class);
15903ae02089SMasatake YAMATO 			}
15913ae02089SMasatake YAMATO 			else if (isKeyword (token, KEYWORD_var) ||
15923ae02089SMasatake YAMATO 					 isKeyword (token, KEYWORD_let) ||
15933ae02089SMasatake YAMATO 					 isKeyword (token, KEYWORD_const))
15943ae02089SMasatake YAMATO 			{
15953ae02089SMasatake YAMATO 				/*
15963ae02089SMasatake YAMATO 				 * Potentially we have found an inner function.
15973ae02089SMasatake YAMATO 				 * Set something to indicate the scope
15983ae02089SMasatake YAMATO 				 */
15994fd7a374SColomban Wendling 				read_next_token = parseLine (token, is_class);
16003ae02089SMasatake YAMATO 			}
16013ae02089SMasatake YAMATO 			else if (isType (token, TOKEN_OPEN_CURLY))
16023ae02089SMasatake YAMATO 			{
16033ae02089SMasatake YAMATO 				/* Handle nested blocks */
16044fd7a374SColomban Wendling 				parseBlock (token, NULL);
16053ae02089SMasatake YAMATO 			}
16063ae02089SMasatake YAMATO 			else
16073ae02089SMasatake YAMATO 			{
16083ae02089SMasatake YAMATO 				/*
16093ae02089SMasatake YAMATO 				 * It is possible for a line to have no terminator
16103ae02089SMasatake YAMATO 				 * if the following line is a closing brace.
16113ae02089SMasatake YAMATO 				 * parseLine will detect this case and indicate
16123ae02089SMasatake YAMATO 				 * whether we should read an additional token.
16133ae02089SMasatake YAMATO 				 */
16144fd7a374SColomban Wendling 				read_next_token = parseLine (token, is_class);
16153ae02089SMasatake YAMATO 			}
16163ae02089SMasatake YAMATO 
16173ae02089SMasatake YAMATO 			/*
16183ae02089SMasatake YAMATO 			 * Always read a new token unless we find a statement without
16193ae02089SMasatake YAMATO 			 * a ending terminator
16203ae02089SMasatake YAMATO 			 */
16213ae02089SMasatake YAMATO 			if( read_next_token )
16223ae02089SMasatake YAMATO 				readToken(token);
16233ae02089SMasatake YAMATO 
16243ae02089SMasatake YAMATO 			/*
16253ae02089SMasatake YAMATO 			 * If we find a statement without a terminator consider the
16263ae02089SMasatake YAMATO 			 * block finished, otherwise the stack will be off by one.
16273ae02089SMasatake YAMATO 			 */
16283ae02089SMasatake YAMATO 		} while (! isType (token, TOKEN_EOF) &&
16293ae02089SMasatake YAMATO 				 ! isType (token, TOKEN_CLOSE_CURLY) && read_next_token);
16303ae02089SMasatake YAMATO 	}
16313ae02089SMasatake YAMATO 
16324fd7a374SColomban Wendling 	vStringCopy(token->scope, saveScope);
16333ae02089SMasatake YAMATO 	vStringDelete(saveScope);
1634f5e0c35dSColomban Wendling 	if (parentScope)
16353ae02089SMasatake YAMATO 		token->nestLevel--;
16363ae02089SMasatake YAMATO 
1637c93e1170SMasatake YAMATO 	TRACE_LEAVE();
163885bb93f2SSzymon Tomasz Stefanek 
16393ae02089SMasatake YAMATO 	return is_class;
16403ae02089SMasatake YAMATO }
16413ae02089SMasatake YAMATO 
parseMethods(tokenInfo * const token,const tokenInfo * const class,const bool is_es6_class)1642d543a241SColomban Wendling static bool parseMethods (tokenInfo *const token, const tokenInfo *const class,
1643d543a241SColomban Wendling                           const bool is_es6_class)
16443ae02089SMasatake YAMATO {
164501b28274SMasatake YAMATO 	TRACE_ENTER_TEXT("token is '%s' of type %s in classToken '%s' of type %s (es6: %s)",
164601b28274SMasatake YAMATO 					 vStringValue(token->string), tokenTypeName (token->type),
164750eb5201SJohn Lindal 					 class == NULL ? "none" : vStringValue(class->string),
164850eb5201SJohn Lindal 					 class == NULL ? "none" : tokenTypeName (class->type),
164901b28274SMasatake YAMATO 					 is_es6_class? "yes": "no");
165085bb93f2SSzymon Tomasz Stefanek 
16513ae02089SMasatake YAMATO 	tokenInfo *const name = newToken ();
1652ce990805SThomas Braun 	bool has_methods = false;
16534fd7a374SColomban Wendling 	vString *saveScope = vStringNew ();
16544fd7a374SColomban Wendling 
16554fd7a374SColomban Wendling 	vStringCopy (saveScope, token->scope);
165650eb5201SJohn Lindal 	if (class != NULL)
16574fd7a374SColomban Wendling 		addToScope (token, class->string);
16583ae02089SMasatake YAMATO 
16593ae02089SMasatake YAMATO 	/*
16603ae02089SMasatake YAMATO 	 * This deals with these formats
16613ae02089SMasatake YAMATO 	 *	   validProperty  : 2,
16623ae02089SMasatake YAMATO 	 *	   validMethod    : function(a,b) {}
16633ae02089SMasatake YAMATO 	 *	   'validMethod2' : function(a,b) {}
16643ae02089SMasatake YAMATO      *     container.dirtyTab = {'url': false, 'title':false, 'snapshot':false, '*': false}
16659adac004SMasatake YAMATO 	 *     get prop() {}
16669adac004SMasatake YAMATO 	 *     set prop(val) {}
1667661398c1SJohn Lindal 	 *     get(...) {}
1668661398c1SJohn Lindal 	 *     set(...) {}
1669459be705SColomban Wendling      *
1670459be705SColomban Wendling      * ES6 methods:
1671459be705SColomban Wendling      *     property(...) {}
1672459be705SColomban Wendling      *     *generator() {}
16739d44448dSMasatake YAMATO      *
16749d44448dSMasatake YAMATO      * ES6 computed name:
1675459be705SColomban Wendling      *     [property]() {}
16769d44448dSMasatake YAMATO      *     get [property]() {}
16779d44448dSMasatake YAMATO      *     set [property]() {}
1678459be705SColomban Wendling      *     *[generator]() {}
167923d2f194SMasatake YAMATO 	 *
168023d2f194SMasatake YAMATO 	 * tc39/proposal-class-fields
168123d2f194SMasatake YAMATO 	 *     field0 = function(a,b) {}
168223d2f194SMasatake YAMATO 	 *     field1 = 1
168323d2f194SMasatake YAMATO 	 * The parser extracts field0 as a method because the left value
168423d2f194SMasatake YAMATO 	 * is a function (kind propagation), and field1 as a field.
16853ae02089SMasatake YAMATO 	 */
16863ae02089SMasatake YAMATO 
168723d2f194SMasatake YAMATO 	bool dont_read = false;
16883ae02089SMasatake YAMATO 	do
16893ae02089SMasatake YAMATO 	{
16908d0d236fSMasatake YAMATO 		bool is_setter = false;
16918d0d236fSMasatake YAMATO 		bool is_getter = false;
16928d0d236fSMasatake YAMATO 
169323d2f194SMasatake YAMATO 		if (!dont_read)
16943ae02089SMasatake YAMATO 			readToken (token);
169523d2f194SMasatake YAMATO 		dont_read = false;
169623d2f194SMasatake YAMATO 
16973ae02089SMasatake YAMATO 		if (isType (token, TOKEN_CLOSE_CURLY))
16983ae02089SMasatake YAMATO 		{
16993ae02089SMasatake YAMATO 			goto cleanUp;
17003ae02089SMasatake YAMATO 		}
17013ae02089SMasatake YAMATO 
170241c2c77eSColomban Wendling 		if (isKeyword (token, KEYWORD_async))
170341c2c77eSColomban Wendling 			readToken (token);
1704661398c1SJohn Lindal 		else if (isType (token, TOKEN_KEYWORD) &&
1705661398c1SJohn Lindal 				 (isKeyword (token, KEYWORD_get) || isKeyword (token, KEYWORD_set)))
1706661398c1SJohn Lindal 		{
1707a244137fSJohn Lindal 			tokenInfo *saved_token = newToken ();
1708a244137fSJohn Lindal 			copyToken (saved_token, token, true);
1709661398c1SJohn Lindal 			readToken (token);
1710661398c1SJohn Lindal 			if (isType(token, TOKEN_OPEN_PAREN))
1711661398c1SJohn Lindal 			{
1712661398c1SJohn Lindal 				Assert (NextToken == NULL);
1713661398c1SJohn Lindal 				NextToken = newToken ();
1714661398c1SJohn Lindal 				copyToken (NextToken, token, false);	/* save token for next read */
1715a244137fSJohn Lindal 				copyToken (token, saved_token, true);	/* restore token to process */
1716661398c1SJohn Lindal 				token->type = TOKEN_IDENTIFIER;			/* process as identifier */
1717661398c1SJohn Lindal 				token->keyword = KEYWORD_NONE;
1718661398c1SJohn Lindal 			}
1719a244137fSJohn Lindal 			else if (isKeyword (saved_token, KEYWORD_get))
17208d0d236fSMasatake YAMATO 			{
17218d0d236fSMasatake YAMATO 				is_getter = true;
17228d0d236fSMasatake YAMATO 			}
1723661398c1SJohn Lindal 			else
17248d0d236fSMasatake YAMATO 			{
17258d0d236fSMasatake YAMATO 				is_setter = true;
1726661398c1SJohn Lindal 			}
1727a244137fSJohn Lindal 			deleteToken (saved_token);
17288d0d236fSMasatake YAMATO 		}
172941c2c77eSColomban Wendling 
17302f14c4d1SColomban Wendling 		if (! isType (token, TOKEN_KEYWORD) &&
17312f14c4d1SColomban Wendling 		    ! isType (token, TOKEN_SEMICOLON))
17323ae02089SMasatake YAMATO 		{
1733459be705SColomban Wendling 			bool is_generator = false;
1734459be705SColomban Wendling 			bool is_shorthand = false; /* ES6 shorthand syntax */
17359d44448dSMasatake YAMATO 			bool is_computed_name = false; /* ES6 computed property name */
1736c3f80c4aSMasatake YAMATO 			bool is_dynamic_prop = false;
1737c3f80c4aSMasatake YAMATO 			vString *dprop = NULL; /* is_computed_name is true but
1738ebdbd8e2SK.Takata 									* the name is not represented in
1739c3f80c4aSMasatake YAMATO 									* a string literal. The expressions
1740c3f80c4aSMasatake YAMATO 									* go this string. */
1741459be705SColomban Wendling 
1742459be705SColomban Wendling 			if (isType (token, TOKEN_STAR)) /* shorthand generator */
1743459be705SColomban Wendling 			{
1744459be705SColomban Wendling 				is_generator = true;
1745459be705SColomban Wendling 				readToken (token);
1746459be705SColomban Wendling 			}
1747459be705SColomban Wendling 
17489d44448dSMasatake YAMATO 			if (isType (token, TOKEN_OPEN_SQUARE))
17499d44448dSMasatake YAMATO 			{
17509d44448dSMasatake YAMATO 				is_computed_name = true;
1751c3f80c4aSMasatake YAMATO 				dprop = vStringNewInit ("[");
1752c3f80c4aSMasatake YAMATO 				readTokenFull (token, false, dprop);
17539d44448dSMasatake YAMATO 			}
17549d44448dSMasatake YAMATO 
1755ce990805SThomas Braun 			copyToken(name, token, true);
17569d44448dSMasatake YAMATO 			if (is_computed_name && ! isType (token, TOKEN_STRING))
17579d44448dSMasatake YAMATO 				is_dynamic_prop = true;
17583ae02089SMasatake YAMATO 
1759c3f80c4aSMasatake YAMATO 			readTokenFull (token, false, dprop);
17609d44448dSMasatake YAMATO 
17619d44448dSMasatake YAMATO 			if (is_computed_name)
17629d44448dSMasatake YAMATO 			{
17639d44448dSMasatake YAMATO 				int depth = 1;
17649d44448dSMasatake YAMATO 				do
17659d44448dSMasatake YAMATO 				{
17669d44448dSMasatake YAMATO 					if (isType (token, TOKEN_CLOSE_SQUARE))
17679d44448dSMasatake YAMATO 						depth--;
17689d44448dSMasatake YAMATO 					else
17699d44448dSMasatake YAMATO 					{
17709d44448dSMasatake YAMATO 						is_dynamic_prop = true;
17719d44448dSMasatake YAMATO 						if (isType (token, TOKEN_OPEN_SQUARE))
17729d44448dSMasatake YAMATO 							depth++;
17739d44448dSMasatake YAMATO 					}
1774c3f80c4aSMasatake YAMATO 					readTokenFull (token, false, (is_dynamic_prop && depth != 0)? dprop: NULL);
17759d44448dSMasatake YAMATO 				} while (! isType (token, TOKEN_EOF) && depth > 0);
17769d44448dSMasatake YAMATO 			}
17779d44448dSMasatake YAMATO 
1778c3f80c4aSMasatake YAMATO 			if (is_dynamic_prop)
1779c3f80c4aSMasatake YAMATO 			{
1780c3f80c4aSMasatake YAMATO 				injectDynamicName (name, dprop);
1781c3f80c4aSMasatake YAMATO 				dprop = NULL;
1782c3f80c4aSMasatake YAMATO 			}
1783c3f80c4aSMasatake YAMATO 			else
1784c3f80c4aSMasatake YAMATO 				vStringDelete (dprop);
1785c3f80c4aSMasatake YAMATO 
1786459be705SColomban Wendling 			is_shorthand = isType (token, TOKEN_OPEN_PAREN);
178723d2f194SMasatake YAMATO 			bool can_be_field = isType (token, TOKEN_EQUAL_SIGN);
178823d2f194SMasatake YAMATO 			if ( isType (token, TOKEN_COLON) || can_be_field || is_shorthand )
17893ae02089SMasatake YAMATO 			{
1790459be705SColomban Wendling 				if (! is_shorthand)
179141c2c77eSColomban Wendling 				{
17923ae02089SMasatake YAMATO 					readToken (token);
179341c2c77eSColomban Wendling 					if (isKeyword (token, KEYWORD_async))
179441c2c77eSColomban Wendling 						readToken (token);
179541c2c77eSColomban Wendling 				}
179650eb5201SJohn Lindal 
179750eb5201SJohn Lindal 				vString * signature = vStringNew ();
1798459be705SColomban Wendling 				if ( is_shorthand || isKeyword (token, KEYWORD_function) )
17993ae02089SMasatake YAMATO 				{
1800c93e1170SMasatake YAMATO 					TRACE_PRINT("Seems to be a function or shorthand");
18013ae02089SMasatake YAMATO 
1802459be705SColomban Wendling 					if (! is_shorthand)
1803459be705SColomban Wendling 					{
18043ae02089SMasatake YAMATO 						readToken (token);
1805d01b4a7cSColomban Wendling 						if (isType (token, TOKEN_STAR))
1806d01b4a7cSColomban Wendling 						{
1807d01b4a7cSColomban Wendling 							/* generator: 'function' '*' '(' ... ')' '{' ... '}' */
1808d01b4a7cSColomban Wendling 							is_generator = true;
1809d01b4a7cSColomban Wendling 							readToken (token);
1810d01b4a7cSColomban Wendling 						}
1811459be705SColomban Wendling 					}
18123ae02089SMasatake YAMATO 					if ( isType (token, TOKEN_OPEN_PAREN) )
18133ae02089SMasatake YAMATO 					{
1814ce990805SThomas Braun 						skipArgumentList(token, false, signature);
18153ae02089SMasatake YAMATO 					}
18163ae02089SMasatake YAMATO 
181750eb5201SJohn Lindal function:
18183ae02089SMasatake YAMATO 					if (isType (token, TOKEN_OPEN_CURLY))
18193ae02089SMasatake YAMATO 					{
1820ce990805SThomas Braun 						has_methods = true;
18218d0d236fSMasatake YAMATO 
18228d0d236fSMasatake YAMATO 						int kind = JSTAG_METHOD;
18238d0d236fSMasatake YAMATO 						if (is_generator)
18248d0d236fSMasatake YAMATO 							kind = JSTAG_GENERATOR;
18258d0d236fSMasatake YAMATO 						else if (is_getter)
18268d0d236fSMasatake YAMATO 							kind = JSTAG_GETTER;
18278d0d236fSMasatake YAMATO 						else if (is_setter)
18288d0d236fSMasatake YAMATO 							kind = JSTAG_SETTER;
18298d0d236fSMasatake YAMATO 
18308d0d236fSMasatake YAMATO 						makeJsTag (name, kind, signature, NULL);
18314fd7a374SColomban Wendling 						parseBlock (token, name->string);
18323ae02089SMasatake YAMATO 
18333ae02089SMasatake YAMATO 						/*
1834bc95f783SColomban Wendling 						 * If we aren't parsing an ES6 class (for which there
1835bc95f783SColomban Wendling 						 * is no mandatory separators), read to the closing
1836bc95f783SColomban Wendling 						 * curly, check next token, if a comma, we must loop
1837bc95f783SColomban Wendling 						 * again.
18383ae02089SMasatake YAMATO 						 */
1839bc95f783SColomban Wendling 						if (! is_es6_class)
18403ae02089SMasatake YAMATO 							readToken (token);
18413ae02089SMasatake YAMATO 					}
18423ae02089SMasatake YAMATO 				}
1843bc95f783SColomban Wendling 				else if (! is_es6_class)
18443ae02089SMasatake YAMATO 				{
1845ce990805SThomas Braun 					bool has_child_methods = false;
184650eb5201SJohn Lindal 					tokenInfo *saved_token = newToken ();
18473ae02089SMasatake YAMATO 
18483ae02089SMasatake YAMATO 					/* skip whatever is the value */
18493ae02089SMasatake YAMATO 					while (! isType (token, TOKEN_COMMA) &&
18503ae02089SMasatake YAMATO 					       ! isType (token, TOKEN_CLOSE_CURLY) &&
18513ae02089SMasatake YAMATO 					       ! isType (token, TOKEN_EOF))
18523ae02089SMasatake YAMATO 					{
18533ae02089SMasatake YAMATO 						if (isType (token, TOKEN_OPEN_CURLY))
18543ae02089SMasatake YAMATO 						{
18553ae02089SMasatake YAMATO 							/* Recurse to find child properties/methods */
1856bc95f783SColomban Wendling 							has_child_methods = parseMethods (token, name, false);
18573ae02089SMasatake YAMATO 							readToken (token);
18583ae02089SMasatake YAMATO 						}
18593ae02089SMasatake YAMATO 						else if (isType (token, TOKEN_OPEN_PAREN))
18603ae02089SMasatake YAMATO 						{
186150eb5201SJohn Lindal 							vStringClear (signature);
186250eb5201SJohn Lindal 							skipArgumentList (token, false, signature);
18633ae02089SMasatake YAMATO 						}
18643ae02089SMasatake YAMATO 						else if (isType (token, TOKEN_OPEN_SQUARE))
18653ae02089SMasatake YAMATO 						{
1866ce990805SThomas Braun 							skipArrayList (token, false);
18673ae02089SMasatake YAMATO 						}
186850eb5201SJohn Lindal 						else if (isType (token, TOKEN_ARROW))
186950eb5201SJohn Lindal 						{
187050eb5201SJohn Lindal 							TRACE_PRINT("Seems to be an anonymous function");
187150eb5201SJohn Lindal 							if (vStringIsEmpty (signature) &&
187250eb5201SJohn Lindal 								isType (saved_token, TOKEN_IDENTIFIER))
187350eb5201SJohn Lindal 							{
187450eb5201SJohn Lindal 								vStringPut (signature, '(');
187550eb5201SJohn Lindal 								vStringCat (signature, saved_token->string);
187650eb5201SJohn Lindal 								vStringPut (signature, ')');
187750eb5201SJohn Lindal 							}
187850eb5201SJohn Lindal 							readToken (token);
187950eb5201SJohn Lindal 							deleteToken (saved_token);
188050eb5201SJohn Lindal 							goto function;
188150eb5201SJohn Lindal 						}
18823ae02089SMasatake YAMATO 						else
18833ae02089SMasatake YAMATO 						{
188450eb5201SJohn Lindal 							copyToken (saved_token, token, true);
18853ae02089SMasatake YAMATO 							readToken (token);
18863ae02089SMasatake YAMATO 						}
18873ae02089SMasatake YAMATO 					}
188850eb5201SJohn Lindal 					deleteToken (saved_token);
18893ae02089SMasatake YAMATO 
1890ce990805SThomas Braun 					has_methods = true;
18913ae02089SMasatake YAMATO 					if (has_child_methods)
1892a53a76deSColomban Wendling 						makeJsTag (name, JSTAG_CLASS, NULL, NULL);
1893c3f80c4aSMasatake YAMATO 					else
1894a53a76deSColomban Wendling 						makeJsTag (name, JSTAG_PROPERTY, NULL, NULL);
18953ae02089SMasatake YAMATO 				}
189623d2f194SMasatake YAMATO 				else if (can_be_field)
189723d2f194SMasatake YAMATO 				{
189823d2f194SMasatake YAMATO 					makeJsTag (name, JSTAG_FIELD, NULL, NULL);
189923d2f194SMasatake YAMATO 					parseLine (token, true);
190023d2f194SMasatake YAMATO 				}
190150eb5201SJohn Lindal 
190250eb5201SJohn Lindal 				vStringDelete (signature);
190323d2f194SMasatake YAMATO 			}
190423d2f194SMasatake YAMATO 			else
190523d2f194SMasatake YAMATO 			{
190623d2f194SMasatake YAMATO 				makeJsTag (name, JSTAG_FIELD, NULL, NULL);
190723d2f194SMasatake YAMATO 				if (!isType (token, TOKEN_SEMICOLON))
190823d2f194SMasatake YAMATO 					dont_read = true;
19093ae02089SMasatake YAMATO 			}
19103ae02089SMasatake YAMATO 		}
1911bc95f783SColomban Wendling 	} while ( isType(token, TOKEN_COMMA) ||
1912bc95f783SColomban Wendling 	          ( is_es6_class && ! isType(token, TOKEN_EOF) ) );
19133ae02089SMasatake YAMATO 
1914c93e1170SMasatake YAMATO 	TRACE_PRINT("Finished parsing methods");
191585bb93f2SSzymon Tomasz Stefanek 
1916ce990805SThomas Braun 	findCmdTerm (token, false, false);
19173ae02089SMasatake YAMATO 
19183ae02089SMasatake YAMATO cleanUp:
19194fd7a374SColomban Wendling 	vStringCopy (token->scope, saveScope);
19204fd7a374SColomban Wendling 	vStringDelete (saveScope);
19213ae02089SMasatake YAMATO 	deleteToken (name);
19223ae02089SMasatake YAMATO 
192301b28274SMasatake YAMATO 	TRACE_LEAVE_TEXT("found method(s): %s", has_methods? "yes": "no");
192485bb93f2SSzymon Tomasz Stefanek 
19253ae02089SMasatake YAMATO 	return has_methods;
19263ae02089SMasatake YAMATO }
19273ae02089SMasatake YAMATO 
parseES6Class(tokenInfo * const token,const tokenInfo * targetName)19284fd7a374SColomban Wendling static bool parseES6Class (tokenInfo *const token, const tokenInfo *targetName)
1929d543a241SColomban Wendling {
1930c93e1170SMasatake YAMATO 	TRACE_ENTER();
1931d543a241SColomban Wendling 
1932d543a241SColomban Wendling 	tokenInfo * className = newToken ();
1933a53a76deSColomban Wendling 	vString *inheritance = NULL;
1934d543a241SColomban Wendling 	bool is_anonymous = true;
1935d543a241SColomban Wendling 
1936e81a1060SColomban Wendling 	copyToken (className, token, true);
1937d543a241SColomban Wendling 	readToken (className);
1938e81a1060SColomban Wendling 
1939d543a241SColomban Wendling 	/* optional name */
1940d543a241SColomban Wendling 	if (isType (className, TOKEN_IDENTIFIER))
1941d543a241SColomban Wendling 	{
1942d543a241SColomban Wendling 		readToken (token);
1943d543a241SColomban Wendling 		is_anonymous = false;
1944d543a241SColomban Wendling 	}
1945d543a241SColomban Wendling 	else
1946d543a241SColomban Wendling 	{
1947d543a241SColomban Wendling 		copyToken (token, className, true);
1948d543a241SColomban Wendling 		/* We create a fake name so we have a scope for the members */
1949d543a241SColomban Wendling 		if (! targetName)
1950763d9df4SMasatake YAMATO 			anonGenerate (className->string, "AnonymousClass", JSTAG_CLASS);
1951d543a241SColomban Wendling 	}
1952d543a241SColomban Wendling 
1953d543a241SColomban Wendling 	if (! targetName)
1954d543a241SColomban Wendling 		targetName = className;
1955d543a241SColomban Wendling 
1956d543a241SColomban Wendling 	if (isKeyword (token, KEYWORD_extends))
1957a53a76deSColomban Wendling 		inheritance = vStringNew ();
1958d543a241SColomban Wendling 
1959a53a76deSColomban Wendling 	/* skip inheritance info */
1960a53a76deSColomban Wendling 	while (! isType (token, TOKEN_OPEN_CURLY) &&
1961a53a76deSColomban Wendling 	       ! isType (token, TOKEN_EOF) &&
1962a53a76deSColomban Wendling 	       ! isType (token, TOKEN_SEMICOLON))
1963a53a76deSColomban Wendling 		readTokenFull (token, false, inheritance);
1964d543a241SColomban Wendling 
1965a53a76deSColomban Wendling 	/* remove the last added token (here we assume it's one char, "{" or ";" */
1966a53a76deSColomban Wendling 	if (inheritance && vStringLength (inheritance) > 0 &&
1967a53a76deSColomban Wendling 	    ! isType (token, TOKEN_EOF))
1968a53a76deSColomban Wendling 	{
1969a53a76deSColomban Wendling 		vStringChop (inheritance);
1970a53a76deSColomban Wendling 		vStringStripTrailing (inheritance);
1971a53a76deSColomban Wendling 		vStringStripLeading (inheritance);
1972a53a76deSColomban Wendling 	}
1973d543a241SColomban Wendling 
1974c93e1170SMasatake YAMATO 	TRACE_PRINT("Emitting tag for class '%s'", vStringValue(targetName->string));
1975d543a241SColomban Wendling 
19760e4c5d4aSMasatake YAMATO 	makeJsTagCommon (targetName, JSTAG_CLASS, NULL, inheritance,
19770e4c5d4aSMasatake YAMATO 					 (is_anonymous && (targetName == className)));
1978d543a241SColomban Wendling 
1979d543a241SColomban Wendling 	if (! is_anonymous && targetName != className)
1980d543a241SColomban Wendling 	{
1981d543a241SColomban Wendling 		/* FIXME: what to do with the secondary name?  It's local to the
1982d543a241SColomban Wendling 		 *        class itself, so not very useful... let's hope people
1983d543a241SColomban Wendling 		 *        don't give it another name than the target in case of
1984d543a241SColomban Wendling 		 *        	var MyClass = class MyClassSecondaryName { ... }
1985d543a241SColomban Wendling 		 *        I guess it could be an alias to MyClass, or duplicate it
1986d543a241SColomban Wendling 		 *        altogether, not sure. */
1987a53a76deSColomban Wendling 		makeJsTag (className, JSTAG_CLASS, NULL, inheritance);
1988d543a241SColomban Wendling 	}
1989d543a241SColomban Wendling 
1990a53a76deSColomban Wendling 	if (inheritance)
1991a53a76deSColomban Wendling 		vStringDelete (inheritance);
1992d543a241SColomban Wendling 
1993d543a241SColomban Wendling 	if (isType (token, TOKEN_OPEN_CURLY))
1994f05a7612SColomban Wendling 		parseMethods (token, targetName, true);
1995d543a241SColomban Wendling 
1996d543a241SColomban Wendling 	deleteToken (className);
1997d543a241SColomban Wendling 
1998c93e1170SMasatake YAMATO 	TRACE_LEAVE();
1999f05a7612SColomban Wendling 	return true;
2000d543a241SColomban Wendling }
2001d543a241SColomban Wendling 
parseStatement(tokenInfo * const token,bool is_inside_class)20024fd7a374SColomban Wendling static bool parseStatement (tokenInfo *const token, bool is_inside_class)
20033ae02089SMasatake YAMATO {
200401b28274SMasatake YAMATO 	TRACE_ENTER_TEXT("is_inside_class: %s", is_inside_class? "yes": "no");
200585bb93f2SSzymon Tomasz Stefanek 
20063ae02089SMasatake YAMATO 	tokenInfo *const name = newToken ();
20073ae02089SMasatake YAMATO 	tokenInfo *const secondary_name = newToken ();
20083ae02089SMasatake YAMATO 	tokenInfo *const method_body_token = newToken ();
20093ae02089SMasatake YAMATO 	vString * saveScope = vStringNew ();
2010ce990805SThomas Braun 	bool is_class = false;
2011ce990805SThomas Braun 	bool is_var = false;
2012ce990805SThomas Braun 	bool is_const = false;
2013ce990805SThomas Braun 	bool is_terminated = true;
2014ce990805SThomas Braun 	bool is_global = false;
2015ce990805SThomas Braun 	bool has_methods = false;
20163ae02089SMasatake YAMATO 	vString *	fulltag;
20173ae02089SMasatake YAMATO 
20184fd7a374SColomban Wendling 	vStringCopy (saveScope, token->scope);
20193ae02089SMasatake YAMATO 	/*
20203ae02089SMasatake YAMATO 	 * Functions can be named or unnamed.
20213ae02089SMasatake YAMATO 	 * This deals with these formats:
20223ae02089SMasatake YAMATO 	 * Function
20233ae02089SMasatake YAMATO 	 *	   validFunctionOne = function(a,b) {}
20243ae02089SMasatake YAMATO 	 *	   testlib.validFunctionFive = function(a,b) {}
20253ae02089SMasatake YAMATO 	 *	   var innerThree = function(a,b) {}
20263ae02089SMasatake YAMATO 	 *	   var innerFour = (a,b) {}
20273ae02089SMasatake YAMATO 	 *	   var D2 = secondary_fcn_name(a,b) {}
20283ae02089SMasatake YAMATO 	 *	   var D3 = new Function("a", "b", "return a+b;");
20293ae02089SMasatake YAMATO 	 * Class
20303ae02089SMasatake YAMATO 	 *	   testlib.extras.ValidClassOne = function(a,b) {
20313ae02089SMasatake YAMATO 	 *		   this.a = a;
20323ae02089SMasatake YAMATO 	 *	   }
20333ae02089SMasatake YAMATO 	 * Class Methods
20343ae02089SMasatake YAMATO 	 *	   testlib.extras.ValidClassOne.prototype = {
20353ae02089SMasatake YAMATO 	 *		   'validMethodOne' : function(a,b) {},
20363ae02089SMasatake YAMATO 	 *		   'validMethodTwo' : function(a,b) {}
20373ae02089SMasatake YAMATO 	 *	   }
20383ae02089SMasatake YAMATO      *     ValidClassTwo = function ()
20393ae02089SMasatake YAMATO      *     {
20403ae02089SMasatake YAMATO      *         this.validMethodThree = function() {}
20413ae02089SMasatake YAMATO      *         // unnamed method
20423ae02089SMasatake YAMATO      *         this.validMethodFour = () {}
20433ae02089SMasatake YAMATO      *     }
20443ae02089SMasatake YAMATO 	 *	   Database.prototype.validMethodThree = Database_getTodaysDate;
20453ae02089SMasatake YAMATO 	 */
20463ae02089SMasatake YAMATO 
20473ae02089SMasatake YAMATO 	if ( is_inside_class )
2048ce990805SThomas Braun 		is_class = true;
20493ae02089SMasatake YAMATO 	/*
205046204f78SBen Wiederhake 	 * var can precede an inner function
20513ae02089SMasatake YAMATO 	 */
20523ae02089SMasatake YAMATO 	if ( isKeyword(token, KEYWORD_var) ||
20533ae02089SMasatake YAMATO 		 isKeyword(token, KEYWORD_let) ||
20543ae02089SMasatake YAMATO 		 isKeyword(token, KEYWORD_const) )
20553ae02089SMasatake YAMATO 	{
2056c93e1170SMasatake YAMATO 		TRACE_PRINT("var/let/const case");
20573ae02089SMasatake YAMATO 		is_const = isKeyword(token, KEYWORD_const);
20583ae02089SMasatake YAMATO 		/*
20593ae02089SMasatake YAMATO 		 * Only create variables for global scope
20603ae02089SMasatake YAMATO 		 */
20613ae02089SMasatake YAMATO 		if ( token->nestLevel == 0 )
20623ae02089SMasatake YAMATO 		{
2063ce990805SThomas Braun 			is_global = true;
20643ae02089SMasatake YAMATO 		}
20653ae02089SMasatake YAMATO 		readToken(token);
20663ae02089SMasatake YAMATO 	}
20673ae02089SMasatake YAMATO 
20684aa0017cSColomban Wendling nextVar:
20693ae02089SMasatake YAMATO 	if ( isKeyword(token, KEYWORD_this) )
20703ae02089SMasatake YAMATO 	{
2071c93e1170SMasatake YAMATO 		TRACE_PRINT("found 'this' keyword");
207285bb93f2SSzymon Tomasz Stefanek 
20733ae02089SMasatake YAMATO 		readToken(token);
20743ae02089SMasatake YAMATO 		if (isType (token, TOKEN_PERIOD))
20753ae02089SMasatake YAMATO 		{
20763ae02089SMasatake YAMATO 			readToken(token);
20773ae02089SMasatake YAMATO 		}
20783ae02089SMasatake YAMATO 	}
20793ae02089SMasatake YAMATO 
2080ce990805SThomas Braun 	copyToken(name, token, true);
20810b62aad1SMasatake YAMATO 	TRACE_PRINT("name becomes '%s' of type %s",
20820b62aad1SMasatake YAMATO 				vStringValue(token->string), tokenTypeName (token->type));
20833ae02089SMasatake YAMATO 
20843ae02089SMasatake YAMATO 	while (! isType (token, TOKEN_CLOSE_CURLY) &&
20853ae02089SMasatake YAMATO 	       ! isType (token, TOKEN_SEMICOLON)   &&
20863ae02089SMasatake YAMATO 	       ! isType (token, TOKEN_EQUAL_SIGN)  &&
20874aa0017cSColomban Wendling 	       ! isType (token, TOKEN_COMMA)       &&
20883ae02089SMasatake YAMATO 	       ! isType (token, TOKEN_EOF))
20893ae02089SMasatake YAMATO 	{
20903ae02089SMasatake YAMATO 		if (isType (token, TOKEN_OPEN_CURLY))
20914fd7a374SColomban Wendling 			parseBlock (token, NULL);
20923ae02089SMasatake YAMATO 
20933ae02089SMasatake YAMATO 		/* Potentially the name of the function */
20943ae02089SMasatake YAMATO 		if (isType (token, TOKEN_PERIOD))
20953ae02089SMasatake YAMATO 		{
20963ae02089SMasatake YAMATO 			/*
20973ae02089SMasatake YAMATO 			 * Cannot be a global variable is it has dot references in the name
20983ae02089SMasatake YAMATO 			 */
2099ce990805SThomas Braun 			is_global = false;
21004fd7a374SColomban Wendling 			/* Assume it's an assignment to a global name (e.g. a class) using
21014fd7a374SColomban Wendling 			 * its fully qualified name, so strip the scope.
21024fd7a374SColomban Wendling 			 * FIXME: resolve the scope so we can make more than an assumption. */
21034fd7a374SColomban Wendling 			vStringClear (token->scope);
21044fd7a374SColomban Wendling 			vStringClear (name->scope);
21053ae02089SMasatake YAMATO 			do
21063ae02089SMasatake YAMATO 			{
21073ae02089SMasatake YAMATO 				readToken (token);
210851d7d471SColomban Wendling 				if (! isType(token, TOKEN_KEYWORD))
21093ae02089SMasatake YAMATO 				{
21103ae02089SMasatake YAMATO 					if ( is_class )
21113ae02089SMasatake YAMATO 					{
21123ae02089SMasatake YAMATO 						addToScope(token, name->string);
21133ae02089SMasatake YAMATO 					}
21143ae02089SMasatake YAMATO 					else
21153ae02089SMasatake YAMATO 						addContext (name, token);
21163ae02089SMasatake YAMATO 
21173ae02089SMasatake YAMATO 					readToken (token);
21183ae02089SMasatake YAMATO 				}
21193ae02089SMasatake YAMATO 				else if ( isKeyword(token, KEYWORD_prototype) )
21203ae02089SMasatake YAMATO 				{
21213ae02089SMasatake YAMATO 					/*
21223ae02089SMasatake YAMATO 					 * When we reach the "prototype" tag, we infer:
21233ae02089SMasatake YAMATO 					 *     "BindAgent" is a class
21243ae02089SMasatake YAMATO 					 *     "build"     is a method
21253ae02089SMasatake YAMATO 					 *
21263ae02089SMasatake YAMATO 					 * function BindAgent( repeatableIdName, newParentIdName ) {
21273ae02089SMasatake YAMATO 					 * }
21283ae02089SMasatake YAMATO 					 *
21293ae02089SMasatake YAMATO 					 * CASE 1
21303ae02089SMasatake YAMATO 					 * Specified function name: "build"
21313ae02089SMasatake YAMATO 					 *     BindAgent.prototype.build = function( mode ) {
21323ae02089SMasatake YAMATO 					 *     	  maybe parse nested functions
21333ae02089SMasatake YAMATO 					 *     }
21343ae02089SMasatake YAMATO 					 *
21353ae02089SMasatake YAMATO 					 * CASE 2
21363ae02089SMasatake YAMATO 					 * Prototype listing
21373ae02089SMasatake YAMATO 					 *     ValidClassOne.prototype = {
21383ae02089SMasatake YAMATO 					 *         'validMethodOne' : function(a,b) {},
21393ae02089SMasatake YAMATO 					 *         'validMethodTwo' : function(a,b) {}
21403ae02089SMasatake YAMATO 					 *     }
21413ae02089SMasatake YAMATO 					 *
21423ae02089SMasatake YAMATO 					 */
2143d89d585aSMasatake YAMATO 					if (! ( isType (name, TOKEN_IDENTIFIER)
2144d89d585aSMasatake YAMATO 						|| isType (name, TOKEN_STRING) ) )
2145d89d585aSMasatake YAMATO 						/*
2146d89d585aSMasatake YAMATO 						 * Unexpected input. Try to reset the parsing.
2147d89d585aSMasatake YAMATO 						 *
2148d89d585aSMasatake YAMATO 						 * TOKEN_STRING is acceptable. e.g.:
2149d89d585aSMasatake YAMATO 						 * -----------------------------------
2150d89d585aSMasatake YAMATO 						 * "a".prototype = function( mode ) {}
2151d89d585aSMasatake YAMATO 						 */
2152d89d585aSMasatake YAMATO 						goto cleanUp;
2153d89d585aSMasatake YAMATO 
2154a53a76deSColomban Wendling 					makeClassTag (name, NULL, NULL);
2155ce990805SThomas Braun 					is_class = true;
21563ae02089SMasatake YAMATO 
21573ae02089SMasatake YAMATO 					/*
21583ae02089SMasatake YAMATO 					 * There should a ".function_name" next.
21593ae02089SMasatake YAMATO 					 */
21603ae02089SMasatake YAMATO 					readToken (token);
21613ae02089SMasatake YAMATO 					if (isType (token, TOKEN_PERIOD))
21623ae02089SMasatake YAMATO 					{
21633ae02089SMasatake YAMATO 						/*
21643ae02089SMasatake YAMATO 						 * Handle CASE 1
21653ae02089SMasatake YAMATO 						 */
21663ae02089SMasatake YAMATO 						readToken (token);
216751d7d471SColomban Wendling 						if (! isType(token, TOKEN_KEYWORD))
21683ae02089SMasatake YAMATO 						{
21693ae02089SMasatake YAMATO 							vString *const signature = vStringNew ();
21703ae02089SMasatake YAMATO 
21713ae02089SMasatake YAMATO 							addToScope(token, name->string);
21723ae02089SMasatake YAMATO 
21734fd7a374SColomban Wendling 							copyToken (method_body_token, token, true);
21743ae02089SMasatake YAMATO 							readToken (method_body_token);
21753ae02089SMasatake YAMATO 
21763ae02089SMasatake YAMATO 							while (! isType (method_body_token, TOKEN_SEMICOLON) &&
21773ae02089SMasatake YAMATO 							       ! isType (method_body_token, TOKEN_CLOSE_CURLY) &&
21783ae02089SMasatake YAMATO 							       ! isType (method_body_token, TOKEN_OPEN_CURLY) &&
21793ae02089SMasatake YAMATO 							       ! isType (method_body_token, TOKEN_EOF))
21803ae02089SMasatake YAMATO 							{
21813ae02089SMasatake YAMATO 								if ( isType (method_body_token, TOKEN_OPEN_PAREN) )
2182ce990805SThomas Braun 									skipArgumentList(method_body_token, false,
21833ae02089SMasatake YAMATO 													 vStringLength (signature) == 0 ? signature : NULL);
21843ae02089SMasatake YAMATO 								else
21853ae02089SMasatake YAMATO 									readToken (method_body_token);
21863ae02089SMasatake YAMATO 							}
21873ae02089SMasatake YAMATO 
2188a53a76deSColomban Wendling 							makeJsTag (token, JSTAG_METHOD, signature, NULL);
21893ae02089SMasatake YAMATO 							vStringDelete (signature);
21903ae02089SMasatake YAMATO 
21913ae02089SMasatake YAMATO 							if ( isType (method_body_token, TOKEN_OPEN_CURLY))
21923ae02089SMasatake YAMATO 							{
21934fd7a374SColomban Wendling 								parseBlock (method_body_token, token->string);
2194ce990805SThomas Braun 								is_terminated = true;
21953ae02089SMasatake YAMATO 							}
21963ae02089SMasatake YAMATO 							else
21973ae02089SMasatake YAMATO 								is_terminated = isType (method_body_token, TOKEN_SEMICOLON);
21983ae02089SMasatake YAMATO 							goto cleanUp;
21993ae02089SMasatake YAMATO 						}
22003ae02089SMasatake YAMATO 					}
22013ae02089SMasatake YAMATO 					else if (isType (token, TOKEN_EQUAL_SIGN))
22023ae02089SMasatake YAMATO 					{
22033ae02089SMasatake YAMATO 						readToken (token);
22043ae02089SMasatake YAMATO 						if (isType (token, TOKEN_OPEN_CURLY))
22053ae02089SMasatake YAMATO 						{
22063ae02089SMasatake YAMATO 							/*
22073ae02089SMasatake YAMATO 							 * Handle CASE 2
22083ae02089SMasatake YAMATO 							 *
22093ae02089SMasatake YAMATO 							 * Creates tags for each of these class methods
22103ae02089SMasatake YAMATO 							 *     ValidClassOne.prototype = {
22113ae02089SMasatake YAMATO 							 *         'validMethodOne' : function(a,b) {},
22123ae02089SMasatake YAMATO 							 *         'validMethodTwo' : function(a,b) {}
22133ae02089SMasatake YAMATO 							 *     }
22143ae02089SMasatake YAMATO 							 */
2215bc95f783SColomban Wendling 							parseMethods(token, name, false);
22163ae02089SMasatake YAMATO 							/*
22173ae02089SMasatake YAMATO 							 * Find to the end of the statement
22183ae02089SMasatake YAMATO 							 */
2219ce990805SThomas Braun 							findCmdTerm (token, false, false);
2220ce990805SThomas Braun 							is_terminated = true;
22213ae02089SMasatake YAMATO 							goto cleanUp;
22223ae02089SMasatake YAMATO 						}
22233ae02089SMasatake YAMATO 					}
22243ae02089SMasatake YAMATO 				}
22253ae02089SMasatake YAMATO 				else
22263ae02089SMasatake YAMATO 					readToken (token);
22273ae02089SMasatake YAMATO 			} while (isType (token, TOKEN_PERIOD));
22283ae02089SMasatake YAMATO 		}
222993ae3e8bSColomban Wendling 		else
2230e0a4381fSColomban Wendling 			readTokenFull (token, true, NULL);
22313ae02089SMasatake YAMATO 
22323ae02089SMasatake YAMATO 		if ( isType (token, TOKEN_OPEN_PAREN) )
2233ce990805SThomas Braun 			skipArgumentList(token, false, NULL);
22343ae02089SMasatake YAMATO 
22353ae02089SMasatake YAMATO 		if ( isType (token, TOKEN_OPEN_SQUARE) )
2236ce990805SThomas Braun 			skipArrayList(token, false);
22373ae02089SMasatake YAMATO 
22383ae02089SMasatake YAMATO 		/*
22393ae02089SMasatake YAMATO 		if ( isType (token, TOKEN_OPEN_CURLY) )
22403ae02089SMasatake YAMATO 		{
22414fd7a374SColomban Wendling 			is_class = parseBlock (token, name->string);
22423ae02089SMasatake YAMATO 		}
22433ae02089SMasatake YAMATO 		*/
22443ae02089SMasatake YAMATO 	}
22453ae02089SMasatake YAMATO 
22463ae02089SMasatake YAMATO 	if ( isType (token, TOKEN_CLOSE_CURLY) )
22473ae02089SMasatake YAMATO 	{
22483ae02089SMasatake YAMATO 		/*
22493ae02089SMasatake YAMATO 		 * Reaching this section without having
22503ae02089SMasatake YAMATO 		 * processed an open curly brace indicates
22513ae02089SMasatake YAMATO 		 * the statement is most likely not terminated.
22523ae02089SMasatake YAMATO 		 */
2253ce990805SThomas Braun 		is_terminated = false;
22543ae02089SMasatake YAMATO 		goto cleanUp;
22553ae02089SMasatake YAMATO 	}
22563ae02089SMasatake YAMATO 
22574aa0017cSColomban Wendling 	if ( isType (token, TOKEN_SEMICOLON) ||
22583efb4044SColomban Wendling 	     isType (token, TOKEN_EOF) ||
22594aa0017cSColomban Wendling 	     isType (token, TOKEN_COMMA) )
22603ae02089SMasatake YAMATO 	{
22613ae02089SMasatake YAMATO 		/*
22623ae02089SMasatake YAMATO 		 * Only create variables for global scope
22633ae02089SMasatake YAMATO 		 */
22643ae02089SMasatake YAMATO 		if ( token->nestLevel == 0 && is_global )
22653ae02089SMasatake YAMATO 		{
22663ae02089SMasatake YAMATO 			/*
22673ae02089SMasatake YAMATO 			 * Handles this syntax:
22683ae02089SMasatake YAMATO 			 *	   var g_var2;
22693ae02089SMasatake YAMATO 			 */
2270a53a76deSColomban Wendling 			makeJsTag (name, is_const ? JSTAG_CONSTANT : JSTAG_VARIABLE, NULL, NULL);
22713ae02089SMasatake YAMATO 		}
22723ae02089SMasatake YAMATO 		/*
22733ae02089SMasatake YAMATO 		 * Statement has ended.
22743ae02089SMasatake YAMATO 		 * This deals with calls to functions, like:
22753ae02089SMasatake YAMATO 		 *     alert(..);
22763ae02089SMasatake YAMATO 		 */
22774aa0017cSColomban Wendling 		if (isType (token, TOKEN_COMMA))
22784aa0017cSColomban Wendling 		{
22794aa0017cSColomban Wendling 			readToken (token);
22804aa0017cSColomban Wendling 			goto nextVar;
22814aa0017cSColomban Wendling 		}
22823ae02089SMasatake YAMATO 		goto cleanUp;
22833ae02089SMasatake YAMATO 	}
22843ae02089SMasatake YAMATO 
22853ae02089SMasatake YAMATO 	if ( isType (token, TOKEN_EQUAL_SIGN) )
22863ae02089SMasatake YAMATO 	{
22873ae02089SMasatake YAMATO 		int parenDepth = 0;
22883ae02089SMasatake YAMATO 
22893ae02089SMasatake YAMATO 		readToken (token);
22903ae02089SMasatake YAMATO 
22913ae02089SMasatake YAMATO 		/* rvalue might be surrounded with parentheses */
22923ae02089SMasatake YAMATO 		while (isType (token, TOKEN_OPEN_PAREN))
22933ae02089SMasatake YAMATO 		{
22943ae02089SMasatake YAMATO 			parenDepth++;
22953ae02089SMasatake YAMATO 			readToken (token);
22963ae02089SMasatake YAMATO 		}
22973ae02089SMasatake YAMATO 
229841c2c77eSColomban Wendling 		if (isKeyword (token, KEYWORD_async))
229941c2c77eSColomban Wendling 			readToken (token);
230041c2c77eSColomban Wendling 
23013ae02089SMasatake YAMATO 		if ( isKeyword (token, KEYWORD_function) )
23023ae02089SMasatake YAMATO 		{
23033ae02089SMasatake YAMATO 			vString *const signature = vStringNew ();
2304d01b4a7cSColomban Wendling 			bool is_generator = false;
23053ae02089SMasatake YAMATO 
23063ae02089SMasatake YAMATO 			readToken (token);
2307d01b4a7cSColomban Wendling 			if (isType (token, TOKEN_STAR))
2308d01b4a7cSColomban Wendling 			{
2309d01b4a7cSColomban Wendling 				is_generator = true;
2310d01b4a7cSColomban Wendling 				readToken (token);
2311d01b4a7cSColomban Wendling 			}
23123ae02089SMasatake YAMATO 
231351d7d471SColomban Wendling 			if (! isType (token, TOKEN_KEYWORD) &&
23143ae02089SMasatake YAMATO 			    ! isType (token, TOKEN_OPEN_PAREN))
23153ae02089SMasatake YAMATO 			{
23163ae02089SMasatake YAMATO 				/*
23173ae02089SMasatake YAMATO 				 * Functions of this format:
23183ae02089SMasatake YAMATO 				 *	   var D2A = function theAdd(a, b)
23193ae02089SMasatake YAMATO 				 *	   {
23203ae02089SMasatake YAMATO 				 *		  return a+b;
23213ae02089SMasatake YAMATO 				 *	   }
23223ae02089SMasatake YAMATO 				 * Are really two separate defined functions and
23233ae02089SMasatake YAMATO 				 * can be referenced in two ways:
23243ae02089SMasatake YAMATO 				 *	   alert( D2A(1,2) );			  // produces 3
23253ae02089SMasatake YAMATO 				 *	   alert( theAdd(1,2) );		  // also produces 3
23263ae02089SMasatake YAMATO 				 * So it must have two tags:
23273ae02089SMasatake YAMATO 				 *	   D2A
23283ae02089SMasatake YAMATO 				 *	   theAdd
23293ae02089SMasatake YAMATO 				 * Save the reference to the name for later use, once
23303ae02089SMasatake YAMATO 				 * we have established this is a valid function we will
23313ae02089SMasatake YAMATO 				 * create the secondary reference to it.
23323ae02089SMasatake YAMATO 				 */
2333ce990805SThomas Braun 				copyToken(secondary_name, token, true);
23343ae02089SMasatake YAMATO 				readToken (token);
23353ae02089SMasatake YAMATO 			}
23363ae02089SMasatake YAMATO 
23373ae02089SMasatake YAMATO 			if ( isType (token, TOKEN_OPEN_PAREN) )
2338ce990805SThomas Braun 				skipArgumentList(token, false, signature);
23393ae02089SMasatake YAMATO 
23403ae02089SMasatake YAMATO 			if (isType (token, TOKEN_OPEN_CURLY))
23413ae02089SMasatake YAMATO 			{
23423ae02089SMasatake YAMATO 				/*
23433ae02089SMasatake YAMATO 				 * This will be either a function or a class.
23443ae02089SMasatake YAMATO 				 * We can only determine this by checking the body
23453ae02089SMasatake YAMATO 				 * of the function.  If we find a "this." we know
23463ae02089SMasatake YAMATO 				 * it is a class, otherwise it is a function.
23473ae02089SMasatake YAMATO 				 */
23483ae02089SMasatake YAMATO 				if ( is_inside_class )
23493ae02089SMasatake YAMATO 				{
2350a53a76deSColomban Wendling 					makeJsTag (name, is_generator ? JSTAG_GENERATOR : JSTAG_METHOD, signature, NULL);
23513ae02089SMasatake YAMATO 					if ( vStringLength(secondary_name->string) > 0 )
2352d01b4a7cSColomban Wendling 						makeFunctionTag (secondary_name, signature, is_generator);
23533ae02089SMasatake YAMATO 				}
23543ae02089SMasatake YAMATO 				else
23553ae02089SMasatake YAMATO 				{
23566df0e0f0SMasatake YAMATO 					if (! ( isType (name, TOKEN_IDENTIFIER)
235788ec5491SSzymon Tomasz Stefanek 					     || isType (name, TOKEN_STRING)
235888ec5491SSzymon Tomasz Stefanek 					     || isType (name, TOKEN_KEYWORD) ) )
23596df0e0f0SMasatake YAMATO 					{
23606df0e0f0SMasatake YAMATO 						/* Unexpected input. Try to reset the parsing. */
2361c93e1170SMasatake YAMATO 						TRACE_PRINT("Unexpected input, trying to reset");
23626df0e0f0SMasatake YAMATO 						vStringDelete (signature);
23636df0e0f0SMasatake YAMATO 						goto cleanUp;
23646df0e0f0SMasatake YAMATO 					}
23656df0e0f0SMasatake YAMATO 
23664fd7a374SColomban Wendling 					is_class = parseBlock (token, name->string);
23673ae02089SMasatake YAMATO 					if ( is_class )
2368a53a76deSColomban Wendling 						makeClassTag (name, signature, NULL);
23693ae02089SMasatake YAMATO 					else
2370d01b4a7cSColomban Wendling 						makeFunctionTag (name, signature, is_generator);
23713ae02089SMasatake YAMATO 
23723ae02089SMasatake YAMATO 					if ( vStringLength(secondary_name->string) > 0 )
2373d01b4a7cSColomban Wendling 						makeFunctionTag (secondary_name, signature, is_generator);
23743ae02089SMasatake YAMATO 				}
2375c77a1b9eSJohn Lindal 				parseBlock (token, name->string);
23763ae02089SMasatake YAMATO 			}
23773ae02089SMasatake YAMATO 
23783ae02089SMasatake YAMATO 			vStringDelete (signature);
23793ae02089SMasatake YAMATO 		}
2380d543a241SColomban Wendling 		else if (isKeyword (token, KEYWORD_class))
2381d543a241SColomban Wendling 		{
23824fd7a374SColomban Wendling 			is_terminated = parseES6Class (token, name);
2383d543a241SColomban Wendling 		}
23843ae02089SMasatake YAMATO 		else if (isType (token, TOKEN_OPEN_CURLY))
23853ae02089SMasatake YAMATO 		{
23863ae02089SMasatake YAMATO 			/*
23873ae02089SMasatake YAMATO 			 * Creates tags for each of these class methods
23883ae02089SMasatake YAMATO 			 *     ValidClassOne.prototype = {
23893ae02089SMasatake YAMATO 			 *         'validMethodOne' : function(a,b) {},
23903ae02089SMasatake YAMATO 			 *         'validMethodTwo' : function(a,b) {}
23913ae02089SMasatake YAMATO 			 *     }
23923ae02089SMasatake YAMATO 			 * Or checks if this is a hash variable.
23933ae02089SMasatake YAMATO 			 *     var z = {};
23943ae02089SMasatake YAMATO 			 */
23956349e217SMasatake YAMATO 			bool anonClass = vStringIsEmpty (name->string);
23966349e217SMasatake YAMATO 			if (anonClass)
23976349e217SMasatake YAMATO 				anonGenerate (name->string, "AnonymousClass", JSTAG_CLASS);
2398bc95f783SColomban Wendling 			has_methods = parseMethods(token, name, false);
23993ae02089SMasatake YAMATO 			if (has_methods)
24006349e217SMasatake YAMATO 				makeJsTagCommon (name, JSTAG_CLASS, NULL, NULL, anonClass);
24013ae02089SMasatake YAMATO 			else
24023ae02089SMasatake YAMATO 			{
24033ae02089SMasatake YAMATO 				/*
24043ae02089SMasatake YAMATO 				 * Only create variables for global scope
24053ae02089SMasatake YAMATO 				 */
24063ae02089SMasatake YAMATO 				if ( token->nestLevel == 0 && is_global )
24073ae02089SMasatake YAMATO 				{
24083ae02089SMasatake YAMATO 					/*
24093ae02089SMasatake YAMATO 					 * A pointer can be created to the function.
24103ae02089SMasatake YAMATO 					 * If we recognize the function/class name ignore the variable.
24113ae02089SMasatake YAMATO 					 * This format looks identical to a variable definition.
24123ae02089SMasatake YAMATO 					 * A variable defined outside of a block is considered
24133ae02089SMasatake YAMATO 					 * a global variable:
24143ae02089SMasatake YAMATO 					 *	   var g_var1 = 1;
24153ae02089SMasatake YAMATO 					 *	   var g_var2;
24163ae02089SMasatake YAMATO 					 * This is not a global variable:
24173ae02089SMasatake YAMATO 					 *	   var g_var = function;
24183ae02089SMasatake YAMATO 					 * This is a global variable:
24193ae02089SMasatake YAMATO 					 *	   var g_var = different_var_name;
24203ae02089SMasatake YAMATO 					 */
24213ae02089SMasatake YAMATO 					fulltag = vStringNew ();
24223ae02089SMasatake YAMATO 					if (vStringLength (token->scope) > 0)
24233ae02089SMasatake YAMATO 					{
24243ae02089SMasatake YAMATO 						vStringCopy(fulltag, token->scope);
24251da6e7e4SMasatake YAMATO 						vStringPut (fulltag, '.');
24264e6bcb7bSColomban Wendling 						vStringCat (fulltag, token->string);
24273ae02089SMasatake YAMATO 					}
24283ae02089SMasatake YAMATO 					else
24293ae02089SMasatake YAMATO 					{
24303ae02089SMasatake YAMATO 						vStringCopy(fulltag, token->string);
24313ae02089SMasatake YAMATO 					}
24323ae02089SMasatake YAMATO 					if ( ! stringListHas(FunctionNames, vStringValue (fulltag)) &&
24333ae02089SMasatake YAMATO 							! stringListHas(ClassNames, vStringValue (fulltag)) )
24343ae02089SMasatake YAMATO 					{
2435a53a76deSColomban Wendling 						makeJsTag (name, is_const ? JSTAG_CONSTANT : JSTAG_VARIABLE, NULL, NULL);
24363ae02089SMasatake YAMATO 					}
24373ae02089SMasatake YAMATO 					vStringDelete (fulltag);
24383ae02089SMasatake YAMATO 				}
24393ae02089SMasatake YAMATO 			}
244034f6ef82SColomban Wendling 			/* Here we should be at the end of the block, on the close curly.
244134f6ef82SColomban Wendling 			 * If so, read the next token not to confuse that close curly with
244234f6ef82SColomban Wendling 			 * the end of the current statement. */
24433ae02089SMasatake YAMATO 			if (isType (token, TOKEN_CLOSE_CURLY))
24443ae02089SMasatake YAMATO 			{
244534f6ef82SColomban Wendling 				readTokenFull(token, true, NULL);
244634f6ef82SColomban Wendling 				is_terminated = isType (token, TOKEN_SEMICOLON);
24473ae02089SMasatake YAMATO 			}
24483ae02089SMasatake YAMATO 		}
24493ae02089SMasatake YAMATO 		else if (isKeyword (token, KEYWORD_new))
24503ae02089SMasatake YAMATO 		{
24513ae02089SMasatake YAMATO 			readToken (token);
24523ae02089SMasatake YAMATO 			is_var = isType (token, TOKEN_IDENTIFIER);
24533ae02089SMasatake YAMATO 			if ( isKeyword (token, KEYWORD_function) ||
24543ae02089SMasatake YAMATO 					isKeyword (token, KEYWORD_capital_function) ||
24553ae02089SMasatake YAMATO 					isKeyword (token, KEYWORD_capital_object) ||
24563ae02089SMasatake YAMATO 					is_var )
24573ae02089SMasatake YAMATO 			{
24583ae02089SMasatake YAMATO 				if ( isKeyword (token, KEYWORD_capital_object) )
2459ce990805SThomas Braun 					is_class = true;
24603ae02089SMasatake YAMATO 
2461d1a0367eSMasatake YAMATO 				if (is_var)
2462d1a0367eSMasatake YAMATO 					skipQualifiedIdentifier (token);
2463d1a0367eSMasatake YAMATO 				else
24643ae02089SMasatake YAMATO 					readToken (token);
2465d1a0367eSMasatake YAMATO 
24663ae02089SMasatake YAMATO 				if ( isType (token, TOKEN_OPEN_PAREN) )
2467ce990805SThomas Braun 					skipArgumentList(token, true, NULL);
24683ae02089SMasatake YAMATO 
24693ae02089SMasatake YAMATO 				if (isType (token, TOKEN_SEMICOLON))
24703ae02089SMasatake YAMATO 				{
24713ae02089SMasatake YAMATO 					if ( token->nestLevel == 0 )
24723ae02089SMasatake YAMATO 					{
24733ae02089SMasatake YAMATO 						if ( is_var )
24743ae02089SMasatake YAMATO 						{
2475a53a76deSColomban Wendling 							makeJsTag (name, is_const ? JSTAG_CONSTANT : JSTAG_VARIABLE, NULL, NULL);
24763ae02089SMasatake YAMATO 						}
2477b2dc11a1SMasatake YAMATO 						else if ( is_class )
24783ae02089SMasatake YAMATO 						{
2479a53a76deSColomban Wendling 							makeClassTag (name, NULL, NULL);
2480b2dc11a1SMasatake YAMATO 						}
2481b2dc11a1SMasatake YAMATO 						else
2482b2dc11a1SMasatake YAMATO 						{
24833ae02089SMasatake YAMATO 							/* FIXME: we cannot really get a meaningful
24843ae02089SMasatake YAMATO 							 * signature from a `new Function()` call,
24853ae02089SMasatake YAMATO 							 * so for now just don't set any */
2486d01b4a7cSColomban Wendling 							makeFunctionTag (name, NULL, false);
24873ae02089SMasatake YAMATO 						}
24883ae02089SMasatake YAMATO 					}
24893ae02089SMasatake YAMATO 				}
24903ae02089SMasatake YAMATO 				else if (isType (token, TOKEN_CLOSE_CURLY))
2491ce990805SThomas Braun 					is_terminated = false;
24923ae02089SMasatake YAMATO 			}
24933ae02089SMasatake YAMATO 		}
249451d7d471SColomban Wendling 		else if (! isType (token, TOKEN_KEYWORD))
24953ae02089SMasatake YAMATO 		{
24963ae02089SMasatake YAMATO 			/*
24973ae02089SMasatake YAMATO 			 * Only create variables for global scope
24983ae02089SMasatake YAMATO 			 */
24993ae02089SMasatake YAMATO 			if ( token->nestLevel == 0 && is_global )
25003ae02089SMasatake YAMATO 			{
25013ae02089SMasatake YAMATO 				/*
25023ae02089SMasatake YAMATO 				 * A pointer can be created to the function.
25033ae02089SMasatake YAMATO 				 * If we recognize the function/class name ignore the variable.
25043ae02089SMasatake YAMATO 				 * This format looks identical to a variable definition.
25053ae02089SMasatake YAMATO 				 * A variable defined outside of a block is considered
25063ae02089SMasatake YAMATO 				 * a global variable:
25073ae02089SMasatake YAMATO 				 *	   var g_var1 = 1;
25083ae02089SMasatake YAMATO 				 *	   var g_var2;
25093ae02089SMasatake YAMATO 				 * This is not a global variable:
25103ae02089SMasatake YAMATO 				 *	   var g_var = function;
25113ae02089SMasatake YAMATO 				 * This is a global variable:
25123ae02089SMasatake YAMATO 				 *	   var g_var = different_var_name;
25133ae02089SMasatake YAMATO 				 */
25143ae02089SMasatake YAMATO 				fulltag = vStringNew ();
25153ae02089SMasatake YAMATO 				if (vStringLength (token->scope) > 0)
25163ae02089SMasatake YAMATO 				{
25173ae02089SMasatake YAMATO 					vStringCopy(fulltag, token->scope);
25181da6e7e4SMasatake YAMATO 					vStringPut (fulltag, '.');
25194e6bcb7bSColomban Wendling 					vStringCat (fulltag, token->string);
25203ae02089SMasatake YAMATO 				}
25213ae02089SMasatake YAMATO 				else
25223ae02089SMasatake YAMATO 				{
25233ae02089SMasatake YAMATO 					vStringCopy(fulltag, token->string);
25243ae02089SMasatake YAMATO 				}
25253ae02089SMasatake YAMATO 				if ( ! stringListHas(FunctionNames, vStringValue (fulltag)) &&
25263ae02089SMasatake YAMATO 						! stringListHas(ClassNames, vStringValue (fulltag)) )
25273ae02089SMasatake YAMATO 				{
2528a53a76deSColomban Wendling 					makeJsTag (name, is_const ? JSTAG_CONSTANT : JSTAG_VARIABLE, NULL, NULL);
25293ae02089SMasatake YAMATO 				}
25303ae02089SMasatake YAMATO 				vStringDelete (fulltag);
25313ae02089SMasatake YAMATO 			}
25323ae02089SMasatake YAMATO 		}
25333ae02089SMasatake YAMATO 
25343ae02089SMasatake YAMATO 		if (parenDepth > 0)
25353ae02089SMasatake YAMATO 		{
25363ae02089SMasatake YAMATO 			while (parenDepth > 0 && ! isType (token, TOKEN_EOF))
25373ae02089SMasatake YAMATO 			{
25383ae02089SMasatake YAMATO 				if (isType (token, TOKEN_OPEN_PAREN))
25393ae02089SMasatake YAMATO 					parenDepth++;
25403ae02089SMasatake YAMATO 				else if (isType (token, TOKEN_CLOSE_PAREN))
25413ae02089SMasatake YAMATO 					parenDepth--;
2542ce990805SThomas Braun 				readTokenFull (token, true, NULL);
25433ae02089SMasatake YAMATO 			}
25443ae02089SMasatake YAMATO 			if (isType (token, TOKEN_CLOSE_CURLY))
2545ce990805SThomas Braun 				is_terminated = false;
25463ae02089SMasatake YAMATO 		}
25473ae02089SMasatake YAMATO 	}
25483ae02089SMasatake YAMATO 	/* if we aren't already at the cmd end, advance to it and check whether
25493ae02089SMasatake YAMATO 	 * the statement was terminated */
25503ae02089SMasatake YAMATO 	if (! isType (token, TOKEN_CLOSE_CURLY) &&
25513ae02089SMasatake YAMATO 	    ! isType (token, TOKEN_SEMICOLON))
25523ae02089SMasatake YAMATO 	{
25533ae02089SMasatake YAMATO 		/*
25543ae02089SMasatake YAMATO 		 * Statements can be optionally terminated in the case of
25553ae02089SMasatake YAMATO 		 * statement prior to a close curly brace as in the
25563ae02089SMasatake YAMATO 		 * document.write line below:
25573ae02089SMasatake YAMATO 		 *
25583ae02089SMasatake YAMATO 		 * function checkForUpdate() {
25593ae02089SMasatake YAMATO 		 *	   if( 1==1 ) {
25603ae02089SMasatake YAMATO 		 *		   document.write("hello from checkForUpdate<br>")
25613ae02089SMasatake YAMATO 		 *	   }
25623ae02089SMasatake YAMATO 		 *	   return 1;
25633ae02089SMasatake YAMATO 		 * }
25643ae02089SMasatake YAMATO 		 */
2565ce990805SThomas Braun 		is_terminated = findCmdTerm (token, true, true);
25664aa0017cSColomban Wendling 		/* if we're at a comma, try and read a second var */
25674aa0017cSColomban Wendling 		if (isType (token, TOKEN_COMMA))
25684aa0017cSColomban Wendling 		{
25694aa0017cSColomban Wendling 			readToken (token);
25704aa0017cSColomban Wendling 			goto nextVar;
25714aa0017cSColomban Wendling 		}
25723ae02089SMasatake YAMATO 	}
25733ae02089SMasatake YAMATO 
25743ae02089SMasatake YAMATO cleanUp:
25753ae02089SMasatake YAMATO 	vStringCopy(token->scope, saveScope);
25763ae02089SMasatake YAMATO 	deleteToken (name);
25773ae02089SMasatake YAMATO 	deleteToken (secondary_name);
25783ae02089SMasatake YAMATO 	deleteToken (method_body_token);
25793ae02089SMasatake YAMATO 	vStringDelete(saveScope);
25803ae02089SMasatake YAMATO 
2581c93e1170SMasatake YAMATO 	TRACE_LEAVE();
258285bb93f2SSzymon Tomasz Stefanek 
25833ae02089SMasatake YAMATO 	return is_terminated;
25843ae02089SMasatake YAMATO }
25853ae02089SMasatake YAMATO 
parseUI5(tokenInfo * const token)25863ae02089SMasatake YAMATO static void parseUI5 (tokenInfo *const token)
25873ae02089SMasatake YAMATO {
25883ae02089SMasatake YAMATO 	tokenInfo *const name = newToken ();
25893ae02089SMasatake YAMATO 	/*
25903ae02089SMasatake YAMATO 	 * SAPUI5 is built on top of jQuery.
25913ae02089SMasatake YAMATO 	 * It follows a standard format:
25923ae02089SMasatake YAMATO 	 *     sap.ui.controller("id.of.controller", {
25933ae02089SMasatake YAMATO 	 *         method_name : function... {
25943ae02089SMasatake YAMATO 	 *         },
25953ae02089SMasatake YAMATO 	 *
25963ae02089SMasatake YAMATO 	 *         method_name : function ... {
25973ae02089SMasatake YAMATO 	 *         }
25983ae02089SMasatake YAMATO 	 *     }
25993ae02089SMasatake YAMATO 	 *
26003ae02089SMasatake YAMATO 	 * Handle the parsing of the initial controller (and the
26013ae02089SMasatake YAMATO 	 * same for "view") and then allow the methods to be
26023ae02089SMasatake YAMATO 	 * parsed as usual.
26033ae02089SMasatake YAMATO 	 */
26043ae02089SMasatake YAMATO 
26053ae02089SMasatake YAMATO 	readToken (token);
26063ae02089SMasatake YAMATO 
26073ae02089SMasatake YAMATO 	if (isType (token, TOKEN_PERIOD))
26083ae02089SMasatake YAMATO 	{
26093ae02089SMasatake YAMATO 		readToken (token);
26103ae02089SMasatake YAMATO 		while (! isType (token, TOKEN_OPEN_PAREN) &&
26113ae02089SMasatake YAMATO 			   ! isType (token, TOKEN_EOF))
26123ae02089SMasatake YAMATO 		{
26133ae02089SMasatake YAMATO 			readToken (token);
26143ae02089SMasatake YAMATO 		}
26153ae02089SMasatake YAMATO 		readToken (token);
26163ae02089SMasatake YAMATO 
26173ae02089SMasatake YAMATO 		if (isType (token, TOKEN_STRING))
26183ae02089SMasatake YAMATO 		{
2619ce990805SThomas Braun 			copyToken(name, token, true);
26203ae02089SMasatake YAMATO 			readToken (token);
26213ae02089SMasatake YAMATO 		}
26223ae02089SMasatake YAMATO 
26233ae02089SMasatake YAMATO 		if (isType (token, TOKEN_COMMA))
26243ae02089SMasatake YAMATO 			readToken (token);
26253ae02089SMasatake YAMATO 
26263ae02089SMasatake YAMATO 		do
26273ae02089SMasatake YAMATO 		{
2628bc95f783SColomban Wendling 			parseMethods (token, name, false);
26293ae02089SMasatake YAMATO 		} while (! isType (token, TOKEN_CLOSE_CURLY) &&
26303ae02089SMasatake YAMATO 				 ! isType (token, TOKEN_EOF));
26313ae02089SMasatake YAMATO 	}
26323ae02089SMasatake YAMATO 
26333ae02089SMasatake YAMATO 	deleteToken (name);
26343ae02089SMasatake YAMATO }
26353ae02089SMasatake YAMATO 
parseLine(tokenInfo * const token,bool is_inside_class)26364fd7a374SColomban Wendling static bool parseLine (tokenInfo *const token, bool is_inside_class)
26373ae02089SMasatake YAMATO {
26380b62aad1SMasatake YAMATO 	TRACE_ENTER_TEXT("token is '%s' of type %s",
26390b62aad1SMasatake YAMATO 					 vStringValue(token->string), tokenTypeName (token->type));
264085bb93f2SSzymon Tomasz Stefanek 
2641ce990805SThomas Braun 	bool is_terminated = true;
26423ae02089SMasatake YAMATO 	/*
26433ae02089SMasatake YAMATO 	 * Detect the common statements, if, while, for, do, ...
26443ae02089SMasatake YAMATO 	 * This is necessary since the last statement within a block "{}"
26453ae02089SMasatake YAMATO 	 * can be optionally terminated.
26463ae02089SMasatake YAMATO 	 *
26473ae02089SMasatake YAMATO 	 * If the statement is not terminated, we need to tell
26483ae02089SMasatake YAMATO 	 * the calling routine to prevent reading an additional token
26493ae02089SMasatake YAMATO 	 * looking for the end of the statement.
26503ae02089SMasatake YAMATO 	 */
26513ae02089SMasatake YAMATO 
26523ae02089SMasatake YAMATO 	if (isType(token, TOKEN_KEYWORD))
26533ae02089SMasatake YAMATO 	{
26543ae02089SMasatake YAMATO 		switch (token->keyword)
26553ae02089SMasatake YAMATO 		{
26563ae02089SMasatake YAMATO 			case KEYWORD_for:
26573ae02089SMasatake YAMATO 			case KEYWORD_while:
26583ae02089SMasatake YAMATO 			case KEYWORD_do:
26594fd7a374SColomban Wendling 				is_terminated = parseLoop (token);
26603ae02089SMasatake YAMATO 				break;
26613ae02089SMasatake YAMATO 			case KEYWORD_if:
26623ae02089SMasatake YAMATO 			case KEYWORD_else:
26633ae02089SMasatake YAMATO 			case KEYWORD_try:
26643ae02089SMasatake YAMATO 			case KEYWORD_catch:
26653ae02089SMasatake YAMATO 			case KEYWORD_finally:
26663ae02089SMasatake YAMATO 				/* Common semantics */
26674fd7a374SColomban Wendling 				is_terminated = parseIf (token);
26683ae02089SMasatake YAMATO 				break;
26693ae02089SMasatake YAMATO 			case KEYWORD_switch:
26703ae02089SMasatake YAMATO 				parseSwitch (token);
26713ae02089SMasatake YAMATO 				break;
26723ae02089SMasatake YAMATO 			case KEYWORD_return:
267341c2c77eSColomban Wendling 			case KEYWORD_async:
267467637d9eSColomban Wendling 				readToken (token);
26754fd7a374SColomban Wendling 				is_terminated = parseLine (token, is_inside_class);
26763ae02089SMasatake YAMATO 				break;
267711238959SColomban Wendling 			case KEYWORD_function:
267811238959SColomban Wendling 				parseFunction (token);
267911238959SColomban Wendling 				break;
268088ec5491SSzymon Tomasz Stefanek 			case KEYWORD_class:
26814fd7a374SColomban Wendling 				is_terminated = parseES6Class (token, NULL);
268288ec5491SSzymon Tomasz Stefanek 				break;
26833ae02089SMasatake YAMATO 			default:
26844fd7a374SColomban Wendling 				is_terminated = parseStatement (token, is_inside_class);
26853ae02089SMasatake YAMATO 				break;
26863ae02089SMasatake YAMATO 		}
26873ae02089SMasatake YAMATO 	}
26883ae02089SMasatake YAMATO 	else
26893ae02089SMasatake YAMATO 	{
26903ae02089SMasatake YAMATO 		/*
26913ae02089SMasatake YAMATO 		 * Special case where single line statements may not be
26923ae02089SMasatake YAMATO 		 * SEMICOLON terminated.  parseBlock needs to know this
26933ae02089SMasatake YAMATO 		 * so that it does not read the next token.
26943ae02089SMasatake YAMATO 		 */
26954fd7a374SColomban Wendling 		is_terminated = parseStatement (token, is_inside_class);
26963ae02089SMasatake YAMATO 	}
269785bb93f2SSzymon Tomasz Stefanek 
2698c93e1170SMasatake YAMATO 	TRACE_LEAVE();
269985bb93f2SSzymon Tomasz Stefanek 
27003ae02089SMasatake YAMATO 	return is_terminated;
27013ae02089SMasatake YAMATO }
27023ae02089SMasatake YAMATO 
parseJsFile(tokenInfo * const token)27033ae02089SMasatake YAMATO static void parseJsFile (tokenInfo *const token)
27043ae02089SMasatake YAMATO {
2705c93e1170SMasatake YAMATO 	TRACE_ENTER();
270685bb93f2SSzymon Tomasz Stefanek 
27073ae02089SMasatake YAMATO 	do
27083ae02089SMasatake YAMATO 	{
27093ae02089SMasatake YAMATO 		readToken (token);
27103ae02089SMasatake YAMATO 
271111238959SColomban Wendling 		if (isType (token, TOKEN_KEYWORD) && token->keyword == KEYWORD_sap)
27123ae02089SMasatake YAMATO 			parseUI5 (token);
27131917d23dSColomban Wendling 		else if (isType (token, TOKEN_KEYWORD) && (token->keyword == KEYWORD_export ||
27141917d23dSColomban Wendling 		                                           token->keyword == KEYWORD_default))
27151917d23dSColomban Wendling 			/* skip those at top-level */;
27163ae02089SMasatake YAMATO 		else
27174fd7a374SColomban Wendling 			parseLine (token, false);
27183ae02089SMasatake YAMATO 	} while (! isType (token, TOKEN_EOF));
271985bb93f2SSzymon Tomasz Stefanek 
2720c93e1170SMasatake YAMATO 	TRACE_LEAVE();
27213ae02089SMasatake YAMATO }
27223ae02089SMasatake YAMATO 
27230b62aad1SMasatake YAMATO #ifdef DO_TRACING
2724*6f5dd0b1SMasatake YAMATO #if DO_TRACING_USE_DUMP_TOKEN
dumpToken(const tokenInfo * const token)27250b62aad1SMasatake YAMATO static void dumpToken (const tokenInfo *const token)
27260b62aad1SMasatake YAMATO {
27270b62aad1SMasatake YAMATO 	fprintf(stderr, "Token <%p>: %s: %s\n",
27280b62aad1SMasatake YAMATO 			token,
27290b62aad1SMasatake YAMATO 			tokenTypeName (token->type),
27300b62aad1SMasatake YAMATO 			(token->type == TOKEN_KEYWORD   ? keywordName (token->keyword):
27310b62aad1SMasatake YAMATO 			 token->type == TOKEN_IDENTIFIER? vStringValue (token->string):
27320b62aad1SMasatake YAMATO 			 ""));
27330b62aad1SMasatake YAMATO }
27342cf5f15cSK.Takata #endif
27350b62aad1SMasatake YAMATO 
tokenTypeName(enum eTokenType e)27360b62aad1SMasatake YAMATO static const char *tokenTypeName(enum eTokenType e)
27370b62aad1SMasatake YAMATO { /* Generated by misc/enumstr.sh with cmdline "parsers/jscript.c" "eTokenType" "tokenTypeName" */
27380b62aad1SMasatake YAMATO 	switch (e)
27390b62aad1SMasatake YAMATO 	{
27400b62aad1SMasatake YAMATO 		case    TOKEN_BINARY_OPERATOR: return "TOKEN_BINARY_OPERATOR";
27410b62aad1SMasatake YAMATO 		case          TOKEN_CHARACTER: return "TOKEN_CHARACTER";
27420b62aad1SMasatake YAMATO 		case        TOKEN_CLOSE_CURLY: return "TOKEN_CLOSE_CURLY";
27430b62aad1SMasatake YAMATO 		case        TOKEN_CLOSE_PAREN: return "TOKEN_CLOSE_PAREN";
27440b62aad1SMasatake YAMATO 		case       TOKEN_CLOSE_SQUARE: return "TOKEN_CLOSE_SQUARE";
27450b62aad1SMasatake YAMATO 		case              TOKEN_COLON: return "TOKEN_COLON";
27460b62aad1SMasatake YAMATO 		case              TOKEN_COMMA: return "TOKEN_COMMA";
27470b62aad1SMasatake YAMATO 		case                TOKEN_EOF: return "TOKEN_EOF";
27480b62aad1SMasatake YAMATO 		case         TOKEN_EQUAL_SIGN: return "TOKEN_EQUAL_SIGN";
27490b62aad1SMasatake YAMATO 		case         TOKEN_IDENTIFIER: return "TOKEN_IDENTIFIER";
27500b62aad1SMasatake YAMATO 		case            TOKEN_KEYWORD: return "TOKEN_KEYWORD";
27510b62aad1SMasatake YAMATO 		case         TOKEN_OPEN_CURLY: return "TOKEN_OPEN_CURLY";
27520b62aad1SMasatake YAMATO 		case         TOKEN_OPEN_PAREN: return "TOKEN_OPEN_PAREN";
27530b62aad1SMasatake YAMATO 		case        TOKEN_OPEN_SQUARE: return "TOKEN_OPEN_SQUARE";
27540b62aad1SMasatake YAMATO 		case             TOKEN_PERIOD: return "TOKEN_PERIOD";
27550b62aad1SMasatake YAMATO 		case   TOKEN_POSTFIX_OPERATOR: return "TOKEN_POSTFIX_OPERATOR";
27560b62aad1SMasatake YAMATO 		case             TOKEN_REGEXP: return "TOKEN_REGEXP";
27570b62aad1SMasatake YAMATO 		case          TOKEN_SEMICOLON: return "TOKEN_SEMICOLON";
27580b62aad1SMasatake YAMATO 		case               TOKEN_STAR: return "TOKEN_STAR";
27590b62aad1SMasatake YAMATO 		case             TOKEN_STRING: return "TOKEN_STRING";
27600b62aad1SMasatake YAMATO 		case    TOKEN_TEMPLATE_STRING: return "TOKEN_TEMPLATE_STRING";
27610b62aad1SMasatake YAMATO 		case          TOKEN_UNDEFINED: return "TOKEN_UNDEFINED";
27620b62aad1SMasatake YAMATO 		default: return "UNKNOWN";
27630b62aad1SMasatake YAMATO 	}
27640b62aad1SMasatake YAMATO }
27650b62aad1SMasatake YAMATO 
2766*6f5dd0b1SMasatake YAMATO #if DO_TRACING_USE_DUMP_TOKEN
keywordName(enum eKeywordId e)27670b62aad1SMasatake YAMATO static const char *keywordName(enum eKeywordId e)
27680b62aad1SMasatake YAMATO { /* Generated by misc/enumstr.sh with cmdline "parsers/jscript.c" "eKeywordId" "keywordName" */
27690b62aad1SMasatake YAMATO 	switch (e)
27700b62aad1SMasatake YAMATO 	{
27710b62aad1SMasatake YAMATO 		case            KEYWORD_async: return "KEYWORD_async";
27720b62aad1SMasatake YAMATO 		case KEYWORD_capital_function: return "KEYWORD_capital_function";
27730b62aad1SMasatake YAMATO 		case   KEYWORD_capital_object: return "KEYWORD_capital_object";
27740b62aad1SMasatake YAMATO 		case            KEYWORD_catch: return "KEYWORD_catch";
27750b62aad1SMasatake YAMATO 		case            KEYWORD_class: return "KEYWORD_class";
27760b62aad1SMasatake YAMATO 		case            KEYWORD_const: return "KEYWORD_const";
27770b62aad1SMasatake YAMATO 		case          KEYWORD_default: return "KEYWORD_default";
27780b62aad1SMasatake YAMATO 		case               KEYWORD_do: return "KEYWORD_do";
27790b62aad1SMasatake YAMATO 		case             KEYWORD_else: return "KEYWORD_else";
27800b62aad1SMasatake YAMATO 		case           KEYWORD_export: return "KEYWORD_export";
27810b62aad1SMasatake YAMATO 		case          KEYWORD_extends: return "KEYWORD_extends";
27820b62aad1SMasatake YAMATO 		case          KEYWORD_finally: return "KEYWORD_finally";
27830b62aad1SMasatake YAMATO 		case              KEYWORD_for: return "KEYWORD_for";
27840b62aad1SMasatake YAMATO 		case         KEYWORD_function: return "KEYWORD_function";
27850b62aad1SMasatake YAMATO 		case              KEYWORD_get: return "KEYWORD_get";
27860b62aad1SMasatake YAMATO 		case               KEYWORD_if: return "KEYWORD_if";
27870b62aad1SMasatake YAMATO 		case              KEYWORD_let: return "KEYWORD_let";
27880b62aad1SMasatake YAMATO 		case              KEYWORD_new: return "KEYWORD_new";
27890b62aad1SMasatake YAMATO 		case        KEYWORD_prototype: return "KEYWORD_prototype";
27900b62aad1SMasatake YAMATO 		case           KEYWORD_return: return "KEYWORD_return";
27910b62aad1SMasatake YAMATO 		case              KEYWORD_sap: return "KEYWORD_sap";
27920b62aad1SMasatake YAMATO 		case              KEYWORD_set: return "KEYWORD_set";
27930b62aad1SMasatake YAMATO 		case           KEYWORD_static: return "KEYWORD_static";
27940b62aad1SMasatake YAMATO 		case           KEYWORD_switch: return "KEYWORD_switch";
27950b62aad1SMasatake YAMATO 		case             KEYWORD_this: return "KEYWORD_this";
27960b62aad1SMasatake YAMATO 		case              KEYWORD_try: return "KEYWORD_try";
27970b62aad1SMasatake YAMATO 		case              KEYWORD_var: return "KEYWORD_var";
27980b62aad1SMasatake YAMATO 		case            KEYWORD_while: return "KEYWORD_while";
27990b62aad1SMasatake YAMATO 		default: return "UNKNOWN";
28000b62aad1SMasatake YAMATO 	}
28010b62aad1SMasatake YAMATO }
28020b62aad1SMasatake YAMATO #endif
28032cf5f15cSK.Takata #endif
28040b62aad1SMasatake YAMATO 
initialize(const langType language)28053ae02089SMasatake YAMATO static void initialize (const langType language)
28063ae02089SMasatake YAMATO {
2807158a3387SMasatake YAMATO 	Assert (ARRAY_SIZE (JsKinds) == JSTAG_COUNT);
28083ae02089SMasatake YAMATO 	Lang_js = language;
28093815cb18SJiří Techet 
2810e013efc1SMasatake YAMATO 	TokenPool = objPoolNew (16, newPoolToken, deletePoolToken, clearPoolToken, NULL);
28113815cb18SJiří Techet }
28123815cb18SJiří Techet 
finalize(langType language CTAGS_ATTR_UNUSED,bool initialized)28133815cb18SJiří Techet static void finalize (langType language CTAGS_ATTR_UNUSED, bool initialized)
28143815cb18SJiří Techet {
28153815cb18SJiří Techet 	if (!initialized)
28163815cb18SJiří Techet 		return;
28173815cb18SJiří Techet 
28183815cb18SJiří Techet 	objPoolDelete (TokenPool);
28193ae02089SMasatake YAMATO }
28203ae02089SMasatake YAMATO 
findJsTags(void)28213ae02089SMasatake YAMATO static void findJsTags (void)
28223ae02089SMasatake YAMATO {
28233ae02089SMasatake YAMATO 	tokenInfo *const token = newToken ();
28243ae02089SMasatake YAMATO 
2825fc4ca4b7SColomban Wendling 	NextToken = NULL;
28263ae02089SMasatake YAMATO 	ClassNames = stringListNew ();
28273ae02089SMasatake YAMATO 	FunctionNames = stringListNew ();
28283ae02089SMasatake YAMATO 	LastTokenType = TOKEN_UNDEFINED;
28293ae02089SMasatake YAMATO 
28303ae02089SMasatake YAMATO 	parseJsFile (token);
28313ae02089SMasatake YAMATO 
28323ae02089SMasatake YAMATO 	stringListDelete (ClassNames);
28333ae02089SMasatake YAMATO 	stringListDelete (FunctionNames);
28343ae02089SMasatake YAMATO 	ClassNames = NULL;
28353ae02089SMasatake YAMATO 	FunctionNames = NULL;
28363ae02089SMasatake YAMATO 	deleteToken (token);
2837fc4ca4b7SColomban Wendling 
28384d985ad2SColomban Wendling #ifdef HAVE_ICONV
28394d985ad2SColomban Wendling 	if (JSUnicodeConverter != (iconv_t) -2 && /* not created */
28404d985ad2SColomban Wendling 	    JSUnicodeConverter != (iconv_t) -1 /* creation failed */)
28414d985ad2SColomban Wendling 	{
28424d985ad2SColomban Wendling 		iconv_close (JSUnicodeConverter);
28434d985ad2SColomban Wendling 		JSUnicodeConverter = (iconv_t) -2;
28444d985ad2SColomban Wendling 	}
28454d985ad2SColomban Wendling #endif
28464d985ad2SColomban Wendling 
2847fc4ca4b7SColomban Wendling 	Assert (NextToken == NULL);
28483ae02089SMasatake YAMATO }
28493ae02089SMasatake YAMATO 
2850137eb990SK.Takata /* Create parser definition structure */
JavaScriptParser(void)28513ae02089SMasatake YAMATO extern parserDefinition* JavaScriptParser (void)
28523ae02089SMasatake YAMATO {
28533f2d1cf8SWilfred Hughes 	// .jsx files are JSX: https://facebook.github.io/jsx/
28543f2d1cf8SWilfred Hughes 	// which have JS function definitions, so we just use the JS parser
285583c6a8b5SMasatake YAMATO 	static const char *const extensions [] = { "js", "jsx", "mjs", NULL };
28563ae02089SMasatake YAMATO 	static const char *const aliases [] = { "js", "node", "nodejs",
2857b5efdd2aSMasatake YAMATO 	                                        "seed", "gjs",
2858b5efdd2aSMasatake YAMATO 											/* Used in PostgreSQL
2859b5efdd2aSMasatake YAMATO 											 * https://github.com/plv8/plv8 */
2860b5efdd2aSMasatake YAMATO 											"v8",
2861b5efdd2aSMasatake YAMATO 											NULL };
28623ae02089SMasatake YAMATO 	parserDefinition *const def = parserNew ("JavaScript");
28633ae02089SMasatake YAMATO 	def->extensions = extensions;
28643ae02089SMasatake YAMATO 	def->aliases = aliases;
28653ae02089SMasatake YAMATO 	/*
28663ae02089SMasatake YAMATO 	 * New definitions for parsing instead of regex
28673ae02089SMasatake YAMATO 	 */
286809ae690fSMasatake YAMATO 	def->kindTable	= JsKinds;
28693db72c21SMasatake YAMATO 	def->kindCount	= ARRAY_SIZE (JsKinds);
28703ae02089SMasatake YAMATO 	def->parser		= findJsTags;
28713ae02089SMasatake YAMATO 	def->initialize = initialize;
28723815cb18SJiří Techet 	def->finalize   = finalize;
2873c379c5d2SMasatake YAMATO 	def->keywordTable = JsKeywordTable;
28743db72c21SMasatake YAMATO 	def->keywordCount = ARRAY_SIZE (JsKeywordTable);
28753ae02089SMasatake YAMATO 
28763ae02089SMasatake YAMATO 	return def;
28773ae02089SMasatake YAMATO }
2878