コード例 #1
0
ファイル: cxx_tag.c プロジェクト: sohgett/ctags
vString * cxxTagSetProperties(unsigned int uProperties)
{
	if(uProperties == 0)
		return NULL;

	if(!cxxTagFieldEnabled(CXXTagFieldProperties))
			return NULL;

	vString * pszProperties = vStringNew();

	boolean bFirst = TRUE;

#define ADD_PROPERTY(_szProperty) \
	do { \
		if(bFirst) \
			bFirst = FALSE; \
		else \
			vStringPut(pszProperties,','); \
		vStringCatS(pszProperties,_szProperty); \
	} while(0)

	if(uProperties & CXXTagPropertyConst)
		ADD_PROPERTY("const");
	if(uProperties & CXXTagPropertyDefault)
		ADD_PROPERTY("default");
	if(uProperties & CXXTagPropertyDelete)
		ADD_PROPERTY("delete");
	if(uProperties & CXXTagPropertyExplicit)
		ADD_PROPERTY("explicit");
	if(uProperties & CXXTagPropertyExtern)
		ADD_PROPERTY("extern");
	if(uProperties & CXXTagPropertyFinal)
		ADD_PROPERTY("final");
	if(uProperties & CXXTagPropertyInline)
		ADD_PROPERTY("inline");
	if(uProperties & CXXTagPropertyMutable)
		ADD_PROPERTY("mutable");
	if(uProperties & CXXTagPropertyOverride)
		ADD_PROPERTY("override");
	if(uProperties & CXXTagPropertyPure)
		ADD_PROPERTY("pure");
	if(uProperties & CXXTagPropertyScopeTemplateSpecialization)
		ADD_PROPERTY("scopespecialization");
	if(uProperties & CXXTagPropertyStatic)
		ADD_PROPERTY("static");
	if(uProperties & CXXTagPropertyTemplateSpecialization)
		ADD_PROPERTY("specialization");
	if(uProperties & CXXTagPropertyVirtual)
		ADD_PROPERTY("virtual");
	if(uProperties & CXXTagPropertyVolatile)
		ADD_PROPERTY("volatile");
	if(uProperties & CXXTagPropertyDeprecated)
		ADD_PROPERTY("deprecated");

	cxxTagSetField(CXXTagFieldProperties,vStringValue(pszProperties));

	return pszProperties;
}
コード例 #2
0
ファイル: cxx_parser_namespace.c プロジェクト: amosbird/ctags
boolean cxxParserParseNamespace(void)
{
	CXX_DEBUG_ENTER();

	CXX_DEBUG_ASSERT(cxxParserCurrentLanguageIsCPP(),"This should be called only in C++");

	/*
		Spec is:

			namespace ns_name { declarations }	(1)
			inline namespace ns_name { declarations }	(2)	(since C++11)
			namespace { declarations }	(3)
			namespace name = qualified-namespace ;	(7)
			namespace ns_name::name	{ (8)	(since C++17)

		Note that the using clauses have their own parsing routine and do not end up here.
	*/

	// namespace <X> {
	// namespace <X>::<Y>::<Z> {
	// namespace <X>::<Y>::<Z>;
	// namespace <X>;
	// namespace;

	unsigned int uProperties = 0;

	if(cxxTagFieldEnabled(CXXTagFieldProperties))
	{
		if(g_cxx.uKeywordState & CXXParserKeywordStateSeenInline)
			uProperties |= CXXTagPropertyInline;
	}

	cxxParserNewStatement(); // always a new statement

	int iScopeCount = 0;

	int i;

	int aCorkQueueIndices[MAX_NESTED_NAMESPACES];

	for(i=0;i<MAX_NESTED_NAMESPACES;i++)
		aCorkQueueIndices[i] = CORK_NIL;

	if(!cxxParserParseNextToken())
	{
		// syntax error, but we tolerate this
		CXX_DEBUG_LEAVE_TEXT("Implicit EOF in cxxParserParseNextToken");
		return TRUE; // EOF
	}

	if(cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeIdentifier))
	{
		// OK, check next token to see what's coming after

		CXX_DEBUG_PRINT("Got identifier %s",g_cxx.pToken->pszWord->buffer);

		CXXToken * pFirstIdentifier = g_cxx.pToken;
		CXXToken * pLastIdentifier = g_cxx.pToken;

		if(!cxxParserParseNextToken())
		{
			// syntax error, but we tolerate this
			CXX_DEBUG_LEAVE_TEXT("EOF in cxxParserParseNextToken");
			return TRUE; // EOF
		}

		switch(g_cxx.pToken->eType)
		{
			case CXXTokenTypeAssignment:
			{
				// probably namespace alias
				CXX_DEBUG_PRINT("Found assignment");

				if(!cxxParserParseNextToken())
				{
					// syntax error, but we tolerate this
					CXX_DEBUG_LEAVE_TEXT("EOF in cxxParserParseNextToken");
					return TRUE; // EOF
				}

				if(!cxxTokenTypeIsOneOf(
						g_cxx.pToken,
						CXXTokenTypeIdentifier | CXXTokenTypeMultipleColons
					))
				{
					CXX_DEBUG_LEAVE_TEXT("Some kind of syntax error here");
					return cxxParserSkipToSemicolonOrEOF();
				}

				CXXToken * pAlias = pFirstIdentifier;
				pFirstIdentifier = g_cxx.pToken;

				if(!cxxParserParseToEndOfQualifedName())
				{
					CXX_DEBUG_LEAVE_TEXT("Failed to parse the aliased name");
					return cxxParserSkipToSemicolonOrEOF();
				}

				pLastIdentifier = g_cxx.pToken->pPrev;

				tagEntryInfo * tag = cxxTagBegin(CXXTagCPPKindALIAS,pAlias);

				if(tag)
				{
					// This is highly questionable but well.. it's how old ctags did, so we do.
					tag->isFileScope = !isInputHeaderFile();

					CXXToken * pAliasedName = cxxTokenChainExtractRange(
							pFirstIdentifier,
							pLastIdentifier,
							CXXTokenChainExtractRangeNoTrailingSpaces
						);

					cxxTagSetField(
							CXXTagCPPFieldAliasedName,
							vStringValue(pAliasedName->pszWord)
						);

					cxxTagCommit();

					cxxTokenDestroy(pAliasedName);
				}

				CXX_DEBUG_LEAVE_TEXT("Finished parsing namespace alias");
				return cxxParserSkipToSemicolonOrEOF();
			}
			break;
			case CXXTokenTypeMultipleColons:
				// multi-namespace
				CXX_DEBUG_PRINT("Found multiple colons");

				if(!cxxParserParseToEndOfQualifedName())
				{
					CXX_DEBUG_LEAVE_TEXT("Failed to parse the namespace name");
					return cxxParserSkipToSemicolonOrEOF();
				}

				pLastIdentifier = g_cxx.pToken->pPrev;

				CXX_DEBUG_ASSERT(
						pFirstIdentifier != pLastIdentifier,
						"We expected multiple identifiers here"
					);

				if(!cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeOpeningBracket))
				{
					if(!cxxParserParseUpToOneOf(
							CXXTokenTypeOpeningBracket | CXXTokenTypeSemicolon | CXXTokenTypeEOF
						))
					{
						CXX_DEBUG_LEAVE_TEXT("Failed to parse up to an opening bracket");
						return FALSE;
					}

					if(!cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeOpeningBracket))
					{
						// tolerate syntax error
						CXX_DEBUG_LEAVE_TEXT("Found semicolon just after namespace declaration");
						return TRUE;
					}

					CXX_DEBUG_LEAVE_TEXT("Was expecting an opening bracket here");
					// FIXME: Maybe we could attempt to recover here?
					return TRUE;
				}
			break;
			case CXXTokenTypeOpeningBracket:
				// single name namespace
				CXX_DEBUG_PRINT("Found opening bracket");
			break;
			case CXXTokenTypeSemicolon:
				// tolerate syntax error
				CXX_DEBUG_LEAVE_TEXT("Found semicolon just after namespace declaration");
				return TRUE;
			break;
			default:
				CXX_DEBUG_LEAVE_TEXT("Some kind of syntax error here");
				return cxxParserSkipToSemicolonOrEOF();
			break;
		}

		CXX_DEBUG_ASSERT(
				cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeOpeningBracket),
				"Should have an opening bracket here!"
			);

		CXX_DEBUG_PRINT("Found regular namespace start");

		CXXToken * t = pFirstIdentifier;

		while(t)
		{
			tagEntryInfo * tag = cxxTagBegin(CXXTagCPPKindNAMESPACE,t);

			if(tag)
			{
				// This is highly questionable but well.. it's how old ctags did, so we do.
				tag->isFileScope = !isInputHeaderFile();

				vString * pszProperties = uProperties ? cxxTagSetProperties(uProperties) : NULL;

				int iCorkQueueIndex = cxxTagCommit();

				if(iScopeCount < MAX_NESTED_NAMESPACES)
					aCorkQueueIndices[iScopeCount] = iCorkQueueIndex;

				if(pszProperties)
					vStringDelete(pszProperties);
			}

			CXXToken * pNext = (t == pLastIdentifier) ? NULL : t->pNext->pNext;

			cxxTokenChainTake(g_cxx.pTokenChain,t);

			cxxScopePush(
					t,
					CXXScopeTypeNamespace,
					CXXScopeAccessUnknown
				);

			iScopeCount++;

			t = pNext;
		}

	} else if(cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeOpeningBracket))
	{
		// anonymous namespace
		CXX_DEBUG_PRINT("Found anonymous namespace start");

		CXXToken * t = cxxTokenCreateAnonymousIdentifier(CXXTagCPPKindNAMESPACE);
		tagEntryInfo * tag = cxxTagBegin(CXXTagCPPKindNAMESPACE,t);
		if(tag)
		{
			tag->isFileScope = !isInputHeaderFile();

			vString * pszProperties = uProperties ? cxxTagSetProperties(uProperties) : NULL;

			aCorkQueueIndices[0] = cxxTagCommit();

			if(pszProperties)
				vStringDelete(pszProperties);
		}
		cxxScopePush(t,CXXScopeTypeNamespace,CXXScopeAccessUnknown);

		iScopeCount++;

	} else {

		CXX_DEBUG_LEAVE_TEXT("Some kind of syntax error after namespace declaration");
		return cxxParserSkipToSemicolonOrEOF();
	}

	CXX_DEBUG_ASSERT(
			cxxTokenTypeIs(g_cxx.pToken,CXXTokenTypeOpeningBracket),
			"Should have an opening bracket here!"
		);

	// Here we certainly got an opening bracket: namespace block

	if(!cxxParserParseBlock(TRUE))
	{
		CXX_DEBUG_LEAVE_TEXT("Failed to parse namespace block");
		return FALSE;
	}

	while(iScopeCount > 0)
	{
		cxxScopePop();
		iScopeCount--;

		if(aCorkQueueIndices[iScopeCount] > CORK_NIL)
			cxxParserMarkEndLineForTagInCorkQueue(aCorkQueueIndices[iScopeCount]);
	}

	CXX_DEBUG_LEAVE_TEXT("Finished parsing namespace");
	return TRUE;
}
コード例 #3
0
ファイル: cxx_parser_lambda.c プロジェクト: codebrainz/ctags
// In case of a lambda without parentheses this is the capture list token.
boolean cxxParserHandleLambda(CXXToken * pParenthesis)
{
	CXX_DEBUG_ENTER();
	
	CXX_DEBUG_ASSERT(cxxParserCurrentLanguageIsCPP(),"C++ only");

	CXXToken * pIdentifier = cxxTokenCreateAnonymousIdentifier(CXXTagKindFUNCTION);

	CXXTokenChain * pSave = g_cxx.pTokenChain;
	CXXTokenChain * pNew = cxxTokenChainCreate();
	g_cxx.pTokenChain = pNew;

	tagEntryInfo * tag = cxxTagBegin(CXXTagKindFUNCTION,pIdentifier);

	CXXToken * pAfterParenthesis = pParenthesis ? pParenthesis->pNext : NULL;

	CXXToken * pCaptureList = NULL;
	
	if(pParenthesis)
	{
		if(cxxTokenTypeIs(pParenthesis,CXXTokenTypeSquareParenthesisChain))
		{
			// form (4) of lambda (see cxxParserOpeningBracketIsLambda()).
			pCaptureList = pParenthesis;
		} else if(
			pParenthesis->pPrev &&
			cxxTokenTypeIs(pParenthesis->pPrev,CXXTokenTypeSquareParenthesisChain)
		)
		{
			// other forms of lambda (see cxxParserOpeningBracketIsLambda()).
			pCaptureList = pParenthesis->pPrev;
		}
	}

	if(
		pAfterParenthesis &&
		cxxTokenTypeIs(pAfterParenthesis,CXXTokenTypeKeyword) &&
		(pAfterParenthesis->eKeyword == CXXKeywordCONST)
	)
		pAfterParenthesis = pAfterParenthesis->pNext;

	CXXToken * pTypeStart = NULL;
	CXXToken * pTypeEnd;

	if(
			pAfterParenthesis &&
			cxxTokenTypeIs(pAfterParenthesis,CXXTokenTypePointerOperator) &&
			pAfterParenthesis->pNext &&
			!cxxTokenTypeIs(pAfterParenthesis->pNext,CXXTokenTypeOpeningBracket)
		)
	{
		pTypeStart = pAfterParenthesis->pNext;
		pTypeEnd = pTypeStart;
		while(
				pTypeEnd->pNext &&
				(!cxxTokenTypeIs(pTypeEnd->pNext,CXXTokenTypeOpeningBracket))
			)
			pTypeEnd = pTypeEnd->pNext;

		while(
				(pTypeStart != pTypeEnd) &&
				cxxTokenTypeIs(pTypeStart,CXXTokenTypeKeyword) &&
				cxxKeywordExcludeFromTypeNames(pTypeStart->eKeyword)
			)
			pTypeStart = pTypeStart->pNext;
	}

	int iCorkQueueIndex = CORK_NIL;

	if(tag)
	{
		tag->isFileScope = TRUE;

		CXXToken * pTypeName;

		if(pTypeStart)
			pTypeName = cxxTagSetTypeField(pTypeStart,pTypeEnd);
		else
			pTypeName = NULL;

		if(pCaptureList && cxxTagFieldEnabled(CXXTagCPPFieldLambdaCaptureList))
		{
			CXX_DEBUG_ASSERT(pCaptureList->pChain,"The capture list must be a chain");
			cxxTokenChainCondense(pCaptureList->pChain,0);
			CXX_DEBUG_ASSERT(
					cxxTokenChainFirst(pCaptureList->pChain),
					"Condensation should have created a single token in the chain"
				);
			cxxTagSetField(
					CXXTagCPPFieldLambdaCaptureList,
					vStringValue(cxxTokenChainFirst(pCaptureList->pChain)->pszWord)
				);
		}

		// FIXME: Properties?

		vString * pszSignature = NULL;
		if(cxxTokenTypeIs(pParenthesis,CXXTokenTypeParenthesisChain))
			pszSignature = cxxTokenChainJoin(pParenthesis->pChain,NULL,0);

		if(pszSignature)
			tag->extensionFields.signature = vStringValue(pszSignature);

		iCorkQueueIndex = cxxTagCommit();

		if(pTypeName)
			cxxTokenDestroy(pTypeName);

		if(pszSignature)
			vStringDelete(pszSignature);
	}

	cxxScopePush(
			pIdentifier,
			CXXScopeTypeFunction,
			CXXScopeAccessUnknown
		);

	if(
		pParenthesis &&
		cxxTokenTypeIs(pParenthesis,CXXTokenTypeParenthesisChain) &&
		cxxTagKindEnabled(CXXTagKindPARAMETER)
	)
	{
		CXXFunctionParameterInfo oParamInfo;
		if(cxxParserTokenChainLooksLikeFunctionParameterList(
				pParenthesis->pChain,&oParamInfo
			))
			cxxParserEmitFunctionParameterTags(&oParamInfo);
	}

	boolean bRet = cxxParserParseBlock(TRUE);

	if(iCorkQueueIndex > CORK_NIL)
		cxxParserMarkEndLineForTagInCorkQueue(iCorkQueueIndex);

	cxxScopePop();

	pNew = g_cxx.pTokenChain; // May have been destroyed and re-created

	g_cxx.pTokenChain = pSave;
	g_cxx.pToken = pSave->pTail;

	// change the type of token so following parsing code is not confused too much
	g_cxx.pToken->eType = CXXTokenTypeAngleBracketChain;
	g_cxx.pToken->pChain = pNew;

	cxxTokenChainClear(pNew);

	CXXToken * t = cxxTokenCreate();
	t->eType = CXXTokenTypeOpeningBracket;
	vStringCatS(t->pszWord,"{");
	cxxTokenChainAppend(pNew,t);

	t = cxxTokenCreate();
	t->eType = CXXTokenTypeClosingBracket;
	vStringCatS(t->pszWord,"}");
	cxxTokenChainAppend(pNew,t);

	CXX_DEBUG_LEAVE();
	return bRet;
}