2 * Copyright 2014, Rene Gollent, rene@gollent.com.
3 * Distributed under the terms of the MIT License.
7 #include "CLanguageFamilySyntaxHighlightInfo.h"
9 #include <AutoDeleter.h>
11 #include "CLanguageTokenizer.h"
12 #include "LineDataSource.h"
13 #include "TeamTypeInformation.h"
14 #include "TypeLookupConstraints.h"
17 using namespace CLanguage
;
20 static const char* kLanguageKeywords
[] = {
86 static bool IsLanguageKeyword(const Token
& token
)
89 int upper
= (sizeof(kLanguageKeywords
)/sizeof(char*)) - 1;
91 while (lower
< upper
) {
92 int mid
= (lower
+ upper
+ 1) / 2;
94 int cmp
= token
.string
.Compare(kLanguageKeywords
[mid
]);
103 return token
.string
.Compare(kLanguageKeywords
[lower
]) == 0;
107 // #pragma mark - CLanguageFamilySyntaxHighlightInfo::SyntaxPair
110 struct CLanguageFamilySyntaxHighlightInfo::SyntaxPair
{
112 syntax_highlight_type type
;
114 SyntaxPair(int32 column
, syntax_highlight_type type
)
123 // #pragma mark - CLanguageFamilySyntaxHighlightInfo::LineInfo
126 class CLanguageFamilySyntaxHighlightInfo::LineInfo
{
135 inline int32
CountPairs() const
137 return fPairs
.CountItems();
140 SyntaxPair
* PairAt(int32 index
) const
142 return fPairs
.ItemAt(index
);
145 bool AddPair(int32 column
, syntax_highlight_type type
)
147 SyntaxPair
* pair
= new(std::nothrow
) SyntaxPair(column
, type
);
151 ObjectDeleter
<SyntaxPair
> pairDeleter(pair
);
152 if (!fPairs
.AddItem(pair
))
155 pairDeleter
.Detach();
160 typedef BObjectList
<SyntaxPair
> SyntaxPairList
;
164 SyntaxPairList fPairs
;
168 // #pragma mark - CLanguageFamilySyntaxHighlightInfo;
171 CLanguageFamilySyntaxHighlightInfo::CLanguageFamilySyntaxHighlightInfo(
172 LineDataSource
* source
, Tokenizer
* tokenizer
,
173 TeamTypeInformation
* typeInfo
)
175 SyntaxHighlightInfo(),
176 fHighlightSource(source
),
177 fTokenizer(tokenizer
),
181 fHighlightSource
->AcquireReference();
185 CLanguageFamilySyntaxHighlightInfo::~CLanguageFamilySyntaxHighlightInfo()
187 fHighlightSource
->ReleaseReference();
193 CLanguageFamilySyntaxHighlightInfo::GetLineHighlightRanges(int32 line
,
194 int32
* _columns
, syntax_highlight_type
* _types
, int32 maxCount
)
196 if (line
>= fHighlightSource
->CountLines())
199 // lazily parse the source's highlight information the first time
200 // it's actually requested. Subsequently it's cached for quick retrieval.
201 if (fLineInfos
.CountItems() == 0) {
202 if (_ParseLines() != B_OK
)
206 LineInfo
* info
= fLineInfos
.ItemAt(line
);
211 for (; count
< info
->CountPairs(); count
++) {
212 if (count
== maxCount
- 1)
215 SyntaxPair
* pair
= info
->PairAt(count
);
219 _columns
[count
] = pair
->column
;
220 _types
[count
] = pair
->type
;
228 CLanguageFamilySyntaxHighlightInfo::_ParseLines()
230 syntax_highlight_type type
= SYNTAX_HIGHLIGHT_NONE
;
232 for (int32 i
= 0; i
< fHighlightSource
->CountLines(); i
++) {
233 const char* line
= fHighlightSource
->LineAt(i
);
234 fTokenizer
->SetTo(line
);
235 LineInfo
* info
= NULL
;
237 status_t error
= _ParseLine(i
, type
, info
);
241 ObjectDeleter
<LineInfo
> infoDeleter(info
);
242 if (!fLineInfos
.AddItem(info
))
245 infoDeleter
.Detach();
253 CLanguageFamilySyntaxHighlightInfo::_ParseLine(int32 line
,
254 syntax_highlight_type
& _lastType
, LineInfo
*& _info
)
256 bool inCommentBlock
= (_lastType
== SYNTAX_HIGHLIGHT_COMMENT
);
257 bool inPreprocessor
= false;
259 _info
= new(std::nothrow
) LineInfo(line
);
262 ObjectDeleter
<LineInfo
> infoDeleter(_info
);
263 if (inCommentBlock
) {
264 if (!_info
->AddPair(0, SYNTAX_HIGHLIGHT_COMMENT
))
270 const Token
& token
= fTokenizer
->NextToken();
271 if (token
.type
== TOKEN_END_OF_LINE
)
274 if (inCommentBlock
) {
275 if (token
.type
== TOKEN_END_COMMENT_BLOCK
)
276 inCommentBlock
= false;
278 } else if (inPreprocessor
) {
279 fTokenizer
->NextToken();
280 inPreprocessor
= false;
281 } else if (token
.type
== TOKEN_INLINE_COMMENT
) {
282 if (!_info
->AddPair(token
.position
, SYNTAX_HIGHLIGHT_COMMENT
))
287 syntax_highlight_type current
= _MapTokenToSyntaxType(token
);
288 if (_lastType
== current
)
292 if (!_info
->AddPair(token
.position
, current
))
295 if (token
.type
== TOKEN_BEGIN_COMMENT_BLOCK
)
296 inCommentBlock
= true;
297 else if (token
.type
== TOKEN_POUND
)
298 inPreprocessor
= true;
301 // if a parse exception was thrown, simply ignore it.
302 // in such a case, we can't guarantee correct highlight
303 // information anyhow, so simply return whatever we started
307 _lastType
= inCommentBlock
308 ? SYNTAX_HIGHLIGHT_COMMENT
: SYNTAX_HIGHLIGHT_NONE
;
309 infoDeleter
.Detach();
314 syntax_highlight_type
315 CLanguageFamilySyntaxHighlightInfo::_MapTokenToSyntaxType(const Token
& token
)
317 static TypeLookupConstraints constraints
;
319 switch (token
.type
) {
320 case TOKEN_IDENTIFIER
:
321 if (IsLanguageKeyword(token
))
322 return SYNTAX_HIGHLIGHT_KEYWORD
;
323 else if (fTypeInfo
->TypeExistsByName(token
.string
, constraints
))
324 return SYNTAX_HIGHLIGHT_TYPE
;
328 return SYNTAX_HIGHLIGHT_NUMERIC_LITERAL
;
330 case TOKEN_END_OF_LINE
:
338 case TOKEN_OPENING_PAREN
:
339 case TOKEN_CLOSING_PAREN
:
340 case TOKEN_OPENING_SQUARE_BRACKET
:
341 case TOKEN_CLOSING_SQUARE_BRACKET
:
342 case TOKEN_OPENING_CURLY_BRACE
:
343 case TOKEN_CLOSING_CURLY_BRACE
:
344 case TOKEN_LOGICAL_AND
:
345 case TOKEN_LOGICAL_OR
:
346 case TOKEN_LOGICAL_NOT
:
347 case TOKEN_BITWISE_AND
:
348 case TOKEN_BITWISE_OR
:
349 case TOKEN_BITWISE_NOT
:
350 case TOKEN_BITWISE_XOR
:
357 case TOKEN_MEMBER_PTR
:
358 case TOKEN_CONDITION
:
360 case TOKEN_SEMICOLON
:
361 case TOKEN_BACKSLASH
:
362 return SYNTAX_HIGHLIGHT_OPERATOR
;
364 case TOKEN_STRING_LITERAL
:
365 return SYNTAX_HIGHLIGHT_STRING_LITERAL
;
368 return SYNTAX_HIGHLIGHT_PREPROCESSOR_KEYWORD
;
370 case TOKEN_BEGIN_COMMENT_BLOCK
:
371 case TOKEN_END_COMMENT_BLOCK
:
372 case TOKEN_INLINE_COMMENT
:
373 return SYNTAX_HIGHLIGHT_COMMENT
;
376 return SYNTAX_HIGHLIGHT_NONE
;