xref: /Universal-ctags/parsers/php.c (revision f476dfe1d31ba7d25d0a1f50f94a756d3fc6cd34)
13ae02089SMasatake YAMATO /*
23ae02089SMasatake YAMATO *   Copyright (c) 2013, Colomban Wendling <ban@herbesfolles.org>
33ae02089SMasatake YAMATO *
43ae02089SMasatake YAMATO *   This source code is released for free distribution under the terms of the
50ce38835Sviccuad *   GNU General Public License version 2 or (at your option) any later version.
63ae02089SMasatake YAMATO *
73ae02089SMasatake YAMATO *   This module contains code for generating tags for the PHP scripting
83ae02089SMasatake YAMATO *   language.
91b68ab24SMasatake YAMATO *
101b68ab24SMasatake YAMATO *   The language reference: http://php.net/manual/en/langref.php
113ae02089SMasatake YAMATO */
123ae02089SMasatake YAMATO 
133ae02089SMasatake YAMATO /*
143ae02089SMasatake YAMATO *   INCLUDE FILES
153ae02089SMasatake YAMATO */
163ae02089SMasatake YAMATO #include "general.h"  /* must always come first */
1746f05046SMasatake YAMATO 
1846f05046SMasatake YAMATO #include <string.h>
1946f05046SMasatake YAMATO 
203ae02089SMasatake YAMATO #include "parse.h"
213ae02089SMasatake YAMATO #include "read.h"
223ae02089SMasatake YAMATO #include "vstring.h"
233ae02089SMasatake YAMATO #include "keyword.h"
243ae02089SMasatake YAMATO #include "entry.h"
253ae02089SMasatake YAMATO #include "routines.h"
263ae02089SMasatake YAMATO #include "debug.h"
270988269fSJiří Techet #include "objpool.h"
28*f476dfe1SMasatake YAMATO #include "promise.h"
293ae02089SMasatake YAMATO 
302b28d0e0SJiří Techet #define isIdentChar(c) (isalnum (c) || (c) == '_' || (c) >= 0x80)
310988269fSJiří Techet #define newToken() (objPoolGet (TokenPool))
320988269fSJiří Techet #define deleteToken(t) (objPoolPut (TokenPool, (t)))
333ae02089SMasatake YAMATO 
344faa2076SColomban Wendling enum {
353ae02089SMasatake YAMATO 	KEYWORD_abstract,
363ae02089SMasatake YAMATO 	KEYWORD_and,
373ae02089SMasatake YAMATO 	KEYWORD_as,
383ae02089SMasatake YAMATO 	KEYWORD_break,
393ae02089SMasatake YAMATO 	KEYWORD_callable,
403ae02089SMasatake YAMATO 	KEYWORD_case,
413ae02089SMasatake YAMATO 	KEYWORD_catch,
423ae02089SMasatake YAMATO 	KEYWORD_class,
433ae02089SMasatake YAMATO 	KEYWORD_clone,
443ae02089SMasatake YAMATO 	KEYWORD_const,
453ae02089SMasatake YAMATO 	KEYWORD_continue,
463ae02089SMasatake YAMATO 	KEYWORD_declare,
473ae02089SMasatake YAMATO 	KEYWORD_define,
483ae02089SMasatake YAMATO 	KEYWORD_default,
493ae02089SMasatake YAMATO 	KEYWORD_do,
503ae02089SMasatake YAMATO 	KEYWORD_echo,
513ae02089SMasatake YAMATO 	KEYWORD_else,
523ae02089SMasatake YAMATO 	KEYWORD_elif,
533ae02089SMasatake YAMATO 	KEYWORD_enddeclare,
543ae02089SMasatake YAMATO 	KEYWORD_endfor,
553ae02089SMasatake YAMATO 	KEYWORD_endforeach,
563ae02089SMasatake YAMATO 	KEYWORD_endif,
573ae02089SMasatake YAMATO 	KEYWORD_endswitch,
583ae02089SMasatake YAMATO 	KEYWORD_endwhile,
593ae02089SMasatake YAMATO 	KEYWORD_extends,
603ae02089SMasatake YAMATO 	KEYWORD_final,
613ae02089SMasatake YAMATO 	KEYWORD_finally,
623ae02089SMasatake YAMATO 	KEYWORD_for,
633ae02089SMasatake YAMATO 	KEYWORD_foreach,
643ae02089SMasatake YAMATO 	KEYWORD_function,
653ae02089SMasatake YAMATO 	KEYWORD_global,
663ae02089SMasatake YAMATO 	KEYWORD_goto,
673ae02089SMasatake YAMATO 	KEYWORD_if,
683ae02089SMasatake YAMATO 	KEYWORD_implements,
693ae02089SMasatake YAMATO 	KEYWORD_include,
703ae02089SMasatake YAMATO 	KEYWORD_include_once,
713ae02089SMasatake YAMATO 	KEYWORD_instanceof,
723ae02089SMasatake YAMATO 	KEYWORD_insteadof,
733ae02089SMasatake YAMATO 	KEYWORD_interface,
743ae02089SMasatake YAMATO 	KEYWORD_namespace,
753ae02089SMasatake YAMATO 	KEYWORD_new,
763ae02089SMasatake YAMATO 	KEYWORD_or,
773ae02089SMasatake YAMATO 	KEYWORD_print,
783ae02089SMasatake YAMATO 	KEYWORD_private,
793ae02089SMasatake YAMATO 	KEYWORD_protected,
803ae02089SMasatake YAMATO 	KEYWORD_public,
813ae02089SMasatake YAMATO 	KEYWORD_require,
823ae02089SMasatake YAMATO 	KEYWORD_require_once,
833ae02089SMasatake YAMATO 	KEYWORD_return,
843ae02089SMasatake YAMATO 	KEYWORD_static,
853ae02089SMasatake YAMATO 	KEYWORD_switch,
863ae02089SMasatake YAMATO 	KEYWORD_throw,
873ae02089SMasatake YAMATO 	KEYWORD_trait,
883ae02089SMasatake YAMATO 	KEYWORD_try,
893ae02089SMasatake YAMATO 	KEYWORD_use,
903ae02089SMasatake YAMATO 	KEYWORD_var,
913ae02089SMasatake YAMATO 	KEYWORD_while,
923ae02089SMasatake YAMATO 	KEYWORD_xor,
933ae02089SMasatake YAMATO 	KEYWORD_yield
944faa2076SColomban Wendling };
954faa2076SColomban Wendling typedef int keywordId; /* to allow KEYWORD_NONE */
963ae02089SMasatake YAMATO 
973ae02089SMasatake YAMATO typedef enum {
983ae02089SMasatake YAMATO 	ACCESS_UNDEFINED,
993ae02089SMasatake YAMATO 	ACCESS_PRIVATE,
1003ae02089SMasatake YAMATO 	ACCESS_PROTECTED,
1013ae02089SMasatake YAMATO 	ACCESS_PUBLIC,
1023ae02089SMasatake YAMATO 	COUNT_ACCESS
1033ae02089SMasatake YAMATO } accessType;
1043ae02089SMasatake YAMATO 
1053ae02089SMasatake YAMATO typedef enum {
1063ae02089SMasatake YAMATO 	IMPL_UNDEFINED,
1073ae02089SMasatake YAMATO 	IMPL_ABSTRACT,
1083ae02089SMasatake YAMATO 	COUNT_IMPL
1093ae02089SMasatake YAMATO } implType;
1103ae02089SMasatake YAMATO 
1113ae02089SMasatake YAMATO typedef enum {
1123ae02089SMasatake YAMATO 	K_CLASS,
1133ae02089SMasatake YAMATO 	K_DEFINE,
1143ae02089SMasatake YAMATO 	K_FUNCTION,
1153ae02089SMasatake YAMATO 	K_INTERFACE,
1163ae02089SMasatake YAMATO 	K_LOCAL_VARIABLE,
1173ae02089SMasatake YAMATO 	K_NAMESPACE,
1183ae02089SMasatake YAMATO 	K_TRAIT,
1193ae02089SMasatake YAMATO 	K_VARIABLE,
120c65c05feSColomban Wendling 	K_ALIAS,
1213ae02089SMasatake YAMATO 	COUNT_KIND
1223ae02089SMasatake YAMATO } phpKind;
1233ae02089SMasatake YAMATO 
124a4af1067SMasatake YAMATO #define NAMESPACE_SEPARATOR "\\"
125a4af1067SMasatake YAMATO static scopeSeparator PhpGenericSeparators [] = {
126f92e6bf2SMasatake YAMATO 	{ K_NAMESPACE        , NAMESPACE_SEPARATOR },
127f92e6bf2SMasatake YAMATO 	{ KIND_WILDCARD_INDEX, "::" },
128a4af1067SMasatake YAMATO };
129a4af1067SMasatake YAMATO 
130e112e8abSMasatake YAMATO static kindDefinition PhpKinds[COUNT_KIND] = {
131ce990805SThomas Braun 	{ true, 'c', "class",		"classes",
132a4af1067SMasatake YAMATO 	  ATTACH_SEPARATORS(PhpGenericSeparators) },
133ce990805SThomas Braun 	{ true, 'd', "define",		"constant definitions",
134a4af1067SMasatake YAMATO 	  ATTACH_SEPARATORS(PhpGenericSeparators)},
135ce990805SThomas Braun 	{ true, 'f', "function",	"functions",
136a4af1067SMasatake YAMATO 	  ATTACH_SEPARATORS(PhpGenericSeparators)},
137ce990805SThomas Braun 	{ true, 'i', "interface",	"interfaces",
138a4af1067SMasatake YAMATO 	  ATTACH_SEPARATORS(PhpGenericSeparators)},
139ce990805SThomas Braun 	{ false, 'l', "local",		"local variables",
140a4af1067SMasatake YAMATO 	  ATTACH_SEPARATORS(PhpGenericSeparators)},
141ce990805SThomas Braun 	{ true, 'n', "namespace",	"namespaces",
142a4af1067SMasatake YAMATO 	  ATTACH_SEPARATORS(PhpGenericSeparators)},
143ce990805SThomas Braun 	{ true, 't', "trait",		"traits",
144a4af1067SMasatake YAMATO 	  ATTACH_SEPARATORS(PhpGenericSeparators)},
145ce990805SThomas Braun 	{ true, 'v', "variable",	"variables",
146a4af1067SMasatake YAMATO 	  ATTACH_SEPARATORS(PhpGenericSeparators)},
147ce990805SThomas Braun 	{ true, 'a', "alias",		"aliases",
148c65c05feSColomban Wendling 	  ATTACH_SEPARATORS(PhpGenericSeparators)},
1493ae02089SMasatake YAMATO };
1503ae02089SMasatake YAMATO 
15182c11d8cSRich Siegel static const keywordTable PhpKeywordTable[] = {
1523ae02089SMasatake YAMATO 	/* keyword			keyword ID */
1533ae02089SMasatake YAMATO 	{ "abstract",		KEYWORD_abstract		},
1543ae02089SMasatake YAMATO 	{ "and",			KEYWORD_and				},
1553ae02089SMasatake YAMATO 	{ "as",				KEYWORD_as				},
1563ae02089SMasatake YAMATO 	{ "break",			KEYWORD_break			},
1573ae02089SMasatake YAMATO 	{ "callable",		KEYWORD_callable		},
1583ae02089SMasatake YAMATO 	{ "case",			KEYWORD_case			},
1593ae02089SMasatake YAMATO 	{ "catch",			KEYWORD_catch			},
1603ae02089SMasatake YAMATO 	{ "cfunction",		KEYWORD_function		}, /* nobody knows what the hell this is, but it seems to behave much like "function" so bind it to it */
1613ae02089SMasatake YAMATO 	{ "class",			KEYWORD_class			},
1623ae02089SMasatake YAMATO 	{ "clone",			KEYWORD_clone			},
1633ae02089SMasatake YAMATO 	{ "const",			KEYWORD_const			},
1643ae02089SMasatake YAMATO 	{ "continue",		KEYWORD_continue		},
1653ae02089SMasatake YAMATO 	{ "declare",		KEYWORD_declare			},
1663ae02089SMasatake YAMATO 	{ "define",			KEYWORD_define			}, /* this isn't really a keyword but we handle it so it's easier this way */
1673ae02089SMasatake YAMATO 	{ "default",		KEYWORD_default			},
1683ae02089SMasatake YAMATO 	{ "do",				KEYWORD_do				},
1693ae02089SMasatake YAMATO 	{ "echo",			KEYWORD_echo			},
1703ae02089SMasatake YAMATO 	{ "else",			KEYWORD_else			},
1713ae02089SMasatake YAMATO 	{ "elseif",			KEYWORD_elif			},
1723ae02089SMasatake YAMATO 	{ "enddeclare",		KEYWORD_enddeclare		},
1733ae02089SMasatake YAMATO 	{ "endfor",			KEYWORD_endfor			},
1743ae02089SMasatake YAMATO 	{ "endforeach",		KEYWORD_endforeach		},
1753ae02089SMasatake YAMATO 	{ "endif",			KEYWORD_endif			},
1763ae02089SMasatake YAMATO 	{ "endswitch",		KEYWORD_endswitch		},
1773ae02089SMasatake YAMATO 	{ "endwhile",		KEYWORD_endwhile		},
1783ae02089SMasatake YAMATO 	{ "extends",		KEYWORD_extends			},
1793ae02089SMasatake YAMATO 	{ "final",			KEYWORD_final			},
1803ae02089SMasatake YAMATO 	{ "finally",		KEYWORD_finally			},
1813ae02089SMasatake YAMATO 	{ "for",			KEYWORD_for				},
1823ae02089SMasatake YAMATO 	{ "foreach",		KEYWORD_foreach			},
1833ae02089SMasatake YAMATO 	{ "function",		KEYWORD_function		},
1843ae02089SMasatake YAMATO 	{ "global",			KEYWORD_global			},
1853ae02089SMasatake YAMATO 	{ "goto",			KEYWORD_goto			},
1863ae02089SMasatake YAMATO 	{ "if",				KEYWORD_if				},
1873ae02089SMasatake YAMATO 	{ "implements",		KEYWORD_implements		},
1883ae02089SMasatake YAMATO 	{ "include",		KEYWORD_include			},
1893ae02089SMasatake YAMATO 	{ "include_once",	KEYWORD_include_once	},
1903ae02089SMasatake YAMATO 	{ "instanceof",		KEYWORD_instanceof		},
1913ae02089SMasatake YAMATO 	{ "insteadof",		KEYWORD_insteadof		},
1923ae02089SMasatake YAMATO 	{ "interface",		KEYWORD_interface		},
1933ae02089SMasatake YAMATO 	{ "namespace",		KEYWORD_namespace		},
1943ae02089SMasatake YAMATO 	{ "new",			KEYWORD_new				},
1953ae02089SMasatake YAMATO 	{ "or",				KEYWORD_or				},
1963ae02089SMasatake YAMATO 	{ "print",			KEYWORD_print			},
1973ae02089SMasatake YAMATO 	{ "private",		KEYWORD_private			},
1983ae02089SMasatake YAMATO 	{ "protected",		KEYWORD_protected		},
1993ae02089SMasatake YAMATO 	{ "public",			KEYWORD_public			},
2003ae02089SMasatake YAMATO 	{ "require",		KEYWORD_require			},
2013ae02089SMasatake YAMATO 	{ "require_once",	KEYWORD_require_once	},
2023ae02089SMasatake YAMATO 	{ "return",			KEYWORD_return			},
2033ae02089SMasatake YAMATO 	{ "static",			KEYWORD_static			},
2043ae02089SMasatake YAMATO 	{ "switch",			KEYWORD_switch			},
2053ae02089SMasatake YAMATO 	{ "throw",			KEYWORD_throw			},
2063ae02089SMasatake YAMATO 	{ "trait",			KEYWORD_trait			},
2073ae02089SMasatake YAMATO 	{ "try",			KEYWORD_try				},
2083ae02089SMasatake YAMATO 	{ "use",			KEYWORD_use				},
2093ae02089SMasatake YAMATO 	{ "var",			KEYWORD_var				},
2103ae02089SMasatake YAMATO 	{ "while",			KEYWORD_while			},
2113ae02089SMasatake YAMATO 	{ "xor",			KEYWORD_xor				},
2123ae02089SMasatake YAMATO 	{ "yield",			KEYWORD_yield			}
2133ae02089SMasatake YAMATO };
2143ae02089SMasatake YAMATO 
2153ae02089SMasatake YAMATO 
2163ae02089SMasatake YAMATO typedef enum eTokenType {
2173ae02089SMasatake YAMATO 	TOKEN_UNDEFINED,
2183ae02089SMasatake YAMATO 	TOKEN_EOF,
2193ae02089SMasatake YAMATO 	TOKEN_CHARACTER,
2203ae02089SMasatake YAMATO 	TOKEN_CLOSE_PAREN,
2213ae02089SMasatake YAMATO 	TOKEN_SEMICOLON,
2223ae02089SMasatake YAMATO 	TOKEN_COLON,
2233ae02089SMasatake YAMATO 	TOKEN_COMMA,
2243ae02089SMasatake YAMATO 	TOKEN_KEYWORD,
2253ae02089SMasatake YAMATO 	TOKEN_OPEN_PAREN,
2263ae02089SMasatake YAMATO 	TOKEN_OPERATOR,
2273ae02089SMasatake YAMATO 	TOKEN_IDENTIFIER,
2283ae02089SMasatake YAMATO 	TOKEN_STRING,
2293ae02089SMasatake YAMATO 	TOKEN_PERIOD,
2303ae02089SMasatake YAMATO 	TOKEN_OPEN_CURLY,
2313ae02089SMasatake YAMATO 	TOKEN_CLOSE_CURLY,
2323ae02089SMasatake YAMATO 	TOKEN_EQUAL_SIGN,
2333ae02089SMasatake YAMATO 	TOKEN_OPEN_SQUARE,
2343ae02089SMasatake YAMATO 	TOKEN_CLOSE_SQUARE,
2353ae02089SMasatake YAMATO 	TOKEN_VARIABLE,
236acbcd162SColomban Wendling 	TOKEN_AMPERSAND,
23751f37d45SMasatake YAMATO 	TOKEN_BACKSLASH,
23851f37d45SMasatake YAMATO 	TOKEN_QMARK,
2393ae02089SMasatake YAMATO } tokenType;
2403ae02089SMasatake YAMATO 
2413ae02089SMasatake YAMATO typedef struct {
2423ae02089SMasatake YAMATO 	tokenType		type;
2433ae02089SMasatake YAMATO 	keywordId		keyword;
2443ae02089SMasatake YAMATO 	vString *		string;
2453ae02089SMasatake YAMATO 	vString *		scope;
2463ae02089SMasatake YAMATO 	unsigned long 	lineNumber;
247509a47dbSJiří Techet 	MIOPos			filePosition;
2483ae02089SMasatake YAMATO 	int 			parentKind; /* -1 if none */
2493165d268SMasatake YAMATO 	bool			anonymous;	/* true if token specifies
2503165d268SMasatake YAMATO 								 * an anonymous class */
2513ae02089SMasatake YAMATO } tokenInfo;
2523ae02089SMasatake YAMATO 
2533ae02089SMasatake YAMATO static langType Lang_php;
2543ae02089SMasatake YAMATO static langType Lang_zephir;
2553ae02089SMasatake YAMATO 
256ce990805SThomas Braun static bool InPhp = false; /* whether we are between <? ?> */
25775ba24d4SColomban Wendling /* whether the next token may be a keyword, e.g. not after "::" or "->" */
25875ba24d4SColomban Wendling static bool MayBeKeyword = true;
2593ae02089SMasatake YAMATO 
2603ae02089SMasatake YAMATO /* current statement details */
2613ae02089SMasatake YAMATO static struct {
2623ae02089SMasatake YAMATO 	accessType access;
2633ae02089SMasatake YAMATO 	implType impl;
2643ae02089SMasatake YAMATO } CurrentStatement;
2653ae02089SMasatake YAMATO 
2663ae02089SMasatake YAMATO /* Current namespace */
2673ae02089SMasatake YAMATO static vString *CurrentNamesapce;
2683ae02089SMasatake YAMATO /* Cache variable to build the tag's scope.  It has no real meaning outside
2693ae02089SMasatake YAMATO  * of initPhpEntry()'s scope. */
2703ae02089SMasatake YAMATO static vString *FullScope;
271f176923cSMasatake YAMATO /* The class name specified at "extends" keyword in the current class
272f176923cSMasatake YAMATO  * definition. Used to resolve "parent" in return type. */
273f176923cSMasatake YAMATO static vString *ParentClass;
2743ae02089SMasatake YAMATO 
2750988269fSJiří Techet static objPool *TokenPool = NULL;
2760988269fSJiří Techet 
phpScopeSeparatorFor(int kind,int upperScopeKind)277c06d97daSColomban Wendling static const char *phpScopeSeparatorFor (int kind, int upperScopeKind)
278a4af1067SMasatake YAMATO {
279c06d97daSColomban Wendling 	return scopeSeparatorFor (getInputLanguage(), kind, upperScopeKind);
280a4af1067SMasatake YAMATO }
2813ae02089SMasatake YAMATO 
accessToString(const accessType access)2823ae02089SMasatake YAMATO static const char *accessToString (const accessType access)
2833ae02089SMasatake YAMATO {
2843ae02089SMasatake YAMATO 	static const char *const names[COUNT_ACCESS] = {
2853ae02089SMasatake YAMATO 		"undefined",
2863ae02089SMasatake YAMATO 		"private",
2873ae02089SMasatake YAMATO 		"protected",
2883ae02089SMasatake YAMATO 		"public"
2893ae02089SMasatake YAMATO 	};
2903ae02089SMasatake YAMATO 
2913ae02089SMasatake YAMATO 	Assert (access < COUNT_ACCESS);
2923ae02089SMasatake YAMATO 
2933ae02089SMasatake YAMATO 	return names[access];
2943ae02089SMasatake YAMATO }
2953ae02089SMasatake YAMATO 
implToString(const implType impl)2963ae02089SMasatake YAMATO static const char *implToString (const implType impl)
2973ae02089SMasatake YAMATO {
2983ae02089SMasatake YAMATO 	static const char *const names[COUNT_IMPL] = {
2993ae02089SMasatake YAMATO 		"undefined",
3003ae02089SMasatake YAMATO 		"abstract"
3013ae02089SMasatake YAMATO 	};
3023ae02089SMasatake YAMATO 
3033ae02089SMasatake YAMATO 	Assert (impl < COUNT_IMPL);
3043ae02089SMasatake YAMATO 
3053ae02089SMasatake YAMATO 	return names[impl];
3063ae02089SMasatake YAMATO }
3073ae02089SMasatake YAMATO 
initPhpEntry(tagEntryInfo * const e,const tokenInfo * const token,const phpKind kind,const accessType access)3083ae02089SMasatake YAMATO static void initPhpEntry (tagEntryInfo *const e, const tokenInfo *const token,
3093ae02089SMasatake YAMATO 						  const phpKind kind, const accessType access)
3103ae02089SMasatake YAMATO {
3113ae02089SMasatake YAMATO 	int parentKind = -1;
3123ae02089SMasatake YAMATO 
3133ae02089SMasatake YAMATO 	vStringClear (FullScope);
3143ae02089SMasatake YAMATO 
3153ae02089SMasatake YAMATO 	if (vStringLength (CurrentNamesapce) > 0)
3163ae02089SMasatake YAMATO 	{
3173ae02089SMasatake YAMATO 		parentKind = K_NAMESPACE;
318e9e86f51SMasatake YAMATO 		vStringCat (FullScope, CurrentNamesapce);
319e9e86f51SMasatake YAMATO 
3203ae02089SMasatake YAMATO 	}
3213ae02089SMasatake YAMATO 
32216a2541cSMasatake YAMATO 	initTagEntry (e, vStringValue (token->string), kind);
3233ae02089SMasatake YAMATO 
3243ae02089SMasatake YAMATO 	e->lineNumber	= token->lineNumber;
3253ae02089SMasatake YAMATO 	e->filePosition	= token->filePosition;
3263ae02089SMasatake YAMATO 
3273ae02089SMasatake YAMATO 	if (access != ACCESS_UNDEFINED)
3283ae02089SMasatake YAMATO 		e->extensionFields.access = accessToString (access);
3293ae02089SMasatake YAMATO 	if (vStringLength (token->scope) > 0)
3303ae02089SMasatake YAMATO 	{
3313ae02089SMasatake YAMATO 		parentKind = token->parentKind;
332a4af1067SMasatake YAMATO 
3333ae02089SMasatake YAMATO 		if (vStringLength (FullScope) > 0)
334a4af1067SMasatake YAMATO 		{
335a4af1067SMasatake YAMATO 			const char* sep;
336a4af1067SMasatake YAMATO 
337a4af1067SMasatake YAMATO 			sep = phpScopeSeparatorFor (parentKind,
338a4af1067SMasatake YAMATO 						    K_NAMESPACE);
339a4af1067SMasatake YAMATO 			vStringCatS (FullScope, sep);
340a4af1067SMasatake YAMATO 		}
3413ae02089SMasatake YAMATO 			vStringCat (FullScope, token->scope);
3423ae02089SMasatake YAMATO 	}
3433ae02089SMasatake YAMATO 	if (vStringLength (FullScope) > 0)
3443ae02089SMasatake YAMATO 	{
3453ae02089SMasatake YAMATO 		Assert (parentKind >= 0);
3463ae02089SMasatake YAMATO 
347f92e6bf2SMasatake YAMATO 		e->extensionFields.scopeKindIndex = parentKind;
348015ab54cSMasatake YAMATO 		e->extensionFields.scopeName = vStringValue (FullScope);
3493ae02089SMasatake YAMATO 	}
3503165d268SMasatake YAMATO 
3513165d268SMasatake YAMATO 	if (token->anonymous)
3523165d268SMasatake YAMATO 		markTagExtraBit (e, XTAG_ANONYMOUS);
3533ae02089SMasatake YAMATO }
3543ae02089SMasatake YAMATO 
makePhpTagEntry(tagEntryInfo * const e)3559014223fSMasatake YAMATO static void  makePhpTagEntry  (tagEntryInfo *const e)
3569014223fSMasatake YAMATO {
3579014223fSMasatake YAMATO 	makeTagEntry (e);
3589014223fSMasatake YAMATO 	makeQualifiedTagEntry (e);
3599014223fSMasatake YAMATO }
3605ed230b0SMasatake YAMATO 
fillTypeRefField(tagEntryInfo * const e,const vString * const rtype,const tokenInfo * const token)3615ed230b0SMasatake YAMATO static void fillTypeRefField (tagEntryInfo *const e,
3625ed230b0SMasatake YAMATO 							  const vString *const rtype, const tokenInfo *const token)
3635ed230b0SMasatake YAMATO {
3645ed230b0SMasatake YAMATO 	if ((vStringLength (rtype) == 4)
3655ed230b0SMasatake YAMATO 		&& (strcmp (vStringValue (rtype), "self") == 0)
3665ed230b0SMasatake YAMATO 		&& vStringLength (token->scope) > 0)
3675ed230b0SMasatake YAMATO 	{
3685ed230b0SMasatake YAMATO 		if (token->parentKind == -1)
3695ed230b0SMasatake YAMATO 			e->extensionFields.typeRef [0] = "unknown";
3705ed230b0SMasatake YAMATO 		else
3715ed230b0SMasatake YAMATO 			e->extensionFields.typeRef [0] = PhpKinds [token->parentKind].name;
3725ed230b0SMasatake YAMATO 		e->extensionFields.typeRef [1] = vStringValue (token->scope);
3735ed230b0SMasatake YAMATO 	}
3745ed230b0SMasatake YAMATO 	else if ((vStringLength (rtype) == 6)
3755ed230b0SMasatake YAMATO 			 && (strcmp (vStringValue (rtype), "parent") == 0)
3765ed230b0SMasatake YAMATO 			 && (ParentClass && vStringLength (ParentClass) > 0))
3775ed230b0SMasatake YAMATO 	{
3785ed230b0SMasatake YAMATO 		e->extensionFields.typeRef [0] = "class";
3795ed230b0SMasatake YAMATO 		e->extensionFields.typeRef [1] = vStringValue (ParentClass);
3805ed230b0SMasatake YAMATO 	}
3815ed230b0SMasatake YAMATO 	else
3825ed230b0SMasatake YAMATO 	{
3835ed230b0SMasatake YAMATO 		e->extensionFields.typeRef [0] = "unknown";
3845ed230b0SMasatake YAMATO 		e->extensionFields.typeRef [1] = vStringValue (rtype);
3855ed230b0SMasatake YAMATO 	}
3865ed230b0SMasatake YAMATO }
3875ed230b0SMasatake YAMATO 
makeTypedPhpTag(const tokenInfo * const token,const phpKind kind,const accessType access,vString * typeName)3885ed230b0SMasatake YAMATO static void makeTypedPhpTag (const tokenInfo *const token, const phpKind kind,
3895ed230b0SMasatake YAMATO 							 const accessType access, vString* typeName)
3903ae02089SMasatake YAMATO {
3913ae02089SMasatake YAMATO 	if (PhpKinds[kind].enabled)
3923ae02089SMasatake YAMATO 	{
3933ae02089SMasatake YAMATO 		tagEntryInfo e;
3943ae02089SMasatake YAMATO 
3953ae02089SMasatake YAMATO 		initPhpEntry (&e, token, kind, access);
3965ed230b0SMasatake YAMATO 		if (typeName)
3975ed230b0SMasatake YAMATO 			fillTypeRefField (&e, typeName, token);
3989014223fSMasatake YAMATO 		makePhpTagEntry (&e);
3993ae02089SMasatake YAMATO 	}
4003ae02089SMasatake YAMATO }
4013ae02089SMasatake YAMATO 
makeSimplePhpTag(const tokenInfo * const token,const phpKind kind,const accessType access)4025ed230b0SMasatake YAMATO static void makeSimplePhpTag (const tokenInfo *const token, const phpKind kind,
4035ed230b0SMasatake YAMATO 							  const accessType access)
4045ed230b0SMasatake YAMATO {
4055ed230b0SMasatake YAMATO 	makeTypedPhpTag (token, kind, access, NULL);
4065ed230b0SMasatake YAMATO }
4075ed230b0SMasatake YAMATO 
makeNamespacePhpTag(const tokenInfo * const token,const vString * const name)4083ae02089SMasatake YAMATO static void makeNamespacePhpTag (const tokenInfo *const token, const vString *const name)
4093ae02089SMasatake YAMATO {
4103ae02089SMasatake YAMATO 	if (PhpKinds[K_NAMESPACE].enabled)
4113ae02089SMasatake YAMATO 	{
4123ae02089SMasatake YAMATO 		tagEntryInfo e;
4133ae02089SMasatake YAMATO 
41416a2541cSMasatake YAMATO 		initTagEntry (&e, vStringValue (name), K_NAMESPACE);
4153ae02089SMasatake YAMATO 
4163ae02089SMasatake YAMATO 		e.lineNumber	= token->lineNumber;
4173ae02089SMasatake YAMATO 		e.filePosition	= token->filePosition;
4183ae02089SMasatake YAMATO 
4199014223fSMasatake YAMATO 		makePhpTagEntry (&e);
4203ae02089SMasatake YAMATO 	}
4213ae02089SMasatake YAMATO }
4223ae02089SMasatake YAMATO 
makeClassOrIfaceTag(const phpKind kind,const tokenInfo * const token,vString * const inheritance,const implType impl)4233ae02089SMasatake YAMATO static void makeClassOrIfaceTag (const phpKind kind, const tokenInfo *const token,
4243ae02089SMasatake YAMATO 								 vString *const inheritance, const implType impl)
4253ae02089SMasatake YAMATO {
4263ae02089SMasatake YAMATO 	if (PhpKinds[kind].enabled)
4273ae02089SMasatake YAMATO 	{
4283ae02089SMasatake YAMATO 		tagEntryInfo e;
4293ae02089SMasatake YAMATO 
4303ae02089SMasatake YAMATO 		initPhpEntry (&e, token, kind, ACCESS_UNDEFINED);
4313ae02089SMasatake YAMATO 
4323ae02089SMasatake YAMATO 		if (impl != IMPL_UNDEFINED)
4333ae02089SMasatake YAMATO 			e.extensionFields.implementation = implToString (impl);
4343ae02089SMasatake YAMATO 		if (vStringLength (inheritance) > 0)
4353ae02089SMasatake YAMATO 			e.extensionFields.inheritance = vStringValue (inheritance);
4363ae02089SMasatake YAMATO 
4379014223fSMasatake YAMATO 		makePhpTagEntry (&e);
4383ae02089SMasatake YAMATO 	}
4393ae02089SMasatake YAMATO }
4403ae02089SMasatake YAMATO 
makeFunctionTag(const tokenInfo * const token,const vString * const arglist,const vString * const rtype,const accessType access,const implType impl)4413ae02089SMasatake YAMATO static void makeFunctionTag (const tokenInfo *const token,
4423ae02089SMasatake YAMATO 							 const vString *const arglist,
443c74b5ff0SMasatake YAMATO 							 const vString *const rtype,
4443ae02089SMasatake YAMATO 							 const accessType access, const implType impl)
4453ae02089SMasatake YAMATO {
4463ae02089SMasatake YAMATO 	if (PhpKinds[K_FUNCTION].enabled)
4473ae02089SMasatake YAMATO 	{
4483ae02089SMasatake YAMATO 		tagEntryInfo e;
4493ae02089SMasatake YAMATO 
4503ae02089SMasatake YAMATO 		initPhpEntry (&e, token, K_FUNCTION, access);
4513ae02089SMasatake YAMATO 
4523ae02089SMasatake YAMATO 		if (impl != IMPL_UNDEFINED)
4533ae02089SMasatake YAMATO 			e.extensionFields.implementation = implToString (impl);
4543ae02089SMasatake YAMATO 		if (arglist)
4553ae02089SMasatake YAMATO 			e.extensionFields.signature = vStringValue (arglist);
456c74b5ff0SMasatake YAMATO 		if (rtype)
4575ed230b0SMasatake YAMATO 			fillTypeRefField (&e, rtype, token);
4583ae02089SMasatake YAMATO 
4599014223fSMasatake YAMATO 		makePhpTagEntry (&e);
4603ae02089SMasatake YAMATO 	}
4613ae02089SMasatake YAMATO }
4623ae02089SMasatake YAMATO 
newPoolToken(void * createArg CTAGS_ATTR_UNUSED)463e013efc1SMasatake YAMATO static void *newPoolToken (void *createArg CTAGS_ATTR_UNUSED)
4643ae02089SMasatake YAMATO {
4650988269fSJiří Techet 	tokenInfo *token = xMalloc (1, tokenInfo);
4663ae02089SMasatake YAMATO 
4673ae02089SMasatake YAMATO 	token->string = vStringNew ();
4683ae02089SMasatake YAMATO 	token->scope  = vStringNew ();
4693ae02089SMasatake YAMATO 	return token;
4703ae02089SMasatake YAMATO }
4713ae02089SMasatake YAMATO 
clearPoolToken(void * data)4720988269fSJiří Techet static void clearPoolToken (void *data)
4733ae02089SMasatake YAMATO {
4740988269fSJiří Techet 	tokenInfo *token = data;
4750988269fSJiří Techet 
4760988269fSJiří Techet 	token->type			= TOKEN_UNDEFINED;
4770988269fSJiří Techet 	token->keyword		= KEYWORD_NONE;
4780988269fSJiří Techet 	token->lineNumber   = getInputLineNumber ();
4790988269fSJiří Techet 	token->filePosition = getInputFilePosition ();
4800988269fSJiří Techet 	token->parentKind	= -1;
4813165d268SMasatake YAMATO 	token->anonymous	= false;
4820988269fSJiří Techet 	vStringClear (token->string);
4830988269fSJiří Techet 	vStringClear (token->scope);
4840988269fSJiří Techet }
4850988269fSJiří Techet 
deletePoolToken(void * data)4860988269fSJiří Techet static void deletePoolToken (void *data)
4870988269fSJiří Techet {
4880988269fSJiří Techet 	tokenInfo *token = data;
4893ae02089SMasatake YAMATO 	vStringDelete (token->string);
4903ae02089SMasatake YAMATO 	vStringDelete (token->scope);
4913ae02089SMasatake YAMATO 	eFree (token);
4923ae02089SMasatake YAMATO }
4933ae02089SMasatake YAMATO 
copyToken(tokenInfo * const dest,const tokenInfo * const src,bool scope)4943ae02089SMasatake YAMATO static void copyToken (tokenInfo *const dest, const tokenInfo *const src,
495ce990805SThomas Braun 					   bool scope)
4963ae02089SMasatake YAMATO {
4973ae02089SMasatake YAMATO 	dest->lineNumber = src->lineNumber;
4983ae02089SMasatake YAMATO 	dest->filePosition = src->filePosition;
4993ae02089SMasatake YAMATO 	dest->type = src->type;
5003ae02089SMasatake YAMATO 	dest->keyword = src->keyword;
5013ae02089SMasatake YAMATO 	vStringCopy(dest->string, src->string);
5023ae02089SMasatake YAMATO 	dest->parentKind = src->parentKind;
5033ae02089SMasatake YAMATO 	if (scope)
5043ae02089SMasatake YAMATO 		vStringCopy(dest->scope, src->scope);
5053165d268SMasatake YAMATO 	dest->anonymous = src->anonymous;
5063ae02089SMasatake YAMATO }
5073ae02089SMasatake YAMATO 
5083ae02089SMasatake YAMATO #if 0
5093ae02089SMasatake YAMATO #include <stdio.h>
5103ae02089SMasatake YAMATO 
5113ae02089SMasatake YAMATO static const char *tokenTypeName (const tokenType type)
5123ae02089SMasatake YAMATO {
5133ae02089SMasatake YAMATO 	switch (type)
5143ae02089SMasatake YAMATO 	{
5153ae02089SMasatake YAMATO 		case TOKEN_UNDEFINED:		return "undefined";
5163ae02089SMasatake YAMATO 		case TOKEN_EOF:				return "EOF";
5173ae02089SMasatake YAMATO 		case TOKEN_CHARACTER:		return "character";
5183ae02089SMasatake YAMATO 		case TOKEN_CLOSE_PAREN:		return "')'";
5193ae02089SMasatake YAMATO 		case TOKEN_SEMICOLON:		return "';'";
5203ae02089SMasatake YAMATO 		case TOKEN_COLON:			return "':'";
5213ae02089SMasatake YAMATO 		case TOKEN_COMMA:			return "','";
5223ae02089SMasatake YAMATO 		case TOKEN_OPEN_PAREN:		return "'('";
5233ae02089SMasatake YAMATO 		case TOKEN_OPERATOR:		return "operator";
5243ae02089SMasatake YAMATO 		case TOKEN_IDENTIFIER:		return "identifier";
5253ae02089SMasatake YAMATO 		case TOKEN_KEYWORD:			return "keyword";
5263ae02089SMasatake YAMATO 		case TOKEN_STRING:			return "string";
5273ae02089SMasatake YAMATO 		case TOKEN_PERIOD:			return "'.'";
5283ae02089SMasatake YAMATO 		case TOKEN_OPEN_CURLY:		return "'{'";
5293ae02089SMasatake YAMATO 		case TOKEN_CLOSE_CURLY:		return "'}'";
5303ae02089SMasatake YAMATO 		case TOKEN_EQUAL_SIGN:		return "'='";
5313ae02089SMasatake YAMATO 		case TOKEN_OPEN_SQUARE:		return "'['";
5323ae02089SMasatake YAMATO 		case TOKEN_CLOSE_SQUARE:	return "']'";
5333ae02089SMasatake YAMATO 		case TOKEN_VARIABLE:		return "variable";
5343ae02089SMasatake YAMATO 	}
5353ae02089SMasatake YAMATO 	return NULL;
5363ae02089SMasatake YAMATO }
5373ae02089SMasatake YAMATO 
5383ae02089SMasatake YAMATO static void printToken (const tokenInfo *const token)
5393ae02089SMasatake YAMATO {
5403ae02089SMasatake YAMATO 	fprintf (stderr, "%p:\n\ttype:\t%s\n\tline:\t%lu\n\tscope:\t%s\n", (void *) token,
5413ae02089SMasatake YAMATO 			 tokenTypeName (token->type),
5423ae02089SMasatake YAMATO 			 token->lineNumber,
5433ae02089SMasatake YAMATO 			 vStringValue (token->scope));
5443ae02089SMasatake YAMATO 	switch (token->type)
5453ae02089SMasatake YAMATO 	{
5463ae02089SMasatake YAMATO 		case TOKEN_IDENTIFIER:
5473ae02089SMasatake YAMATO 		case TOKEN_STRING:
5483ae02089SMasatake YAMATO 		case TOKEN_VARIABLE:
5493ae02089SMasatake YAMATO 			fprintf (stderr, "\tcontent:\t%s\n", vStringValue (token->string));
5503ae02089SMasatake YAMATO 			break;
5513ae02089SMasatake YAMATO 
5523ae02089SMasatake YAMATO 		case TOKEN_KEYWORD:
5533ae02089SMasatake YAMATO 		{
554158a3387SMasatake YAMATO 			size_t n = ARRAY_SIZE (PhpKeywordTable);
5553ae02089SMasatake YAMATO 			size_t i;
5563ae02089SMasatake YAMATO 
5573ae02089SMasatake YAMATO 			fprintf (stderr, "\tkeyword:\t");
5583ae02089SMasatake YAMATO 			for (i = 0; i < n; i++)
5593ae02089SMasatake YAMATO 			{
5603ae02089SMasatake YAMATO 				if (PhpKeywordTable[i].id == token->keyword)
5613ae02089SMasatake YAMATO 				{
5623ae02089SMasatake YAMATO 					fprintf (stderr, "%s\n", PhpKeywordTable[i].name);
5633ae02089SMasatake YAMATO 					break;
5643ae02089SMasatake YAMATO 				}
5653ae02089SMasatake YAMATO 			}
5663ae02089SMasatake YAMATO 			if (i >= n)
5673ae02089SMasatake YAMATO 				fprintf (stderr, "(unknown)\n");
5683ae02089SMasatake YAMATO 		}
5693ae02089SMasatake YAMATO 
5703ae02089SMasatake YAMATO 		default: break;
5713ae02089SMasatake YAMATO 	}
5723ae02089SMasatake YAMATO }
5733ae02089SMasatake YAMATO #endif
5743ae02089SMasatake YAMATO 
addToScope(tokenInfo * const token,const vString * const extra,int kindOfUpperScope)575a4af1067SMasatake YAMATO static void addToScope (tokenInfo *const token, const vString *const extra,
576a4af1067SMasatake YAMATO 			int kindOfUpperScope)
5773ae02089SMasatake YAMATO {
5783ae02089SMasatake YAMATO 	if (vStringLength (token->scope) > 0)
579a4af1067SMasatake YAMATO 	{
580a4af1067SMasatake YAMATO 		const char* sep;
581a4af1067SMasatake YAMATO 
582a4af1067SMasatake YAMATO 		sep = phpScopeSeparatorFor(token->parentKind,
583a4af1067SMasatake YAMATO 					   kindOfUpperScope);
584a4af1067SMasatake YAMATO 		vStringCatS (token->scope, sep);
585a4af1067SMasatake YAMATO 	}
586c11faac7SMasatake YAMATO 	vStringCat (token->scope, extra);
5873ae02089SMasatake YAMATO }
5883ae02089SMasatake YAMATO 
skipToCharacter(const int c)5893ae02089SMasatake YAMATO static int skipToCharacter (const int c)
5903ae02089SMasatake YAMATO {
5913ae02089SMasatake YAMATO 	int d;
5923ae02089SMasatake YAMATO 	do
5933ae02089SMasatake YAMATO 	{
594018bce0bSMasatake YAMATO 		d = getcFromInputFile ();
5953ae02089SMasatake YAMATO 	} while (d != EOF  &&  d != c);
5963ae02089SMasatake YAMATO 	return d;
5973ae02089SMasatake YAMATO }
5983ae02089SMasatake YAMATO 
parseString(vString * const string,const int delimiter)5993ae02089SMasatake YAMATO static void parseString (vString *const string, const int delimiter)
6003ae02089SMasatake YAMATO {
601ce990805SThomas Braun 	while (true)
6023ae02089SMasatake YAMATO 	{
603018bce0bSMasatake YAMATO 		int c = getcFromInputFile ();
6043ae02089SMasatake YAMATO 
605018bce0bSMasatake YAMATO 		if (c == '\\' && (c = getcFromInputFile ()) != EOF)
6063ae02089SMasatake YAMATO 			vStringPut (string, (char) c);
6073ae02089SMasatake YAMATO 		else if (c == EOF || c == delimiter)
6083ae02089SMasatake YAMATO 			break;
6093ae02089SMasatake YAMATO 		else
6103ae02089SMasatake YAMATO 			vStringPut (string, (char) c);
6113ae02089SMasatake YAMATO 	}
6123ae02089SMasatake YAMATO }
6133ae02089SMasatake YAMATO 
6144c42296bSColomban Wendling /* Strips @indent_len characters from lines in @string to get the correct
6154c42296bSColomban Wendling  * string value for an indented heredoc (PHP 7.3+).
6164c42296bSColomban Wendling  * This doesn't handle invalid values specially and might yield surprising
6174c42296bSColomban Wendling  * results with them, but it doesn't really matter as it's invalid anyway. */
stripHeredocIndent(vString * const string,size_t indent_len)6184c42296bSColomban Wendling static void stripHeredocIndent (vString *const string, size_t indent_len)
6194c42296bSColomban Wendling {
6204c42296bSColomban Wendling 	char *str = vStringValue (string);
6214c42296bSColomban Wendling 	size_t str_len = vStringLength (string);
6224c42296bSColomban Wendling 	char *p = str;
6234c42296bSColomban Wendling 	size_t new_len = str_len;
6244c42296bSColomban Wendling 	bool at_line_start = true;
6254c42296bSColomban Wendling 
6264c42296bSColomban Wendling 	while (*p)
6274c42296bSColomban Wendling 	{
6284c42296bSColomban Wendling 		if (at_line_start)
6294c42296bSColomban Wendling 		{
6304c42296bSColomban Wendling 			size_t p_len;
6314c42296bSColomban Wendling 			size_t strip_len;
6324c42296bSColomban Wendling 
6334c42296bSColomban Wendling 			p_len = str_len - (p - str);
6344c42296bSColomban Wendling 			strip_len = p_len < indent_len ? p_len : indent_len;
6354c42296bSColomban Wendling 			memmove (p, p + strip_len, p_len - strip_len);
6364c42296bSColomban Wendling 			p += strip_len;
6374c42296bSColomban Wendling 			new_len -= strip_len;
6384c42296bSColomban Wendling 		}
6394c42296bSColomban Wendling 		/* CRLF is already normalized as LF */
6404c42296bSColomban Wendling 		at_line_start = (*p == '\r' || *p == '\n');
6414c42296bSColomban Wendling 		p++;
6424c42296bSColomban Wendling 	}
6434c42296bSColomban Wendling 	vStringTruncate (string, new_len);
6444c42296bSColomban Wendling }
6454c42296bSColomban Wendling 
64616798065SColomban Wendling /* reads a PHP >= 7.3 HereDoc or a NowDoc (the part after the <<<).
6473ae02089SMasatake YAMATO  * 	<<<[ \t]*(ID|'ID'|"ID")
6483ae02089SMasatake YAMATO  * 	...
64916798065SColomban Wendling  * 	[ \t]*ID[^:indent-char:];?
6503ae02089SMasatake YAMATO  *
6513ae02089SMasatake YAMATO  * note that:
6523ae02089SMasatake YAMATO  *  1) starting ID must be immediately followed by a newline;
6533ae02089SMasatake YAMATO  *  2) closing ID is the same as opening one;
65416798065SColomban Wendling  *  3) closing ID must not be immediately followed by an identifier character;
65516798065SColomban Wendling  *  4) optional indentation of the closing ID is stripped from body lines,
65616798065SColomban Wendling  *     which lines must have the exact same prefix indentation.
6573ae02089SMasatake YAMATO  *
65816798065SColomban Wendling  * This is slightly relaxed from PHP < 7.3, where the closing ID had to be the
65916798065SColomban Wendling  * only thing on its line, with the only exception of a semicolon right after
66016798065SColomban Wendling  * the ID.
66116798065SColomban Wendling  *
66216798065SColomban Wendling  * Example of a single valid heredoc:
6633ae02089SMasatake YAMATO  * 	<<< FOO
6643ae02089SMasatake YAMATO  * 	something
6653ae02089SMasatake YAMATO  * 	something else
66616798065SColomban Wendling  * 	FOO_this is not an end
6673ae02089SMasatake YAMATO  * 	FOO;
6683ae02089SMasatake YAMATO  * 	# previous line was the end, but the semicolon wasn't required
66916798065SColomban Wendling  *
67016798065SColomban Wendling  * Another example using indentation and more code after the heredoc:
67116798065SColomban Wendling  * 	<<<FOO
67216798065SColomban Wendling  * 		something
67316798065SColomban Wendling  * 		something else
67416798065SColomban Wendling  * 		FOO . 'hello';
67516798065SColomban Wendling  * 	# the heredoc ends at FOO, and leading tabs are stripped from the body.
67616798065SColomban Wendling  * 	# ". 'hello'" is a normal concatenation operator and the string "hello".
6773ae02089SMasatake YAMATO  */
parseHeredoc(vString * const string)6783ae02089SMasatake YAMATO static void parseHeredoc (vString *const string)
6793ae02089SMasatake YAMATO {
6803ae02089SMasatake YAMATO 	int c;
6813ae02089SMasatake YAMATO 	unsigned int len;
6823ae02089SMasatake YAMATO 	char delimiter[64]; /* arbitrary limit, but more is crazy anyway */
6833ae02089SMasatake YAMATO 	int quote = 0;
6843ae02089SMasatake YAMATO 
6853ae02089SMasatake YAMATO 	do
6863ae02089SMasatake YAMATO 	{
687018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
6883ae02089SMasatake YAMATO 	}
6893ae02089SMasatake YAMATO 	while (c == ' ' || c == '\t');
6903ae02089SMasatake YAMATO 
6913ae02089SMasatake YAMATO 	if (c == '\'' || c == '"')
6923ae02089SMasatake YAMATO 	{
6933ae02089SMasatake YAMATO 		quote = c;
694018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
6953ae02089SMasatake YAMATO 	}
696158a3387SMasatake YAMATO 	for (len = 0; len < ARRAY_SIZE (delimiter) - 1; len++)
6973ae02089SMasatake YAMATO 	{
6983ae02089SMasatake YAMATO 		if (! isIdentChar (c))
6993ae02089SMasatake YAMATO 			break;
7003ae02089SMasatake YAMATO 		delimiter[len] = (char) c;
701018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
7023ae02089SMasatake YAMATO 	}
7033ae02089SMasatake YAMATO 	delimiter[len] = 0;
7043ae02089SMasatake YAMATO 
7053ae02089SMasatake YAMATO 	if (len == 0) /* no delimiter, give up */
7063ae02089SMasatake YAMATO 		goto error;
7073ae02089SMasatake YAMATO 	if (quote)
7083ae02089SMasatake YAMATO 	{
7093ae02089SMasatake YAMATO 		if (c != quote) /* no closing quote for quoted identifier, give up */
7103ae02089SMasatake YAMATO 			goto error;
711018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
7123ae02089SMasatake YAMATO 	}
7133ae02089SMasatake YAMATO 	if (c != '\r' && c != '\n') /* missing newline, give up */
7143ae02089SMasatake YAMATO 		goto error;
7153ae02089SMasatake YAMATO 
7163ae02089SMasatake YAMATO 	do
7173ae02089SMasatake YAMATO 	{
718018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
7193ae02089SMasatake YAMATO 
7203ae02089SMasatake YAMATO 		vStringPut (string, (char) c);
7214c42296bSColomban Wendling 		if (c == '\r' || c == '\n')
7223ae02089SMasatake YAMATO 		{
7234c42296bSColomban Wendling 			/* new line, check for a delimiter right after.  No need to handle
7244c42296bSColomban Wendling 			 * CRLF, getcFromInputFile() normalizes it to LF already. */
7254c42296bSColomban Wendling 			const size_t prev_string_len = vStringLength (string) - 1;
7264c42296bSColomban Wendling 			size_t indent_len = 0;
7273ae02089SMasatake YAMATO 
728018bce0bSMasatake YAMATO 			c = getcFromInputFile ();
72916798065SColomban Wendling 			while (c == ' ' || c == '\t')
73016798065SColomban Wendling 			{
73116798065SColomban Wendling 				vStringPut (string, (char) c);
73216798065SColomban Wendling 				c = getcFromInputFile ();
7334c42296bSColomban Wendling 				indent_len++;
73416798065SColomban Wendling 			}
73516798065SColomban Wendling 
7363ae02089SMasatake YAMATO 			for (len = 0; c != 0 && (c - delimiter[len]) == 0; len++)
737018bce0bSMasatake YAMATO 				c = getcFromInputFile ();
7383ae02089SMasatake YAMATO 
7393ae02089SMasatake YAMATO 			if (delimiter[len] != 0)
74061f14fa5SMasatake YAMATO 				ungetcToInputFile (c);
74116798065SColomban Wendling 			else if (! isIdentChar (c))
7423ae02089SMasatake YAMATO 			{
74316798065SColomban Wendling 				/* line start matched the delimiter and has a separator, we're done */
74461f14fa5SMasatake YAMATO 				ungetcToInputFile (c);
7454c42296bSColomban Wendling 
7464c42296bSColomban Wendling 				/* strip trailing newline and indent of the end delimiter */
7474c42296bSColomban Wendling 				vStringTruncate (string, prev_string_len);
7484c42296bSColomban Wendling 
7494c42296bSColomban Wendling 				/* strip indent from the value if needed */
7504c42296bSColomban Wendling 				if (indent_len > 0)
7514c42296bSColomban Wendling 					stripHeredocIndent (string, indent_len);
7523ae02089SMasatake YAMATO 				break;
7533ae02089SMasatake YAMATO 			}
7543ae02089SMasatake YAMATO 			/* if we are here it wasn't a delimiter, so put everything in the
7553ae02089SMasatake YAMATO 			 * string */
7563ae02089SMasatake YAMATO 			vStringNCatS (string, delimiter, len);
7573ae02089SMasatake YAMATO 		}
7583ae02089SMasatake YAMATO 	}
7593ae02089SMasatake YAMATO 	while (c != EOF);
7603ae02089SMasatake YAMATO 
7613ae02089SMasatake YAMATO 	return;
7623ae02089SMasatake YAMATO 
7633ae02089SMasatake YAMATO error:
76461f14fa5SMasatake YAMATO 	ungetcToInputFile (c);
7653ae02089SMasatake YAMATO }
7663ae02089SMasatake YAMATO 
parseIdentifier(vString * const string,const int firstChar)7673ae02089SMasatake YAMATO static void parseIdentifier (vString *const string, const int firstChar)
7683ae02089SMasatake YAMATO {
7693ae02089SMasatake YAMATO 	int c = firstChar;
7703ae02089SMasatake YAMATO 	do
7713ae02089SMasatake YAMATO 	{
7723ae02089SMasatake YAMATO 		vStringPut (string, (char) c);
773018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
7743ae02089SMasatake YAMATO 	} while (isIdentChar (c));
77561f14fa5SMasatake YAMATO 	ungetcToInputFile (c);
7763ae02089SMasatake YAMATO }
7773ae02089SMasatake YAMATO 
isSpace(int c)778ce990805SThomas Braun static bool isSpace (int c)
7793ae02089SMasatake YAMATO {
7803ae02089SMasatake YAMATO 	return (c == '\t' || c == ' ' || c == '\v' ||
7813ae02089SMasatake YAMATO 			c == '\n' || c == '\r' || c == '\f');
7823ae02089SMasatake YAMATO }
7833ae02089SMasatake YAMATO 
skipWhitespaces(int c)7843ae02089SMasatake YAMATO static int skipWhitespaces (int c)
7853ae02089SMasatake YAMATO {
7863ae02089SMasatake YAMATO 	while (isSpace (c))
787018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
7883ae02089SMasatake YAMATO 	return c;
7893ae02089SMasatake YAMATO }
7903ae02089SMasatake YAMATO 
7913ae02089SMasatake YAMATO /* <script[:white:]+language[:white:]*=[:white:]*(php|'php'|"php")[:white:]*>
7923ae02089SMasatake YAMATO  *
7933ae02089SMasatake YAMATO  * This is ugly, but the whole "<script language=php>" tag is and we can't
7943ae02089SMasatake YAMATO  * really do better without adding a lot of code only for this */
isOpenScriptLanguagePhp(int c)795ce990805SThomas Braun static bool isOpenScriptLanguagePhp (int c)
7963ae02089SMasatake YAMATO {
7973ae02089SMasatake YAMATO 	int quote = 0;
7983ae02089SMasatake YAMATO 
7993ae02089SMasatake YAMATO 	/* <script[:white:]+language[:white:]*= */
8003ae02089SMasatake YAMATO 	if (c                                   != '<' ||
801018bce0bSMasatake YAMATO 		tolower ((c = getcFromInputFile ()))         != 's' ||
802018bce0bSMasatake YAMATO 		tolower ((c = getcFromInputFile ()))         != 'c' ||
803018bce0bSMasatake YAMATO 		tolower ((c = getcFromInputFile ()))         != 'r' ||
804018bce0bSMasatake YAMATO 		tolower ((c = getcFromInputFile ()))         != 'i' ||
805018bce0bSMasatake YAMATO 		tolower ((c = getcFromInputFile ()))         != 'p' ||
806018bce0bSMasatake YAMATO 		tolower ((c = getcFromInputFile ()))         != 't' ||
807018bce0bSMasatake YAMATO 		! isSpace ((c = getcFromInputFile ()))              ||
8083ae02089SMasatake YAMATO 		tolower ((c = skipWhitespaces (c))) != 'l' ||
809018bce0bSMasatake YAMATO 		tolower ((c = getcFromInputFile ()))         != 'a' ||
810018bce0bSMasatake YAMATO 		tolower ((c = getcFromInputFile ()))         != 'n' ||
811018bce0bSMasatake YAMATO 		tolower ((c = getcFromInputFile ()))         != 'g' ||
812018bce0bSMasatake YAMATO 		tolower ((c = getcFromInputFile ()))         != 'u' ||
813018bce0bSMasatake YAMATO 		tolower ((c = getcFromInputFile ()))         != 'a' ||
814018bce0bSMasatake YAMATO 		tolower ((c = getcFromInputFile ()))         != 'g' ||
815018bce0bSMasatake YAMATO 		tolower ((c = getcFromInputFile ()))         != 'e' ||
816018bce0bSMasatake YAMATO 		(c = skipWhitespaces (getcFromInputFile ())) != '=')
817ce990805SThomas Braun 		return false;
8183ae02089SMasatake YAMATO 
8193ae02089SMasatake YAMATO 	/* (php|'php'|"php")> */
820018bce0bSMasatake YAMATO 	c = skipWhitespaces (getcFromInputFile ());
8213ae02089SMasatake YAMATO 	if (c == '"' || c == '\'')
8223ae02089SMasatake YAMATO 	{
8233ae02089SMasatake YAMATO 		quote = c;
824018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
8253ae02089SMasatake YAMATO 	}
8263ae02089SMasatake YAMATO 	if (tolower (c)                         != 'p' ||
827018bce0bSMasatake YAMATO 		tolower ((c = getcFromInputFile ()))         != 'h' ||
828018bce0bSMasatake YAMATO 		tolower ((c = getcFromInputFile ()))         != 'p' ||
829018bce0bSMasatake YAMATO 		(quote != 0 && (c = getcFromInputFile ()) != quote) ||
830018bce0bSMasatake YAMATO 		(c = skipWhitespaces (getcFromInputFile ())) != '>')
831ce990805SThomas Braun 		return false;
8323ae02089SMasatake YAMATO 
833ce990805SThomas Braun 	return true;
8343ae02089SMasatake YAMATO }
8353ae02089SMasatake YAMATO 
findPhpStart(void)8363ae02089SMasatake YAMATO static int findPhpStart (void)
8373ae02089SMasatake YAMATO {
8383ae02089SMasatake YAMATO 	int c;
8393ae02089SMasatake YAMATO 	do
8403ae02089SMasatake YAMATO 	{
841018bce0bSMasatake YAMATO 		if ((c = getcFromInputFile ()) == '<')
8423ae02089SMasatake YAMATO 		{
843018bce0bSMasatake YAMATO 			c = getcFromInputFile ();
844a34c80d3SColomban Wendling 			/* <?, <?= and <?php, but not <?xml */
8453ae02089SMasatake YAMATO 			if (c == '?')
8463ae02089SMasatake YAMATO 			{
847a34c80d3SColomban Wendling 				c = getcFromInputFile ();
848a34c80d3SColomban Wendling 				/* echo tag */
849a34c80d3SColomban Wendling 				if (c == '=')
850a34c80d3SColomban Wendling 					c = getcFromInputFile ();
8513ae02089SMasatake YAMATO 				/* don't enter PHP mode on "<?xml", yet still support short open tags (<?) */
852a34c80d3SColomban Wendling 				else if (tolower (c)                          != 'x' ||
853018bce0bSMasatake YAMATO 				         tolower ((c = getcFromInputFile ())) != 'm' ||
854018bce0bSMasatake YAMATO 				         tolower ((c = getcFromInputFile ())) != 'l')
8553ae02089SMasatake YAMATO 				{
8563ae02089SMasatake YAMATO 					break;
8573ae02089SMasatake YAMATO 				}
8583ae02089SMasatake YAMATO 			}
8593ae02089SMasatake YAMATO 			/* <script language="php"> */
8603ae02089SMasatake YAMATO 			else
8613ae02089SMasatake YAMATO 			{
86261f14fa5SMasatake YAMATO 				ungetcToInputFile (c);
8633ae02089SMasatake YAMATO 				if (isOpenScriptLanguagePhp ('<'))
8643ae02089SMasatake YAMATO 					break;
8653ae02089SMasatake YAMATO 			}
8663ae02089SMasatake YAMATO 		}
8673ae02089SMasatake YAMATO 	}
8683ae02089SMasatake YAMATO 	while (c != EOF);
8693ae02089SMasatake YAMATO 
8703ae02089SMasatake YAMATO 	return c;
8713ae02089SMasatake YAMATO }
8723ae02089SMasatake YAMATO 
skipSingleComment(void)8733ae02089SMasatake YAMATO static int skipSingleComment (void)
8743ae02089SMasatake YAMATO {
8753ae02089SMasatake YAMATO 	int c;
8763ae02089SMasatake YAMATO 	do
8773ae02089SMasatake YAMATO 	{
878018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
8793ae02089SMasatake YAMATO 		/* ?> in single-line comments leaves PHP mode */
88005d5ad5fSColomban Wendling 		if (c == '?')
8813ae02089SMasatake YAMATO 		{
882018bce0bSMasatake YAMATO 			int next = getcFromInputFile ();
8833ae02089SMasatake YAMATO 			if (next == '>')
884ce990805SThomas Braun 				InPhp = false;
8853ae02089SMasatake YAMATO 			else
88661f14fa5SMasatake YAMATO 				ungetcToInputFile (next);
8873ae02089SMasatake YAMATO 		}
8883ae02089SMasatake YAMATO 	} while (InPhp && c != EOF && c != '\n' && c != '\r');
8893ae02089SMasatake YAMATO 	return c;
8903ae02089SMasatake YAMATO }
8913ae02089SMasatake YAMATO 
readToken(tokenInfo * const token)8923ae02089SMasatake YAMATO static void readToken (tokenInfo *const token)
8933ae02089SMasatake YAMATO {
8943ae02089SMasatake YAMATO 	int c;
89575ba24d4SColomban Wendling 	bool nextMayBeKeyword = true;
8963ae02089SMasatake YAMATO 
8973ae02089SMasatake YAMATO 	token->type		= TOKEN_UNDEFINED;
8983ae02089SMasatake YAMATO 	token->keyword	= KEYWORD_NONE;
8993ae02089SMasatake YAMATO 	vStringClear (token->string);
9003ae02089SMasatake YAMATO 
9013ae02089SMasatake YAMATO getNextChar:
9023ae02089SMasatake YAMATO 
9033ae02089SMasatake YAMATO 	if (! InPhp)
9043ae02089SMasatake YAMATO 	{
905*f476dfe1SMasatake YAMATO 		unsigned long startSourceLineNumber = getSourceLineNumber ();
906*f476dfe1SMasatake YAMATO 		unsigned long startLineNumber = startSourceLineNumber;
907*f476dfe1SMasatake YAMATO 		int startLineOffset = getInputLineOffset ();
908*f476dfe1SMasatake YAMATO 
9093ae02089SMasatake YAMATO 		c = findPhpStart ();
9103ae02089SMasatake YAMATO 		if (c != EOF)
911ce990805SThomas Braun 			InPhp = true;
912*f476dfe1SMasatake YAMATO 
913*f476dfe1SMasatake YAMATO 		unsigned long endLineNumber = getInputLineNumber ();
914*f476dfe1SMasatake YAMATO 		int endLineOffset = getInputLineOffset ();
915*f476dfe1SMasatake YAMATO 
916*f476dfe1SMasatake YAMATO 		if ((startLineNumber != endLineNumber)
917*f476dfe1SMasatake YAMATO 			|| (startLineOffset != endLineOffset))
918*f476dfe1SMasatake YAMATO 			makePromise ("HTML", startLineNumber, startLineOffset,
919*f476dfe1SMasatake YAMATO 						 endLineNumber, endLineOffset, startSourceLineNumber);
9203ae02089SMasatake YAMATO 	}
9213ae02089SMasatake YAMATO 	else
922018bce0bSMasatake YAMATO 		c = getcFromInputFile ();
9233ae02089SMasatake YAMATO 
9243ae02089SMasatake YAMATO 	c = skipWhitespaces (c);
9253ae02089SMasatake YAMATO 
926a31b37dcSMasatake YAMATO 	token->lineNumber   = getInputLineNumber ();
9273ae02089SMasatake YAMATO 	token->filePosition = getInputFilePosition ();
9283ae02089SMasatake YAMATO 
9293ae02089SMasatake YAMATO 	switch (c)
9303ae02089SMasatake YAMATO 	{
9313ae02089SMasatake YAMATO 		case EOF: token->type = TOKEN_EOF;					break;
9323ae02089SMasatake YAMATO 		case '(': token->type = TOKEN_OPEN_PAREN;			break;
9333ae02089SMasatake YAMATO 		case ')': token->type = TOKEN_CLOSE_PAREN;			break;
9343ae02089SMasatake YAMATO 		case ';': token->type = TOKEN_SEMICOLON;			break;
9353ae02089SMasatake YAMATO 		case ',': token->type = TOKEN_COMMA;				break;
9363ae02089SMasatake YAMATO 		case '.': token->type = TOKEN_PERIOD;				break;
9373ae02089SMasatake YAMATO 		case '{': token->type = TOKEN_OPEN_CURLY;			break;
9383ae02089SMasatake YAMATO 		case '}': token->type = TOKEN_CLOSE_CURLY;			break;
9393ae02089SMasatake YAMATO 		case '[': token->type = TOKEN_OPEN_SQUARE;			break;
9403ae02089SMasatake YAMATO 		case ']': token->type = TOKEN_CLOSE_SQUARE;			break;
9413ae02089SMasatake YAMATO 		case '&': token->type = TOKEN_AMPERSAND;			break;
942acbcd162SColomban Wendling 		case '\\': token->type = TOKEN_BACKSLASH;			break;
9433ae02089SMasatake YAMATO 
94475ba24d4SColomban Wendling 		case ':':
94575ba24d4SColomban Wendling 		{
94675ba24d4SColomban Wendling 			int d = getcFromInputFile ();
94775ba24d4SColomban Wendling 			if (d == c) /* :: */
94875ba24d4SColomban Wendling 			{
94975ba24d4SColomban Wendling 				nextMayBeKeyword = false;
95075ba24d4SColomban Wendling 				token->type = TOKEN_OPERATOR;
95175ba24d4SColomban Wendling 			}
95275ba24d4SColomban Wendling 			else
95375ba24d4SColomban Wendling 			{
95475ba24d4SColomban Wendling 				ungetcToInputFile (d);
95575ba24d4SColomban Wendling 				token->type = TOKEN_COLON;
95675ba24d4SColomban Wendling 			}
95775ba24d4SColomban Wendling 			break;
95875ba24d4SColomban Wendling 		}
95975ba24d4SColomban Wendling 
9603ae02089SMasatake YAMATO 		case '=':
9613ae02089SMasatake YAMATO 		{
962018bce0bSMasatake YAMATO 			int d = getcFromInputFile ();
9633ae02089SMasatake YAMATO 			if (d == '=' || d == '>')
9643ae02089SMasatake YAMATO 				token->type = TOKEN_OPERATOR;
9653ae02089SMasatake YAMATO 			else
9663ae02089SMasatake YAMATO 			{
96761f14fa5SMasatake YAMATO 				ungetcToInputFile (d);
9683ae02089SMasatake YAMATO 				token->type = TOKEN_EQUAL_SIGN;
9693ae02089SMasatake YAMATO 			}
9703ae02089SMasatake YAMATO 			break;
9713ae02089SMasatake YAMATO 		}
9723ae02089SMasatake YAMATO 
9733ae02089SMasatake YAMATO 		case '\'':
9743ae02089SMasatake YAMATO 		case '"':
9753ae02089SMasatake YAMATO 			token->type = TOKEN_STRING;
9763ae02089SMasatake YAMATO 			parseString (token->string, c);
977a31b37dcSMasatake YAMATO 			token->lineNumber = getInputLineNumber ();
9783ae02089SMasatake YAMATO 			token->filePosition = getInputFilePosition ();
9793ae02089SMasatake YAMATO 			break;
9803ae02089SMasatake YAMATO 
9813ae02089SMasatake YAMATO 		case '<':
9823ae02089SMasatake YAMATO 		{
983018bce0bSMasatake YAMATO 			int d = getcFromInputFile ();
9843ae02089SMasatake YAMATO 			if (d == '/')
9853ae02089SMasatake YAMATO 			{
9863ae02089SMasatake YAMATO 				/* </script[:white:]*> */
987018bce0bSMasatake YAMATO 				if (tolower ((d = getcFromInputFile ())) == 's' &&
988018bce0bSMasatake YAMATO 					tolower ((d = getcFromInputFile ())) == 'c' &&
989018bce0bSMasatake YAMATO 					tolower ((d = getcFromInputFile ())) == 'r' &&
990018bce0bSMasatake YAMATO 					tolower ((d = getcFromInputFile ())) == 'i' &&
991018bce0bSMasatake YAMATO 					tolower ((d = getcFromInputFile ())) == 'p' &&
992018bce0bSMasatake YAMATO 					tolower ((d = getcFromInputFile ())) == 't' &&
993018bce0bSMasatake YAMATO 					(d = skipWhitespaces (getcFromInputFile ())) == '>')
9943ae02089SMasatake YAMATO 				{
995ce990805SThomas Braun 					InPhp = false;
9963ae02089SMasatake YAMATO 					goto getNextChar;
9973ae02089SMasatake YAMATO 				}
9983ae02089SMasatake YAMATO 				else
9993ae02089SMasatake YAMATO 				{
100061f14fa5SMasatake YAMATO 					ungetcToInputFile (d);
10013ae02089SMasatake YAMATO 					token->type = TOKEN_UNDEFINED;
10023ae02089SMasatake YAMATO 				}
10033ae02089SMasatake YAMATO 			}
1004018bce0bSMasatake YAMATO 			else if (d == '<' && (d = getcFromInputFile ()) == '<')
10053ae02089SMasatake YAMATO 			{
10063ae02089SMasatake YAMATO 				token->type = TOKEN_STRING;
10073ae02089SMasatake YAMATO 				parseHeredoc (token->string);
10083ae02089SMasatake YAMATO 			}
10093ae02089SMasatake YAMATO 			else
10103ae02089SMasatake YAMATO 			{
101161f14fa5SMasatake YAMATO 				ungetcToInputFile (d);
10123ae02089SMasatake YAMATO 				token->type = TOKEN_UNDEFINED;
10133ae02089SMasatake YAMATO 			}
10143ae02089SMasatake YAMATO 			break;
10153ae02089SMasatake YAMATO 		}
10163ae02089SMasatake YAMATO 
10173ae02089SMasatake YAMATO 		case '#': /* comment */
10183ae02089SMasatake YAMATO 			skipSingleComment ();
10193ae02089SMasatake YAMATO 			goto getNextChar;
10203ae02089SMasatake YAMATO 			break;
10213ae02089SMasatake YAMATO 
10223ae02089SMasatake YAMATO 		case '+':
10233ae02089SMasatake YAMATO 		case '-':
10243ae02089SMasatake YAMATO 		case '*':
10253ae02089SMasatake YAMATO 		case '%':
10263ae02089SMasatake YAMATO 		{
1027018bce0bSMasatake YAMATO 			int d = getcFromInputFile ();
102875ba24d4SColomban Wendling 			if (c == '-' && d == '>')
102975ba24d4SColomban Wendling 				nextMayBeKeyword = false;
103075ba24d4SColomban Wendling 			else if (d != '=')
103161f14fa5SMasatake YAMATO 				ungetcToInputFile (d);
10323ae02089SMasatake YAMATO 			token->type = TOKEN_OPERATOR;
10333ae02089SMasatake YAMATO 			break;
10343ae02089SMasatake YAMATO 		}
10353ae02089SMasatake YAMATO 
10363ae02089SMasatake YAMATO 		case '/': /* division or comment start */
10373ae02089SMasatake YAMATO 		{
1038018bce0bSMasatake YAMATO 			int d = getcFromInputFile ();
10393ae02089SMasatake YAMATO 			if (d == '/') /* single-line comment */
10403ae02089SMasatake YAMATO 			{
10413ae02089SMasatake YAMATO 				skipSingleComment ();
10423ae02089SMasatake YAMATO 				goto getNextChar;
10433ae02089SMasatake YAMATO 			}
10443ae02089SMasatake YAMATO 			else if (d == '*')
10453ae02089SMasatake YAMATO 			{
10463ae02089SMasatake YAMATO 				do
10473ae02089SMasatake YAMATO 				{
10483ae02089SMasatake YAMATO 					c = skipToCharacter ('*');
10493ae02089SMasatake YAMATO 					if (c != EOF)
10503ae02089SMasatake YAMATO 					{
1051018bce0bSMasatake YAMATO 						c = getcFromInputFile ();
10523ae02089SMasatake YAMATO 						if (c == '/')
10533ae02089SMasatake YAMATO 							break;
10543ae02089SMasatake YAMATO 						else
105561f14fa5SMasatake YAMATO 							ungetcToInputFile (c);
10563ae02089SMasatake YAMATO 					}
10573ae02089SMasatake YAMATO 				} while (c != EOF && c != '\0');
10583ae02089SMasatake YAMATO 				goto getNextChar;
10593ae02089SMasatake YAMATO 			}
10603ae02089SMasatake YAMATO 			else
10613ae02089SMasatake YAMATO 			{
10623ae02089SMasatake YAMATO 				if (d != '=')
106361f14fa5SMasatake YAMATO 					ungetcToInputFile (d);
10643ae02089SMasatake YAMATO 				token->type = TOKEN_OPERATOR;
10653ae02089SMasatake YAMATO 			}
10663ae02089SMasatake YAMATO 			break;
10673ae02089SMasatake YAMATO 		}
10683ae02089SMasatake YAMATO 
10693ae02089SMasatake YAMATO 		case '$': /* variable start */
10703ae02089SMasatake YAMATO 		{
1071018bce0bSMasatake YAMATO 			int d = getcFromInputFile ();
10723ae02089SMasatake YAMATO 			if (! isIdentChar (d))
10733ae02089SMasatake YAMATO 			{
107461f14fa5SMasatake YAMATO 				ungetcToInputFile (d);
10753ae02089SMasatake YAMATO 				token->type = TOKEN_UNDEFINED;
10763ae02089SMasatake YAMATO 			}
10773ae02089SMasatake YAMATO 			else
10783ae02089SMasatake YAMATO 			{
10793ae02089SMasatake YAMATO 				parseIdentifier (token->string, d);
10803ae02089SMasatake YAMATO 				token->type = TOKEN_VARIABLE;
10813ae02089SMasatake YAMATO 			}
10823ae02089SMasatake YAMATO 			break;
10833ae02089SMasatake YAMATO 		}
10843ae02089SMasatake YAMATO 
10853ae02089SMasatake YAMATO 		case '?': /* maybe the end of the PHP chunk */
10863ae02089SMasatake YAMATO 		{
1087018bce0bSMasatake YAMATO 			int d = getcFromInputFile ();
10883ae02089SMasatake YAMATO 			if (d == '>')
10893ae02089SMasatake YAMATO 			{
1090ce990805SThomas Braun 				InPhp = false;
10913ae02089SMasatake YAMATO 				goto getNextChar;
10923ae02089SMasatake YAMATO 			}
10933ae02089SMasatake YAMATO 			else
10943ae02089SMasatake YAMATO 			{
109561f14fa5SMasatake YAMATO 				ungetcToInputFile (d);
109651f37d45SMasatake YAMATO 				token->type = TOKEN_QMARK;
10973ae02089SMasatake YAMATO 			}
10983ae02089SMasatake YAMATO 			break;
10993ae02089SMasatake YAMATO 		}
11003ae02089SMasatake YAMATO 
11013ae02089SMasatake YAMATO 		default:
11023ae02089SMasatake YAMATO 			if (! isIdentChar (c))
11033ae02089SMasatake YAMATO 				token->type = TOKEN_UNDEFINED;
11043ae02089SMasatake YAMATO 			else
11053ae02089SMasatake YAMATO 			{
11063ae02089SMasatake YAMATO 				parseIdentifier (token->string, c);
110775ba24d4SColomban Wendling 				if (MayBeKeyword)
110831a85388SJiří Techet 					token->keyword = lookupCaseKeyword (vStringValue (token->string), getInputLanguage ());
110975ba24d4SColomban Wendling 				else
111075ba24d4SColomban Wendling 					token->keyword = KEYWORD_NONE;
111175ba24d4SColomban Wendling 
11123ae02089SMasatake YAMATO 				if (token->keyword == KEYWORD_NONE)
11133ae02089SMasatake YAMATO 					token->type = TOKEN_IDENTIFIER;
11143ae02089SMasatake YAMATO 				else
11153ae02089SMasatake YAMATO 					token->type = TOKEN_KEYWORD;
11163ae02089SMasatake YAMATO 			}
11173ae02089SMasatake YAMATO 			break;
11183ae02089SMasatake YAMATO 	}
11193ae02089SMasatake YAMATO 
11203ae02089SMasatake YAMATO 	if (token->type == TOKEN_SEMICOLON ||
11213ae02089SMasatake YAMATO 		token->type == TOKEN_OPEN_CURLY ||
11223ae02089SMasatake YAMATO 		token->type == TOKEN_CLOSE_CURLY)
11233ae02089SMasatake YAMATO 	{
11243ae02089SMasatake YAMATO 		/* reset current statement details on statement end, and when entering
11253ae02089SMasatake YAMATO 		 * a deeper scope.
11263ae02089SMasatake YAMATO 		 * it is a bit ugly to do this in readToken(), but it makes everything
11273ae02089SMasatake YAMATO 		 * a lot simpler. */
11283ae02089SMasatake YAMATO 		CurrentStatement.access = ACCESS_UNDEFINED;
11293ae02089SMasatake YAMATO 		CurrentStatement.impl = IMPL_UNDEFINED;
11303ae02089SMasatake YAMATO 	}
113175ba24d4SColomban Wendling 
113275ba24d4SColomban Wendling 	MayBeKeyword = nextMayBeKeyword;
11333ae02089SMasatake YAMATO }
11343ae02089SMasatake YAMATO 
readQualifiedName(tokenInfo * const token,vString * name,tokenInfo * const lastToken)1135c74b5ff0SMasatake YAMATO static void readQualifiedName (tokenInfo *const token, vString *name,
1136c74b5ff0SMasatake YAMATO                                tokenInfo *const lastToken)
1137c74b5ff0SMasatake YAMATO {
1138c74b5ff0SMasatake YAMATO 	while (token->type == TOKEN_IDENTIFIER || token->type == TOKEN_BACKSLASH)
1139c74b5ff0SMasatake YAMATO 	{
1140c74b5ff0SMasatake YAMATO 		if (name)
1141c74b5ff0SMasatake YAMATO 		{
1142c74b5ff0SMasatake YAMATO 			if (token->type == TOKEN_BACKSLASH)
1143c74b5ff0SMasatake YAMATO 				vStringPut (name, '\\');
1144c74b5ff0SMasatake YAMATO 			else
1145c74b5ff0SMasatake YAMATO 				vStringCat (name, token->string);
1146c74b5ff0SMasatake YAMATO 		}
1147c74b5ff0SMasatake YAMATO 		if (lastToken)
1148c74b5ff0SMasatake YAMATO 			copyToken (lastToken, token, true);
1149c74b5ff0SMasatake YAMATO 		readToken (token);
1150c74b5ff0SMasatake YAMATO 	}
1151c74b5ff0SMasatake YAMATO }
1152c74b5ff0SMasatake YAMATO 
11533ae02089SMasatake YAMATO static void enterScope (tokenInfo *const parentToken,
11543ae02089SMasatake YAMATO 						const vString *const extraScope,
11553ae02089SMasatake YAMATO 						const int parentKind);
11563ae02089SMasatake YAMATO 
skipOverParens(tokenInfo * token)1157d0d29d63SColomban Wendling static void skipOverParens (tokenInfo *token)
1158d0d29d63SColomban Wendling {
1159d0d29d63SColomban Wendling 	if (token->type == TOKEN_OPEN_PAREN)
1160d0d29d63SColomban Wendling 	{
1161d0d29d63SColomban Wendling 		int depth = 1;
1162d0d29d63SColomban Wendling 
1163d0d29d63SColomban Wendling 		do
1164d0d29d63SColomban Wendling 		{
1165d0d29d63SColomban Wendling 			readToken (token);
1166d0d29d63SColomban Wendling 			switch (token->type)
1167d0d29d63SColomban Wendling 			{
1168d0d29d63SColomban Wendling 				case TOKEN_OPEN_PAREN:  depth++; break;
1169d0d29d63SColomban Wendling 				case TOKEN_CLOSE_PAREN: depth--; break;
1170d0d29d63SColomban Wendling 				default: break;
1171d0d29d63SColomban Wendling 			}
1172d0d29d63SColomban Wendling 		}
1173d0d29d63SColomban Wendling 		while (token->type != TOKEN_EOF && depth > 0);
1174d0d29d63SColomban Wendling 
1175d0d29d63SColomban Wendling 		readToken (token);
1176d0d29d63SColomban Wendling 	}
1177d0d29d63SColomban Wendling }
1178d0d29d63SColomban Wendling 
11793ae02089SMasatake YAMATO /* parses a class or an interface:
11803ae02089SMasatake YAMATO  * 	class Foo {}
11813ae02089SMasatake YAMATO  * 	class Foo extends Bar {}
11823ae02089SMasatake YAMATO  * 	class Foo extends Bar implements iFoo, iBar {}
11833ae02089SMasatake YAMATO  * 	interface iFoo {}
1184d0d29d63SColomban Wendling  * 	interface iBar extends iFoo {}
1185d0d29d63SColomban Wendling  *
1186d0d29d63SColomban Wendling  * if @name is not NULL, parses an anonymous class with name @name
1187d0d29d63SColomban Wendling  * 	new class {}
1188d0d29d63SColomban Wendling  * 	new class(1, 2) {}
1189d0d29d63SColomban Wendling  * 	new class(1, 2) extends Foo implements iFoo, iBar {} */
parseClassOrIface(tokenInfo * const token,const phpKind kind,const tokenInfo * name)1190ce990805SThomas Braun static bool parseClassOrIface (tokenInfo *const token, const phpKind kind,
1191d0d29d63SColomban Wendling                                   const tokenInfo *name)
11923ae02089SMasatake YAMATO {
1193ce990805SThomas Braun 	bool readNext = true;
11943ae02089SMasatake YAMATO 	implType impl = CurrentStatement.impl;
1195d0d29d63SColomban Wendling 	tokenInfo *nameFree = NULL;
11963ae02089SMasatake YAMATO 	vString *inheritance = NULL;
1197f176923cSMasatake YAMATO 	vString *parent = NULL;
11983ae02089SMasatake YAMATO 
11993ae02089SMasatake YAMATO 	readToken (token);
1200d0d29d63SColomban Wendling 	if (name) /* anonymous class */
1201d0d29d63SColomban Wendling 	{
1202d0d29d63SColomban Wendling 		/* skip possible construction arguments */
1203d0d29d63SColomban Wendling 		skipOverParens (token);
1204d0d29d63SColomban Wendling 	}
1205d0d29d63SColomban Wendling 	else /* normal, named class */
1206d0d29d63SColomban Wendling 	{
12073ae02089SMasatake YAMATO 		if (token->type != TOKEN_IDENTIFIER)
1208ce990805SThomas Braun 			return false;
12093ae02089SMasatake YAMATO 
1210d0d29d63SColomban Wendling 		name = nameFree = newToken ();
1211ce990805SThomas Braun 		copyToken (nameFree, token, true);
1212d0d29d63SColomban Wendling 
1213d0d29d63SColomban Wendling 		readToken (token);
1214d0d29d63SColomban Wendling 	}
12153ae02089SMasatake YAMATO 
12163ae02089SMasatake YAMATO 	inheritance = vStringNew ();
121759282227SMasatake YAMATO 	/* read every identifiers, keywords and commas, and assume each
121859282227SMasatake YAMATO 	 *  identifier (not keyword) is an inheritance
121959282227SMasatake YAMATO 	 * (like in "class Foo extends Bar implements iA, iB") */
1220f176923cSMasatake YAMATO 	enum { inheritance_initial,
1221f176923cSMasatake YAMATO 		   inheritance_extends,
1222f176923cSMasatake YAMATO 		   inheritance_implements
1223f176923cSMasatake YAMATO 	} istat = inheritance_initial;
12242c4744daSColomban Wendling 	while (token->type == TOKEN_IDENTIFIER ||
1225810c6fdfSColomban Wendling 	       token->type == TOKEN_BACKSLASH ||
12262c4744daSColomban Wendling 	       token->type == TOKEN_KEYWORD ||
12272c4744daSColomban Wendling 	       token->type == TOKEN_COMMA)
12283ae02089SMasatake YAMATO 	{
1229810c6fdfSColomban Wendling 		if (token->type == TOKEN_IDENTIFIER || token->type == TOKEN_BACKSLASH)
12303ae02089SMasatake YAMATO 		{
1231810c6fdfSColomban Wendling 			vString *qualifiedName = vStringNew ();
1232810c6fdfSColomban Wendling 
1233810c6fdfSColomban Wendling 			readQualifiedName (token, qualifiedName, NULL);
12343ae02089SMasatake YAMATO 			if (vStringLength (inheritance) > 0)
12353ae02089SMasatake YAMATO 				vStringPut (inheritance, ',');
1236810c6fdfSColomban Wendling 			vStringCat (inheritance, qualifiedName);
1237810c6fdfSColomban Wendling 			if (istat == inheritance_extends && !parent)
1238810c6fdfSColomban Wendling 				parent = qualifiedName;
1239810c6fdfSColomban Wendling 			else
1240810c6fdfSColomban Wendling 				vStringDelete (qualifiedName);
1241f176923cSMasatake YAMATO 		}
1242810c6fdfSColomban Wendling 		else
1243810c6fdfSColomban Wendling 		{
1244810c6fdfSColomban Wendling 			if (token->type == TOKEN_KEYWORD)
1245f176923cSMasatake YAMATO 			{
1246f176923cSMasatake YAMATO 				if (token->keyword == KEYWORD_extends)
1247f176923cSMasatake YAMATO 					istat = inheritance_extends;
1248f176923cSMasatake YAMATO 				else if (token->keyword == KEYWORD_implements)
1249f176923cSMasatake YAMATO 					istat = inheritance_implements;
12503ae02089SMasatake YAMATO 			}
1251d0d29d63SColomban Wendling 			readToken (token);
12523ae02089SMasatake YAMATO 		}
1253810c6fdfSColomban Wendling 	}
12543ae02089SMasatake YAMATO 
12553ae02089SMasatake YAMATO 	makeClassOrIfaceTag (kind, name, inheritance, impl);
12563ae02089SMasatake YAMATO 
12573ae02089SMasatake YAMATO 	if (token->type == TOKEN_OPEN_CURLY)
1258f176923cSMasatake YAMATO 	{
1259f176923cSMasatake YAMATO 		vString *backup = ParentClass;
1260f176923cSMasatake YAMATO 		ParentClass = parent;
1261bc9f0d91SColomban Wendling 		enterScope (token, name->string, kind);
1262f176923cSMasatake YAMATO 		ParentClass = backup;
1263f176923cSMasatake YAMATO 	}
12643ae02089SMasatake YAMATO 	else
1265ce990805SThomas Braun 		readNext = false;
12663ae02089SMasatake YAMATO 
1267d0d29d63SColomban Wendling 	if (nameFree)
1268d0d29d63SColomban Wendling 		deleteToken (nameFree);
1269f176923cSMasatake YAMATO 	vStringDelete (parent);
12703ae02089SMasatake YAMATO 	vStringDelete (inheritance);
12713ae02089SMasatake YAMATO 
12723ae02089SMasatake YAMATO 	return readNext;
12733ae02089SMasatake YAMATO }
12743ae02089SMasatake YAMATO 
12753ae02089SMasatake YAMATO /* parses a trait:
12763ae02089SMasatake YAMATO  * 	trait Foo {} */
parseTrait(tokenInfo * const token)1277ce990805SThomas Braun static bool parseTrait (tokenInfo *const token)
12783ae02089SMasatake YAMATO {
1279ce990805SThomas Braun 	bool readNext = true;
12803ae02089SMasatake YAMATO 	tokenInfo *name;
12813ae02089SMasatake YAMATO 
12823ae02089SMasatake YAMATO 	readToken (token);
12833ae02089SMasatake YAMATO 	if (token->type != TOKEN_IDENTIFIER)
1284ce990805SThomas Braun 		return false;
12853ae02089SMasatake YAMATO 
12863ae02089SMasatake YAMATO 	name = newToken ();
1287ce990805SThomas Braun 	copyToken (name, token, true);
12883ae02089SMasatake YAMATO 
12893ae02089SMasatake YAMATO 	makeSimplePhpTag (name, K_TRAIT, ACCESS_UNDEFINED);
12903ae02089SMasatake YAMATO 
12913ae02089SMasatake YAMATO 	readToken (token);
12923ae02089SMasatake YAMATO 	if (token->type == TOKEN_OPEN_CURLY)
12933ae02089SMasatake YAMATO 		enterScope (token, name->string, K_TRAIT);
12943ae02089SMasatake YAMATO 	else
1295ce990805SThomas Braun 		readNext = false;
12963ae02089SMasatake YAMATO 
12973ae02089SMasatake YAMATO 	deleteToken (name);
12983ae02089SMasatake YAMATO 
12993ae02089SMasatake YAMATO 	return readNext;
13003ae02089SMasatake YAMATO }
13013ae02089SMasatake YAMATO 
13023ae02089SMasatake YAMATO /* parse a function
13033ae02089SMasatake YAMATO  *
13043ae02089SMasatake YAMATO  * if @name is NULL, parses a normal function
13053ae02089SMasatake YAMATO  * 	function myfunc($foo, $bar) {}
13063ae02089SMasatake YAMATO  * 	function &myfunc($foo, $bar) {}
1307bf43dadcSColomban Wendling  * 	function myfunc($foo, $bar) : type {}
130884dbaf52SMasatake YAMATO  * 	function myfunc($foo, $bar) : ?type {}
13093ae02089SMasatake YAMATO  *
13103ae02089SMasatake YAMATO  * if @name is not NULL, parses an anonymous function with name @name
13113ae02089SMasatake YAMATO  * 	$foo = function($foo, $bar) {}
13123ae02089SMasatake YAMATO  * 	$foo = function&($foo, $bar) {}
1313bf43dadcSColomban Wendling  * 	$foo = function($foo, $bar) use ($x, &$y) {}
131484dbaf52SMasatake YAMATO  * 	$foo = function($foo, $bar) use ($x, &$y) : type {}
131584dbaf52SMasatake YAMATO  * 	$foo = function($foo, $bar) use ($x, &$y) : ?type {} */
parseFunction(tokenInfo * const token,const tokenInfo * name)1316ce990805SThomas Braun static bool parseFunction (tokenInfo *const token, const tokenInfo *name)
13173ae02089SMasatake YAMATO {
1318ce990805SThomas Braun 	bool readNext = true;
13193ae02089SMasatake YAMATO 	accessType access = CurrentStatement.access;
13203ae02089SMasatake YAMATO 	implType impl = CurrentStatement.impl;
13213ae02089SMasatake YAMATO 	tokenInfo *nameFree = NULL;
1322c74b5ff0SMasatake YAMATO 	vString *rtype = NULL;
1323c74b5ff0SMasatake YAMATO 	vString *arglist = NULL;
13243ae02089SMasatake YAMATO 
13253ae02089SMasatake YAMATO 	readToken (token);
13263ae02089SMasatake YAMATO 	/* skip a possible leading ampersand (return by reference) */
13273ae02089SMasatake YAMATO 	if (token->type == TOKEN_AMPERSAND)
13283ae02089SMasatake YAMATO 		readToken (token);
13293ae02089SMasatake YAMATO 
13303ae02089SMasatake YAMATO 	if (! name)
13313ae02089SMasatake YAMATO 	{
1332a1f68541SColomban Wendling 		if (token->type != TOKEN_IDENTIFIER && token->type != TOKEN_KEYWORD)
1333ce990805SThomas Braun 			return false;
13343ae02089SMasatake YAMATO 
13353ae02089SMasatake YAMATO 		name = nameFree = newToken ();
1336ce990805SThomas Braun 		copyToken (nameFree, token, true);
13373ae02089SMasatake YAMATO 		readToken (token);
13383ae02089SMasatake YAMATO 	}
13393ae02089SMasatake YAMATO 
13403ae02089SMasatake YAMATO 	if (token->type == TOKEN_OPEN_PAREN)
13413ae02089SMasatake YAMATO 	{
13423ae02089SMasatake YAMATO 		int depth = 1;
13433ae02089SMasatake YAMATO 
1344c74b5ff0SMasatake YAMATO 		arglist = vStringNew ();
13453ae02089SMasatake YAMATO 		vStringPut (arglist, '(');
13463ae02089SMasatake YAMATO 		do
13473ae02089SMasatake YAMATO 		{
13483ae02089SMasatake YAMATO 			readToken (token);
13493ae02089SMasatake YAMATO 
13503ae02089SMasatake YAMATO 			switch (token->type)
13513ae02089SMasatake YAMATO 			{
13523ae02089SMasatake YAMATO 				case TOKEN_OPEN_PAREN:  depth++; break;
13533ae02089SMasatake YAMATO 				case TOKEN_CLOSE_PAREN: depth--; break;
13543ae02089SMasatake YAMATO 				default: break;
13553ae02089SMasatake YAMATO 			}
13563ae02089SMasatake YAMATO 			/* display part */
13573ae02089SMasatake YAMATO 			switch (token->type)
13583ae02089SMasatake YAMATO 			{
13593ae02089SMasatake YAMATO 				case TOKEN_AMPERSAND:		vStringPut (arglist, '&');		break;
13603ae02089SMasatake YAMATO 				case TOKEN_CLOSE_CURLY:		vStringPut (arglist, '}');		break;
13613ae02089SMasatake YAMATO 				case TOKEN_CLOSE_PAREN:		vStringPut (arglist, ')');		break;
13623ae02089SMasatake YAMATO 				case TOKEN_CLOSE_SQUARE:	vStringPut (arglist, ']');		break;
13633ae02089SMasatake YAMATO 				case TOKEN_COLON:			vStringPut (arglist, ':');		break;
13643ae02089SMasatake YAMATO 				case TOKEN_COMMA:			vStringCatS (arglist, ", ");	break;
13653ae02089SMasatake YAMATO 				case TOKEN_EQUAL_SIGN:		vStringCatS (arglist, " = ");	break;
13663ae02089SMasatake YAMATO 				case TOKEN_OPEN_CURLY:		vStringPut (arglist, '{');		break;
13673ae02089SMasatake YAMATO 				case TOKEN_OPEN_PAREN:		vStringPut (arglist, '(');		break;
13683ae02089SMasatake YAMATO 				case TOKEN_OPEN_SQUARE:		vStringPut (arglist, '[');		break;
13693ae02089SMasatake YAMATO 				case TOKEN_PERIOD:			vStringPut (arglist, '.');		break;
13703ae02089SMasatake YAMATO 				case TOKEN_SEMICOLON:		vStringPut (arglist, ';');		break;
1371acbcd162SColomban Wendling 				case TOKEN_BACKSLASH:		vStringPut (arglist, '\\');		break;
13723ae02089SMasatake YAMATO 				case TOKEN_STRING:
13733ae02089SMasatake YAMATO 				{
13741da6e7e4SMasatake YAMATO 					vStringPut (arglist, '\'');
13753ae02089SMasatake YAMATO 					vStringCat  (arglist, token->string);
13761da6e7e4SMasatake YAMATO 					vStringPut (arglist, '\'');
13773ae02089SMasatake YAMATO 					break;
13783ae02089SMasatake YAMATO 				}
13793ae02089SMasatake YAMATO 
13803ae02089SMasatake YAMATO 				case TOKEN_IDENTIFIER:
13813ae02089SMasatake YAMATO 				case TOKEN_KEYWORD:
13823ae02089SMasatake YAMATO 				case TOKEN_VARIABLE:
13833ae02089SMasatake YAMATO 				{
13843ae02089SMasatake YAMATO 					switch (vStringLast (arglist))
13853ae02089SMasatake YAMATO 					{
13863ae02089SMasatake YAMATO 						case 0:
13873ae02089SMasatake YAMATO 						case ' ':
13883ae02089SMasatake YAMATO 						case '{':
13893ae02089SMasatake YAMATO 						case '(':
13903ae02089SMasatake YAMATO 						case '[':
13913ae02089SMasatake YAMATO 						case '.':
1392acbcd162SColomban Wendling 						case '\\':
13933ae02089SMasatake YAMATO 							/* no need for a space between those and the identifier */
13943ae02089SMasatake YAMATO 							break;
13953ae02089SMasatake YAMATO 
13963ae02089SMasatake YAMATO 						default:
13973ae02089SMasatake YAMATO 							vStringPut (arglist, ' ');
13983ae02089SMasatake YAMATO 							break;
13993ae02089SMasatake YAMATO 					}
14003ae02089SMasatake YAMATO 					if (token->type == TOKEN_VARIABLE)
14013ae02089SMasatake YAMATO 						vStringPut (arglist, '$');
14023ae02089SMasatake YAMATO 					vStringCat (arglist, token->string);
14033ae02089SMasatake YAMATO 					break;
14043ae02089SMasatake YAMATO 				}
14053ae02089SMasatake YAMATO 
14063ae02089SMasatake YAMATO 				default: break;
14073ae02089SMasatake YAMATO 			}
14083ae02089SMasatake YAMATO 		}
14093ae02089SMasatake YAMATO 		while (token->type != TOKEN_EOF && depth > 0);
14103ae02089SMasatake YAMATO 
14113ae02089SMasatake YAMATO 		readToken (token); /* normally it's an open brace or "use" keyword */
14123ae02089SMasatake YAMATO 	}
14133ae02089SMasatake YAMATO 
14143ae02089SMasatake YAMATO 	/* skip use(...) */
14153ae02089SMasatake YAMATO 	if (token->type == TOKEN_KEYWORD && token->keyword == KEYWORD_use)
14163ae02089SMasatake YAMATO 	{
14173ae02089SMasatake YAMATO 		readToken (token);
1418d0d29d63SColomban Wendling 		skipOverParens (token);
14193ae02089SMasatake YAMATO 	}
14203ae02089SMasatake YAMATO 
1421c74b5ff0SMasatake YAMATO 	/* PHP7 return type declaration or if parsing Zephir, gather function return
1422c74b5ff0SMasatake YAMATO 	 * type hint to fill typeRef. */
1423bf43dadcSColomban Wendling 	if ((getInputLanguage () == Lang_php && token->type == TOKEN_COLON) ||
1424bf43dadcSColomban Wendling 	    (getInputLanguage () == Lang_zephir && token->type == TOKEN_OPERATOR))
1425bf43dadcSColomban Wendling 	{
1426c74b5ff0SMasatake YAMATO 		if (arglist)
1427c74b5ff0SMasatake YAMATO 			rtype = vStringNew ();
1428c74b5ff0SMasatake YAMATO 
1429bf43dadcSColomban Wendling 		readToken (token);
143051f37d45SMasatake YAMATO 		if (token->type == TOKEN_QMARK)
143151f37d45SMasatake YAMATO 		{
143251f37d45SMasatake YAMATO 			if (rtype)
143351f37d45SMasatake YAMATO 				vStringPut (rtype, '?');
143451f37d45SMasatake YAMATO 			readToken (token);
143551f37d45SMasatake YAMATO 		}
1436c74b5ff0SMasatake YAMATO 		readQualifiedName (token, rtype, NULL);
1437c74b5ff0SMasatake YAMATO 
1438c74b5ff0SMasatake YAMATO 		if (rtype && vStringIsEmpty (rtype))
1439c74b5ff0SMasatake YAMATO 		{
1440c74b5ff0SMasatake YAMATO 			vStringDelete (rtype);
1441c74b5ff0SMasatake YAMATO 			rtype = NULL;
1442bf43dadcSColomban Wendling 		}
1443c74b5ff0SMasatake YAMATO 	}
1444c74b5ff0SMasatake YAMATO 
1445c74b5ff0SMasatake YAMATO 	if (arglist)
1446c74b5ff0SMasatake YAMATO 		makeFunctionTag (name, arglist, rtype, access, impl);
1447bf43dadcSColomban Wendling 
14483ae02089SMasatake YAMATO 	if (token->type == TOKEN_OPEN_CURLY)
14493ae02089SMasatake YAMATO 		enterScope (token, name->string, K_FUNCTION);
14503ae02089SMasatake YAMATO 	else
1451ce990805SThomas Braun 		readNext = false;
14523ae02089SMasatake YAMATO 
1453c74b5ff0SMasatake YAMATO 	vStringDelete (rtype);
1454c74b5ff0SMasatake YAMATO 	vStringDelete (arglist);
14553ae02089SMasatake YAMATO 	if (nameFree)
14563ae02089SMasatake YAMATO 		deleteToken (nameFree);
14573ae02089SMasatake YAMATO 
14583ae02089SMasatake YAMATO 	return readNext;
14593ae02089SMasatake YAMATO }
14603ae02089SMasatake YAMATO 
14613ae02089SMasatake YAMATO /* parses declarations of the form
14623ae02089SMasatake YAMATO  * 	const NAME = VALUE */
parseConstant(tokenInfo * const token)1463ce990805SThomas Braun static bool parseConstant (tokenInfo *const token)
14643ae02089SMasatake YAMATO {
14653ae02089SMasatake YAMATO 	tokenInfo *name;
14663ae02089SMasatake YAMATO 
14673ae02089SMasatake YAMATO 	readToken (token); /* skip const keyword */
1468a1f68541SColomban Wendling 	if (token->type != TOKEN_IDENTIFIER && token->type != TOKEN_KEYWORD)
1469ce990805SThomas Braun 		return false;
14703ae02089SMasatake YAMATO 
14713ae02089SMasatake YAMATO 	name = newToken ();
1472ce990805SThomas Braun 	copyToken (name, token, true);
14733ae02089SMasatake YAMATO 
14743ae02089SMasatake YAMATO 	readToken (token);
14753ae02089SMasatake YAMATO 	if (token->type == TOKEN_EQUAL_SIGN)
14763ae02089SMasatake YAMATO 		makeSimplePhpTag (name, K_DEFINE, ACCESS_UNDEFINED);
14773ae02089SMasatake YAMATO 
14783ae02089SMasatake YAMATO 	deleteToken (name);
14793ae02089SMasatake YAMATO 
14803ae02089SMasatake YAMATO 	return token->type == TOKEN_EQUAL_SIGN;
14813ae02089SMasatake YAMATO }
14823ae02089SMasatake YAMATO 
14833ae02089SMasatake YAMATO /* parses declarations of the form
14843ae02089SMasatake YAMATO  * 	define('NAME', 'VALUE')
14853ae02089SMasatake YAMATO  * 	define(NAME, 'VALUE) */
parseDefine(tokenInfo * const token)1486ce990805SThomas Braun static bool parseDefine (tokenInfo *const token)
14873ae02089SMasatake YAMATO {
14883ae02089SMasatake YAMATO 	int depth = 1;
14893ae02089SMasatake YAMATO 
14903ae02089SMasatake YAMATO 	readToken (token); /* skip "define" identifier */
14913ae02089SMasatake YAMATO 	if (token->type != TOKEN_OPEN_PAREN)
1492ce990805SThomas Braun 		return false;
14933ae02089SMasatake YAMATO 
14943ae02089SMasatake YAMATO 	readToken (token);
14953ae02089SMasatake YAMATO 	if (token->type == TOKEN_STRING ||
14963ae02089SMasatake YAMATO 		token->type == TOKEN_IDENTIFIER)
14973ae02089SMasatake YAMATO 	{
14983ae02089SMasatake YAMATO 		makeSimplePhpTag (token, K_DEFINE, ACCESS_UNDEFINED);
14993ae02089SMasatake YAMATO 		readToken (token);
15003ae02089SMasatake YAMATO 	}
15013ae02089SMasatake YAMATO 
15023ae02089SMasatake YAMATO 	/* skip until the close parenthesis.
15033ae02089SMasatake YAMATO 	 * no need to handle nested blocks since they would be invalid
15043ae02089SMasatake YAMATO 	 * in this context anyway (the VALUE may only be a scalar, like
15053ae02089SMasatake YAMATO 	 * 	42
15063ae02089SMasatake YAMATO 	 * 	(42)
15073ae02089SMasatake YAMATO 	 * and alike) */
15083ae02089SMasatake YAMATO 	while (token->type != TOKEN_EOF && depth > 0)
15093ae02089SMasatake YAMATO 	{
15103ae02089SMasatake YAMATO 		switch (token->type)
15113ae02089SMasatake YAMATO 		{
15123ae02089SMasatake YAMATO 			case TOKEN_OPEN_PAREN:	depth++; break;
15133ae02089SMasatake YAMATO 			case TOKEN_CLOSE_PAREN:	depth--; break;
15143ae02089SMasatake YAMATO 			default: break;
15153ae02089SMasatake YAMATO 		}
15163ae02089SMasatake YAMATO 		readToken (token);
15173ae02089SMasatake YAMATO 	}
15183ae02089SMasatake YAMATO 
1519ce990805SThomas Braun 	return false;
15203ae02089SMasatake YAMATO }
15213ae02089SMasatake YAMATO 
15223ae02089SMasatake YAMATO /* parses declarations of the form
1523c65c05feSColomban Wendling  * 	use Foo
1524c65c05feSColomban Wendling  * 	use Foo\Bar\Class
1525c65c05feSColomban Wendling  * 	use Foo\Bar\Class as FooBarClass
1526c65c05feSColomban Wendling  * 	use function Foo\Bar\func
1527c65c05feSColomban Wendling  * 	use function Foo\Bar\func as foobarfunc
1528c65c05feSColomban Wendling  * 	use const Foo\Bar\CONST
1529c65c05feSColomban Wendling  * 	use const Foo\Bar\CONST as FOOBARCONST
1530c65c05feSColomban Wendling  * 	use Foo, Bar
1531c65c05feSColomban Wendling  * 	use Foo, Bar as Baz
153250d1ddbaSColomban Wendling  * 	use Foo as Test, Bar as Baz
153350d1ddbaSColomban Wendling  * 	use Foo\{Bar, Baz as Child, Nested\Other, Even\More as Something} */
parseUse(tokenInfo * const token)1534ce990805SThomas Braun static bool parseUse (tokenInfo *const token)
1535c65c05feSColomban Wendling {
1536ce990805SThomas Braun 	bool readNext = false;
1537c65c05feSColomban Wendling 	/* we can't know the use type, because class, interface and namespaces
1538c65c05feSColomban Wendling 	 * aliases are the same, and the only difference is the referenced name's
1539c65c05feSColomban Wendling 	 * type */
1540c65c05feSColomban Wendling 	const char *refType = "unknown";
154150d1ddbaSColomban Wendling 	vString *refName = vStringNew ();
154250d1ddbaSColomban Wendling 	tokenInfo *nameToken = newToken ();
1543ce990805SThomas Braun 	bool grouped = false;
1544c65c05feSColomban Wendling 
1545c65c05feSColomban Wendling 	readToken (token); /* skip use keyword itself */
1546c65c05feSColomban Wendling 	if (token->type == TOKEN_KEYWORD && (token->keyword == KEYWORD_function ||
1547c65c05feSColomban Wendling 	                                     token->keyword == KEYWORD_const))
1548c65c05feSColomban Wendling 	{
1549c65c05feSColomban Wendling 		switch (token->keyword)
1550c65c05feSColomban Wendling 		{
1551c65c05feSColomban Wendling 			case KEYWORD_function:	refType = PhpKinds[K_FUNCTION].name;	break;
1552c65c05feSColomban Wendling 			case KEYWORD_const:		refType = PhpKinds[K_DEFINE].name;		break;
1553c65c05feSColomban Wendling 			default: break; /* silence compilers */
1554c65c05feSColomban Wendling 		}
1555ce990805SThomas Braun 		readNext = true;
1556c65c05feSColomban Wendling 	}
1557c65c05feSColomban Wendling 
1558c65c05feSColomban Wendling 	if (readNext)
1559c65c05feSColomban Wendling 		readToken (token);
1560c65c05feSColomban Wendling 
156150d1ddbaSColomban Wendling 	readQualifiedName (token, refName, nameToken);
156250d1ddbaSColomban Wendling 	grouped = readNext = (token->type == TOKEN_OPEN_CURLY);
156350d1ddbaSColomban Wendling 
156450d1ddbaSColomban Wendling 	do
1565c65c05feSColomban Wendling 	{
156650d1ddbaSColomban Wendling 		size_t refNamePrefixLength = grouped ? vStringLength (refName) : 0;
156750d1ddbaSColomban Wendling 
156850d1ddbaSColomban Wendling 		/* if it's either not the first name in a comma-separated list, or we
156950d1ddbaSColomban Wendling 		 * are in a grouped alias and need to read the leaf name */
157050d1ddbaSColomban Wendling 		if (readNext)
157150d1ddbaSColomban Wendling 		{
1572c65c05feSColomban Wendling 			readToken (token);
157323121268SColomban Wendling 			/* in case of a trailing comma (or an empty group) */
157423121268SColomban Wendling 			if (token->type == TOKEN_CLOSE_CURLY)
157523121268SColomban Wendling 				break;
157650d1ddbaSColomban Wendling 			readQualifiedName (token, refName, nameToken);
1577c65c05feSColomban Wendling 		}
1578c65c05feSColomban Wendling 
1579c65c05feSColomban Wendling 		if (token->type == TOKEN_KEYWORD && token->keyword == KEYWORD_as)
1580c65c05feSColomban Wendling 		{
1581c65c05feSColomban Wendling 			readToken (token);
1582ce990805SThomas Braun 			copyToken (nameToken, token, true);
1583c65c05feSColomban Wendling 			readToken (token);
1584c65c05feSColomban Wendling 		}
1585c65c05feSColomban Wendling 
1586169a661fSDawid Zamirski 		if (nameToken->type == TOKEN_IDENTIFIER && PhpKinds[K_ALIAS].enabled)
1587c65c05feSColomban Wendling 		{
1588c65c05feSColomban Wendling 			tagEntryInfo entry;
1589c65c05feSColomban Wendling 
1590c65c05feSColomban Wendling 			initPhpEntry (&entry, nameToken, K_ALIAS, ACCESS_UNDEFINED);
1591c65c05feSColomban Wendling 
1592c65c05feSColomban Wendling 			entry.extensionFields.typeRef[0] = refType;
1593c65c05feSColomban Wendling 			entry.extensionFields.typeRef[1] = vStringValue (refName);
1594c65c05feSColomban Wendling 
1595c65c05feSColomban Wendling 			makePhpTagEntry (&entry);
1596c65c05feSColomban Wendling 		}
1597c65c05feSColomban Wendling 
159850d1ddbaSColomban Wendling 		vStringTruncate (refName, refNamePrefixLength);
1599c65c05feSColomban Wendling 
1600ce990805SThomas Braun 		readNext = true;
1601c65c05feSColomban Wendling 	}
1602c65c05feSColomban Wendling 	while (token->type == TOKEN_COMMA);
1603c65c05feSColomban Wendling 
160450d1ddbaSColomban Wendling 	if (grouped && token->type == TOKEN_CLOSE_CURLY)
160550d1ddbaSColomban Wendling 		readToken (token);
160650d1ddbaSColomban Wendling 
160750d1ddbaSColomban Wendling 	vStringDelete (refName);
160850d1ddbaSColomban Wendling 	deleteToken (nameToken);
160950d1ddbaSColomban Wendling 
1610c65c05feSColomban Wendling 	return (token->type == TOKEN_SEMICOLON);
1611c65c05feSColomban Wendling }
1612c65c05feSColomban Wendling 
1613c65c05feSColomban Wendling /* parses declarations of the form
16143ae02089SMasatake YAMATO  * 	$var = VALUE
16153ae02089SMasatake YAMATO  * 	$var; */
parseVariable(tokenInfo * const token,vString * typeName)16165ed230b0SMasatake YAMATO static bool parseVariable (tokenInfo *const token, vString * typeName)
16173ae02089SMasatake YAMATO {
16183ae02089SMasatake YAMATO 	tokenInfo *name;
1619ce990805SThomas Braun 	bool readNext = true;
16203ae02089SMasatake YAMATO 	accessType access = CurrentStatement.access;
16213ae02089SMasatake YAMATO 
16223ae02089SMasatake YAMATO 	name = newToken ();
1623ce990805SThomas Braun 	copyToken (name, token, true);
16243ae02089SMasatake YAMATO 
16253ae02089SMasatake YAMATO 	readToken (token);
16263ae02089SMasatake YAMATO 	if (token->type == TOKEN_EQUAL_SIGN)
16273ae02089SMasatake YAMATO 	{
16283ae02089SMasatake YAMATO 		phpKind kind = K_VARIABLE;
16293ae02089SMasatake YAMATO 
16303ae02089SMasatake YAMATO 		if (token->parentKind == K_FUNCTION)
16313ae02089SMasatake YAMATO 			kind = K_LOCAL_VARIABLE;
16323ae02089SMasatake YAMATO 
16333ae02089SMasatake YAMATO 		readToken (token);
16343ae02089SMasatake YAMATO 		if (token->type == TOKEN_KEYWORD &&
16353ae02089SMasatake YAMATO 			token->keyword == KEYWORD_function &&
16363ae02089SMasatake YAMATO 			PhpKinds[kind].enabled)
16373ae02089SMasatake YAMATO 		{
16383ae02089SMasatake YAMATO 			if (parseFunction (token, name))
16393ae02089SMasatake YAMATO 				readToken (token);
1640ce990805SThomas Braun 			readNext = (bool) (token->type == TOKEN_SEMICOLON);
16413ae02089SMasatake YAMATO 		}
16423ae02089SMasatake YAMATO 		else
16433ae02089SMasatake YAMATO 		{
16443ae02089SMasatake YAMATO 			makeSimplePhpTag (name, kind, access);
1645ce990805SThomas Braun 			readNext = false;
16463ae02089SMasatake YAMATO 		}
16473ae02089SMasatake YAMATO 	}
16483ae02089SMasatake YAMATO 	else if (token->type == TOKEN_SEMICOLON)
16493ae02089SMasatake YAMATO 	{
16503ae02089SMasatake YAMATO 		/* generate tags for variable declarations in classes
16513ae02089SMasatake YAMATO 		 * 	class Foo {
16523ae02089SMasatake YAMATO 		 * 		protected $foo;
16533ae02089SMasatake YAMATO 		 * 	}
16543ae02089SMasatake YAMATO 		 * but don't get fooled by stuff like $foo = $bar; */
1655a5c4c7d1SColomban Wendling 		if (token->parentKind == K_CLASS ||
1656a5c4c7d1SColomban Wendling 		    token->parentKind == K_INTERFACE ||
1657a5c4c7d1SColomban Wendling 		    token->parentKind == K_TRAIT)
16585ed230b0SMasatake YAMATO 			makeTypedPhpTag (name, K_VARIABLE, access, typeName);
16593ae02089SMasatake YAMATO 	}
16603ae02089SMasatake YAMATO 	else
1661ce990805SThomas Braun 		readNext = false;
16623ae02089SMasatake YAMATO 
16633ae02089SMasatake YAMATO 	deleteToken (name);
16643ae02089SMasatake YAMATO 
16653ae02089SMasatake YAMATO 	return readNext;
16663ae02089SMasatake YAMATO }
16673ae02089SMasatake YAMATO 
16683ae02089SMasatake YAMATO /* parses namespace declarations
16693ae02089SMasatake YAMATO  * 	namespace Foo {}
16703ae02089SMasatake YAMATO  * 	namespace Foo\Bar {}
16713ae02089SMasatake YAMATO  * 	namespace Foo;
16723ae02089SMasatake YAMATO  * 	namespace Foo\Bar;
16733ae02089SMasatake YAMATO  * 	namespace;
1674759d281dSK.Takata  * 	namespace {} */
parseNamespace(tokenInfo * const token)1675ce990805SThomas Braun static bool parseNamespace (tokenInfo *const token)
16763ae02089SMasatake YAMATO {
16773ae02089SMasatake YAMATO 	tokenInfo *nsToken = newToken ();
16783ae02089SMasatake YAMATO 
16793ae02089SMasatake YAMATO 	vStringClear (CurrentNamesapce);
1680ce990805SThomas Braun 	copyToken (nsToken, token, false);
16813ae02089SMasatake YAMATO 
16823ae02089SMasatake YAMATO 	do
16833ae02089SMasatake YAMATO 	{
16843ae02089SMasatake YAMATO 		readToken (token);
16853ae02089SMasatake YAMATO 		if (token->type == TOKEN_IDENTIFIER)
16863ae02089SMasatake YAMATO 		{
16873ae02089SMasatake YAMATO 			if (vStringLength (CurrentNamesapce) > 0)
1688a4af1067SMasatake YAMATO 			{
1689a4af1067SMasatake YAMATO 				const char *sep;
1690a4af1067SMasatake YAMATO 
1691a4af1067SMasatake YAMATO 				sep = phpScopeSeparatorFor(K_NAMESPACE,
1692a4af1067SMasatake YAMATO 							   K_NAMESPACE);
1693a4af1067SMasatake YAMATO 				vStringCatS (CurrentNamesapce, sep);
1694a4af1067SMasatake YAMATO 			}
16953ae02089SMasatake YAMATO 			vStringCat (CurrentNamesapce, token->string);
16963ae02089SMasatake YAMATO 		}
16973ae02089SMasatake YAMATO 	}
16983ae02089SMasatake YAMATO 	while (token->type != TOKEN_EOF &&
16993ae02089SMasatake YAMATO 		   token->type != TOKEN_SEMICOLON &&
17003ae02089SMasatake YAMATO 		   token->type != TOKEN_OPEN_CURLY);
17013ae02089SMasatake YAMATO 
17023ae02089SMasatake YAMATO 	if (vStringLength (CurrentNamesapce) > 0)
17033ae02089SMasatake YAMATO 		makeNamespacePhpTag (nsToken, CurrentNamesapce);
17043ae02089SMasatake YAMATO 
17053ae02089SMasatake YAMATO 	if (token->type == TOKEN_OPEN_CURLY)
17063ae02089SMasatake YAMATO 		enterScope (token, NULL, -1);
17073ae02089SMasatake YAMATO 
17083ae02089SMasatake YAMATO 	deleteToken (nsToken);
17093ae02089SMasatake YAMATO 
1710ce990805SThomas Braun 	return true;
17113ae02089SMasatake YAMATO }
17123ae02089SMasatake YAMATO 
enterScope(tokenInfo * const parentToken,const vString * const extraScope,const int parentKind)17133ae02089SMasatake YAMATO static void enterScope (tokenInfo *const parentToken,
17143ae02089SMasatake YAMATO 						const vString *const extraScope,
17153ae02089SMasatake YAMATO 						const int parentKind)
17163ae02089SMasatake YAMATO {
17173ae02089SMasatake YAMATO 	tokenInfo *token = newToken ();
17185ed230b0SMasatake YAMATO 	vString *typeName = vStringNew ();
17193ae02089SMasatake YAMATO 	int origParentKind = parentToken->parentKind;
17203ae02089SMasatake YAMATO 
1721ce990805SThomas Braun 	copyToken (token, parentToken, true);
17223ae02089SMasatake YAMATO 
17233ae02089SMasatake YAMATO 	if (extraScope)
17243ae02089SMasatake YAMATO 	{
17253ae02089SMasatake YAMATO 		token->parentKind = parentKind;
1726a4af1067SMasatake YAMATO 		addToScope (token, extraScope, origParentKind);
17273ae02089SMasatake YAMATO 	}
17283ae02089SMasatake YAMATO 
17293ae02089SMasatake YAMATO 	readToken (token);
17303ae02089SMasatake YAMATO 	while (token->type != TOKEN_EOF &&
17313ae02089SMasatake YAMATO 		   token->type != TOKEN_CLOSE_CURLY)
17323ae02089SMasatake YAMATO 	{
1733ce990805SThomas Braun 		bool readNext = true;
17343ae02089SMasatake YAMATO 
17353ae02089SMasatake YAMATO 		switch (token->type)
17363ae02089SMasatake YAMATO 		{
17373ae02089SMasatake YAMATO 			case TOKEN_OPEN_CURLY:
17383ae02089SMasatake YAMATO 				enterScope (token, NULL, -1);
17393ae02089SMasatake YAMATO 				break;
17403ae02089SMasatake YAMATO 
17413ae02089SMasatake YAMATO 			case TOKEN_KEYWORD:
17423ae02089SMasatake YAMATO 				switch (token->keyword)
17433ae02089SMasatake YAMATO 				{
1744d0d29d63SColomban Wendling 					/* handle anonymous classes */
1745d0d29d63SColomban Wendling 					case KEYWORD_new:
1746d0d29d63SColomban Wendling 						readToken (token);
1747d0d29d63SColomban Wendling 						if (token->keyword != KEYWORD_class)
1748ce990805SThomas Braun 							readNext = false;
1749d0d29d63SColomban Wendling 						else
1750d0d29d63SColomban Wendling 						{
1751d0d29d63SColomban Wendling 							tokenInfo *name = newToken ();
1752d0d29d63SColomban Wendling 
1753ce990805SThomas Braun 							copyToken (name, token, true);
17543165d268SMasatake YAMATO 							anonGenerate (name->string, "AnonymousClass", K_CLASS);
17553165d268SMasatake YAMATO 							name->anonymous = true;
1756d0d29d63SColomban Wendling 							readNext = parseClassOrIface (token, K_CLASS, name);
1757d0d29d63SColomban Wendling 							deleteToken (name);
1758d0d29d63SColomban Wendling 						}
1759d0d29d63SColomban Wendling 						break;
1760d0d29d63SColomban Wendling 
1761d0d29d63SColomban Wendling 					case KEYWORD_class:		readNext = parseClassOrIface (token, K_CLASS, NULL);		break;
1762d0d29d63SColomban Wendling 					case KEYWORD_interface:	readNext = parseClassOrIface (token, K_INTERFACE, NULL);	break;
17633ae02089SMasatake YAMATO 					case KEYWORD_trait:		readNext = parseTrait (token);								break;
17643ae02089SMasatake YAMATO 					case KEYWORD_function:	readNext = parseFunction (token, NULL);						break;
17653ae02089SMasatake YAMATO 					case KEYWORD_const:		readNext = parseConstant (token);							break;
17663ae02089SMasatake YAMATO 					case KEYWORD_define:	readNext = parseDefine (token);								break;
17673ae02089SMasatake YAMATO 
1768c65c05feSColomban Wendling 					case KEYWORD_use:
1769c65c05feSColomban Wendling 						/* aliases are only allowed at root scope, but the keyword
1770c65c05feSColomban Wendling 						 * is also used to i.e. "import" traits into a class */
1771c65c05feSColomban Wendling 						if (vStringLength (token->scope) == 0)
1772c65c05feSColomban Wendling 							readNext = parseUse (token);
1773c65c05feSColomban Wendling 						break;
1774c65c05feSColomban Wendling 
17753ae02089SMasatake YAMATO 					case KEYWORD_namespace:	readNext = parseNamespace (token);	break;
17763ae02089SMasatake YAMATO 
17773ae02089SMasatake YAMATO 					case KEYWORD_private:	CurrentStatement.access = ACCESS_PRIVATE;	break;
17783ae02089SMasatake YAMATO 					case KEYWORD_protected:	CurrentStatement.access = ACCESS_PROTECTED;	break;
17793ae02089SMasatake YAMATO 					case KEYWORD_public:	CurrentStatement.access = ACCESS_PUBLIC;	break;
17803ae02089SMasatake YAMATO 					case KEYWORD_var:		CurrentStatement.access = ACCESS_PUBLIC;	break;
17813ae02089SMasatake YAMATO 
17823ae02089SMasatake YAMATO 					case KEYWORD_abstract:	CurrentStatement.impl = IMPL_ABSTRACT;		break;
17833ae02089SMasatake YAMATO 
17843ae02089SMasatake YAMATO 					default: break;
17853ae02089SMasatake YAMATO 				}
17863ae02089SMasatake YAMATO 				break;
17873ae02089SMasatake YAMATO 
17885ed230b0SMasatake YAMATO 			case TOKEN_QMARK:
17895ed230b0SMasatake YAMATO 				vStringClear (typeName);
17905ed230b0SMasatake YAMATO 				vStringPut (typeName, '?');
17915ed230b0SMasatake YAMATO 				readNext = true;
17925ed230b0SMasatake YAMATO 				break;
17935ed230b0SMasatake YAMATO 			case TOKEN_IDENTIFIER:
17945ed230b0SMasatake YAMATO 				vStringCat (typeName, token->string);
17955ed230b0SMasatake YAMATO 				readNext = true;
17965ed230b0SMasatake YAMATO 				break;
17973ae02089SMasatake YAMATO 			case TOKEN_VARIABLE:
17985ed230b0SMasatake YAMATO 				readNext = parseVariable (token,
17995ed230b0SMasatake YAMATO 										  vStringIsEmpty(typeName)
18005ed230b0SMasatake YAMATO 										  ? NULL
18015ed230b0SMasatake YAMATO 										  : typeName);
18025ed230b0SMasatake YAMATO 				vStringClear (typeName);
18033ae02089SMasatake YAMATO 				break;
18043ae02089SMasatake YAMATO 
18053ae02089SMasatake YAMATO 			default: break;
18063ae02089SMasatake YAMATO 		}
18073ae02089SMasatake YAMATO 
18083ae02089SMasatake YAMATO 		if (readNext)
18093ae02089SMasatake YAMATO 			readToken (token);
18103ae02089SMasatake YAMATO 	}
18113ae02089SMasatake YAMATO 
1812ce990805SThomas Braun 	copyToken (parentToken, token, false);
18133ae02089SMasatake YAMATO 	parentToken->parentKind = origParentKind;
18145ed230b0SMasatake YAMATO 	vStringDelete (typeName);
18153ae02089SMasatake YAMATO 	deleteToken (token);
18163ae02089SMasatake YAMATO }
18173ae02089SMasatake YAMATO 
findTags(bool startsInPhpMode)1818ce990805SThomas Braun static void findTags (bool startsInPhpMode)
18193ae02089SMasatake YAMATO {
18203ae02089SMasatake YAMATO 	tokenInfo *const token = newToken ();
18213ae02089SMasatake YAMATO 
18223ae02089SMasatake YAMATO 	InPhp = startsInPhpMode;
182375ba24d4SColomban Wendling 	MayBeKeyword = true;
18243ae02089SMasatake YAMATO 	CurrentStatement.access = ACCESS_UNDEFINED;
18253ae02089SMasatake YAMATO 	CurrentStatement.impl = IMPL_UNDEFINED;
18263ae02089SMasatake YAMATO 	CurrentNamesapce = vStringNew ();
18273ae02089SMasatake YAMATO 	FullScope = vStringNew ();
1828f176923cSMasatake YAMATO 	Assert (ParentClass == NULL);
18293ae02089SMasatake YAMATO 
18303ae02089SMasatake YAMATO 	do
18313ae02089SMasatake YAMATO 	{
18323ae02089SMasatake YAMATO 		enterScope (token, NULL, -1);
18333ae02089SMasatake YAMATO 	}
18343ae02089SMasatake YAMATO 	while (token->type != TOKEN_EOF); /* keep going even with unmatched braces */
18353ae02089SMasatake YAMATO 
18363ae02089SMasatake YAMATO 	vStringDelete (FullScope);
18373ae02089SMasatake YAMATO 	vStringDelete (CurrentNamesapce);
18383ae02089SMasatake YAMATO 	deleteToken (token);
18393ae02089SMasatake YAMATO }
18403ae02089SMasatake YAMATO 
findPhpTags(void)18413ae02089SMasatake YAMATO static void findPhpTags (void)
18423ae02089SMasatake YAMATO {
1843ce990805SThomas Braun 	findTags (false);
18443ae02089SMasatake YAMATO }
18453ae02089SMasatake YAMATO 
findZephirTags(void)18463ae02089SMasatake YAMATO static void findZephirTags (void)
18473ae02089SMasatake YAMATO {
1848ce990805SThomas Braun 	findTags (true);
18493ae02089SMasatake YAMATO }
18503ae02089SMasatake YAMATO 
initializePool(void)18510988269fSJiří Techet static void initializePool (void)
18520988269fSJiří Techet {
18530988269fSJiří Techet 	if (TokenPool == NULL)
1854e013efc1SMasatake YAMATO 		TokenPool = objPoolNew (16, newPoolToken, deletePoolToken, clearPoolToken, NULL);
18550988269fSJiří Techet }
18560988269fSJiří Techet 
initializePhpParser(const langType language)18573ae02089SMasatake YAMATO static void initializePhpParser (const langType language)
18583ae02089SMasatake YAMATO {
18593ae02089SMasatake YAMATO 	Lang_php = language;
18600988269fSJiří Techet 	initializePool ();
18613ae02089SMasatake YAMATO }
18623ae02089SMasatake YAMATO 
initializeZephirParser(const langType language)18633ae02089SMasatake YAMATO static void initializeZephirParser (const langType language)
18643ae02089SMasatake YAMATO {
18653ae02089SMasatake YAMATO 	Lang_zephir = language;
18660988269fSJiří Techet 	initializePool ();
18670988269fSJiří Techet }
18680988269fSJiří Techet 
finalize(langType language CTAGS_ATTR_UNUSED,bool initialized)18690988269fSJiří Techet static void finalize (langType language CTAGS_ATTR_UNUSED, bool initialized)
18700988269fSJiří Techet {
18710988269fSJiří Techet 	if (!initialized)
18720988269fSJiří Techet 		return;
18730988269fSJiří Techet 
18740988269fSJiří Techet 	if (TokenPool != NULL)
18750988269fSJiří Techet 	{
18760988269fSJiří Techet 		objPoolDelete (TokenPool);
18770988269fSJiří Techet 		TokenPool = NULL;
18780988269fSJiří Techet 	}
18793ae02089SMasatake YAMATO }
18803ae02089SMasatake YAMATO 
PhpParser(void)18813ae02089SMasatake YAMATO extern parserDefinition* PhpParser (void)
18823ae02089SMasatake YAMATO {
1883ed38f7a3SColomban Wendling 	static const char *const extensions [] = { "php", "php3", "php4", "php5", "php7", "phtml", NULL };
18843ae02089SMasatake YAMATO 	parserDefinition* def = parserNew ("PHP");
188509ae690fSMasatake YAMATO 	def->kindTable      = PhpKinds;
18863db72c21SMasatake YAMATO 	def->kindCount  = ARRAY_SIZE (PhpKinds);
18873ae02089SMasatake YAMATO 	def->extensions = extensions;
18883ae02089SMasatake YAMATO 	def->parser     = findPhpTags;
18893ae02089SMasatake YAMATO 	def->initialize = initializePhpParser;
18900988269fSJiří Techet 	def->finalize   = finalize;
1891c379c5d2SMasatake YAMATO 	def->keywordTable = PhpKeywordTable;
18923db72c21SMasatake YAMATO 	def->keywordCount = ARRAY_SIZE (PhpKeywordTable);
18933ae02089SMasatake YAMATO 	return def;
18943ae02089SMasatake YAMATO }
18953ae02089SMasatake YAMATO 
ZephirParser(void)18963ae02089SMasatake YAMATO extern parserDefinition* ZephirParser (void)
18973ae02089SMasatake YAMATO {
18983ae02089SMasatake YAMATO 	static const char *const extensions [] = { "zep", NULL };
18993ae02089SMasatake YAMATO 	parserDefinition* def = parserNew ("Zephir");
190009ae690fSMasatake YAMATO 	def->kindTable      = PhpKinds;
19013db72c21SMasatake YAMATO 	def->kindCount  = ARRAY_SIZE (PhpKinds);
19023ae02089SMasatake YAMATO 	def->extensions = extensions;
19033ae02089SMasatake YAMATO 	def->parser     = findZephirTags;
19043ae02089SMasatake YAMATO 	def->initialize = initializeZephirParser;
19050988269fSJiří Techet 	def->finalize   = finalize;
1906c379c5d2SMasatake YAMATO 	def->keywordTable = PhpKeywordTable;
19073db72c21SMasatake YAMATO 	def->keywordCount = ARRAY_SIZE (PhpKeywordTable);
19083ae02089SMasatake YAMATO 	return def;
19093ae02089SMasatake YAMATO }
1910