xref: /Universal-ctags/parsers/python.c (revision 23ceb0b685e027153abaace7a550a98e42d8128e)
13ae02089SMasatake YAMATO /*
23ae02089SMasatake YAMATO *   Copyright (c) 2000-2003, Darren Hiebert
32ff1f9d2SColomban Wendling *   Copyright (c) 2014-2016, Colomban Wendling <ban@herbesfolles.org>
43ae02089SMasatake YAMATO *
53ae02089SMasatake YAMATO *   This source code is released for free distribution under the terms of the
60ce38835Sviccuad *   GNU General Public License version 2 or (at your option) any later version.
73ae02089SMasatake YAMATO *
83ae02089SMasatake YAMATO *   This module contains functions for generating tags for Python language
93ae02089SMasatake YAMATO *   files.
103ae02089SMasatake YAMATO */
112ff1f9d2SColomban Wendling 
123ae02089SMasatake YAMATO #include "general.h"  /* must always come first */
133ae02089SMasatake YAMATO 
143ae02089SMasatake YAMATO #include <string.h>
153ae02089SMasatake YAMATO 
163ae02089SMasatake YAMATO #include "entry.h"
1791ccf7d7SFrank Fesevur #include "nestlevel.h"
183ae02089SMasatake YAMATO #include "read.h"
192ff1f9d2SColomban Wendling #include "parse.h"
203ae02089SMasatake YAMATO #include "vstring.h"
212ff1f9d2SColomban Wendling #include "keyword.h"
223ae02089SMasatake YAMATO #include "routines.h"
233ae02089SMasatake YAMATO #include "debug.h"
24f5f8bd9aSMasatake YAMATO #include "xtag.h"
25d3bb2b5aSJiří Techet #include "objpool.h"
2634454f72SMasatake YAMATO #include "ptrarray.h"
273ae02089SMasatake YAMATO 
28670267e5SJiří Techet #define isIdentifierChar(c) \
29670267e5SJiří Techet 	(isalnum (c) || (c) == '_' || (c) >= 0x80)
306ff4799bSJiří Techet #define newToken() (objPoolGet (TokenPool))
316ff4799bSJiří Techet #define deleteToken(t) (objPoolPut (TokenPool, (t)))
32090afdd9SMasatake YAMATO 
334faa2076SColomban Wendling enum {
342ff1f9d2SColomban Wendling 	KEYWORD_as,
3516845a4eSColomban Wendling 	KEYWORD_async,
362ff1f9d2SColomban Wendling 	KEYWORD_cdef,
372ff1f9d2SColomban Wendling 	KEYWORD_class,
382ff1f9d2SColomban Wendling 	KEYWORD_cpdef,
392ff1f9d2SColomban Wendling 	KEYWORD_def,
402ff1f9d2SColomban Wendling 	KEYWORD_extern,
412ff1f9d2SColomban Wendling 	KEYWORD_from,
422ff1f9d2SColomban Wendling 	KEYWORD_import,
432ff1f9d2SColomban Wendling 	KEYWORD_inline,
442ff1f9d2SColomban Wendling 	KEYWORD_lambda,
452ff1f9d2SColomban Wendling 	KEYWORD_pass,
462ff1f9d2SColomban Wendling 	KEYWORD_return,
474faa2076SColomban Wendling };
484faa2076SColomban Wendling typedef int keywordId; /* to allow KEYWORD_NONE */
492ff1f9d2SColomban Wendling 
502ff1f9d2SColomban Wendling typedef enum {
512ff1f9d2SColomban Wendling 	ACCESS_PRIVATE,
522ff1f9d2SColomban Wendling 	ACCESS_PROTECTED,
532ff1f9d2SColomban Wendling 	ACCESS_PUBLIC,
542ff1f9d2SColomban Wendling 	COUNT_ACCESS
552ff1f9d2SColomban Wendling } accessType;
562ff1f9d2SColomban Wendling 
572ff1f9d2SColomban Wendling static const char *const PythonAccesses[COUNT_ACCESS] = {
582ff1f9d2SColomban Wendling 	"private",
592ff1f9d2SColomban Wendling 	"protected",
602ff1f9d2SColomban Wendling 	"public"
612ff1f9d2SColomban Wendling };
622ff1f9d2SColomban Wendling 
632ff1f9d2SColomban Wendling typedef enum {
645d0fd5feSColomban Wendling 	F_DECORATORS,
656f605b92SMasatake YAMATO 	F_NAMEREF,
665d0fd5feSColomban Wendling 	COUNT_FIELD
675d0fd5feSColomban Wendling } pythonField;
685d0fd5feSColomban Wendling 
69b56bd065SMasatake YAMATO static fieldDefinition PythonFields[COUNT_FIELD] = {
705d0fd5feSColomban Wendling 	{ .name = "decorators",
715d0fd5feSColomban Wendling 	  .description = "decorators on functions and classes",
72ce990805SThomas Braun 	  .enabled = false },
736f605b92SMasatake YAMATO 	{ .name = "nameref",
746f605b92SMasatake YAMATO 	  .description = "the original name for the tag",
756f605b92SMasatake YAMATO 	  .enabled = true },
765d0fd5feSColomban Wendling };
775d0fd5feSColomban Wendling 
785d0fd5feSColomban Wendling typedef enum {
792ff1f9d2SColomban Wendling 	K_CLASS,
802ff1f9d2SColomban Wendling 	K_FUNCTION,
812ff1f9d2SColomban Wendling 	K_METHOD,
822ff1f9d2SColomban Wendling 	K_VARIABLE,
832ff1f9d2SColomban Wendling 	K_NAMESPACE,
842ff1f9d2SColomban Wendling 	K_MODULE,
852ff1f9d2SColomban Wendling 	K_UNKNOWN,
86257674afSColomban Wendling 	K_PARAMETER,
8798a8ebe8SColomban Wendling 	K_LOCAL_VARIABLE,
882ff1f9d2SColomban Wendling 	COUNT_KIND
893ae02089SMasatake YAMATO } pythonKind;
903ae02089SMasatake YAMATO 
91f5f8bd9aSMasatake YAMATO typedef enum {
92f5f8bd9aSMasatake YAMATO 	PYTHON_MODULE_IMPORTED,
93f5f8bd9aSMasatake YAMATO 	PYTHON_MODULE_NAMESPACE,
94f5f8bd9aSMasatake YAMATO 	PYTHON_MODULE_INDIRECTLY_IMPORTED,
95f5f8bd9aSMasatake YAMATO } pythonModuleRole;
96f5f8bd9aSMasatake YAMATO 
97f5f8bd9aSMasatake YAMATO typedef enum {
98f5f8bd9aSMasatake YAMATO 	PYTHON_UNKNOWN_IMPORTED,
99f5f8bd9aSMasatake YAMATO 	PYTHON_UNKNOWN_INDIRECTLY_IMPORTED,
100f5f8bd9aSMasatake YAMATO } pythonUnknownRole;
101f5f8bd9aSMasatake YAMATO 
1022ff1f9d2SColomban Wendling /* Roles related to `import'
103f5f8bd9aSMasatake YAMATO  * ==========================
104f5f8bd9aSMasatake YAMATO  * import X              X = (kind:module, role:imported)
105f5f8bd9aSMasatake YAMATO  *
106a25c30ffSMasatake YAMATO  * import X as Y         X = (kind:module, role:indirectlyImported),
1076f605b92SMasatake YAMATO  *                       Y = (kind:namespace, nameref:module:X)
108f5f8bd9aSMasatake YAMATO  *                       ------------------------------------------------
1096f605b92SMasatake YAMATO  *                       Don't confuse the kind of Y with namespace role of module kind.
110f5f8bd9aSMasatake YAMATO  *
111f5f8bd9aSMasatake YAMATO  * from X import *       X = (kind:module,  role:namespace)
112f5f8bd9aSMasatake YAMATO  *
113f5f8bd9aSMasatake YAMATO  * from X import Y       X = (kind:module,  role:namespace),
11472ab2762SMasatake YAMATO  *                       Y = (kind:unknown, role:imported, scope:module:X)
115f5f8bd9aSMasatake YAMATO  *
116f5f8bd9aSMasatake YAMATO  * from X import Y as Z  X = (kind:module,  role:namespace),
11772ab2762SMasatake YAMATO  *                       Y = (kind:unknown, role:indirectlyImported, scope:module:X)
1186f605b92SMasatake YAMATO  *                       Z = (kind:unknown, nameref:unknown:Y) */
119f5f8bd9aSMasatake YAMATO 
12013457258SMasatake YAMATO static roleDefinition PythonModuleRoles [] = {
121ce990805SThomas Braun 	{ true, "imported",
122f5f8bd9aSMasatake YAMATO 	  "imported modules" },
123ce990805SThomas Braun 	{ true, "namespace",
124f5f8bd9aSMasatake YAMATO 	  "namespace from where classes/variables/functions are imported" },
125a25c30ffSMasatake YAMATO 	{ true, "indirectlyImported",
126f5f8bd9aSMasatake YAMATO 	  "module imported in alternative name" },
127f5f8bd9aSMasatake YAMATO };
128f5f8bd9aSMasatake YAMATO 
12913457258SMasatake YAMATO static roleDefinition PythonUnknownRoles [] = {
130ce990805SThomas Braun 	{ true, "imported",   "imported from the other module" },
131a25c30ffSMasatake YAMATO 	{ true, "indirectlyImported",
1326dea6ba7SMasatake YAMATO 	  "classes/variables/functions/modules imported in alternative name" },
133f5f8bd9aSMasatake YAMATO };
134f5f8bd9aSMasatake YAMATO 
135e112e8abSMasatake YAMATO static kindDefinition PythonKinds[COUNT_KIND] = {
136ce990805SThomas Braun 	{true, 'c', "class",    "classes"},
137ce990805SThomas Braun 	{true, 'f', "function", "functions"},
138ce990805SThomas Braun 	{true, 'm', "member",   "class members"},
139ce990805SThomas Braun 	{true, 'v', "variable", "variables"},
140ce990805SThomas Braun 	{true, 'I', "namespace", "name referring a module defined in other file"},
141ce990805SThomas Braun 	{true, 'i', "module",    "modules",
142ce990805SThomas Braun 	 .referenceOnly = true,  ATTACH_ROLES(PythonModuleRoles)},
143ce990805SThomas Braun 	{true, 'x', "unknown",   "name referring a class/variable/function/module defined in other module",
144ce990805SThomas Braun 	 .referenceOnly = false, ATTACH_ROLES(PythonUnknownRoles)},
145ce990805SThomas Braun 	{false, 'z', "parameter", "function parameters" },
146ce990805SThomas Braun 	{false, 'l', "local",    "local variables" },
1473ae02089SMasatake YAMATO };
1483ae02089SMasatake YAMATO 
149b0470ee9SMasatake YAMATO static const keywordTable PythonKeywordTable[] = {
1502ff1f9d2SColomban Wendling 	/* keyword			keyword ID */
1512ff1f9d2SColomban Wendling 	{ "as",				KEYWORD_as				},
15216845a4eSColomban Wendling 	{ "async",			KEYWORD_async			},
1532ff1f9d2SColomban Wendling 	{ "cdef",			KEYWORD_cdef			},
1542ff1f9d2SColomban Wendling 	{ "cimport",		KEYWORD_import			},
1552ff1f9d2SColomban Wendling 	{ "class",			KEYWORD_class			},
1562ff1f9d2SColomban Wendling 	{ "cpdef",			KEYWORD_cpdef			},
1572ff1f9d2SColomban Wendling 	{ "def",			KEYWORD_def				},
1582ff1f9d2SColomban Wendling 	{ "extern",			KEYWORD_extern			},
1592ff1f9d2SColomban Wendling 	{ "from",			KEYWORD_from			},
1602ff1f9d2SColomban Wendling 	{ "import",			KEYWORD_import			},
1612ff1f9d2SColomban Wendling 	{ "inline",			KEYWORD_inline			},
1622ff1f9d2SColomban Wendling 	{ "lambda",			KEYWORD_lambda			},
1632ff1f9d2SColomban Wendling 	{ "pass",			KEYWORD_pass			},
1642ff1f9d2SColomban Wendling 	{ "return",			KEYWORD_return			},
1653ae02089SMasatake YAMATO };
1663ae02089SMasatake YAMATO 
1672ff1f9d2SColomban Wendling typedef enum eTokenType {
1682ff1f9d2SColomban Wendling 	/* 0..255 are the byte's value */
1692ff1f9d2SColomban Wendling 	TOKEN_EOF = 256,
1702ff1f9d2SColomban Wendling 	TOKEN_UNDEFINED,
1712ff1f9d2SColomban Wendling 	TOKEN_INDENT,
1722ff1f9d2SColomban Wendling 	TOKEN_KEYWORD,
1732ff1f9d2SColomban Wendling 	TOKEN_OPERATOR,
1742ff1f9d2SColomban Wendling 	TOKEN_IDENTIFIER,
1752ff1f9d2SColomban Wendling 	TOKEN_STRING,
176c378e8b6SMasatake YAMATO 	TOKEN_ARROW,				/* -> */
1772ff1f9d2SColomban Wendling 	TOKEN_WHITESPACE,
1782ff1f9d2SColomban Wendling } tokenType;
1796c11b8afSMasatake YAMATO 
1802ff1f9d2SColomban Wendling typedef struct {
1812ff1f9d2SColomban Wendling 	int				type;
1822ff1f9d2SColomban Wendling 	keywordId		keyword;
1832ff1f9d2SColomban Wendling 	vString *		string;
1842ff1f9d2SColomban Wendling 	int				indent;
1852ff1f9d2SColomban Wendling 	unsigned long 	lineNumber;
1862ff1f9d2SColomban Wendling 	MIOPos			filePosition;
1872ff1f9d2SColomban Wendling } tokenInfo;
1882ff1f9d2SColomban Wendling 
1892ff1f9d2SColomban Wendling struct pythonNestingLevelUserData {
1902ff1f9d2SColomban Wendling 	int indentation;
1916c11b8afSMasatake YAMATO };
1922ff1f9d2SColomban Wendling #define PY_NL(nl) ((struct pythonNestingLevelUserData *) nestingLevelGetUserData (nl))
1936c11b8afSMasatake YAMATO 
1942ff1f9d2SColomban Wendling static langType Lang_python;
1952ff1f9d2SColomban Wendling static unsigned int TokenContinuationDepth = 0;
1962ff1f9d2SColomban Wendling static tokenInfo *NextToken = NULL;
1972ff1f9d2SColomban Wendling static NestingLevels *PythonNestingLevels = NULL;
198d3bb2b5aSJiří Techet static objPool *TokenPool = NULL;
1993ae02089SMasatake YAMATO 
2003ae02089SMasatake YAMATO 
2013ae02089SMasatake YAMATO /* follows PEP-8, and always reports single-underscores as protected
2023ae02089SMasatake YAMATO  * See:
2033ae02089SMasatake YAMATO  * - http://www.python.org/dev/peps/pep-0008/#method-names-and-instance-variables
2043ae02089SMasatake YAMATO  * - http://www.python.org/dev/peps/pep-0008/#designing-for-inheritance
2053ae02089SMasatake YAMATO  */
accessFromIdentifier(const vString * const ident,pythonKind kind,int parentKind)2062ff1f9d2SColomban Wendling static accessType accessFromIdentifier (const vString *const ident,
2072ff1f9d2SColomban Wendling                                         pythonKind kind, int parentKind)
2083ae02089SMasatake YAMATO {
2093ae02089SMasatake YAMATO 	const char *const p = vStringValue (ident);
2103ae02089SMasatake YAMATO 	const size_t len = vStringLength (ident);
2113ae02089SMasatake YAMATO 
2123ae02089SMasatake YAMATO 	/* inside a function/method, private */
2132ff1f9d2SColomban Wendling 	if (parentKind != -1 && parentKind != K_CLASS)
2142ff1f9d2SColomban Wendling 		return ACCESS_PRIVATE;
2153ae02089SMasatake YAMATO 	/* not starting with "_", public */
2163ae02089SMasatake YAMATO 	else if (len < 1 || p[0] != '_')
2172ff1f9d2SColomban Wendling 		return ACCESS_PUBLIC;
2183ae02089SMasatake YAMATO 	/* "__...__": magic methods */
2192ff1f9d2SColomban Wendling 	else if (kind == K_FUNCTION && parentKind == K_CLASS &&
2203ae02089SMasatake YAMATO 	         len > 3 && p[1] == '_' && p[len - 2] == '_' && p[len - 1] == '_')
2212ff1f9d2SColomban Wendling 		return ACCESS_PUBLIC;
2223ae02089SMasatake YAMATO 	/* "__...": name mangling */
2232ff1f9d2SColomban Wendling 	else if (parentKind == K_CLASS && len > 1 && p[1] == '_')
2242ff1f9d2SColomban Wendling 		return ACCESS_PRIVATE;
2253ae02089SMasatake YAMATO 	/* "_...": suggested as non-public, but easily accessible */
2263ae02089SMasatake YAMATO 	else
2272ff1f9d2SColomban Wendling 		return ACCESS_PROTECTED;
2283ae02089SMasatake YAMATO }
2293ae02089SMasatake YAMATO 
initPythonEntry(tagEntryInfo * const e,const tokenInfo * const token,const pythonKind kind)2302ff1f9d2SColomban Wendling static void initPythonEntry (tagEntryInfo *const e, const tokenInfo *const token,
2312ff1f9d2SColomban Wendling                              const pythonKind kind)
2323ae02089SMasatake YAMATO {
2332ff1f9d2SColomban Wendling 	accessType access;
2342ff1f9d2SColomban Wendling 	int parentKind = -1;
2352ff1f9d2SColomban Wendling 	NestingLevel *nl;
2363ae02089SMasatake YAMATO 
23716a2541cSMasatake YAMATO 	initTagEntry (e, vStringValue (token->string), kind);
2382ff1f9d2SColomban Wendling 
2392ff1f9d2SColomban Wendling 	e->lineNumber	= token->lineNumber;
2402ff1f9d2SColomban Wendling 	e->filePosition	= token->filePosition;
2412ff1f9d2SColomban Wendling 
2422ff1f9d2SColomban Wendling 	nl = nestingLevelsGetCurrent (PythonNestingLevels);
2432ff1f9d2SColomban Wendling 	if (nl)
2442ff1f9d2SColomban Wendling 	{
2452ff1f9d2SColomban Wendling 		tagEntryInfo *nlEntry = getEntryOfNestingLevel (nl);
2462ff1f9d2SColomban Wendling 
2472ff1f9d2SColomban Wendling 		e->extensionFields.scopeIndex = nl->corkIndex;
2482ff1f9d2SColomban Wendling 
2492ff1f9d2SColomban Wendling 		/* nlEntry can be NULL if a kind was disabled.  But what can we do
2502ff1f9d2SColomban Wendling 		 * here?  Even disabled kinds should count for the hierarchy I
2512ff1f9d2SColomban Wendling 		 * guess -- as it'd otherwise be wrong -- but with cork we're
2522ff1f9d2SColomban Wendling 		 * fucked up as there's nothing to look up.  Damn. */
2532ff1f9d2SColomban Wendling 		if (nlEntry)
2542ff1f9d2SColomban Wendling 		{
255f92e6bf2SMasatake YAMATO 			parentKind = nlEntry->kindIndex;
2562ff1f9d2SColomban Wendling 
2572ff1f9d2SColomban Wendling 			/* functions directly inside classes are methods, fix it up */
2582ff1f9d2SColomban Wendling 			if (kind == K_FUNCTION && parentKind == K_CLASS)
259f92e6bf2SMasatake YAMATO 				e->kindIndex = K_METHOD;
2602ff1f9d2SColomban Wendling 		}
2612ff1f9d2SColomban Wendling 	}
2622ff1f9d2SColomban Wendling 
2632ff1f9d2SColomban Wendling 	access = accessFromIdentifier (token->string, kind, parentKind);
2642ff1f9d2SColomban Wendling 	e->extensionFields.access = PythonAccesses[access];
2653ae02089SMasatake YAMATO 	/* FIXME: should we really set isFileScope in addition to access? */
2662ff1f9d2SColomban Wendling 	if (access == ACCESS_PRIVATE)
267ce990805SThomas Braun 		e->isFileScope = true;
2683ae02089SMasatake YAMATO }
2693ae02089SMasatake YAMATO 
makeClassTag(const tokenInfo * const token,const vString * const inheritance,const vString * const decorators)2702ff1f9d2SColomban Wendling static int makeClassTag (const tokenInfo *const token,
2715d0fd5feSColomban Wendling                          const vString *const inheritance,
2725d0fd5feSColomban Wendling                          const vString *const decorators)
2733ae02089SMasatake YAMATO {
2742ff1f9d2SColomban Wendling 	if (PythonKinds[K_CLASS].enabled)
2752ff1f9d2SColomban Wendling 	{
2762ff1f9d2SColomban Wendling 		tagEntryInfo e;
277956bd9a1SMasatake YAMATO 
2782ff1f9d2SColomban Wendling 		initPythonEntry (&e, token, K_CLASS);
2792ff1f9d2SColomban Wendling 
2802ff1f9d2SColomban Wendling 		e.extensionFields.inheritance = inheritance ? vStringValue (inheritance) : "";
2815d0fd5feSColomban Wendling 		if (decorators && vStringLength (decorators) > 0)
2825d0fd5feSColomban Wendling 		{
283aa4def17SMasatake YAMATO 			attachParserField (&e, false, PythonFields[F_DECORATORS].ftype,
2845d0fd5feSColomban Wendling 			                   vStringValue (decorators));
2855d0fd5feSColomban Wendling 		}
2862ff1f9d2SColomban Wendling 
2872ff1f9d2SColomban Wendling 		return makeTagEntry (&e);
28802b93863SMasatake YAMATO 	}
2894a95e4a5SColomban Wendling 
290885fbc2cSMasatake YAMATO 	return CORK_NIL;
2913ae02089SMasatake YAMATO }
2923ae02089SMasatake YAMATO 
makeFunctionTag(const tokenInfo * const token,const vString * const arglist,const vString * const decorators)2932ff1f9d2SColomban Wendling static int makeFunctionTag (const tokenInfo *const token,
2945d0fd5feSColomban Wendling                             const vString *const arglist,
2955d0fd5feSColomban Wendling                             const vString *const decorators)
2963ae02089SMasatake YAMATO {
2972ff1f9d2SColomban Wendling 	if (PythonKinds[K_FUNCTION].enabled)
2983ae02089SMasatake YAMATO 	{
2992ff1f9d2SColomban Wendling 		tagEntryInfo e;
3002ff1f9d2SColomban Wendling 
3012ff1f9d2SColomban Wendling 		initPythonEntry (&e, token, K_FUNCTION);
3022ff1f9d2SColomban Wendling 
3032ff1f9d2SColomban Wendling 		if (arglist)
3042ff1f9d2SColomban Wendling 			e.extensionFields.signature = vStringValue (arglist);
3055d0fd5feSColomban Wendling 		if (decorators && vStringLength (decorators) > 0)
3065d0fd5feSColomban Wendling 		{
307aa4def17SMasatake YAMATO 			attachParserField (&e, false, PythonFields[F_DECORATORS].ftype,
3085d0fd5feSColomban Wendling 			                   vStringValue (decorators));
3095d0fd5feSColomban Wendling 		}
3102ff1f9d2SColomban Wendling 
3112ff1f9d2SColomban Wendling 		return makeTagEntry (&e);
3123ae02089SMasatake YAMATO 	}
3132ff1f9d2SColomban Wendling 
3142ff1f9d2SColomban Wendling 	return CORK_NIL;
3152ff1f9d2SColomban Wendling }
3162ff1f9d2SColomban Wendling 
makeSimplePythonTag(const tokenInfo * const token,pythonKind const kind)3172ff1f9d2SColomban Wendling static int makeSimplePythonTag (const tokenInfo *const token, pythonKind const kind)
3182ff1f9d2SColomban Wendling {
3192ff1f9d2SColomban Wendling 	if (PythonKinds[kind].enabled)
3202ff1f9d2SColomban Wendling 	{
3212ff1f9d2SColomban Wendling 		tagEntryInfo e;
3222ff1f9d2SColomban Wendling 
3232ff1f9d2SColomban Wendling 		initPythonEntry (&e, token, kind);
3242ff1f9d2SColomban Wendling 		return makeTagEntry (&e);
3252ff1f9d2SColomban Wendling 	}
3262ff1f9d2SColomban Wendling 
3272ff1f9d2SColomban Wendling 	return CORK_NIL;
3282ff1f9d2SColomban Wendling }
3292ff1f9d2SColomban Wendling 
makeSimplePythonRefTag(const tokenInfo * const token,const vString * const altName,pythonKind const kind,int roleIndex,xtagType xtag)3302ff1f9d2SColomban Wendling static int makeSimplePythonRefTag (const tokenInfo *const token,
3312ff1f9d2SColomban Wendling                                    const vString *const altName,
3322ff1f9d2SColomban Wendling                                    pythonKind const kind,
3332ff1f9d2SColomban Wendling                                    int roleIndex, xtagType xtag)
3342ff1f9d2SColomban Wendling {
335102b735bSColomban Wendling 	if (isXtagEnabled (XTAG_REFERENCE_TAGS) &&
336102b735bSColomban Wendling 	    PythonKinds[kind].roles[roleIndex].enabled)
3372ff1f9d2SColomban Wendling 	{
3382ff1f9d2SColomban Wendling 		tagEntryInfo e;
3392ff1f9d2SColomban Wendling 
3402ff1f9d2SColomban Wendling 		initRefTagEntry (&e, vStringValue (altName ? altName : token->string),
34116a2541cSMasatake YAMATO 		                 kind, roleIndex);
3422ff1f9d2SColomban Wendling 
3432ff1f9d2SColomban Wendling 		e.lineNumber	= token->lineNumber;
3442ff1f9d2SColomban Wendling 		e.filePosition	= token->filePosition;
3452ff1f9d2SColomban Wendling 
3462ff1f9d2SColomban Wendling 		if (xtag != XTAG_UNKNOWN)
3472ff1f9d2SColomban Wendling 			markTagExtraBit (&e, xtag);
3482ff1f9d2SColomban Wendling 
3492ff1f9d2SColomban Wendling 		return makeTagEntry (&e);
3502ff1f9d2SColomban Wendling 	}
3512ff1f9d2SColomban Wendling 
3522ff1f9d2SColomban Wendling 	return CORK_NIL;
3532ff1f9d2SColomban Wendling }
3542ff1f9d2SColomban Wendling 
newPoolToken(void * createArg CTAGS_ATTR_UNUSED)355e013efc1SMasatake YAMATO static void *newPoolToken (void *createArg CTAGS_ATTR_UNUSED)
3562ff1f9d2SColomban Wendling {
3576ff4799bSJiří Techet 	tokenInfo *token = xMalloc (1, tokenInfo);
3582ff1f9d2SColomban Wendling 	token->string = vStringNew ();
3592ff1f9d2SColomban Wendling 	return token;
3602ff1f9d2SColomban Wendling }
3612ff1f9d2SColomban Wendling 
deletePoolToken(void * data)3626ff4799bSJiří Techet static void deletePoolToken (void *data)
3632ff1f9d2SColomban Wendling {
3646ff4799bSJiří Techet 	tokenInfo *token = data;
3652ff1f9d2SColomban Wendling 	vStringDelete (token->string);
3662ff1f9d2SColomban Wendling 	eFree (token);
3672ff1f9d2SColomban Wendling }
3682ff1f9d2SColomban Wendling 
clearPoolToken(void * data)3696ff4799bSJiří Techet static void clearPoolToken (void *data)
370d3bb2b5aSJiří Techet {
3716ff4799bSJiří Techet 	tokenInfo *token = data;
3726ff4799bSJiří Techet 
373d3bb2b5aSJiří Techet 	token->type			= TOKEN_UNDEFINED;
374d3bb2b5aSJiří Techet 	token->keyword		= KEYWORD_NONE;
375d3bb2b5aSJiří Techet 	token->indent		= 0;
376d3bb2b5aSJiří Techet 	token->lineNumber   = getInputLineNumber ();
377d3bb2b5aSJiří Techet 	token->filePosition = getInputFilePosition ();
378d3bb2b5aSJiří Techet 	vStringClear (token->string);
379d3bb2b5aSJiří Techet }
380d3bb2b5aSJiří Techet 
copyToken(tokenInfo * const dest,const tokenInfo * const src)3812ff1f9d2SColomban Wendling static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
3822ff1f9d2SColomban Wendling {
3832ff1f9d2SColomban Wendling 	dest->lineNumber = src->lineNumber;
3842ff1f9d2SColomban Wendling 	dest->filePosition = src->filePosition;
3852ff1f9d2SColomban Wendling 	dest->type = src->type;
3862ff1f9d2SColomban Wendling 	dest->keyword = src->keyword;
3872ff1f9d2SColomban Wendling 	dest->indent = src->indent;
3882ff1f9d2SColomban Wendling 	vStringCopy(dest->string, src->string);
3892ff1f9d2SColomban Wendling }
3902ff1f9d2SColomban Wendling 
3913ae02089SMasatake YAMATO /* Skip a single or double quoted string. */
readString(vString * const string,const int delimiter)3922ff1f9d2SColomban Wendling static void readString (vString *const string, const int delimiter)
3933ae02089SMasatake YAMATO {
3943ae02089SMasatake YAMATO 	int escaped = 0;
3952ff1f9d2SColomban Wendling 	int c;
3962ff1f9d2SColomban Wendling 
3972ff1f9d2SColomban Wendling 	while ((c = getcFromInputFile ()) != EOF)
3983ae02089SMasatake YAMATO 	{
3993ae02089SMasatake YAMATO 		if (escaped)
4002ff1f9d2SColomban Wendling 		{
4012ff1f9d2SColomban Wendling 			vStringPut (string, c);
4023ae02089SMasatake YAMATO 			escaped--;
4032ff1f9d2SColomban Wendling 		}
4042ff1f9d2SColomban Wendling 		else if (c == '\\')
4053ae02089SMasatake YAMATO 			escaped++;
4062ff1f9d2SColomban Wendling 		else if (c == delimiter || c == '\n' || c == '\r')
407f4b83e63SMasatake YAMATO 		{
4082ff1f9d2SColomban Wendling 			if (c != delimiter)
4092ff1f9d2SColomban Wendling 				ungetcToInputFile (c);
4102ff1f9d2SColomban Wendling 			break;
4112ff1f9d2SColomban Wendling 		}
412f4b83e63SMasatake YAMATO 		else
4132ff1f9d2SColomban Wendling 			vStringPut (string, c);
4142ff1f9d2SColomban Wendling 	}
415f4b83e63SMasatake YAMATO }
416f4b83e63SMasatake YAMATO 
4172ff1f9d2SColomban Wendling /* Skip a single or double triple quoted string. */
readTripleString(vString * const string,const int delimiter)4182ff1f9d2SColomban Wendling static void readTripleString (vString *const string, const int delimiter)
4193ae02089SMasatake YAMATO {
4202ff1f9d2SColomban Wendling 	int c;
4212ff1f9d2SColomban Wendling 	int escaped = 0;
4222ff1f9d2SColomban Wendling 	int n = 0;
4232ff1f9d2SColomban Wendling 	while ((c = getcFromInputFile ()) != EOF)
4243ae02089SMasatake YAMATO 	{
4252ff1f9d2SColomban Wendling 		if (c == delimiter && ! escaped)
426f822ba44SMasatake YAMATO 		{
4272ff1f9d2SColomban Wendling 			if (++n >= 3)
4282ff1f9d2SColomban Wendling 				break;
429f822ba44SMasatake YAMATO 		}
4302ff1f9d2SColomban Wendling 		else
4312ff1f9d2SColomban Wendling 		{
4322ff1f9d2SColomban Wendling 			for (; n > 0; n--)
4332ff1f9d2SColomban Wendling 				vStringPut (string, delimiter);
4342ff1f9d2SColomban Wendling 			if (c != '\\' || escaped)
4352ff1f9d2SColomban Wendling 				vStringPut (string, c);
4362ff1f9d2SColomban Wendling 			n = 0;
437f822ba44SMasatake YAMATO 		}
4383ae02089SMasatake YAMATO 
4392ff1f9d2SColomban Wendling 		if (escaped)
4402ff1f9d2SColomban Wendling 			escaped--;
4412ff1f9d2SColomban Wendling 		else if (c == '\\')
4422ff1f9d2SColomban Wendling 			escaped++;
4433ae02089SMasatake YAMATO 	}
44498e25217SJiří Techet }
4453ae02089SMasatake YAMATO 
readIdentifier(vString * const string,const int firstChar)4462ff1f9d2SColomban Wendling static void readIdentifier (vString *const string, const int firstChar)
447cae0f365SMasatake YAMATO {
4482ff1f9d2SColomban Wendling 	int c = firstChar;
4492ff1f9d2SColomban Wendling 	do
4502ff1f9d2SColomban Wendling 	{
4512ff1f9d2SColomban Wendling 		vStringPut (string, (char) c);
4522ff1f9d2SColomban Wendling 		c = getcFromInputFile ();
4532ff1f9d2SColomban Wendling 	}
4542ff1f9d2SColomban Wendling 	while (isIdentifierChar (c));
4552ff1f9d2SColomban Wendling 	ungetcToInputFile (c);
456cae0f365SMasatake YAMATO }
457cae0f365SMasatake YAMATO 
ungetToken(tokenInfo * const token)4582ff1f9d2SColomban Wendling static void ungetToken (tokenInfo *const token)
4597f34b31fSMasatake YAMATO {
4602ff1f9d2SColomban Wendling 	Assert (NextToken == NULL);
4616ff4799bSJiří Techet 	NextToken = newToken ();
4622ff1f9d2SColomban Wendling 	copyToken (NextToken, token);
4637f34b31fSMasatake YAMATO }
4647f34b31fSMasatake YAMATO 
readTokenFull(tokenInfo * const token,bool inclWhitespaces)465ce990805SThomas Braun static void readTokenFull (tokenInfo *const token, bool inclWhitespaces)
4663ae02089SMasatake YAMATO {
4672ff1f9d2SColomban Wendling 	int c;
4682ff1f9d2SColomban Wendling 	int n;
4692ff1f9d2SColomban Wendling 
4702ff1f9d2SColomban Wendling 	/* if we've got a token held back, emit it */
4712ff1f9d2SColomban Wendling 	if (NextToken)
4722ff1f9d2SColomban Wendling 	{
4732ff1f9d2SColomban Wendling 		copyToken (token, NextToken);
4746ff4799bSJiří Techet 		deleteToken (NextToken);
4752ff1f9d2SColomban Wendling 		NextToken = NULL;
4762ff1f9d2SColomban Wendling 		return;
4773ae02089SMasatake YAMATO 	}
4783ae02089SMasatake YAMATO 
4792ff1f9d2SColomban Wendling 	token->type		= TOKEN_UNDEFINED;
4802ff1f9d2SColomban Wendling 	token->keyword	= KEYWORD_NONE;
4812ff1f9d2SColomban Wendling 	vStringClear (token->string);
4822ff1f9d2SColomban Wendling 
4832ff1f9d2SColomban Wendling getNextChar:
4842ff1f9d2SColomban Wendling 
4852ff1f9d2SColomban Wendling 	n = 0;
4862ff1f9d2SColomban Wendling 	do
4873ae02089SMasatake YAMATO 	{
4882ff1f9d2SColomban Wendling 		c = getcFromInputFile ();
4892ff1f9d2SColomban Wendling 		n++;
4903ae02089SMasatake YAMATO 	}
4912ff1f9d2SColomban Wendling 	while (c == ' ' || c == '\t' || c == '\f');
4922ff1f9d2SColomban Wendling 
4934340e862SColomban Wendling 	token->lineNumber   = getInputLineNumber ();
4942ff1f9d2SColomban Wendling 	token->filePosition = getInputFilePosition ();
4952ff1f9d2SColomban Wendling 
4962ff1f9d2SColomban Wendling 	if (inclWhitespaces && n > 1 && c != '\r' && c != '\n')
4972ff1f9d2SColomban Wendling 	{
4982ff1f9d2SColomban Wendling 		ungetcToInputFile (c);
4992ff1f9d2SColomban Wendling 		vStringPut (token->string, ' ');
5002ff1f9d2SColomban Wendling 		token->type = TOKEN_WHITESPACE;
5012ff1f9d2SColomban Wendling 		return;
5023ae02089SMasatake YAMATO 	}
5033ae02089SMasatake YAMATO 
5042ff1f9d2SColomban Wendling 	switch (c)
5053ae02089SMasatake YAMATO 	{
5062ff1f9d2SColomban Wendling 		case EOF:
5072ff1f9d2SColomban Wendling 			token->type = TOKEN_EOF;
5082ff1f9d2SColomban Wendling 			break;
5092ff1f9d2SColomban Wendling 
5102ff1f9d2SColomban Wendling 		case '\'':
5112ff1f9d2SColomban Wendling 		case '"':
5122ff1f9d2SColomban Wendling 		{
5132ff1f9d2SColomban Wendling 			int d = getcFromInputFile ();
5142ff1f9d2SColomban Wendling 			token->type = TOKEN_STRING;
5152ff1f9d2SColomban Wendling 			vStringPut (token->string, c);
5162ff1f9d2SColomban Wendling 			if (d != c)
5172ff1f9d2SColomban Wendling 			{
5182ff1f9d2SColomban Wendling 				ungetcToInputFile (d);
5192ff1f9d2SColomban Wendling 				readString (token->string, c);
5202ff1f9d2SColomban Wendling 			}
5212ff1f9d2SColomban Wendling 			else if ((d = getcFromInputFile ()) == c)
5222ff1f9d2SColomban Wendling 				readTripleString (token->string, c);
5232ff1f9d2SColomban Wendling 			else /* empty string */
5242ff1f9d2SColomban Wendling 				ungetcToInputFile (d);
5252ff1f9d2SColomban Wendling 			vStringPut (token->string, c);
5264340e862SColomban Wendling 			token->lineNumber = getInputLineNumber ();
5272ff1f9d2SColomban Wendling 			token->filePosition = getInputFilePosition ();
5282ff1f9d2SColomban Wendling 			break;
5293ae02089SMasatake YAMATO 		}
5303ae02089SMasatake YAMATO 
5312ff1f9d2SColomban Wendling 		case '=':
5323ae02089SMasatake YAMATO 		{
5332ff1f9d2SColomban Wendling 			int d = getcFromInputFile ();
5342ff1f9d2SColomban Wendling 			vStringPut (token->string, c);
5352ff1f9d2SColomban Wendling 			if (d == c)
5363ae02089SMasatake YAMATO 			{
5372ff1f9d2SColomban Wendling 				vStringPut (token->string, d);
5382ff1f9d2SColomban Wendling 				token->type = TOKEN_OPERATOR;
5393ae02089SMasatake YAMATO 			}
5402ff1f9d2SColomban Wendling 			else
5412ff1f9d2SColomban Wendling 			{
5422ff1f9d2SColomban Wendling 				ungetcToInputFile (d);
5432ff1f9d2SColomban Wendling 				token->type = c;
5442ff1f9d2SColomban Wendling 			}
5452ff1f9d2SColomban Wendling 			break;
5463ae02089SMasatake YAMATO 		}
5473ae02089SMasatake YAMATO 
5482ff1f9d2SColomban Wendling 		case '-':
549c378e8b6SMasatake YAMATO 		{
550c378e8b6SMasatake YAMATO 			int d = getcFromInputFile ();
551c378e8b6SMasatake YAMATO 			if (d == '>')
552c378e8b6SMasatake YAMATO 			{
553c378e8b6SMasatake YAMATO 				vStringPut (token->string, c);
554c378e8b6SMasatake YAMATO 				vStringPut (token->string, d);
555c378e8b6SMasatake YAMATO 				token->type = TOKEN_ARROW;
556c378e8b6SMasatake YAMATO 				break;
557c378e8b6SMasatake YAMATO 			}
558c378e8b6SMasatake YAMATO 			ungetcToInputFile (d);
559c378e8b6SMasatake YAMATO 			/* fall through */
560c378e8b6SMasatake YAMATO 		}
561c378e8b6SMasatake YAMATO 		case '+':
5622ff1f9d2SColomban Wendling 		case '*':
5632ff1f9d2SColomban Wendling 		case '%':
5642ff1f9d2SColomban Wendling 		case '<':
5652ff1f9d2SColomban Wendling 		case '>':
5662ff1f9d2SColomban Wendling 		case '/':
5677f34b31fSMasatake YAMATO 		{
5682ff1f9d2SColomban Wendling 			int d = getcFromInputFile ();
5692ff1f9d2SColomban Wendling 			vStringPut (token->string, c);
5702ff1f9d2SColomban Wendling 			if (d != '=')
571f34b6795SColomban Wendling 			{
5722ff1f9d2SColomban Wendling 				ungetcToInputFile (d);
573f34b6795SColomban Wendling 				token->type = c;
574f34b6795SColomban Wendling 			}
5752ff1f9d2SColomban Wendling 			else
576f34b6795SColomban Wendling 			{
5772ff1f9d2SColomban Wendling 				vStringPut (token->string, d);
5782ff1f9d2SColomban Wendling 				token->type = TOKEN_OPERATOR;
579f34b6795SColomban Wendling 			}
5802ff1f9d2SColomban Wendling 			break;
5817f34b31fSMasatake YAMATO 		}
5827f34b31fSMasatake YAMATO 
5832ff1f9d2SColomban Wendling 		/* eats newline to implement line continuation  */
5842ff1f9d2SColomban Wendling 		case '\\':
5853ae02089SMasatake YAMATO 		{
5862ff1f9d2SColomban Wendling 			int d = getcFromInputFile ();
5872ff1f9d2SColomban Wendling 			if (d == '\r')
5882ff1f9d2SColomban Wendling 				d = getcFromInputFile ();
5892ff1f9d2SColomban Wendling 			if (d != '\n')
5902ff1f9d2SColomban Wendling 				ungetcToInputFile (d);
5912ff1f9d2SColomban Wendling 			goto getNextChar;
5922ff1f9d2SColomban Wendling 		}
5932ff1f9d2SColomban Wendling 
5942ff1f9d2SColomban Wendling 		case '#': /* comment */
5952ff1f9d2SColomban Wendling 		case '\r': /* newlines for indent */
5962ff1f9d2SColomban Wendling 		case '\n':
5970f13d82bSColomban Wendling 		{
5980f13d82bSColomban Wendling 			int indent = 0;
5992ff1f9d2SColomban Wendling 			do
6002ff1f9d2SColomban Wendling 			{
6012ff1f9d2SColomban Wendling 				if (c == '#')
6022ff1f9d2SColomban Wendling 				{
6032ff1f9d2SColomban Wendling 					do
6042ff1f9d2SColomban Wendling 						c = getcFromInputFile ();
6052ff1f9d2SColomban Wendling 					while (c != EOF && c != '\r' && c != '\n');
6062ff1f9d2SColomban Wendling 				}
6072ff1f9d2SColomban Wendling 				if (c == '\r')
6082ff1f9d2SColomban Wendling 				{
6092ff1f9d2SColomban Wendling 					int d = getcFromInputFile ();
6102ff1f9d2SColomban Wendling 					if (d != '\n')
6112ff1f9d2SColomban Wendling 						ungetcToInputFile (d);
6122ff1f9d2SColomban Wendling 				}
6130f13d82bSColomban Wendling 				indent = 0;
6142ff1f9d2SColomban Wendling 				while ((c = getcFromInputFile ()) == ' ' || c == '\t' || c == '\f')
6152ff1f9d2SColomban Wendling 				{
6162ff1f9d2SColomban Wendling 					if (c == '\t')
6170f13d82bSColomban Wendling 						indent += 8 - (indent % 8);
6182ff1f9d2SColomban Wendling 					else if (c == '\f') /* yeah, it's weird */
6190f13d82bSColomban Wendling 						indent = 0;
6202ff1f9d2SColomban Wendling 					else
6210f13d82bSColomban Wendling 						indent++;
6222ff1f9d2SColomban Wendling 				}
6232ff1f9d2SColomban Wendling 			} /* skip completely empty lines, so retry */
6242ff1f9d2SColomban Wendling 			while (c == '\r' || c == '\n' || c == '#');
6252ff1f9d2SColomban Wendling 			ungetcToInputFile (c);
6262ff1f9d2SColomban Wendling 			if (TokenContinuationDepth > 0)
6272ff1f9d2SColomban Wendling 			{
6282ff1f9d2SColomban Wendling 				if (inclWhitespaces)
6292ff1f9d2SColomban Wendling 				{
6302ff1f9d2SColomban Wendling 					vStringPut (token->string, ' ');
6312ff1f9d2SColomban Wendling 					token->type = TOKEN_WHITESPACE;
6322ff1f9d2SColomban Wendling 				}
6332ff1f9d2SColomban Wendling 				else
6342ff1f9d2SColomban Wendling 					goto getNextChar;
6352ff1f9d2SColomban Wendling 			}
6360f13d82bSColomban Wendling 			else
6370f13d82bSColomban Wendling 			{
6380f13d82bSColomban Wendling 				token->type = TOKEN_INDENT;
6390f13d82bSColomban Wendling 				token->indent = indent;
6400f13d82bSColomban Wendling 			}
6412ff1f9d2SColomban Wendling 			break;
6420f13d82bSColomban Wendling 		}
6432ff1f9d2SColomban Wendling 
6442ff1f9d2SColomban Wendling 		default:
6452ff1f9d2SColomban Wendling 			if (! isIdentifierChar (c))
6462ff1f9d2SColomban Wendling 			{
6472ff1f9d2SColomban Wendling 				vStringPut (token->string, c);
6482ff1f9d2SColomban Wendling 				token->type = c;
6492ff1f9d2SColomban Wendling 			}
6502ff1f9d2SColomban Wendling 			else
6512ff1f9d2SColomban Wendling 			{
652c9fc4e04SColomban Wendling 				/* FIXME: handle U, B, R and F string prefixes? */
6532ff1f9d2SColomban Wendling 				readIdentifier (token->string, c);
6548f29d6c9SJiří Techet 				token->keyword = lookupKeyword (vStringValue (token->string), Lang_python);
6552ff1f9d2SColomban Wendling 				if (token->keyword == KEYWORD_NONE)
6562ff1f9d2SColomban Wendling 					token->type = TOKEN_IDENTIFIER;
6572ff1f9d2SColomban Wendling 				else
6582ff1f9d2SColomban Wendling 					token->type = TOKEN_KEYWORD;
6592ff1f9d2SColomban Wendling 			}
6602ff1f9d2SColomban Wendling 			break;
6612ff1f9d2SColomban Wendling 	}
6622ff1f9d2SColomban Wendling 
6632ff1f9d2SColomban Wendling 	/* handle implicit continuation lines not to emit INDENT inside brackets
6642ff1f9d2SColomban Wendling 	 * https://docs.python.org/3.6/reference/lexical_analysis.html#implicit-line-joining */
6652ff1f9d2SColomban Wendling 	if (token->type == '(' ||
6662ff1f9d2SColomban Wendling 	    token->type == '{' ||
6672ff1f9d2SColomban Wendling 	    token->type == '[')
6682ff1f9d2SColomban Wendling 	{
6692ff1f9d2SColomban Wendling 		TokenContinuationDepth ++;
6702ff1f9d2SColomban Wendling 	}
6712ff1f9d2SColomban Wendling 	else if (TokenContinuationDepth > 0 &&
6722ff1f9d2SColomban Wendling 	         (token->type == ')' ||
6732ff1f9d2SColomban Wendling 	          token->type == '}' ||
6742ff1f9d2SColomban Wendling 	          token->type == ']'))
6752ff1f9d2SColomban Wendling 	{
6762ff1f9d2SColomban Wendling 		TokenContinuationDepth --;
6772ff1f9d2SColomban Wendling 	}
6782ff1f9d2SColomban Wendling }
6792ff1f9d2SColomban Wendling 
readToken(tokenInfo * const token)6802ff1f9d2SColomban Wendling static void readToken (tokenInfo *const token)
6812ff1f9d2SColomban Wendling {
682ce990805SThomas Braun 	readTokenFull (token, false);
6832ff1f9d2SColomban Wendling }
6842ff1f9d2SColomban Wendling 
6852ff1f9d2SColomban Wendling /*================================= parsing =================================*/
6862ff1f9d2SColomban Wendling 
6872ff1f9d2SColomban Wendling 
reprCat(vString * const repr,const tokenInfo * const token)6882ff1f9d2SColomban Wendling static void reprCat (vString *const repr, const tokenInfo *const token)
6892ff1f9d2SColomban Wendling {
6902ff1f9d2SColomban Wendling 	if (token->type != TOKEN_INDENT &&
6912ff1f9d2SColomban Wendling 	    token->type != TOKEN_WHITESPACE)
6922ff1f9d2SColomban Wendling 	{
6932ff1f9d2SColomban Wendling 		vStringCat (repr, token->string);
6942ff1f9d2SColomban Wendling 	}
6952ff1f9d2SColomban Wendling 	else if (vStringLength (repr) > 0 && vStringLast (repr) != ' ')
6962ff1f9d2SColomban Wendling 	{
6972ff1f9d2SColomban Wendling 		vStringPut (repr, ' ');
6982ff1f9d2SColomban Wendling 	}
6992ff1f9d2SColomban Wendling }
7002ff1f9d2SColomban Wendling 
skipOverPair(tokenInfo * const token,int tOpen,int tClose,vString * const repr,bool reprOuterPair)701ce990805SThomas Braun static bool skipOverPair (tokenInfo *const token, int tOpen, int tClose,
702ce990805SThomas Braun                              vString *const repr, bool reprOuterPair)
7032ff1f9d2SColomban Wendling {
7042ff1f9d2SColomban Wendling 	if (token->type == tOpen)
7052ff1f9d2SColomban Wendling 	{
7062ff1f9d2SColomban Wendling 		int depth = 1;
7072ff1f9d2SColomban Wendling 
7082ff1f9d2SColomban Wendling 		if (repr && reprOuterPair)
7092ff1f9d2SColomban Wendling 			reprCat (repr, token);
7102ff1f9d2SColomban Wendling 		do
7112ff1f9d2SColomban Wendling 		{
712ce990805SThomas Braun 			readTokenFull (token, true);
7132ff1f9d2SColomban Wendling 			if (repr && (reprOuterPair || token->type != tClose || depth > 1))
7142ff1f9d2SColomban Wendling 			{
7152ff1f9d2SColomban Wendling 				reprCat (repr, token);
7162ff1f9d2SColomban Wendling 			}
7172ff1f9d2SColomban Wendling 			if (token->type == tOpen)
7182ff1f9d2SColomban Wendling 				depth ++;
7192ff1f9d2SColomban Wendling 			else if (token->type == tClose)
7202ff1f9d2SColomban Wendling 				depth --;
7212ff1f9d2SColomban Wendling 		}
7222ff1f9d2SColomban Wendling 		while (token->type != TOKEN_EOF && depth > 0);
7232ff1f9d2SColomban Wendling 	}
7242ff1f9d2SColomban Wendling 
7252ff1f9d2SColomban Wendling 	return token->type == tClose;
7262ff1f9d2SColomban Wendling }
7272ff1f9d2SColomban Wendling 
skipLambdaArglist(tokenInfo * const token,vString * const repr)728ce990805SThomas Braun static bool skipLambdaArglist (tokenInfo *const token, vString *const repr)
7292ff1f9d2SColomban Wendling {
7302ff1f9d2SColomban Wendling 	while (token->type != TOKEN_EOF && token->type != ':' &&
7312ff1f9d2SColomban Wendling 	       /* avoid reading too much, just in case */
7322ff1f9d2SColomban Wendling 	       token->type != TOKEN_INDENT)
7332ff1f9d2SColomban Wendling 	{
734ce990805SThomas Braun 		bool readNext = true;
7352ff1f9d2SColomban Wendling 
7362ff1f9d2SColomban Wendling 		if (token->type == '(')
737ce990805SThomas Braun 			readNext = skipOverPair (token, '(', ')', repr, true);
7382ff1f9d2SColomban Wendling 		else if (token->type == '[')
739ce990805SThomas Braun 			readNext = skipOverPair (token, '[', ']', repr, true);
7402ff1f9d2SColomban Wendling 		else if (token->type == '{')
741ce990805SThomas Braun 			readNext = skipOverPair (token, '{', '}', repr, true);
7422ff1f9d2SColomban Wendling 		else if (token->keyword == KEYWORD_lambda)
7432ff1f9d2SColomban Wendling 		{ /* handle lambdas in a default value */
7442ff1f9d2SColomban Wendling 			if (repr)
7452ff1f9d2SColomban Wendling 				reprCat (repr, token);
746ce990805SThomas Braun 			readTokenFull (token, true);
7472ff1f9d2SColomban Wendling 			readNext = skipLambdaArglist (token, repr);
7482ff1f9d2SColomban Wendling 			if (token->type == ':')
749ce990805SThomas Braun 				readNext = true;
7502ff1f9d2SColomban Wendling 			if (readNext && repr)
7512ff1f9d2SColomban Wendling 				reprCat (repr, token);
7522ff1f9d2SColomban Wendling 		}
7532ff1f9d2SColomban Wendling 		else if (repr)
7542ff1f9d2SColomban Wendling 		{
7552ff1f9d2SColomban Wendling 			reprCat (repr, token);
7562ff1f9d2SColomban Wendling 		}
7572ff1f9d2SColomban Wendling 
7582ff1f9d2SColomban Wendling 		if (readNext)
759ce990805SThomas Braun 			readTokenFull (token, true);
7602ff1f9d2SColomban Wendling 	}
761ce990805SThomas Braun 	return false;
7622ff1f9d2SColomban Wendling }
7632ff1f9d2SColomban Wendling 
readQualifiedName(tokenInfo * const nameToken)7642ff1f9d2SColomban Wendling static void readQualifiedName (tokenInfo *const nameToken)
7652ff1f9d2SColomban Wendling {
7662ff1f9d2SColomban Wendling 	readToken (nameToken);
7672ff1f9d2SColomban Wendling 
7682ff1f9d2SColomban Wendling 	if (nameToken->type == TOKEN_IDENTIFIER ||
7692ff1f9d2SColomban Wendling 	    nameToken->type == '.')
7702ff1f9d2SColomban Wendling 	{
7712ff1f9d2SColomban Wendling 		vString *qualifiedName = vStringNew ();
7726ff4799bSJiří Techet 		tokenInfo *token = newToken ();
7732ff1f9d2SColomban Wendling 
7742ff1f9d2SColomban Wendling 		while (nameToken->type == TOKEN_IDENTIFIER ||
7752ff1f9d2SColomban Wendling 		       nameToken->type == '.')
7762ff1f9d2SColomban Wendling 		{
7772ff1f9d2SColomban Wendling 			vStringCat (qualifiedName, nameToken->string);
7782ff1f9d2SColomban Wendling 			copyToken (token, nameToken);
7792ff1f9d2SColomban Wendling 
7802ff1f9d2SColomban Wendling 			readToken (nameToken);
7812ff1f9d2SColomban Wendling 		}
7822ff1f9d2SColomban Wendling 		/* put the last, non-matching, token back */
7832ff1f9d2SColomban Wendling 		ungetToken (nameToken);
7842ff1f9d2SColomban Wendling 
7852ff1f9d2SColomban Wendling 		copyToken (nameToken, token);
7862ff1f9d2SColomban Wendling 		nameToken->type = TOKEN_IDENTIFIER;
7872ff1f9d2SColomban Wendling 		vStringCopy (nameToken->string, qualifiedName);
7882ff1f9d2SColomban Wendling 
7896ff4799bSJiří Techet 		deleteToken (token);
7902ff1f9d2SColomban Wendling 		vStringDelete (qualifiedName);
7912ff1f9d2SColomban Wendling 	}
7922ff1f9d2SColomban Wendling }
7932ff1f9d2SColomban Wendling 
readCDefName(tokenInfo * const token,pythonKind * kind)794ce990805SThomas Braun static bool readCDefName (tokenInfo *const token, pythonKind *kind)
7952ff1f9d2SColomban Wendling {
7962ff1f9d2SColomban Wendling 	readToken (token);
7972ff1f9d2SColomban Wendling 
7982ff1f9d2SColomban Wendling 	if (token->keyword == KEYWORD_extern ||
7992ff1f9d2SColomban Wendling 	    token->keyword == KEYWORD_import)
8002ff1f9d2SColomban Wendling 	{
8012ff1f9d2SColomban Wendling 		readToken (token);
8022ff1f9d2SColomban Wendling 		if (token->keyword == KEYWORD_from)
803ce990805SThomas Braun 			return false;
8042ff1f9d2SColomban Wendling 	}
8052ff1f9d2SColomban Wendling 
8062ff1f9d2SColomban Wendling 	if (token->keyword == KEYWORD_class)
8072ff1f9d2SColomban Wendling 	{
8082ff1f9d2SColomban Wendling 		*kind = K_CLASS;
8092ff1f9d2SColomban Wendling 		readToken (token);
8102ff1f9d2SColomban Wendling 	}
8112ff1f9d2SColomban Wendling 	else
8121d511f1fSColomban Wendling 	{
8131d511f1fSColomban Wendling 		/* skip the optional type declaration -- everything on the same line
8142ff1f9d2SColomban Wendling 		 * until an identifier followed by "(". */
8156ff4799bSJiří Techet 		tokenInfo *candidate = newToken ();
8162ff1f9d2SColomban Wendling 
8172ff1f9d2SColomban Wendling 		while (token->type != TOKEN_EOF &&
8182ff1f9d2SColomban Wendling 		       token->type != TOKEN_INDENT &&
8192ff1f9d2SColomban Wendling 		       token->type != '=' &&
8202ff1f9d2SColomban Wendling 		       token->type != ',' &&
8212ff1f9d2SColomban Wendling 		       token->type != ':')
8222ff1f9d2SColomban Wendling 		{
8232ff1f9d2SColomban Wendling 			if (token->type == '[')
8242ff1f9d2SColomban Wendling 			{
825ce990805SThomas Braun 				if (skipOverPair (token, '[', ']', NULL, false))
8262ff1f9d2SColomban Wendling 					readToken (token);
8272ff1f9d2SColomban Wendling 			}
8282ff1f9d2SColomban Wendling 			else if (token->type == '(')
8292ff1f9d2SColomban Wendling 			{
830ce990805SThomas Braun 				if (skipOverPair (token, '(', ')', NULL, false))
8312ff1f9d2SColomban Wendling 					readToken (token);
8322ff1f9d2SColomban Wendling 			}
8332ff1f9d2SColomban Wendling 			else if (token->type == TOKEN_IDENTIFIER)
8342ff1f9d2SColomban Wendling 			{
8352ff1f9d2SColomban Wendling 				copyToken (candidate, token);
8362ff1f9d2SColomban Wendling 				readToken (token);
8372ff1f9d2SColomban Wendling 				if (token->type == '(')
8382ff1f9d2SColomban Wendling 				{ /* okay, we really found a function, use this */
8392ff1f9d2SColomban Wendling 					*kind = K_FUNCTION;
8402ff1f9d2SColomban Wendling 					ungetToken (token);
8412ff1f9d2SColomban Wendling 					copyToken (token, candidate);
8422ff1f9d2SColomban Wendling 					break;
8432ff1f9d2SColomban Wendling 				}
8442ff1f9d2SColomban Wendling 			}
8452ff1f9d2SColomban Wendling 			else
8462ff1f9d2SColomban Wendling 				readToken (token);
8472ff1f9d2SColomban Wendling 		}
8482ff1f9d2SColomban Wendling 
8496ff4799bSJiří Techet 		deleteToken (candidate);
8502ff1f9d2SColomban Wendling 	}
8512ff1f9d2SColomban Wendling 
8522ff1f9d2SColomban Wendling 	return token->type == TOKEN_IDENTIFIER;
8532ff1f9d2SColomban Wendling }
8542ff1f9d2SColomban Wendling 
parseParamTypeAnnotation(tokenInfo * const token,vString * arglist)855a1cdce69SMasatake YAMATO static vString *parseParamTypeAnnotation (tokenInfo *const token,
856a1cdce69SMasatake YAMATO 										  vString *arglist)
857a1cdce69SMasatake YAMATO {
858a1cdce69SMasatake YAMATO 	readToken (token);
859a1cdce69SMasatake YAMATO 	if (token->type != ':')
860a1cdce69SMasatake YAMATO 	{
861a1cdce69SMasatake YAMATO 		ungetToken (token);
862a1cdce69SMasatake YAMATO 		return NULL;
863a1cdce69SMasatake YAMATO 	}
864a1cdce69SMasatake YAMATO 
865a1cdce69SMasatake YAMATO 	reprCat (arglist, token);
866a1cdce69SMasatake YAMATO 	int depth = 0;
867a1cdce69SMasatake YAMATO 	vString *t = vStringNew ();
868a1cdce69SMasatake YAMATO 	while (true)
869a1cdce69SMasatake YAMATO 	{
870a1cdce69SMasatake YAMATO 		readTokenFull (token, true);
871a1cdce69SMasatake YAMATO 		if (token->type == TOKEN_WHITESPACE)
872a1cdce69SMasatake YAMATO 		{
873a1cdce69SMasatake YAMATO 			reprCat (arglist, token);
874a1cdce69SMasatake YAMATO 			continue;
875a1cdce69SMasatake YAMATO 		}
876a1cdce69SMasatake YAMATO 		else if (token->type == TOKEN_EOF)
877a1cdce69SMasatake YAMATO 			break;
878a1cdce69SMasatake YAMATO 
879a1cdce69SMasatake YAMATO 		if (token->type == '(' ||
880a1cdce69SMasatake YAMATO 			token->type == '[' ||
881a1cdce69SMasatake YAMATO 			token->type == '{')
882a1cdce69SMasatake YAMATO 			depth ++;
883a1cdce69SMasatake YAMATO 		else if (token->type == ')' ||
884a1cdce69SMasatake YAMATO 				 token->type == ']' ||
885a1cdce69SMasatake YAMATO 				 token->type == '}')
886a1cdce69SMasatake YAMATO 			depth --;
887a1cdce69SMasatake YAMATO 
888a1cdce69SMasatake YAMATO 		if (depth < 0
889a1cdce69SMasatake YAMATO 			|| (depth == 0 && (token->type == '='
890a1cdce69SMasatake YAMATO 							   || token->type == ',')))
891a1cdce69SMasatake YAMATO 		{
892a1cdce69SMasatake YAMATO 			ungetToken (token);
893a1cdce69SMasatake YAMATO 			return t;
894a1cdce69SMasatake YAMATO 		}
895a1cdce69SMasatake YAMATO 		reprCat (arglist, token);
896a1cdce69SMasatake YAMATO 		reprCat (t, token);
897a1cdce69SMasatake YAMATO 	}
898a1cdce69SMasatake YAMATO 	vStringDelete (t);
899a1cdce69SMasatake YAMATO 	return NULL;
900a1cdce69SMasatake YAMATO }
901a1cdce69SMasatake YAMATO 
parseReturnTypeAnnotation(tokenInfo * const token)902c378e8b6SMasatake YAMATO static vString *parseReturnTypeAnnotation (tokenInfo *const token)
903c378e8b6SMasatake YAMATO {
904c378e8b6SMasatake YAMATO 	readToken (token);
905c378e8b6SMasatake YAMATO 	if (token->type != TOKEN_ARROW)
906c378e8b6SMasatake YAMATO 	{
907c378e8b6SMasatake YAMATO 		ungetToken (token);
908c378e8b6SMasatake YAMATO 		return NULL;
909c378e8b6SMasatake YAMATO 	}
910c378e8b6SMasatake YAMATO 
911c378e8b6SMasatake YAMATO 	int depth = 0;
912c378e8b6SMasatake YAMATO 	vString *t = vStringNew ();
913c378e8b6SMasatake YAMATO 	while (true)
914c378e8b6SMasatake YAMATO 	{
915c378e8b6SMasatake YAMATO 		readToken (token);
916c378e8b6SMasatake YAMATO 		if (token->type == TOKEN_EOF)
917c378e8b6SMasatake YAMATO 			break;
918c378e8b6SMasatake YAMATO 
919c378e8b6SMasatake YAMATO 		if (token->type == '(' ||
920c378e8b6SMasatake YAMATO 			token->type == '[' ||
921c378e8b6SMasatake YAMATO 			token->type == '{')
922c378e8b6SMasatake YAMATO 			depth ++;
923c378e8b6SMasatake YAMATO 		else if (token->type == ')' ||
924c378e8b6SMasatake YAMATO 				 token->type == ']' ||
925c378e8b6SMasatake YAMATO 				 token->type == '}')
926c378e8b6SMasatake YAMATO 			depth --;
927c378e8b6SMasatake YAMATO 		if (depth == 0 && token->type == ':')
928c378e8b6SMasatake YAMATO 		{
929c378e8b6SMasatake YAMATO 			ungetToken (token);
930c378e8b6SMasatake YAMATO 			return t;
931c378e8b6SMasatake YAMATO 		}
932c378e8b6SMasatake YAMATO 		else
933c378e8b6SMasatake YAMATO 			reprCat (t, token);
934c378e8b6SMasatake YAMATO 	}
935c378e8b6SMasatake YAMATO 	vStringDelete (t);
936c378e8b6SMasatake YAMATO 	return NULL;
937c378e8b6SMasatake YAMATO }
938c378e8b6SMasatake YAMATO 
93934454f72SMasatake YAMATO struct typedParam {
94034454f72SMasatake YAMATO 	tokenInfo *token;
94134454f72SMasatake YAMATO 	vString *type;
94234454f72SMasatake YAMATO };
94334454f72SMasatake YAMATO 
makeTypedParam(tokenInfo * token,vString * type)94434454f72SMasatake YAMATO static struct typedParam *makeTypedParam (tokenInfo *token, vString *type)
94534454f72SMasatake YAMATO {
94634454f72SMasatake YAMATO 	struct typedParam *p = xMalloc (1, struct typedParam);
94734454f72SMasatake YAMATO 	p->token = token;
94834454f72SMasatake YAMATO 	p->type = type;
94934454f72SMasatake YAMATO 	return p;
95034454f72SMasatake YAMATO }
95134454f72SMasatake YAMATO 
makeTypedParamWithCopy(const tokenInfo * token,const vString * type)952*23ceb0b6SMasatake YAMATO static struct typedParam *makeTypedParamWithCopy (const tokenInfo *token, const vString *type)
953*23ceb0b6SMasatake YAMATO {
954*23ceb0b6SMasatake YAMATO 	tokenInfo *token_copied = newToken ();
955*23ceb0b6SMasatake YAMATO 	copyToken (token_copied, token);
956*23ceb0b6SMasatake YAMATO 
957*23ceb0b6SMasatake YAMATO 
958*23ceb0b6SMasatake YAMATO 	vString *type_copied = type? vStringNewCopy (type): NULL;
959*23ceb0b6SMasatake YAMATO 	return makeTypedParam (token_copied, type_copied);
960*23ceb0b6SMasatake YAMATO }
961*23ceb0b6SMasatake YAMATO 
deleteTypedParam(struct typedParam * p)96234454f72SMasatake YAMATO static void deleteTypedParam (struct typedParam *p)
96334454f72SMasatake YAMATO {
96434454f72SMasatake YAMATO 	deleteToken (p->token);
96534454f72SMasatake YAMATO 	vStringDelete (p->type);	/* NULL is acceptable. */
96634454f72SMasatake YAMATO 	eFree (p);
96734454f72SMasatake YAMATO }
96834454f72SMasatake YAMATO 
parseArglist(tokenInfo * const token,const int kind,vString * const arglist,ptrArray * const parameters)9694491a5beSMasatake YAMATO static void parseArglist (tokenInfo *const token, const int kind,
9704491a5beSMasatake YAMATO 						  vString *const arglist, ptrArray *const parameters)
971f5f8bd9aSMasatake YAMATO {
972257674afSColomban Wendling 	int prevTokenType = token->type;
973257674afSColomban Wendling 	int depth = 1;
974257674afSColomban Wendling 
975257674afSColomban Wendling 	if (kind != K_CLASS)
976257674afSColomban Wendling 		reprCat (arglist, token);
977257674afSColomban Wendling 
978257674afSColomban Wendling 	do
979257674afSColomban Wendling 	{
980f34b6795SColomban Wendling 		if (token->type != TOKEN_WHITESPACE &&
981f34b6795SColomban Wendling 			/* for easy `*args` and `**kwargs` support, we also ignore
982f34b6795SColomban Wendling 			 * `*`, which anyway can't otherwise screw us up */
983f34b6795SColomban Wendling 			token->type != '*')
984f34b6795SColomban Wendling 		{
985257674afSColomban Wendling 			prevTokenType = token->type;
986f34b6795SColomban Wendling 		}
987257674afSColomban Wendling 
988ce990805SThomas Braun 		readTokenFull (token, true);
989257674afSColomban Wendling 		if (kind != K_CLASS || token->type != ')' || depth > 1)
990257674afSColomban Wendling 			reprCat (arglist, token);
991257674afSColomban Wendling 
992f34b6795SColomban Wendling 		if (token->type == '(' ||
993f34b6795SColomban Wendling 			token->type == '[' ||
994f34b6795SColomban Wendling 			token->type == '{')
995257674afSColomban Wendling 			depth ++;
996f34b6795SColomban Wendling 		else if (token->type == ')' ||
997f34b6795SColomban Wendling 				 token->type == ']' ||
998f34b6795SColomban Wendling 				 token->type == '}')
999257674afSColomban Wendling 			depth --;
1000257674afSColomban Wendling 		else if (kind != K_CLASS && depth == 1 &&
1001257674afSColomban Wendling 				 token->type == TOKEN_IDENTIFIER &&
1002257674afSColomban Wendling 				 (prevTokenType == '(' || prevTokenType == ',') &&
1003257674afSColomban Wendling 				 PythonKinds[K_PARAMETER].enabled)
1004257674afSColomban Wendling 		{
100534454f72SMasatake YAMATO 			tokenInfo *parameterName;
100634454f72SMasatake YAMATO 			vString *parameterType;
100734454f72SMasatake YAMATO 			struct typedParam *parameter;
1008257674afSColomban Wendling 
100934454f72SMasatake YAMATO 			parameterName = newToken ();
1010257674afSColomban Wendling 			copyToken (parameterName, token);
101134454f72SMasatake YAMATO 			parameterType = parseParamTypeAnnotation (token, arglist);
101234454f72SMasatake YAMATO 
101334454f72SMasatake YAMATO 			parameter = makeTypedParam (parameterName, parameterType);
101434454f72SMasatake YAMATO 			ptrArrayAdd (parameters, parameter);
1015257674afSColomban Wendling 		}
1016257674afSColomban Wendling 	}
1017257674afSColomban Wendling 	while (token->type != TOKEN_EOF && depth > 0);
1018f5f8bd9aSMasatake YAMATO }
1019f5f8bd9aSMasatake YAMATO 
parseCArglist(tokenInfo * const token,const int kind,vString * const arglist,ptrArray * const parameters)1020*23ceb0b6SMasatake YAMATO static void parseCArglist (tokenInfo *const token, const int kind,
1021*23ceb0b6SMasatake YAMATO 						  vString *const arglist, ptrArray *const parameters)
1022*23ceb0b6SMasatake YAMATO {
1023*23ceb0b6SMasatake YAMATO 	int depth = 1;
1024*23ceb0b6SMasatake YAMATO 	tokenInfo *pname = newToken ();
1025*23ceb0b6SMasatake YAMATO 	vString *ptype = vStringNew ();
1026*23ceb0b6SMasatake YAMATO 	vStringCat (arglist, token->string);	/* '(' */
1027*23ceb0b6SMasatake YAMATO 
1028*23ceb0b6SMasatake YAMATO 	while (true)
1029*23ceb0b6SMasatake YAMATO 	{
1030*23ceb0b6SMasatake YAMATO 		readToken (token);
1031*23ceb0b6SMasatake YAMATO 		if (token->type == TOKEN_EOF)
1032*23ceb0b6SMasatake YAMATO 		{
1033*23ceb0b6SMasatake YAMATO 			/* Unexpected input. */
1034*23ceb0b6SMasatake YAMATO 			vStringClear (arglist);
1035*23ceb0b6SMasatake YAMATO 			ptrArrayClear (parameters);
1036*23ceb0b6SMasatake YAMATO 			break;
1037*23ceb0b6SMasatake YAMATO 		}
1038*23ceb0b6SMasatake YAMATO 
1039*23ceb0b6SMasatake YAMATO 		if (depth == 1 && (token->type == ',' || token->type == ')'))
1040*23ceb0b6SMasatake YAMATO 		{
1041*23ceb0b6SMasatake YAMATO 			if (pname->type == TOKEN_IDENTIFIER)
1042*23ceb0b6SMasatake YAMATO 			{
1043*23ceb0b6SMasatake YAMATO 				struct typedParam *p;
1044*23ceb0b6SMasatake YAMATO 
1045*23ceb0b6SMasatake YAMATO 				/*
1046*23ceb0b6SMasatake YAMATO 				 * Clean up the type string.
1047*23ceb0b6SMasatake YAMATO 				 * The type string includes the parameter name at the end.
1048*23ceb0b6SMasatake YAMATO 				 * 1. Trim the parameter name at the end.
1049*23ceb0b6SMasatake YAMATO 				 * 2. Then, trim the white space at the end of the type string.
1050*23ceb0b6SMasatake YAMATO 				 * 3. If the type string is not empty,
1051*23ceb0b6SMasatake YAMATO 				 *    3.a append (the type stirng + ' ' + the parameter name) to arglist.
1052*23ceb0b6SMasatake YAMATO 				 *    3.b else just append the parameter name to arglist.
1053*23ceb0b6SMasatake YAMATO 				 *
1054*23ceb0b6SMasatake YAMATO 				 * FIXME:
1055*23ceb0b6SMasatake YAMATO 				 * This doesn't work well with an array and a function pointer.
1056*23ceb0b6SMasatake YAMATO 				 *
1057*23ceb0b6SMasatake YAMATO 				 *   f(..., int seq [dim], ...)
1058*23ceb0b6SMasatake YAMATO 				 *      in this case, dim is extacted as a parameter.
1059*23ceb0b6SMasatake YAMATO 				 *
1060*23ceb0b6SMasatake YAMATO 				 *   f(..., int (*fn)(int), ...)
1061*23ceb0b6SMasatake YAMATO 				 *      in this case , int is extacted as a parameter.
1062*23ceb0b6SMasatake YAMATO 				 */
1063*23ceb0b6SMasatake YAMATO 				Assert (vStringLength (ptype) >= vStringLength (pname->string));
1064*23ceb0b6SMasatake YAMATO 				size_t ptype_len = vStringLength (ptype) - vStringLength (pname->string);
1065*23ceb0b6SMasatake YAMATO 				vStringTruncate (ptype, ptype_len);
1066*23ceb0b6SMasatake YAMATO 
1067*23ceb0b6SMasatake YAMATO 				if (vStringLength (ptype) > 0)
1068*23ceb0b6SMasatake YAMATO 				{
1069*23ceb0b6SMasatake YAMATO 					vStringStripTrailing (ptype);
1070*23ceb0b6SMasatake YAMATO 					if (vStringLength (ptype) > 0)
1071*23ceb0b6SMasatake YAMATO 					{
1072*23ceb0b6SMasatake YAMATO 						vStringCat (arglist, ptype);
1073*23ceb0b6SMasatake YAMATO 						vStringPut (arglist, ' ');
1074*23ceb0b6SMasatake YAMATO 					}
1075*23ceb0b6SMasatake YAMATO 				}
1076*23ceb0b6SMasatake YAMATO 				vStringCat (arglist, pname->string);
1077*23ceb0b6SMasatake YAMATO 
1078*23ceb0b6SMasatake YAMATO 				p = makeTypedParamWithCopy (pname, vStringIsEmpty(ptype)? NULL: ptype);
1079*23ceb0b6SMasatake YAMATO 				ptrArrayAdd (parameters, p);
1080*23ceb0b6SMasatake YAMATO 			}
1081*23ceb0b6SMasatake YAMATO 			if (token->type == ')')
1082*23ceb0b6SMasatake YAMATO 			{
1083*23ceb0b6SMasatake YAMATO 				vStringPut (arglist, ')');
1084*23ceb0b6SMasatake YAMATO 				break;
1085*23ceb0b6SMasatake YAMATO 			}
1086*23ceb0b6SMasatake YAMATO 			vStringCatS (arglist, ", ");
1087*23ceb0b6SMasatake YAMATO 			vStringClear (ptype);
1088*23ceb0b6SMasatake YAMATO 			pname->type = TOKEN_UNDEFINED;
1089*23ceb0b6SMasatake YAMATO 			continue;
1090*23ceb0b6SMasatake YAMATO 		}
1091*23ceb0b6SMasatake YAMATO 
1092*23ceb0b6SMasatake YAMATO 		if (token->type == '(' ||
1093*23ceb0b6SMasatake YAMATO 			token->type == '[' ||
1094*23ceb0b6SMasatake YAMATO 			token->type == '{')
1095*23ceb0b6SMasatake YAMATO 		{
1096*23ceb0b6SMasatake YAMATO 			vStringPut (ptype, token->type);
1097*23ceb0b6SMasatake YAMATO 			depth ++;
1098*23ceb0b6SMasatake YAMATO 			continue;
1099*23ceb0b6SMasatake YAMATO 		}
1100*23ceb0b6SMasatake YAMATO 
1101*23ceb0b6SMasatake YAMATO 		if (token->type == ')' ||
1102*23ceb0b6SMasatake YAMATO 			token->type == ']' ||
1103*23ceb0b6SMasatake YAMATO 			token->type == '}')
1104*23ceb0b6SMasatake YAMATO 		{
1105*23ceb0b6SMasatake YAMATO 			vStringPut (ptype, token->type);
1106*23ceb0b6SMasatake YAMATO 			depth --;
1107*23ceb0b6SMasatake YAMATO 			continue;
1108*23ceb0b6SMasatake YAMATO 		}
1109*23ceb0b6SMasatake YAMATO 
1110*23ceb0b6SMasatake YAMATO 		if (token->type == TOKEN_IDENTIFIER || token->type == TOKEN_KEYWORD)
1111*23ceb0b6SMasatake YAMATO 		{
1112*23ceb0b6SMasatake YAMATO 			if (vStringLength (ptype) > 0
1113*23ceb0b6SMasatake YAMATO 				&& (isalnum ((unsigned char)vStringLast (ptype))
1114*23ceb0b6SMasatake YAMATO 					|| vStringLast (ptype) == ','))
1115*23ceb0b6SMasatake YAMATO 				vStringPut (ptype, ' ');
1116*23ceb0b6SMasatake YAMATO 			vStringCat (ptype, token->string);
1117*23ceb0b6SMasatake YAMATO 
1118*23ceb0b6SMasatake YAMATO 			if (!isdigit ((unsigned char)vStringLast (token->string)))
1119*23ceb0b6SMasatake YAMATO 				copyToken (pname, token);
1120*23ceb0b6SMasatake YAMATO 			continue;
1121*23ceb0b6SMasatake YAMATO 		}
1122*23ceb0b6SMasatake YAMATO 
1123*23ceb0b6SMasatake YAMATO 		vStringCat (ptype, token->string);
1124*23ceb0b6SMasatake YAMATO 	}
1125*23ceb0b6SMasatake YAMATO 
1126*23ceb0b6SMasatake YAMATO 	vStringDelete (ptype);
1127*23ceb0b6SMasatake YAMATO 	deleteToken (pname);
1128*23ceb0b6SMasatake YAMATO }
1129*23ceb0b6SMasatake YAMATO 
parseClassOrDef(tokenInfo * const token,const vString * const decorators,pythonKind kind,bool isCDef)11304491a5beSMasatake YAMATO static bool parseClassOrDef (tokenInfo *const token,
11314491a5beSMasatake YAMATO                                 const vString *const decorators,
11324491a5beSMasatake YAMATO                                 pythonKind kind, bool isCDef)
11334491a5beSMasatake YAMATO {
11344491a5beSMasatake YAMATO 	vString *arglist = NULL;
11354491a5beSMasatake YAMATO 	tokenInfo *name = NULL;
11364491a5beSMasatake YAMATO 	ptrArray *parameters = NULL;
11374491a5beSMasatake YAMATO 	NestingLevel *lv;
11384491a5beSMasatake YAMATO 	int corkIndex;
11394491a5beSMasatake YAMATO 
11404491a5beSMasatake YAMATO 	if (isCDef)
11414491a5beSMasatake YAMATO 	{
11424491a5beSMasatake YAMATO 		if (! readCDefName (token, &kind))
11434491a5beSMasatake YAMATO 			return false;
11444491a5beSMasatake YAMATO 	}
11454491a5beSMasatake YAMATO 	else
11464491a5beSMasatake YAMATO 	{
11474491a5beSMasatake YAMATO 		readToken (token);
11484491a5beSMasatake YAMATO 		if (token->type != TOKEN_IDENTIFIER)
11494491a5beSMasatake YAMATO 			return false;
11504491a5beSMasatake YAMATO 	}
11514491a5beSMasatake YAMATO 
11524491a5beSMasatake YAMATO 	name = newToken ();
11534491a5beSMasatake YAMATO 	copyToken (name, token);
11544491a5beSMasatake YAMATO 
11554491a5beSMasatake YAMATO 	readToken (token);
11564491a5beSMasatake YAMATO 	/* collect parameters or inheritance */
11574491a5beSMasatake YAMATO 	if (token->type == '(')
11584491a5beSMasatake YAMATO 	{
11594491a5beSMasatake YAMATO 		arglist = vStringNew ();
11604491a5beSMasatake YAMATO 		parameters = ptrArrayNew ((ptrArrayDeleteFunc)deleteTypedParam);
11614491a5beSMasatake YAMATO 
1162*23ceb0b6SMasatake YAMATO 		if (isCDef && kind != K_CLASS)
1163*23ceb0b6SMasatake YAMATO 			parseCArglist (token, kind, arglist, parameters);
1164*23ceb0b6SMasatake YAMATO 		else
11654491a5beSMasatake YAMATO 			parseArglist (token, kind, arglist, parameters);
11664491a5beSMasatake YAMATO 	}
11674491a5beSMasatake YAMATO 
11682ff1f9d2SColomban Wendling 	if (kind == K_CLASS)
11695d0fd5feSColomban Wendling 		corkIndex = makeClassTag (name, arglist, decorators);
11702ff1f9d2SColomban Wendling 	else
11715d0fd5feSColomban Wendling 		corkIndex = makeFunctionTag (name, arglist, decorators);
1172f5f8bd9aSMasatake YAMATO 
11732ff1f9d2SColomban Wendling 	lv = nestingLevelsPush (PythonNestingLevels, corkIndex);
11742ff1f9d2SColomban Wendling 	PY_NL (lv)->indentation = token->indent;
11752ff1f9d2SColomban Wendling 
11766ff4799bSJiří Techet 	deleteToken (name);
11772ff1f9d2SColomban Wendling 	vStringDelete (arglist);
11782ff1f9d2SColomban Wendling 
117934454f72SMasatake YAMATO 	if (parameters && !ptrArrayIsEmpty (parameters))
1180257674afSColomban Wendling 	{
1181257674afSColomban Wendling 		unsigned int i;
1182257674afSColomban Wendling 
118334454f72SMasatake YAMATO 		for (i = 0; i < ptrArrayCount (parameters); i++)
1184257674afSColomban Wendling 		{
118534454f72SMasatake YAMATO 			struct typedParam *parameter = ptrArrayItem (parameters, i);
118634454f72SMasatake YAMATO 			int paramCorkIndex = makeSimplePythonTag (parameter->token, K_PARAMETER);
1187a1cdce69SMasatake YAMATO 			tagEntryInfo *e = getEntryInCorkQueue (paramCorkIndex);
118834454f72SMasatake YAMATO 			if (e && parameter->type)
1189a1cdce69SMasatake YAMATO 			{
1190a1cdce69SMasatake YAMATO 				e->extensionFields.typeRef [0] = eStrdup ("typename");
119134454f72SMasatake YAMATO 				e->extensionFields.typeRef [1] = vStringDeleteUnwrap (parameter->type);
119234454f72SMasatake YAMATO 				parameter->type = NULL;
1193257674afSColomban Wendling 			}
1194257674afSColomban Wendling 		}
119534454f72SMasatake YAMATO 	}
119634454f72SMasatake YAMATO 	ptrArrayDelete (parameters); /* NULL is acceptable. */
1197257674afSColomban Wendling 
1198c378e8b6SMasatake YAMATO 	tagEntryInfo *e;
1199c378e8b6SMasatake YAMATO 	vString *t;
1200c378e8b6SMasatake YAMATO 	if (kind != K_CLASS
1201c378e8b6SMasatake YAMATO 		&& (e = getEntryInCorkQueue (corkIndex))
1202c378e8b6SMasatake YAMATO 		&& (t = parseReturnTypeAnnotation (token)))
1203c378e8b6SMasatake YAMATO 	{
1204c378e8b6SMasatake YAMATO 		e->extensionFields.typeRef [0] = eStrdup ("typename");
1205c378e8b6SMasatake YAMATO 		e->extensionFields.typeRef [1] = vStringDeleteUnwrap (t);
1206c378e8b6SMasatake YAMATO 	}
1207c378e8b6SMasatake YAMATO 
1208ce990805SThomas Braun 	return true;
12092ff1f9d2SColomban Wendling }
12102ff1f9d2SColomban Wendling 
parseImport(tokenInfo * const token)1211ce990805SThomas Braun static bool parseImport (tokenInfo *const token)
12122ff1f9d2SColomban Wendling {
12132ff1f9d2SColomban Wendling 	tokenInfo *fromModule = NULL;
12142ff1f9d2SColomban Wendling 
12152ff1f9d2SColomban Wendling 	if (token->keyword == KEYWORD_from)
12162ff1f9d2SColomban Wendling 	{
12172ff1f9d2SColomban Wendling 		readQualifiedName (token);
12182ff1f9d2SColomban Wendling 		if (token->type == TOKEN_IDENTIFIER)
12192ff1f9d2SColomban Wendling 		{
12206ff4799bSJiří Techet 			fromModule = newToken ();
12212ff1f9d2SColomban Wendling 			copyToken (fromModule, token);
12222ff1f9d2SColomban Wendling 			readToken (token);
12232ff1f9d2SColomban Wendling 		}
12242ff1f9d2SColomban Wendling 	}
12252ff1f9d2SColomban Wendling 
12262ff1f9d2SColomban Wendling 	if (token->keyword == KEYWORD_import)
12272ff1f9d2SColomban Wendling 	{
1228ce990805SThomas Braun 		bool parenthesized = false;
122972ab2762SMasatake YAMATO 		int moduleIndex;
12302ff1f9d2SColomban Wendling 
12312ff1f9d2SColomban Wendling 		if (fromModule)
12322ff1f9d2SColomban Wendling 		{
12332ff1f9d2SColomban Wendling 			/* from X import ...
12342ff1f9d2SColomban Wendling 			 * --------------------
12352ff1f9d2SColomban Wendling 			 * X = (kind:module, role:namespace) */
123672ab2762SMasatake YAMATO 			moduleIndex = makeSimplePythonRefTag (fromModule, NULL, K_MODULE,
12372ff1f9d2SColomban Wendling 												  PYTHON_MODULE_NAMESPACE,
12382ff1f9d2SColomban Wendling 												  XTAG_UNKNOWN);
12392ff1f9d2SColomban Wendling 		}
12402ff1f9d2SColomban Wendling 
12412ff1f9d2SColomban Wendling 		do
12422ff1f9d2SColomban Wendling 		{
12432ff1f9d2SColomban Wendling 			readQualifiedName (token);
12442ff1f9d2SColomban Wendling 
12452ff1f9d2SColomban Wendling 			/* support for `from x import (...)` */
12462ff1f9d2SColomban Wendling 			if (fromModule && ! parenthesized && token->type == '(')
12472ff1f9d2SColomban Wendling 			{
1248ce990805SThomas Braun 				parenthesized = true;
12492ff1f9d2SColomban Wendling 				readQualifiedName (token);
12502ff1f9d2SColomban Wendling 			}
12512ff1f9d2SColomban Wendling 
12522ff1f9d2SColomban Wendling 			if (token->type == TOKEN_IDENTIFIER)
12532ff1f9d2SColomban Wendling 			{
12546ff4799bSJiří Techet 				tokenInfo *name = newToken ();
12552ff1f9d2SColomban Wendling 
12562ff1f9d2SColomban Wendling 				copyToken (name, token);
12572ff1f9d2SColomban Wendling 				readToken (token);
12582ff1f9d2SColomban Wendling 				/* if there is an "as", use it as the name */
12592ff1f9d2SColomban Wendling 				if (token->keyword == KEYWORD_as)
12602ff1f9d2SColomban Wendling 				{
12612ff1f9d2SColomban Wendling 					readToken (token);
12622ff1f9d2SColomban Wendling 					if (token->type == TOKEN_IDENTIFIER)
12632ff1f9d2SColomban Wendling 					{
12642ff1f9d2SColomban Wendling 						if (fromModule)
1265f5f8bd9aSMasatake YAMATO 						{
1266f5f8bd9aSMasatake YAMATO 							/* from x import Y as Z
12672ff1f9d2SColomban Wendling 							 * ----------------------------
12682ff1f9d2SColomban Wendling 							 * x = (kind:module,  role:namespace),
126972ab2762SMasatake YAMATO 							 * Y = (kind:unknown, role:indirectlyImported, scope:module:X),
12706f605b92SMasatake YAMATO 							 * Z = (kind:unknown, nameref:unknown:Y) */
127172ab2762SMasatake YAMATO 							int index;
1272f5f8bd9aSMasatake YAMATO 
1273f5f8bd9aSMasatake YAMATO 							/* Y */
127472ab2762SMasatake YAMATO 							index = makeSimplePythonRefTag (name, NULL, K_UNKNOWN,
12752ff1f9d2SColomban Wendling 															PYTHON_UNKNOWN_INDIRECTLY_IMPORTED,
12762ff1f9d2SColomban Wendling 															XTAG_UNKNOWN);
127772ab2762SMasatake YAMATO 							/* fill the scope field for Y */
127872ab2762SMasatake YAMATO 							tagEntryInfo *e = getEntryInCorkQueue (index);
127972ab2762SMasatake YAMATO 							if (e)
128072ab2762SMasatake YAMATO 								e->extensionFields.scopeIndex = moduleIndex;
128172ab2762SMasatake YAMATO 
1282f5f8bd9aSMasatake YAMATO 							/* Z */
128372ab2762SMasatake YAMATO 							index = makeSimplePythonTag (token, K_UNKNOWN);
12846f605b92SMasatake YAMATO 							/* fill the nameref filed for Y */
12856f605b92SMasatake YAMATO 							if (PythonFields[F_NAMEREF].enabled)
12866f605b92SMasatake YAMATO 							{
12876f605b92SMasatake YAMATO 								vString *nameref = vStringNewInit (PythonKinds [K_UNKNOWN].name);
12886f605b92SMasatake YAMATO 								vStringPut (nameref, ':');
12896f605b92SMasatake YAMATO 								vStringCat (nameref, name->string);
12906f605b92SMasatake YAMATO 								attachParserFieldToCorkEntry (index, PythonFields[F_NAMEREF].ftype,
12916f605b92SMasatake YAMATO 															  vStringValue (nameref));
12926f605b92SMasatake YAMATO 								vStringDelete (nameref);
12936f605b92SMasatake YAMATO 							}
1294f5f8bd9aSMasatake YAMATO 						}
1295f5f8bd9aSMasatake YAMATO 						else
1296f5f8bd9aSMasatake YAMATO 						{
1297f5f8bd9aSMasatake YAMATO 							/* import x as Y
12982ff1f9d2SColomban Wendling 							 * ----------------------------
12996f605b92SMasatake YAMATO 							 * x = (kind:module, role:indirectlyImported)
13006f605b92SMasatake YAMATO 							 * Y = (kind:namespace, nameref:module:x)*/
13016f605b92SMasatake YAMATO 							/* x */
13022ff1f9d2SColomban Wendling 							makeSimplePythonRefTag (name, NULL, K_MODULE,
13032ff1f9d2SColomban Wendling 							                        PYTHON_MODULE_INDIRECTLY_IMPORTED,
13042ff1f9d2SColomban Wendling 							                        XTAG_UNKNOWN);
1305f5f8bd9aSMasatake YAMATO 							/* Y */
13066f605b92SMasatake YAMATO 							int index = makeSimplePythonTag (token, K_NAMESPACE);
13076f605b92SMasatake YAMATO 							/* fill the nameref filed for Y */
13086f605b92SMasatake YAMATO 							if (PythonFields[F_NAMEREF].enabled)
13096f605b92SMasatake YAMATO 							{
13106f605b92SMasatake YAMATO 								vString *nameref = vStringNewInit (PythonKinds [K_MODULE].name);
13116f605b92SMasatake YAMATO 								vStringPut (nameref, ':');
13126f605b92SMasatake YAMATO 								vStringCat (nameref, name->string);
13136f605b92SMasatake YAMATO 								attachParserFieldToCorkEntry (index, PythonFields[F_NAMEREF].ftype,
13146f605b92SMasatake YAMATO 															  vStringValue (nameref));
13156f605b92SMasatake YAMATO 								vStringDelete (nameref);
13166f605b92SMasatake YAMATO 							}
1317f5f8bd9aSMasatake YAMATO 						}
1318f5f8bd9aSMasatake YAMATO 
13192ff1f9d2SColomban Wendling 						copyToken (name, token);
13202ff1f9d2SColomban Wendling 						readToken (token);
1321f5f8bd9aSMasatake YAMATO 					}
1322f5f8bd9aSMasatake YAMATO 				}
1323f5f8bd9aSMasatake YAMATO 				else
1324f5f8bd9aSMasatake YAMATO 				{
13252ff1f9d2SColomban Wendling 					if (fromModule)
1326f5f8bd9aSMasatake YAMATO 					{
1327f5f8bd9aSMasatake YAMATO 						/* from x import Y
1328f5f8bd9aSMasatake YAMATO 						   --------------
1329f5f8bd9aSMasatake YAMATO 						   x = (kind:module,  role:namespace),
133072ab2762SMasatake YAMATO 						   Y = (kind:unknown, role:imported, scope:module:x) */
1331f5f8bd9aSMasatake YAMATO 						/* Y */
133272ab2762SMasatake YAMATO 						int index = makeSimplePythonRefTag (name, NULL, K_UNKNOWN,
1333978db657SMasatake YAMATO 															PYTHON_UNKNOWN_IMPORTED,
13342ff1f9d2SColomban Wendling 															XTAG_UNKNOWN);
133572ab2762SMasatake YAMATO 						/* fill the scope field for Y */
133672ab2762SMasatake YAMATO 						tagEntryInfo *e = getEntryInCorkQueue (index);
133772ab2762SMasatake YAMATO 						if (e)
133872ab2762SMasatake YAMATO 							e->extensionFields.scopeIndex = moduleIndex;
1339f5f8bd9aSMasatake YAMATO 					}
1340f5f8bd9aSMasatake YAMATO 					else
1341f5f8bd9aSMasatake YAMATO 					{
1342f5f8bd9aSMasatake YAMATO 						/* import X
1343f5f8bd9aSMasatake YAMATO 						   --------------
1344f5f8bd9aSMasatake YAMATO 						   X = (kind:module, role:imported) */
13452ff1f9d2SColomban Wendling 						makeSimplePythonRefTag (name, NULL, K_MODULE,
13462ff1f9d2SColomban Wendling 						                        PYTHON_MODULE_IMPORTED,
13472ff1f9d2SColomban Wendling 						                        XTAG_UNKNOWN);
1348f5f8bd9aSMasatake YAMATO 					}
1349f5f8bd9aSMasatake YAMATO 				}
1350f5f8bd9aSMasatake YAMATO 
13516ff4799bSJiří Techet 				deleteToken (name);
1352f5f8bd9aSMasatake YAMATO 			}
1353f5f8bd9aSMasatake YAMATO 		}
13542ff1f9d2SColomban Wendling 		while (token->type == ',');
1355f5f8bd9aSMasatake YAMATO 
13562ff1f9d2SColomban Wendling 		if (parenthesized && token->type == ')')
13572ff1f9d2SColomban Wendling 			readToken (token);
1358f5f8bd9aSMasatake YAMATO 	}
1359f5f8bd9aSMasatake YAMATO 
13602ff1f9d2SColomban Wendling 	if (fromModule)
13616ff4799bSJiří Techet 		deleteToken (fromModule);
13627489fd61SMasatake YAMATO 
1363ce990805SThomas Braun 	return false;
13647489fd61SMasatake YAMATO }
13657489fd61SMasatake YAMATO 
1366d771a1e5SColomban Wendling /* this only handles the most common cases, but an annotation can be any
1367d771a1e5SColomban Wendling  * expression in theory.
1368d771a1e5SColomban Wendling  * this function assumes there must be an annotation, and doesn't do any check
1369d771a1e5SColomban Wendling  * on the token on which it is called: the caller should do that part. */
skipVariableTypeAnnotation(tokenInfo * const token,vString * const repr)1370ba92e639SMasatake YAMATO static bool skipVariableTypeAnnotation (tokenInfo *const token, vString *const repr)
1371d771a1e5SColomban Wendling {
1372d771a1e5SColomban Wendling 	bool readNext = true;
1373d771a1e5SColomban Wendling 
1374d771a1e5SColomban Wendling 	readToken (token);
1375d771a1e5SColomban Wendling 	switch (token->type)
1376d771a1e5SColomban Wendling 	{
1377ba92e639SMasatake YAMATO 		case '[': readNext = skipOverPair (token, '[', ']', repr, true); break;
1378ba92e639SMasatake YAMATO 		case '(': readNext = skipOverPair (token, '(', ')', repr, true); break;
1379ba92e639SMasatake YAMATO 		case '{': readNext = skipOverPair (token, '{', '}', repr, true); break;
1380ba92e639SMasatake YAMATO 		default: reprCat (repr, token);
1381d771a1e5SColomban Wendling 	}
1382d771a1e5SColomban Wendling 	if (readNext)
1383d771a1e5SColomban Wendling 		readToken (token);
1384d771a1e5SColomban Wendling 	/* skip subscripts and calls */
13850f7e912bSMasatake YAMATO 	while (token->type == '[' || token->type == '(' || token->type == '.' || token->type == '|')
1386d771a1e5SColomban Wendling 	{
1387d771a1e5SColomban Wendling 		switch (token->type)
1388d771a1e5SColomban Wendling 		{
1389ba92e639SMasatake YAMATO 			case '[': readNext = skipOverPair (token, '[', ']', repr, true); break;
1390ba92e639SMasatake YAMATO 			case '(': readNext = skipOverPair (token, '(', ')', repr, true); break;
13910f7e912bSMasatake YAMATO 			case '|':
13920f7e912bSMasatake YAMATO 				reprCat (repr, token);
13930f7e912bSMasatake YAMATO 				skipVariableTypeAnnotation (token, repr);
13940f7e912bSMasatake YAMATO 				readNext = false;
13950f7e912bSMasatake YAMATO 				break;
1396d771a1e5SColomban Wendling 			case '.':
1397ba92e639SMasatake YAMATO 				reprCat (repr, token);
1398d771a1e5SColomban Wendling 				readToken (token);
1399d771a1e5SColomban Wendling 				readNext = token->type == TOKEN_IDENTIFIER;
1400ba92e639SMasatake YAMATO 				if (readNext)
1401ba92e639SMasatake YAMATO 					reprCat (repr, token);
1402d771a1e5SColomban Wendling 				break;
1403d771a1e5SColomban Wendling 			default:  readNext = false; break;
1404d771a1e5SColomban Wendling 		}
1405d771a1e5SColomban Wendling 		if (readNext)
1406d771a1e5SColomban Wendling 			readToken (token);
1407d771a1e5SColomban Wendling 	}
1408d771a1e5SColomban Wendling 
1409d771a1e5SColomban Wendling 	return false;
1410d771a1e5SColomban Wendling }
1411d771a1e5SColomban Wendling 
parseVariable(tokenInfo * const token,const pythonKind kind)1412ce990805SThomas Braun static bool parseVariable (tokenInfo *const token, const pythonKind kind)
14139a4b69e0SColomban Wendling {
14140c188d12SColomban Wendling 	/* In order to support proper tag type for lambdas in multiple
14150c188d12SColomban Wendling 	 * assignations, we first collect all the names, and then try and map
14160c188d12SColomban Wendling 	 * an assignation to it */
14170c188d12SColomban Wendling 	tokenInfo *nameTokens[8] = { NULL };
1418ba92e639SMasatake YAMATO 	vString   *nameTypes [ARRAY_SIZE (nameTokens)] = { NULL };
14190c188d12SColomban Wendling 	unsigned int nameCount = 0;
1420ba92e639SMasatake YAMATO 	vString *type = vStringNew();
14210c188d12SColomban Wendling 
14220c188d12SColomban Wendling 	/* first, collect variable name tokens */
14230c188d12SColomban Wendling 	while (token->type == TOKEN_IDENTIFIER &&
14240c188d12SColomban Wendling 	       nameCount < ARRAY_SIZE (nameTokens))
14250c188d12SColomban Wendling 	{
1426ba92e639SMasatake YAMATO 		unsigned int i;
14276ff4799bSJiří Techet 		tokenInfo *name = newToken ();
14280c188d12SColomban Wendling 		copyToken (name, token);
14290c188d12SColomban Wendling 
1430bbb831cfSColomban Wendling 		readToken (token);
1431bbb831cfSColomban Wendling 		if (token->type == '.')
1432bbb831cfSColomban Wendling 		{
1433bbb831cfSColomban Wendling 			/* FIXME: what to do with dotted names?  We currently ignore them
1434bbb831cfSColomban Wendling 			 *        as we need to do something not to break the whole
1435bbb831cfSColomban Wendling 			 *        declaration, but the expected behavior is questionable */
14366ff4799bSJiří Techet 			deleteToken (name);
1437bbb831cfSColomban Wendling 			name = NULL;
1438bbb831cfSColomban Wendling 
1439bbb831cfSColomban Wendling 			do
1440bbb831cfSColomban Wendling 			{
1441bbb831cfSColomban Wendling 				readToken (token);
1442bbb831cfSColomban Wendling 			}
1443bbb831cfSColomban Wendling 			while (token->type == TOKEN_IDENTIFIER ||
1444bbb831cfSColomban Wendling 			       token->type == '.');
1445bbb831cfSColomban Wendling 		}
1446bbb831cfSColomban Wendling 
1447ba92e639SMasatake YAMATO 		i = nameCount++;
1448ba92e639SMasatake YAMATO 		nameTokens[i] = name;
14490c188d12SColomban Wendling 
1450ba92e639SMasatake YAMATO 		/* (parse and) skip annotations.  we need not to be too permissive because we
1451d771a1e5SColomban Wendling 		 * aren't yet sure we're actually parsing a variable. */
1452ba92e639SMasatake YAMATO 		if (token->type == ':' && skipVariableTypeAnnotation (token, type))
1453d771a1e5SColomban Wendling 			readToken (token);
1454d771a1e5SColomban Wendling 
1455ba92e639SMasatake YAMATO 		if (vStringLength (type) > 0)
1456ba92e639SMasatake YAMATO 		{
1457ba92e639SMasatake YAMATO 			nameTypes[i] = type;
1458ba92e639SMasatake YAMATO 			type = vStringNew ();
1459ba92e639SMasatake YAMATO 		}
1460ba92e639SMasatake YAMATO 
14610c188d12SColomban Wendling 		if (token->type == ',')
14620c188d12SColomban Wendling 			readToken (token);
14630c188d12SColomban Wendling 		else
14640c188d12SColomban Wendling 			break;
14650c188d12SColomban Wendling 	}
1466ba92e639SMasatake YAMATO 	vStringDelete (type);
14670c188d12SColomban Wendling 
14680c188d12SColomban Wendling 	/* then, if it's a proper assignation, try and map assignations so that
14690c188d12SColomban Wendling 	 * we catch lambdas and alike */
14700c188d12SColomban Wendling 	if (token->type == '=')
14710c188d12SColomban Wendling 	{
14720c188d12SColomban Wendling 		unsigned int i = 0;
14739a4b69e0SColomban Wendling 
14749a4b69e0SColomban Wendling 		do
14759a4b69e0SColomban Wendling 		{
1476ba92e639SMasatake YAMATO 			const tokenInfo *const nameToken = nameTokens[i];
1477ba92e639SMasatake YAMATO 			vString **type = &(nameTypes[i++]);
1478bbb831cfSColomban Wendling 
14799a4b69e0SColomban Wendling 			readToken (token);
14800c188d12SColomban Wendling 
1481bbb831cfSColomban Wendling 			if (! nameToken)
1482bbb831cfSColomban Wendling 				/* nothing */;
1483bbb831cfSColomban Wendling 			else if (token->keyword != KEYWORD_lambda)
1484ba92e639SMasatake YAMATO 			{
1485ba92e639SMasatake YAMATO 				int index = makeSimplePythonTag (nameToken, kind);
1486ba92e639SMasatake YAMATO 				tagEntryInfo *e = getEntryInCorkQueue (index);
1487ba92e639SMasatake YAMATO 				if (e && *type)
1488ba92e639SMasatake YAMATO 				{
1489ba92e639SMasatake YAMATO 					e->extensionFields.typeRef [0] = eStrdup ("typename");
1490ba92e639SMasatake YAMATO 					e->extensionFields.typeRef [1] = vStringDeleteUnwrap (*type);
1491ba92e639SMasatake YAMATO 					*type = NULL;
1492ba92e639SMasatake YAMATO 				}
1493ba92e639SMasatake YAMATO 			}
14949a4b69e0SColomban Wendling 			else
14959a4b69e0SColomban Wendling 			{
149671b09f08SMasatake YAMATO 				tokenInfo *anon  = NULL;
14979a4b69e0SColomban Wendling 				vString *arglist = vStringNew ();
149871b09f08SMasatake YAMATO 				if (*type)
149971b09f08SMasatake YAMATO 				{
150071b09f08SMasatake YAMATO 					anon = newToken ();
150171b09f08SMasatake YAMATO 					copyToken (anon, token);
150271b09f08SMasatake YAMATO 				}
15039a4b69e0SColomban Wendling 				readToken (token);
15049a4b69e0SColomban Wendling 				vStringPut (arglist, '(');
15059a4b69e0SColomban Wendling 				skipLambdaArglist (token, arglist);
15069a4b69e0SColomban Wendling 				vStringPut (arglist, ')');
150771b09f08SMasatake YAMATO 				if (*type)
150871b09f08SMasatake YAMATO 				{
150971b09f08SMasatake YAMATO 					/* How to handle lambda assigned to a variable
151071b09f08SMasatake YAMATO 					 * --------------------------------------------
1511ba92e639SMasatake YAMATO 					 *
151271b09f08SMasatake YAMATO 					 * input.py:
1513ba92e639SMasatake YAMATO 					 *
151471b09f08SMasatake YAMATO 					 * 	  id = lambda var: var
151571b09f08SMasatake YAMATO 					 * 	  id_t: Callable[[int], int] = lambda var: var
1516ba92e639SMasatake YAMATO 					 *
151771b09f08SMasatake YAMATO 					 * `id' is tagged as a function kind object like:
1518ba92e639SMasatake YAMATO 					 *
151971b09f08SMasatake YAMATO 					 *    id	input.py	/^id = lambda var: var$/;"	function
1520ba92e639SMasatake YAMATO 					 *
152171b09f08SMasatake YAMATO 					 * For `id_t' we cannot do the same as `id'.
1522ba92e639SMasatake YAMATO 					 *
152371b09f08SMasatake YAMATO 					 * We should not store `Callable[[int], int]' to typeref
152471b09f08SMasatake YAMATO 					 * field of the tag of `id_t' if the tag has "function" as
152571b09f08SMasatake YAMATO 					 * its kind because users expect the typeref field of a
152671b09f08SMasatake YAMATO 					 * function kind represents a type for the value returned
152771b09f08SMasatake YAMATO 					 * from the function (return type).
1528ba92e639SMasatake YAMATO 					 *
152971b09f08SMasatake YAMATO 					 * the unexpected tag:
1530ba92e639SMasatake YAMATO 					 *
153171b09f08SMasatake YAMATO 					 *    id_t	input.py	/^id_t: Callable[[int], int] = lambda var: var$/;"	function \
153271b09f08SMasatake YAMATO 					 *                          typeref:typename:Callable[[int], int]
1533ba92e639SMasatake YAMATO 					 *
153471b09f08SMasatake YAMATO 					 * If we make a tag for `id_t' as a function, we should
153571b09f08SMasatake YAMATO 					 * attach `typeref:typename:int' and `signature:(int)'. To
153671b09f08SMasatake YAMATO 					 * achieve this, we have to make ctags analyze
153771b09f08SMasatake YAMATO 					 * `Callable[[int], int]'.  However, we want to avoid the
153871b09f08SMasatake YAMATO 					 * level of analyzing.
1539ba92e639SMasatake YAMATO 					 *
154071b09f08SMasatake YAMATO 					 * For recording `Callable[[int], int]', a valuable
154171b09f08SMasatake YAMATO 					 * information in the input, we use indirection.
154271b09f08SMasatake YAMATO 					 *
154371b09f08SMasatake YAMATO 					 *    id_t	input.py	/^id_t: Callable[[int], int] = lambda var: var$/;"	variable \
154471b09f08SMasatake YAMATO 					 *                          typeref:typename:Callable[[int], int]	nameref:function:anonFuncNNN
154571b09f08SMasatake YAMATO 					 *    anonFuncNNN	input.py	/^id_t: Callable[[int], int] = lambda var: var$/;"	function \
154671b09f08SMasatake YAMATO 					 *                          extras:anonymous
1547ba92e639SMasatake YAMATO 					 */
154871b09f08SMasatake YAMATO 					int vindex = makeSimplePythonTag (nameToken, kind);
154971b09f08SMasatake YAMATO 					vStringClear (anon->string);
155071b09f08SMasatake YAMATO 					anonGenerate (anon->string, "anonFunc", K_FUNCTION);
155171b09f08SMasatake YAMATO 					int findex = makeFunctionTag (anon, arglist, NULL);
155271b09f08SMasatake YAMATO 					tagEntryInfo *fe = getEntryInCorkQueue (findex);
155371b09f08SMasatake YAMATO 					if (fe)
155471b09f08SMasatake YAMATO 						markTagExtraBit (fe, XTAG_ANONYMOUS);
155571b09f08SMasatake YAMATO 
155671b09f08SMasatake YAMATO 					tagEntryInfo *ve = getEntryInCorkQueue (vindex);
155771b09f08SMasatake YAMATO 					if (ve)
155871b09f08SMasatake YAMATO 					{
155971b09f08SMasatake YAMATO 						ve->extensionFields.typeRef [0] = eStrdup ("typename");
156071b09f08SMasatake YAMATO 						ve->extensionFields.typeRef [1] = vStringDeleteUnwrap (*type);
156171b09f08SMasatake YAMATO 						*type = NULL;
156271b09f08SMasatake YAMATO 						vString *nameref = vStringNewInit (PythonKinds [K_FUNCTION].name);
156371b09f08SMasatake YAMATO 						vStringPut (nameref, ':');
156471b09f08SMasatake YAMATO 						vStringCat (nameref, anon->string);
156571b09f08SMasatake YAMATO 						attachParserField (ve, true, PythonFields[F_NAMEREF].ftype,
156671b09f08SMasatake YAMATO 										   vStringValue (nameref));
156771b09f08SMasatake YAMATO 						vStringDelete (nameref);
156871b09f08SMasatake YAMATO 					}
156971b09f08SMasatake YAMATO 					if (anon)
157071b09f08SMasatake YAMATO 						deleteToken (anon);
157171b09f08SMasatake YAMATO 				}
157271b09f08SMasatake YAMATO 				else
157371b09f08SMasatake YAMATO 					makeFunctionTag (nameToken, arglist, NULL);
15749a4b69e0SColomban Wendling 				vStringDelete (arglist);
15759a4b69e0SColomban Wendling 			}
15769a4b69e0SColomban Wendling 
15770c188d12SColomban Wendling 			/* skip until next initializer */
15780c188d12SColomban Wendling 			while ((TokenContinuationDepth > 0 || token->type != ',') &&
15790c188d12SColomban Wendling 			       token->type != TOKEN_EOF &&
1580cf4e7a83SColomban Wendling 			       token->type != ';' &&
15810c188d12SColomban Wendling 			       token->type != TOKEN_INDENT)
15820c188d12SColomban Wendling 			{
15830c188d12SColomban Wendling 				readToken (token);
15840c188d12SColomban Wendling 			}
15850c188d12SColomban Wendling 		}
15860c188d12SColomban Wendling 		while (token->type == ',' && i < nameCount);
15870c188d12SColomban Wendling 
15880c188d12SColomban Wendling 		/* if we got leftover to initialize, just make variables out of them.
15890c188d12SColomban Wendling 		 * This handles cases like `a, b, c = (c, d, e)` -- or worse */
15905e8ffad2SColomban Wendling 		for (; i < nameCount; i++)
15915e8ffad2SColomban Wendling 		{
15925e8ffad2SColomban Wendling 			if (nameTokens[i])
15935e8ffad2SColomban Wendling 				makeSimplePythonTag (nameTokens[i], kind);
15945e8ffad2SColomban Wendling 		}
15950c188d12SColomban Wendling 	}
15960c188d12SColomban Wendling 
15970c188d12SColomban Wendling 	while (nameCount > 0)
1598bbb831cfSColomban Wendling 	{
1599bbb831cfSColomban Wendling 		if (nameTokens[--nameCount])
16006ff4799bSJiří Techet 			deleteToken (nameTokens[nameCount]);
1601ba92e639SMasatake YAMATO 		vStringDelete (nameTypes[nameCount]); /* NULL is acceptable. */
1602bbb831cfSColomban Wendling 	}
16039a4b69e0SColomban Wendling 
1604ce990805SThomas Braun 	return false;
16059a4b69e0SColomban Wendling }
16069a4b69e0SColomban Wendling 
16077489fd61SMasatake YAMATO /* pops any level >= to indent */
setIndent(tokenInfo * const token)16087489fd61SMasatake YAMATO static void setIndent (tokenInfo *const token)
16097489fd61SMasatake YAMATO {
16107489fd61SMasatake YAMATO 	NestingLevel *lv = nestingLevelsGetCurrent (PythonNestingLevels);
16117489fd61SMasatake YAMATO 
16127489fd61SMasatake YAMATO 	while (lv && PY_NL (lv)->indentation >= token->indent)
16137489fd61SMasatake YAMATO 	{
16143afb5475SMasatake YAMATO 		tagEntryInfo *e = getEntryInCorkQueue (lv->corkIndex);
16153671ad72SMasatake YAMATO 		if (e)
16167489fd61SMasatake YAMATO 			e->extensionFields.endLine = token->lineNumber;
16177489fd61SMasatake YAMATO 
16187489fd61SMasatake YAMATO 		nestingLevelsPop (PythonNestingLevels);
16197489fd61SMasatake YAMATO 		lv = nestingLevelsGetCurrent (PythonNestingLevels);
16207489fd61SMasatake YAMATO 	}
16217489fd61SMasatake YAMATO }
16227489fd61SMasatake YAMATO 
findPythonTags(void)16237489fd61SMasatake YAMATO static void findPythonTags (void)
16247489fd61SMasatake YAMATO {
16256ff4799bSJiří Techet 	tokenInfo *const token = newToken ();
16265d0fd5feSColomban Wendling 	vString *decorators = vStringNew ();
1627ce990805SThomas Braun 	bool atStatementStart = true;
16287489fd61SMasatake YAMATO 
16297489fd61SMasatake YAMATO 	TokenContinuationDepth = 0;
16307489fd61SMasatake YAMATO 	NextToken = NULL;
16317489fd61SMasatake YAMATO 	PythonNestingLevels = nestingLevelsNew (sizeof (struct pythonNestingLevelUserData));
16327489fd61SMasatake YAMATO 
16337489fd61SMasatake YAMATO 	readToken (token);
16347489fd61SMasatake YAMATO 	while (token->type != TOKEN_EOF)
16357489fd61SMasatake YAMATO 	{
16365d0fd5feSColomban Wendling 		tokenType iterationTokenType = token->type;
1637ce990805SThomas Braun 		bool readNext = true;
16387489fd61SMasatake YAMATO 
163916845a4eSColomban Wendling 		/* skip async keyword that confuses decorator parsing before a def */
164016845a4eSColomban Wendling 		if (token->keyword == KEYWORD_async)
164116845a4eSColomban Wendling 			readToken (token);
164216845a4eSColomban Wendling 
16437489fd61SMasatake YAMATO 		if (token->type == TOKEN_INDENT)
16447489fd61SMasatake YAMATO 			setIndent (token);
16457489fd61SMasatake YAMATO 		else if (token->keyword == KEYWORD_class ||
16467489fd61SMasatake YAMATO 		         token->keyword == KEYWORD_def)
16477489fd61SMasatake YAMATO 		{
16487489fd61SMasatake YAMATO 			pythonKind kind = token->keyword == KEYWORD_class ? K_CLASS : K_FUNCTION;
16497489fd61SMasatake YAMATO 
1650ce990805SThomas Braun 			readNext = parseClassOrDef (token, decorators, kind, false);
16517489fd61SMasatake YAMATO 		}
16527489fd61SMasatake YAMATO 		else if (token->keyword == KEYWORD_cdef ||
16537489fd61SMasatake YAMATO 		         token->keyword == KEYWORD_cpdef)
16547489fd61SMasatake YAMATO 		{
1655ce990805SThomas Braun 			readNext = parseClassOrDef (token, decorators, K_FUNCTION, true);
16567489fd61SMasatake YAMATO 		}
16577489fd61SMasatake YAMATO 		else if (token->keyword == KEYWORD_from ||
16587489fd61SMasatake YAMATO 		         token->keyword == KEYWORD_import)
16597489fd61SMasatake YAMATO 		{
16607489fd61SMasatake YAMATO 			readNext = parseImport (token);
1661f5f8bd9aSMasatake YAMATO 		}
16622ff1f9d2SColomban Wendling 		else if (token->type == '(')
16632ff1f9d2SColomban Wendling 		{ /* skip parentheses to avoid finding stuff inside them */
1664ce990805SThomas Braun 			readNext = skipOverPair (token, '(', ')', NULL, false);
1665f5f8bd9aSMasatake YAMATO 		}
1666cf4e7a83SColomban Wendling 		else if (token->type == TOKEN_IDENTIFIER && atStatementStart)
1667f5f8bd9aSMasatake YAMATO 		{
16682ff1f9d2SColomban Wendling 			NestingLevel *lv = nestingLevelsGetCurrent (PythonNestingLevels);
16692ff1f9d2SColomban Wendling 			tagEntryInfo *lvEntry = getEntryOfNestingLevel (lv);
167098a8ebe8SColomban Wendling 			pythonKind kind = K_VARIABLE;
16713ae02089SMasatake YAMATO 
1672f92e6bf2SMasatake YAMATO 			if (lvEntry && lvEntry->kindIndex != K_CLASS)
167398a8ebe8SColomban Wendling 				kind = K_LOCAL_VARIABLE;
167498a8ebe8SColomban Wendling 
167598a8ebe8SColomban Wendling 			readNext = parseVariable (token, kind);
16763ae02089SMasatake YAMATO 		}
16775d0fd5feSColomban Wendling 		else if (token->type == '@' && atStatementStart &&
16785d0fd5feSColomban Wendling 		         PythonFields[F_DECORATORS].enabled)
16795d0fd5feSColomban Wendling 		{
16805d0fd5feSColomban Wendling 			/* collect decorators */
16815d0fd5feSColomban Wendling 			readQualifiedName (token);
16825d0fd5feSColomban Wendling 			if (token->type != TOKEN_IDENTIFIER)
1683ce990805SThomas Braun 				readNext = false;
16845d0fd5feSColomban Wendling 			else
16855d0fd5feSColomban Wendling 			{
16865d0fd5feSColomban Wendling 				if (vStringLength (decorators) > 0)
16875d0fd5feSColomban Wendling 					vStringPut (decorators, ',');
16885d0fd5feSColomban Wendling 				vStringCat (decorators, token->string);
16895d0fd5feSColomban Wendling 				readToken (token);
1690ce990805SThomas Braun 				readNext = skipOverPair (token, '(', ')', decorators, true);
16915d0fd5feSColomban Wendling 			}
16925d0fd5feSColomban Wendling 		}
16935d0fd5feSColomban Wendling 
16945d0fd5feSColomban Wendling 		/* clear collected decorators for any non-decorator tokens non-indent
16955d0fd5feSColomban Wendling 		 * token.  decorator collection takes care of skipping the possible
16965d0fd5feSColomban Wendling 		 * argument list, so we should never hit here parsing a decorator */
16975d0fd5feSColomban Wendling 		if (iterationTokenType != TOKEN_INDENT &&
16985d0fd5feSColomban Wendling 		    iterationTokenType != '@' &&
16995d0fd5feSColomban Wendling 		    PythonFields[F_DECORATORS].enabled)
17005d0fd5feSColomban Wendling 		{
17015d0fd5feSColomban Wendling 			vStringClear (decorators);
17025d0fd5feSColomban Wendling 		}
17036c11b8afSMasatake YAMATO 
1704cf4e7a83SColomban Wendling 		atStatementStart = (token->type == TOKEN_INDENT || token->type == ';');
17056c11b8afSMasatake YAMATO 
17062ff1f9d2SColomban Wendling 		if (readNext)
17072ff1f9d2SColomban Wendling 			readToken (token);
17082ff1f9d2SColomban Wendling 	}
17092ff1f9d2SColomban Wendling 
17102ff1f9d2SColomban Wendling 	nestingLevelsFree (PythonNestingLevels);
17115d0fd5feSColomban Wendling 	vStringDelete (decorators);
17126ff4799bSJiří Techet 	deleteToken (token);
17132ff1f9d2SColomban Wendling 	Assert (NextToken == NULL);
17142ff1f9d2SColomban Wendling }
17152ff1f9d2SColomban Wendling 
initialize(const langType language)17162ff1f9d2SColomban Wendling static void initialize (const langType language)
17172ff1f9d2SColomban Wendling {
17182ff1f9d2SColomban Wendling 	Lang_python = language;
1719d3bb2b5aSJiří Techet 
1720e013efc1SMasatake YAMATO 	TokenPool = objPoolNew (16, newPoolToken, deletePoolToken, clearPoolToken, NULL);
1721d3bb2b5aSJiří Techet }
1722d3bb2b5aSJiří Techet 
finalize(langType language CTAGS_ATTR_UNUSED,bool initialized)1723d3bb2b5aSJiří Techet static void finalize (langType language CTAGS_ATTR_UNUSED, bool initialized)
1724d3bb2b5aSJiří Techet {
1725d3bb2b5aSJiří Techet 	if (!initialized)
1726d3bb2b5aSJiří Techet 		return;
1727d3bb2b5aSJiří Techet 
1728d3bb2b5aSJiří Techet 	objPoolDelete (TokenPool);
17293ae02089SMasatake YAMATO }
17303ae02089SMasatake YAMATO 
PythonParser(void)17313ae02089SMasatake YAMATO extern parserDefinition* PythonParser (void)
17323ae02089SMasatake YAMATO {
1733ce0d6577SMasatake YAMATO 	static const char *const extensions[] = { "py", "pyx", "pxd", "pxi", "scons",
1734ce0d6577SMasatake YAMATO 											  "wsgi", NULL };
17352ff1f9d2SColomban Wendling 	static const char *const aliases[] = { "python[23]*", "scons", NULL };
17363ae02089SMasatake YAMATO 	parserDefinition *def = parserNew ("Python");
173709ae690fSMasatake YAMATO 	def->kindTable = PythonKinds;
17383db72c21SMasatake YAMATO 	def->kindCount = ARRAY_SIZE (PythonKinds);
17393ae02089SMasatake YAMATO 	def->extensions = extensions;
17403ae02089SMasatake YAMATO 	def->aliases = aliases;
17413ae02089SMasatake YAMATO 	def->parser = findPythonTags;
17422ff1f9d2SColomban Wendling 	def->initialize = initialize;
1743d3bb2b5aSJiří Techet 	def->finalize = finalize;
1744b0470ee9SMasatake YAMATO 	def->keywordTable = PythonKeywordTable;
1745b0470ee9SMasatake YAMATO 	def->keywordCount = ARRAY_SIZE (PythonKeywordTable);
1746a739fa5fSMasatake YAMATO 	def->fieldTable = PythonFields;
1747a739fa5fSMasatake YAMATO 	def->fieldCount = ARRAY_SIZE (PythonFields);
17486b1a862eSMasatake YAMATO 	def->useCork = CORK_QUEUE;
1749ce990805SThomas Braun 	def->requestAutomaticFQTag = true;
17503ae02089SMasatake YAMATO 	return def;
17513ae02089SMasatake YAMATO }
1752