2 * Copyright (c) 2019, Karol Samborski
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
7 * This module contains functions for generating tags for TypeScript language
10 * Reference: https://github.com/Microsoft/TypeScript/blob/master/doc/TypeScript%20Language%20Specification.pdf
17 #include "general.h" /* must always come first */
33 #define isType(token,t) (bool) ((token)->type == (t))
34 #define isKeyword(token,k) (bool) ((token)->keyword == (k))
35 #define newToken() (objPoolGet (TokenPool))
36 #define deleteToken(t) (objPoolPut (TokenPool, (t)))
37 #define isIdentChar(c) \
38 (isalpha (c) || isdigit (c) || (c) == '$' || \
39 (c) == '@' || (c) == '_' || (c) == '#' || \
42 #define PARSER_DEF(fname, pfun, word, stateField) \
43 CTAGS_INLINE void parse ## fname (const int c, tokenInfo * const token, parserState *state, parserResult * const result) \
45 pfun (c, token, word, &state->stateField, result); \
48 #define SINGLE_CHAR_PARSER_DEF(fname, ch, ttype) \
49 CTAGS_INLINE void parse ## fname (const int c, tokenInfo * const token, parserState *state, parserResult * const result) \
51 parseOneChar (c, token, ch, ttype, result); \
54 #define MULTI_CHAR_PARSER_DEF(fname, chs, ...) \
55 CTAGS_INLINE void parse ## fname (const int c, tokenInfo * const token, parserState *state, parserResult * const result) \
57 tokenType types[] = { __VA_ARGS__ }; \
58 parseChar (c, token, state, result, chs, types); \
61 #define WORD_TOKEN_PARSER_DEF(fname, w, ttype) \
62 CTAGS_INLINE void parse ## fname (const int c, tokenInfo * const token, parserState *state, parserResult * const result) \
64 parseWordToken (c, token, w, ttype, &state->num, result); \
67 #define BLOCK_PARSER_DEF(fname, start, end, ttype) \
68 CTAGS_INLINE void parse ## fname (const int c, tokenInfo * const token, parserState *state, parserResult * const result) \
70 parseBlock (c, token, ttype, start, end, &state->block, result); \
76 static langType Lang_ts
;
77 static objPool
*TokenPool
= NULL
;
79 /* Used to specify type of keyword.
112 typedef int keywordId
; /* to allow KEYWORD_NONE */
114 typedef enum eTokenType
{
170 typedef struct sTokenInfo
{
175 unsigned long lineNumber
;
177 keywordId accessKeyword
;
180 typedef struct sCommentState
{
186 typedef struct sBlockState
{
192 static const keywordTable TsKeywordTable
[] = {
193 /* keyword keyword ID */
194 { "as" , KEYWORD_as
},
195 { "async" , KEYWORD_async
},
196 { "await" , KEYWORD_await
},
197 { "class" , KEYWORD_class
},
198 { "const" , KEYWORD_const
},
199 { "constructor" , KEYWORD_constructor
},
200 { "enum" , KEYWORD_enum
},
201 { "extends" , KEYWORD_extends
},
202 { "for" , KEYWORD_for
},
203 { "function" , KEYWORD_function
},
204 { "in" , KEYWORD_in
},
205 { "interface" , KEYWORD_interface
},
206 { "implements" , KEYWORD_implements
},
207 { "let" , KEYWORD_let
},
208 { "namespace" , KEYWORD_namespace
},
209 { "new" , KEYWORD_new
},
210 { "of" , KEYWORD_of
},
211 { "private" , KEYWORD_private
},
212 { "protected" , KEYWORD_protected
},
213 { "public" , KEYWORD_public
},
214 { "static" , KEYWORD_static
},
215 { "this" , KEYWORD_this
},
216 { "type" , KEYWORD_type
},
217 { "typeof" , KEYWORD_typeof
},
218 { "var" , KEYWORD_var
},
219 { "while" , KEYWORD_while
}
222 static kindDefinition TsKinds
[] = {
223 { true, 'f', "function", "functions" },
224 { true, 'c', "class", "classes" },
225 { true, 'i', "interface", "interfaces" },
226 { true, 'g', "enum", "enums" },
227 { true, 'e', "enumerator", "enumerators (values inside an enumeration)" },
228 { true, 'm', "method", "methods" },
229 { true, 'n', "namespace", "namespaces" },
230 { false, 'z', "parameter", "function parameters inside function definitions" },
231 { true, 'p', "property", "properties" },
232 { true, 'v', "variable", "variables" },
233 { false, 'l', "local", "local variables" },
234 { true, 'C', "constant", "constants" },
235 { true, 'G', "generator", "generators" },
236 { true, 'a', "alias", "aliases", }
239 typedef enum eParserResult
{
241 PARSER_NEEDS_MORE_INPUT
,
243 } parserResultStatus
;
245 typedef struct sParserResult
{
246 parserResultStatus status
;
247 unsigned int unusedChars
;
250 typedef union uParserState
{
253 commentState comment
;
257 static struct sUwiStats tsUwiStats
;
259 typedef void (*Parser
)(const int c
, tokenInfo
*const, parserState
*state
, parserResult
*const);
261 static bool tryParser(Parser parser
, tokenInfo
*const token
, bool skipWhite
);
262 CTAGS_INLINE
void parseStringRegex(const int c
, tokenInfo
* const token
, parserState
*state
, parserResult
* const result
);
263 CTAGS_INLINE
void parseStringSQuote(const int c
, tokenInfo
* const token
, parserState
*state
, parserResult
* const result
);
264 CTAGS_INLINE
void parseStringDQuote(const int c
, tokenInfo
* const token
, parserState
*state
, parserResult
* const result
);
265 CTAGS_INLINE
void parseStringTemplate(const int c
, tokenInfo
* const token
, parserState
*state
, parserResult
* const result
);
267 static int emitTag(const tokenInfo
*const token
, const tsKind kind
)
269 if (! TsKinds
[kind
].enabled
) return CORK_NIL
;
271 static const char *const access
[3] = {
277 const char *name
= vStringValue (token
->string
);
280 initTagEntry (&e
, name
, kind
);
281 updateTagLine (&e
, token
->lineNumber
, token
->filePosition
);
282 e
.extensionFields
.scopeIndex
= token
->scope
;
284 switch (token
->accessKeyword
)
287 e
.extensionFields
.access
= access
[2];
289 case KEYWORD_protected
:
290 e
.extensionFields
.access
= access
[1];
292 case KEYWORD_private
:
293 e
.extensionFields
.access
= access
[0];
297 return makeTagEntry (&e
);
300 static void *newPoolToken (void *createArg CTAGS_ATTR_UNUSED
)
302 tokenInfo
*token
= xMalloc (1, tokenInfo
);
303 token
->scope
= CORK_NIL
;
304 token
->string
= NULL
;
309 static void clearPoolToken (void *data
)
311 tokenInfo
*token
= data
;
313 token
->type
= TOKEN_UNDEFINED
;
314 token
->keyword
= KEYWORD_NONE
;
315 token
->lineNumber
= uwiGetLineNumber ();
316 token
->filePosition
= uwiGetFilePosition ();
318 token
->scope
= CORK_NIL
;
320 token
->accessKeyword
= KEYWORD_NONE
;
322 token
->string
= vStringNewOrClear (token
->string
);
325 static void deletePoolToken (void *data
)
327 tokenInfo
*token
= data
;
328 vStringDelete (token
->string
); /* NULL is acceptable */
332 static void copyToken (tokenInfo
*const dest
, const tokenInfo
*const src
,
335 dest
->lineNumber
= src
->lineNumber
;
336 dest
->filePosition
= src
->filePosition
;
337 dest
->type
= src
->type
;
338 dest
->keyword
= src
->keyword
;
339 vStringCopy (dest
->string
, src
->string
);
340 if (scope
) dest
->scope
= src
->scope
;
343 static void initToken (tokenInfo
*const token
, tokenType type
)
346 token
->keyword
= KEYWORD_NONE
;
347 token
->lineNumber
= uwiGetLineNumber ();
348 token
->filePosition
= uwiGetFilePosition ();
351 CTAGS_INLINE
bool whiteChar(const int c
)
353 return c
== ' ' || c
== '\r' || c
== '\t';
356 CTAGS_INLINE
void parseWhiteChars(const int c
, tokenInfo
*const token
, parserState
*state
, parserResult
* const result
)
360 result
->status
= PARSER_NEEDS_MORE_INPUT
;
367 result
->status
= PARSER_FAILED
;
371 result
->status
= PARSER_FINISHED
;
372 result
->unusedChars
= 1;
375 CTAGS_INLINE
void parseOneChar(const int c
, tokenInfo
*const token
, const char expected
, const tokenType type
, parserResult
*const result
)
379 result
->status
= PARSER_FAILED
;
383 initToken (token
, type
);
384 result
->status
= PARSER_FINISHED
;
387 CTAGS_INLINE
void parseChar(const int c
, tokenInfo
*const token
, void *state
, parserResult
*const result
, const char *chars
, const tokenType
*types
)
389 const char *pos
= strchr (chars
, c
);
393 result
->status
= PARSER_FINISHED
;
394 initToken (token
, types
[pos
- chars
]);
398 result
->status
= PARSER_FAILED
;
401 CTAGS_INLINE
void parseWord(const int c
, tokenInfo
*const token
, const char *word
, int *parsed
, parserResult
*const result
)
403 if (word
[*parsed
] == '\0')
407 result
->status
= PARSER_FAILED
;
411 vStringCatS (token
->string
, word
);
412 initToken (token
, TOKEN_KEYWORD
);
413 token
->keyword
= lookupKeyword (vStringValue (token
->string
), Lang_ts
);
415 result
->unusedChars
= 1;
416 result
->status
= PARSER_FINISHED
;
420 if (c
== word
[*parsed
])
424 result
->status
= PARSER_NEEDS_MORE_INPUT
;
428 result
->status
= PARSER_FAILED
;
431 CTAGS_INLINE
void parseNumber(const int c
, tokenInfo
*const token
, int *parsed
, parserResult
*const result
)
437 result
->status
= PARSER_NEEDS_MORE_INPUT
;
445 result
->status
= PARSER_NEEDS_MORE_INPUT
;
449 else if (*parsed
== 0)
451 result
->status
= PARSER_FAILED
;
455 initToken (token
, TOKEN_NUMBER
);
457 result
->unusedChars
= 1;
458 result
->status
= PARSER_FINISHED
;
461 CTAGS_INLINE
void parseWordToken(const int c
, tokenInfo
*const token
, const char *word
, const tokenType type
, int *parsed
, parserResult
*const result
)
463 if (c
== word
[*parsed
])
467 if (word
[*parsed
] == '\0')
469 initToken (token
, type
);
470 result
->status
= PARSER_FINISHED
;
474 result
->status
= PARSER_NEEDS_MORE_INPUT
;
478 result
->status
= PARSER_FAILED
;
481 CTAGS_INLINE
void parseComment(const int c
, tokenInfo
*const token
, parserState
*state
, parserResult
*const result
)
483 if (state
->comment
.parsed
< 2)
485 parseWordToken (c
, token
, "//", TOKEN_COMMENT_BLOCK
, &state
->comment
.parsed
, result
);
487 if (result
->status
== PARSER_FAILED
)
489 parseWordToken (c
, token
, "/*", TOKEN_COMMENT_BLOCK
, &state
->comment
.parsed
, result
);
490 if (result
->status
== PARSER_FINISHED
)
492 result
->status
= PARSER_NEEDS_MORE_INPUT
;
493 state
->comment
.isBlock
= true;
496 else if (result
->status
== PARSER_FINISHED
)
498 result
->status
= PARSER_NEEDS_MORE_INPUT
;
499 state
->comment
.isBlock
= false;
505 state
->comment
.parsed
+= 1;
507 if (c
== EOF
) result
->status
= PARSER_FINISHED
;
508 else if (state
->comment
.isBlock
)
510 parseWordToken (c
, token
, "*/", TOKEN_COMMENT_BLOCK
, &state
->comment
.blockParsed
, result
);
512 if (result
->status
== PARSER_FAILED
)
514 state
->comment
.blockParsed
= c
== '*' ? 1 : 0;
515 result
->status
= PARSER_NEEDS_MORE_INPUT
;
520 result
->status
= PARSER_FINISHED
;
521 result
->unusedChars
= 1;
524 if (result
->status
== PARSER_FINISHED
)
526 initToken (token
, TOKEN_COMMENT_BLOCK
);
530 result
->status
= PARSER_NEEDS_MORE_INPUT
;
533 CTAGS_INLINE
void parseString(const int c
, tokenInfo
*const token
, const char quote
, char *prev
, parserResult
*const result
)
540 result
->status
= PARSER_NEEDS_MORE_INPUT
;
542 else result
->status
= PARSER_FAILED
;
548 result
->status
= PARSER_FAILED
;
553 if (c
== '\\' && *prev
== '\\')
556 result
->status
= PARSER_NEEDS_MORE_INPUT
;
560 else if (c
== quote
&& *prev
!= '\\')
562 result
->status
= PARSER_FINISHED
;
563 initToken (token
, TOKEN_STRING
);
567 else if (quote
== '/' && c
== '\n') // regex cannot contain new lines
569 result
->status
= PARSER_FAILED
;
575 result
->status
= PARSER_NEEDS_MORE_INPUT
;
579 CTAGS_INLINE
void parseBlock(const int c
, tokenInfo
*const token
, tokenType
const ttype
, const char start
, const char end
, blockState
*state
, parserResult
*const result
)
581 if (state
->parsed
== 0)
585 result
->status
= PARSER_FAILED
;
592 if (c
== '{') state
->curlyLevel
+= 1;
593 else if (c
== '}') state
->curlyLevel
-= 1;
595 if (c
== start
) state
->nestLevel
+= 1;
596 else if (c
== end
) state
->nestLevel
-= 1;
597 else if ((state
->curlyLevel
< 1 && c
== ';') || c
== EOF
)
599 result
->status
= PARSER_FAILED
;
603 if (state
->nestLevel
<= 0)
605 initToken (token
, ttype
);
606 result
->status
= PARSER_FINISHED
;
612 tryParser ((Parser
) parseComment
, token
, false);
614 tryParser ((Parser
) parseStringRegex
, token
, false);
615 tryParser ((Parser
) parseStringSQuote
, token
, false);
616 tryParser ((Parser
) parseStringDQuote
, token
, false);
617 tryParser ((Parser
) parseStringTemplate
, token
, false);
619 result
->status
= PARSER_NEEDS_MORE_INPUT
;
623 CTAGS_INLINE
void parseIdentifierCommon(const int c
, tokenInfo
*const token
, int *parsed
, parserResult
*const result
,
626 if (isIdentChar (c
) || (acceptFqName
&& c
== '.'))
628 vStringPut (token
->string
, c
);
629 *parsed
= *parsed
+ 1;
630 result
->status
= PARSER_NEEDS_MORE_INPUT
;
637 initToken (token
, TOKEN_IDENTIFIER
);
638 result
->status
= PARSER_FINISHED
;
639 result
->unusedChars
= 1;
643 result
->status
= PARSER_FAILED
;
646 CTAGS_INLINE
void parseIdentifier(const int c
, tokenInfo
*const token
, int *parsed
, parserResult
*const result
)
648 parseIdentifierCommon (c
, token
, parsed
, result
, false);
651 CTAGS_INLINE
void parseFQIdentifier(const int c
, tokenInfo
*const token
, int *parsed
, parserResult
*const result
)
653 parseIdentifierCommon (c
, token
, parsed
, result
, true);
656 PARSER_DEF (AsKeyword
, parseWord
, "as", num
)
657 PARSER_DEF (AsyncKeyword
, parseWord
, "async", num
)
658 PARSER_DEF (AwaitKeyword
, parseWord
, "await", num
)
659 PARSER_DEF (ClassKeyword
, parseWord
, "class", num
)
660 PARSER_DEF (ConstKeyword
, parseWord
, "const", num
)
661 PARSER_DEF (ConstructorKeyword
, parseWord
, "constructor", num
)
662 PARSER_DEF (EnumKeyword
, parseWord
, "enum", num
)
663 PARSER_DEF (ExtendsKeyword
, parseWord
, "extends", num
)
664 PARSER_DEF (ForKeyword
, parseWord
, "for", num
)
665 PARSER_DEF (FunctionKeyword
, parseWord
, "function", num
)
666 PARSER_DEF (InKeyword
, parseWord
, "in", num
)
667 PARSER_DEF (InterfaceKeyword
, parseWord
, "interface", num
)
668 PARSER_DEF (ImplementsKeyword
, parseWord
, "implements", num
)
669 PARSER_DEF (LetKeyword
, parseWord
, "let", num
)
670 PARSER_DEF (NamespaceKeyword
, parseWord
, "namespace", num
)
671 PARSER_DEF (NewKeyword
, parseWord
, "new", num
)
672 PARSER_DEF (OfKeyword
, parseWord
, "of", num
)
673 PARSER_DEF (PrivateKeyword
, parseWord
, "private", num
)
674 PARSER_DEF (ProtectedKeyword
, parseWord
, "protected", num
)
675 PARSER_DEF (PublicKeyword
, parseWord
, "public", num
)
676 PARSER_DEF (ReadonlyKeyword
, parseWord
, "readonly", num
)
677 PARSER_DEF (StaticKeyword
, parseWord
, "static", num
)
678 PARSER_DEF (ThisKeyword
, parseWord
, "this", num
)
679 PARSER_DEF (TypeKeyword
, parseWord
, "type", num
)
680 PARSER_DEF (TypeofKeyword
, parseWord
, "typeof", num
)
681 PARSER_DEF (VarKeyword
, parseWord
, "var", num
)
682 PARSER_DEF (WhileKeyword
, parseWord
, "while", num
)
684 SINGLE_CHAR_PARSER_DEF (Colon
, ':', TOKEN_COLON
)
685 SINGLE_CHAR_PARSER_DEF (Period
, '.', TOKEN_PERIOD
)
686 SINGLE_CHAR_PARSER_DEF (OpenCurly
, '{', TOKEN_OPEN_CURLY
)
687 SINGLE_CHAR_PARSER_DEF (Star
, '*', TOKEN_STAR
)
688 SINGLE_CHAR_PARSER_DEF (At
, '@', TOKEN_AT
)
689 SINGLE_CHAR_PARSER_DEF (NewLine
, '\n', TOKEN_NL
)
691 WORD_TOKEN_PARSER_DEF (Arrow
, "=>", TOKEN_ARROW
)
693 PARSER_DEF (StringSQuote
, parseString
, '\'', ch
)
694 PARSER_DEF (StringDQuote
, parseString
, '"', ch
)
695 PARSER_DEF (StringTemplate
, parseString
, '`', ch
)
696 PARSER_DEF (StringRegex
, parseString
, '/', ch
)
698 BLOCK_PARSER_DEF (Parens
, '(', ')', TOKEN_PARENS
)
699 BLOCK_PARSER_DEF (Squares
, '[', ']', TOKEN_SQUARES
)
700 BLOCK_PARSER_DEF (Template
, '<', '>', TOKEN_TEMPLATE
)
701 BLOCK_PARSER_DEF (Curlies
, '{', '}', TOKEN_CURLIES
)
703 CTAGS_INLINE
bool tryParser(Parser parser
, tokenInfo
*const token
, bool skipWhite
)
705 parserState currentState
;
709 result
.status
= PARSER_NEEDS_MORE_INPUT
;
710 result
.unusedChars
= 0;
711 memset(¤tState
, 0, sizeof (currentState
));
716 if (skipWhite
&& whiteChar (c
))
720 } while (whiteChar (c
));
722 parser (c
, token
, ¤tState
, &result
);
724 while (result
.status
== PARSER_NEEDS_MORE_INPUT
)
727 parser (c
, token
, ¤tState
, &result
);
730 if (result
.status
== PARSER_FAILED
) uwiPopMarker (-1, true);
731 else if (result
.unusedChars
> 0) uwiPopMarker (result
.unusedChars
, true);
732 else uwiDropMaker ();
734 return result
.status
== PARSER_FINISHED
;
737 static bool tryInSequence(tokenInfo
*const token
, bool skipUnparsed
, Parser parser
, ...)
739 Parser currentParser
= NULL
;
742 tryParser (parseWhiteChars
, token
, false);
745 va_start (args
, parser
);
747 currentParser
= parser
;
748 while (! result
&& currentParser
)
750 result
= tryParser (currentParser
, token
, false);
751 currentParser
= va_arg (args
, Parser
);
756 if (skipUnparsed
&& ! result
)
758 bool skippedNextWord
= false;
761 while (c
!= EOF
&& isIdentChar(c
))
764 skippedNextWord
= true;
767 if (c
!= EOF
&& skippedNextWord
) uwiUngetC (c
);
775 MULTI_CHAR_PARSER_DEF (DecoratorChars
, "@\n", TOKEN_AT
, TOKEN_NL
)
776 static void parseDecorator (tokenInfo
*const token
)
782 clearPoolToken (token
);
783 parsed
= tryInSequence (token
, false, parseDecoratorChars
, parseComment
, NULL
);
784 } while (parsed
&& token
->type
!= TOKEN_PARENS
);
788 clearPoolToken (token
);
790 parsed
= tryInSequence (token
, false, parseNewLine
, parseComment
, parseIdentifier
, NULL
);
791 } while (parsed
&& (token
->type
!= TOKEN_IDENTIFIER
|| tryParser ((Parser
) parsePeriod
, token
, true)));
793 //parse optional parens block
794 tryParser ((Parser
) parseParens
, token
, true);
797 MULTI_CHAR_PARSER_DEF (InterfaceBodyChars
, "}:;.,|&",
798 TOKEN_CLOSE_CURLY
, TOKEN_COLON
,
799 TOKEN_SEMICOLON
, TOKEN_PERIOD
, TOKEN_COMMA
,
800 TOKEN_PIPE
, TOKEN_AMPERSAND
)
801 static void parseInterfaceBody (const int scope
, tokenInfo
*const token
)
807 parsed
= tryInSequence (token
, true,
818 } while (parsed
&& ! isType (token
, TOKEN_OPEN_CURLY
));
820 if (! parsed
) return;
822 tokenInfo
*member
= NULL
;
823 bool parsingType
= false;
828 clearPoolToken (token
);
830 parsed
= tryInSequence (token
, true,
842 parseProtectedKeyword
,
844 parseReadonlyKeyword
,
848 parseInterfaceBodyChars
,
857 switch (token
->keyword
)
859 case KEYWORD_private
:
861 case KEYWORD_protected
:
864 emitTag (member
, TSTAG_PROPERTY
);
865 deleteToken (member
);
868 visibility
= token
->keyword
;
879 case TOKEN_AMPERSAND
:
883 case TOKEN_IDENTIFIER
:
886 emitTag (member
, TSTAG_PROPERTY
);
887 deleteToken (member
);
894 member
= newToken ();
895 copyToken (member
, token
, false);
896 member
->scope
= scope
;
897 if (visibility
) member
->accessKeyword
= visibility
;
898 else member
->accessKeyword
= KEYWORD_public
;
903 if (!parsingType
&& member
)
905 emitTag (member
, TSTAG_METHOD
);
906 deleteToken (member
);
913 case TOKEN_SEMICOLON
:
923 } while (parsed
&& ! isType (token
, TOKEN_CLOSE_CURLY
));
927 emitTag (member
, TSTAG_PROPERTY
);
928 deleteToken (member
);
932 static void parseInterface (const int scope
, tokenInfo
*const token
)
938 clearPoolToken (token
);
939 parsed
= tryInSequence (token
, false,
944 } while (parsed
&& token
->type
!= TOKEN_IDENTIFIER
);
946 if (! parsed
) return;
948 token
->scope
= scope
;
950 const int nscope
= emitTag (token
, TSTAG_INTERFACE
);
952 parseInterfaceBody (nscope
, token
);
955 MULTI_CHAR_PARSER_DEF (TypeChars
, ":;,=|&",
956 TOKEN_COLON
, TOKEN_SEMICOLON
, TOKEN_COMMA
,
957 TOKEN_EQUAL_SIGN
, TOKEN_PIPE
, TOKEN_AMPERSAND
)
958 static void parseType (const int scope
, tokenInfo
*const token
)
961 bool parsingType
= false;
962 bool shouldEnd
= false;
966 clearPoolToken (token
);
967 parsed
= tryInSequence (token
, false,
988 switch (token
->keyword
)
1006 parsingType
= false;
1008 case TOKEN_EQUAL_SIGN
:
1010 case TOKEN_AMPERSAND
:
1014 case TOKEN_IDENTIFIER
:
1015 if (! parsingType
&& ! shouldEnd
)
1017 token
->scope
= scope
;
1018 emitTag (token
, TSTAG_ALIAS
);
1020 else if (! parsingType
&& shouldEnd
)
1022 for (int i
= vStringLength(token
->string
); i
>= 0; i
--)
1023 uwiUngetC (vStringChar(token
->string
, i
));
1027 parsingType
= false;
1033 } while (parsed
&& ! isType (token
, TOKEN_COMMA
) && ! isType (token
, TOKEN_SEMICOLON
));
1035 clearPoolToken(token
);
1038 MULTI_CHAR_PARSER_DEF (EnumBodyChars
, "},=|&.",
1039 TOKEN_CLOSE_CURLY
, TOKEN_COMMA
, TOKEN_EQUAL_SIGN
,
1040 TOKEN_PIPE
, TOKEN_AMPERSAND
, TOKEN_PERIOD
)
1041 static void parseEnumBody (const int scope
, tokenInfo
*const token
)
1047 parsed
= tryInSequence (token
, true,
1052 parseStringTemplate
,
1058 } while (parsed
&& token
->type
!= TOKEN_OPEN_CURLY
);
1060 if (! parsed
) return;
1062 tokenInfo
*member
= NULL
;
1063 bool parsingValue
= false;
1066 clearPoolToken (token
);
1067 parsed
= tryInSequence (token
, true,
1072 parseStringTemplate
,
1085 switch (token
->type
)
1088 switch (token
->keyword
)
1091 parsingValue
= true;
1095 case TOKEN_EQUAL_SIGN
:
1097 case TOKEN_AMPERSAND
:
1099 parsingValue
= true;
1102 case TOKEN_SEMICOLON
:
1108 parsingValue
= false;
1110 case TOKEN_IDENTIFIER
:
1113 member
= newToken ();
1114 copyToken (member
, token
, false);
1115 member
->scope
= scope
;
1116 emitTag (member
, TSTAG_ENUMERATOR
);
1117 deleteToken (member
);
1120 parsingValue
= false;
1126 } while (parsed
&& ! isType (token
, TOKEN_CLOSE_CURLY
));
1130 deleteToken (member
);
1134 static void parseEnum (const int scope
, tokenInfo
*const token
)
1140 clearPoolToken (token
);
1141 parsed
= tryInSequence (token
, false,
1145 } while (parsed
&& token
->type
!= TOKEN_IDENTIFIER
);
1147 if (! parsed
) return;
1149 token
->scope
= scope
;
1150 const int nscope
= emitTag (token
, TSTAG_ENUM
);
1152 parseEnumBody (nscope
, token
);
1155 MULTI_CHAR_PARSER_DEF (VariableChars
, "|&=?[]{}()\n:;,.-+/^<>*",
1156 TOKEN_PIPE
, TOKEN_AMPERSAND
, TOKEN_EQUAL_SIGN
, TOKEN_QUESTION_MARK
,
1157 TOKEN_OPEN_SQUARE
, TOKEN_CLOSE_SQUARE
, TOKEN_OPEN_CURLY
, TOKEN_CLOSE_CURLY
,
1158 TOKEN_OPEN_PAREN
, TOKEN_CLOSE_PAREN
, TOKEN_NL
, TOKEN_COLON
, TOKEN_SEMICOLON
,
1159 TOKEN_COMMA
, TOKEN_PERIOD
, TOKEN_MINUS
, TOKEN_PLUS
,
1160 TOKEN_DIV
, TOKEN_POWER
, TOKEN_LOWER
, TOKEN_GREATER
, TOKEN_STAR
)
1161 static void parseVariable (bool constVar
, bool localVar
, const int scope
, tokenInfo
*const token
)
1163 tokenInfo
*member
= NULL
;
1164 bool parsed
= false;
1165 bool parsingType
= false;
1166 bool expectingVariable
= false;
1167 bool mayBeFun
= false;
1168 bool isFunction
= false;
1169 int nestLevel
= 0, parenLevel
= 0;
1170 tsKind varKind
= constVar
? TSTAG_CONSTANT
: (localVar
? TSTAG_LOCAL
: TSTAG_VARIABLE
);
1174 clearPoolToken (token
);
1175 parsed
= tryInSequence (token
, false,
1181 parseStringTemplate
,
1187 parseFunctionKeyword
,
1201 switch (token
->type
)
1203 case TOKEN_OPEN_SQUARE
:
1204 case TOKEN_OPEN_CURLY
:
1207 case TOKEN_OPEN_PAREN
:
1210 if (mayBeFun
) isFunction
= true;
1212 case TOKEN_CLOSE_SQUARE
:
1215 case TOKEN_CLOSE_PAREN
:
1219 case TOKEN_CLOSE_CURLY
:
1221 if (nestLevel
<= 0) isFunction
= false;
1224 expectingVariable
= true;
1225 case TOKEN_SEMICOLON
:
1230 parsingType
= false;
1243 case TOKEN_AMPERSAND
:
1245 case TOKEN_EQUAL_SIGN
:
1251 case TOKEN_IDENTIFIER
:
1252 if (parenLevel
<= 0 && ! isFunction
&& ! parsingType
)
1254 member
= newToken ();
1255 copyToken (member
, token
, false);
1256 member
->scope
= scope
;
1257 emitTag (member
, varKind
);
1258 deleteToken (member
);
1260 expectingVariable
= false;
1261 parsingType
= false;
1264 switch (token
->keyword
)
1267 parseEnum (scope
, token
);
1274 case KEYWORD_typeof
:
1280 if (nestLevel
<= 0) parsingType
= false;
1281 if (token
->type
!= TOKEN_NL
) expectingVariable
= false;
1285 if (isType (token
, TOKEN_EQUAL_SIGN
) || isKeyword (token
, KEYWORD_function
)) mayBeFun
= true;
1286 else if (! isType(token
, TOKEN_COMMENT_BLOCK
) && nestLevel
<= 0) mayBeFun
= false;
1289 ! ((token
->type
== TOKEN_SEMICOLON
1290 || (token
->type
== TOKEN_CLOSE_PAREN
&& ! isFunction
)
1291 || (token
->type
== TOKEN_NL
&& ! expectingVariable
))
1292 && ! parsingType
&& nestLevel
<= 0));
1294 clearPoolToken (token
);
1297 MULTI_CHAR_PARSER_DEF (FunctionArgsChars
, "\n(", TOKEN_NL
, TOKEN_OPEN_PAREN
)
1298 MULTI_CHAR_PARSER_DEF (FunctionArgsAfterParenChars
, "|&=?[]{})\n:,.@",
1299 TOKEN_PIPE
, TOKEN_AMPERSAND
, TOKEN_EQUAL_SIGN
, TOKEN_QUESTION_MARK
,
1300 TOKEN_OPEN_SQUARE
, TOKEN_CLOSE_SQUARE
, TOKEN_OPEN_CURLY
, TOKEN_CLOSE_CURLY
,
1301 TOKEN_CLOSE_PAREN
, TOKEN_NL
, TOKEN_COLON
, TOKEN_COMMA
, TOKEN_PERIOD
, TOKEN_AT
)
1302 static void parseFunctionArgs (const int scope
, tokenInfo
*const token
)
1304 bool parsed
= false;
1305 bool parsingType
= false;
1307 tokenInfo
*member
= NULL
;
1311 clearPoolToken (token
);
1312 parsed
= tryInSequence (token
, false,
1315 parseFunctionArgsChars
,
1317 } while (parsed
&& token
->type
!= TOKEN_OPEN_PAREN
);
1319 if (! parsed
) return;
1323 clearPoolToken (token
);
1324 parsed
= tryInSequence (token
, false,
1329 parseStringTemplate
,
1333 parseFunctionArgsAfterParenChars
,
1340 switch (token
->type
)
1344 parseDecorator (token
);
1346 case TOKEN_OPEN_SQUARE
:
1347 case TOKEN_OPEN_CURLY
:
1348 if (parsingType
) nestLevel
+= 1;
1350 case TOKEN_CLOSE_SQUARE
:
1351 case TOKEN_CLOSE_CURLY
:
1352 if (parsingType
) nestLevel
-= 1;
1357 parsingType
= false;
1362 case TOKEN_EQUAL_SIGN
:
1365 case TOKEN_IDENTIFIER
:
1368 member
= newToken ();
1369 copyToken (member
, token
, false);
1370 member
->scope
= scope
;
1371 emitTag (member
, TSTAG_PARAMETER
);
1372 deleteToken (member
);
1379 } while (parsed
&& token
->type
!= TOKEN_CLOSE_PAREN
);
1382 MULTI_CHAR_PARSER_DEF (FunctionBodyChars
, "{}", TOKEN_OPEN_CURLY
, TOKEN_CLOSE_CURLY
)
1383 static void parseFunctionBody (const int scope
, tokenInfo
*const token
)
1385 bool parsed
= false;
1390 clearPoolToken (token
);
1392 parsed
= tryInSequence (token
, true,
1397 parseStringTemplate
,
1402 } while (parsed
&& ! isType (token
, TOKEN_OPEN_CURLY
));
1404 if (! parsed
) return;
1408 clearPoolToken (token
);
1410 parsed
= tryInSequence (token
, true,
1411 parseFunctionBodyChars
,
1415 parseStringTemplate
,
1425 switch (token
->type
)
1427 case TOKEN_OPEN_CURLY
:
1430 case TOKEN_CLOSE_CURLY
:
1434 switch (token
->keyword
)
1438 parseVariable (false, true, scope
, token
);
1441 parseVariable (true, true, scope
, token
);
1449 } while (parsed
&& ! (isType (token
, TOKEN_CLOSE_CURLY
) && nestLevel
<= 0));
1451 clearPoolToken (token
);
1454 static void parseFunction (const int scope
, tokenInfo
*const token
)
1456 bool isGenerator
= false;
1461 clearPoolToken (token
);
1462 parsed
= tryInSequence (token
, false,
1468 if (parsed
&& isType (token
, TOKEN_STAR
)) isGenerator
= true;
1469 } while (parsed
&& token
->type
!= TOKEN_IDENTIFIER
);
1471 if (! parsed
) return;
1473 token
->scope
= scope
;
1475 const int nscope
= emitTag (token
, isGenerator
? TSTAG_GENERATOR
: TSTAG_FUNCTION
);
1477 parseFunctionArgs (nscope
, token
);
1478 parseFunctionBody (nscope
, token
);
1481 MULTI_CHAR_PARSER_DEF (PropertyTypeChars
, "\n;|&,)",
1482 TOKEN_NL
, TOKEN_SEMICOLON
, TOKEN_PIPE
, TOKEN_AMPERSAND
,
1483 TOKEN_COMMA
, TOKEN_CLOSE_PAREN
)
1484 static void parsePropertyType (tokenInfo
*const token
)
1486 bool parsed
= tryParser ((Parser
) parseColon
, token
, true);
1487 bool parsedIdentifier
= false;
1488 bool parseReturnValue
= false;
1490 if (! parsed
) return;
1494 clearPoolToken (token
);
1496 if (parsedIdentifier
)
1498 parsed
= tryInSequence (token
, false,
1499 parsePropertyTypeChars
,
1506 parseStringTemplate
,
1512 if (isType (token
, TOKEN_PIPE
) || isType (token
, TOKEN_AMPERSAND
)) parsedIdentifier
= false;
1516 parsed
= tryInSequence (token
, false,
1517 parsePropertyTypeChars
,
1524 parseStringTemplate
,
1531 if (isType (token
, TOKEN_IDENTIFIER
)) parsedIdentifier
= true;
1535 if (isType (token
, TOKEN_ARROW
)) parseReturnValue
= true;
1537 && ! isType (token
, TOKEN_CLOSE_PAREN
)
1538 && ! isType (token
, TOKEN_SEMICOLON
)
1539 && ! isType (token
, TOKEN_COMMA
)
1540 && ! (parseReturnValue
&& (
1541 isType (token
, TOKEN_PARENS
)
1542 || isType (token
, TOKEN_CURLIES
)
1543 || isType (token
, TOKEN_SQUARES
))));
1545 if (! parsed
) return;
1547 if (isType (token
, TOKEN_CLOSE_PAREN
)) uwiUngetC (')');
1549 clearPoolToken (token
);
1552 MULTI_CHAR_PARSER_DEF (ConstructorParamsChars
, "\n(", TOKEN_NL
, TOKEN_OPEN_PAREN
)
1553 MULTI_CHAR_PARSER_DEF (ConstructorParamsAfterParenChars
, "\n:,)@",
1554 TOKEN_NL
, TOKEN_COLON
, TOKEN_COMMA
, TOKEN_CLOSE_PAREN
, TOKEN_AT
)
1555 static void parseConstructorParams (const int classScope
, const int constrScope
, tokenInfo
*const token
)
1557 bool parsed
= false;
1561 clearPoolToken (token
);
1563 parsed
= tryInSequence (token
, false,
1564 parseConstructorParamsChars
,
1567 } while (parsed
&& ! isType (token
, TOKEN_OPEN_PAREN
));
1569 if (! parsed
) return;
1571 tokenInfo
*member
= NULL
;
1576 clearPoolToken (token
);
1578 parsed
= tryInSequence (token
, false,
1579 parseConstructorParamsAfterParenChars
,
1581 parsePrivateKeyword
,
1582 parseProtectedKeyword
,
1584 parseReadonlyKeyword
,
1591 switch (token
->type
)
1595 parseDecorator (token
);
1598 switch (token
->keyword
)
1600 case KEYWORD_private
:
1601 case KEYWORD_public
:
1602 case KEYWORD_protected
:
1603 visibility
= token
->keyword
;
1609 parsePropertyType (token
);
1611 case TOKEN_IDENTIFIER
:
1612 member
= newToken ();
1613 copyToken (member
, token
, false);
1616 member
->accessKeyword
= visibility
;
1617 member
->scope
= classScope
;
1618 emitTag (member
, TSTAG_PROPERTY
);
1622 member
->scope
= constrScope
;
1623 emitTag (member
, TSTAG_PARAMETER
);
1625 deleteToken (member
);
1633 } while (parsed
&& ! isType (token
, TOKEN_CLOSE_PAREN
));
1637 MULTI_CHAR_PARSER_DEF (ClassBodyChars
, "\n,{", TOKEN_NL
, TOKEN_COMMA
, TOKEN_OPEN_CURLY
)
1638 MULTI_CHAR_PARSER_DEF (ClassBodyAfterCurlyChars
, "\n}*@(:;=-+/^<>.,|&",
1639 TOKEN_NL
, TOKEN_CLOSE_CURLY
, TOKEN_STAR
, TOKEN_AT
, TOKEN_OPEN_PAREN
,
1640 TOKEN_COLON
, TOKEN_SEMICOLON
, TOKEN_EQUAL_SIGN
,
1641 TOKEN_MINUS
, TOKEN_PLUS
, TOKEN_DIV
, TOKEN_POWER
,
1642 TOKEN_GREATER
, TOKEN_LOWER
, TOKEN_PERIOD
, TOKEN_COMMA
,
1643 TOKEN_PIPE
, TOKEN_AMPERSAND
)
1644 static void parseClassBody (const int scope
, tokenInfo
*const token
)
1646 bool parsed
= false;
1647 vString
*inheritance
= NULL
;
1652 clearPoolToken (token
);
1654 parsed
= tryInSequence (token
, false,
1655 parseClassBodyChars
,
1658 parseExtendsKeyword
,
1659 parseImplementsKeyword
,
1663 if (token
->type
== TOKEN_KEYWORD
1664 && (token
->keyword
== KEYWORD_extends
|| token
->keyword
== KEYWORD_implements
)
1665 && inheritance
== NULL
) inheritance
= vStringNew ();
1666 else if (inheritance
&& token
->type
== TOKEN_IDENTIFIER
) vStringJoin (inheritance
, ',', token
->string
);
1667 } while (parsed
&& token
->type
!= TOKEN_OPEN_CURLY
);
1671 vStringDelete (inheritance
); /* NULL is acceptable. */
1677 tagEntryInfo
*klass
= getEntryInCorkQueue (scope
);
1680 klass
->extensionFields
.inheritance
= vStringDeleteUnwrap (inheritance
);
1683 vStringDelete (inheritance
);
1686 tokenInfo
*member
= NULL
;
1687 bool isGenerator
= false;
1688 bool parsingValue
= false;
1693 clearPoolToken (token
);
1695 parsed
= tryInSequence (token
, false,
1699 parseStringTemplate
,
1702 parseConstructorKeyword
,
1704 parsePrivateKeyword
,
1705 parseProtectedKeyword
,
1707 parseReadonlyKeyword
,
1712 parseClassBodyAfterCurlyChars
,
1720 switch (token
->type
)
1724 parseDecorator (token
);
1727 switch (token
->keyword
)
1729 case KEYWORD_constructor
:
1732 emitTag (member
, TSTAG_PROPERTY
);
1733 deleteToken (member
);
1735 isGenerator
= false;
1737 member
= newToken ();
1738 copyToken (member
, token
, false);
1739 member
->scope
= scope
;
1741 if (visibility
) member
->accessKeyword
= visibility
;
1742 else member
->accessKeyword
= KEYWORD_public
;
1744 const int nscope
= emitTag (member
, TSTAG_METHOD
);
1745 deleteToken (member
);
1749 parseConstructorParams (scope
, nscope
, token
);
1751 parseFunctionBody (nscope
, token
);
1752 parsingValue
= false;
1754 case KEYWORD_private
:
1755 case KEYWORD_public
:
1756 case KEYWORD_protected
:
1759 emitTag (member
, TSTAG_PROPERTY
);
1760 deleteToken (member
);
1763 visibility
= token
->keyword
;
1764 parsingValue
= false;
1767 case KEYWORD_typeof
:
1768 parsingValue
= true;
1771 isGenerator
= false;
1773 case TOKEN_EQUAL_SIGN
:
1776 emitTag (member
, TSTAG_PROPERTY
);
1777 deleteToken (member
);
1779 isGenerator
= false;
1781 parsingValue
= true;
1785 parsePropertyType (token
);
1786 case TOKEN_SEMICOLON
:
1789 emitTag (member
, TSTAG_PROPERTY
);
1790 deleteToken (member
);
1792 isGenerator
= false;
1795 parsingValue
= false;
1807 case TOKEN_AMPERSAND
:
1808 parsingValue
= true;
1815 parsingValue
= false;
1817 case TOKEN_OPEN_PAREN
:
1820 parsed
= tryParser (parseParens
, token
, false);
1824 const int nscope
= emitTag (member
, isGenerator
? TSTAG_GENERATOR
: TSTAG_METHOD
);
1826 deleteToken (member
);
1829 parseFunctionArgs (nscope
, token
);
1830 parseFunctionBody (nscope
, token
);
1832 isGenerator
= false;
1834 parsingValue
= false;
1836 case TOKEN_IDENTIFIER
:
1837 if (!parsingValue
) {
1838 if (member
) deleteToken (member
);
1839 member
= newToken ();
1840 copyToken (member
, token
, false);
1841 member
->scope
= scope
;
1842 if (visibility
) member
->accessKeyword
= visibility
;
1843 else member
->accessKeyword
= KEYWORD_public
;
1846 parsingValue
= false;
1847 isGenerator
= false;
1850 isGenerator
= false;
1855 } while (parsed
&& token
->type
!= TOKEN_CLOSE_CURLY
);
1857 if (parsed
&& member
)
1859 emitTag (member
, TSTAG_PROPERTY
);
1860 deleteToken (member
);
1862 else if (member
) deleteToken (member
);
1865 static void parseClass (const int scope
, tokenInfo
*const token
)
1867 bool parsed
= false;
1871 clearPoolToken (token
);
1873 parsed
= tryInSequence (token
, false,
1878 } while (parsed
&& token
->type
!= TOKEN_IDENTIFIER
);
1880 if (! parsed
) return;
1882 token
->scope
= scope
;
1883 const int nscope
= emitTag (token
, TSTAG_CLASS
);
1885 parseClassBody (nscope
, token
);
1888 MULTI_CHAR_PARSER_DEF (NamespaceBodyChars
, "\n{", TOKEN_NL
, TOKEN_OPEN_CURLY
)
1889 MULTI_CHAR_PARSER_DEF (NamespaceBodyAfterCurlyChars
, "@{}()[]",
1890 TOKEN_AT
, TOKEN_OPEN_CURLY
, TOKEN_CLOSE_CURLY
, TOKEN_OPEN_PAREN
,
1891 TOKEN_CLOSE_PAREN
, TOKEN_OPEN_SQUARE
, TOKEN_CLOSE_SQUARE
)
1892 static void parseNamespaceBody (const int scope
, tokenInfo
*const token
)
1894 bool parsed
= false;
1899 parsed
= tryInSequence (token
, false,
1900 parseNamespaceBodyChars
,
1903 } while (parsed
&& token
->type
!= TOKEN_OPEN_CURLY
);
1905 if (! parsed
) return;
1913 clearPoolToken (token
);
1915 parsed
= tryInSequence (token
, true,
1920 parseStringTemplate
,
1922 parseInterfaceKeyword
,
1925 parseFunctionKeyword
,
1930 parseNamespaceBodyAfterCurlyChars
,
1933 switch (token
->type
)
1936 switch (token
->keyword
)
1938 case KEYWORD_interface
:
1939 parseInterface (scope
, token
);
1942 parseType (scope
, token
);
1945 parseEnum (scope
, token
);
1947 case KEYWORD_function
:
1948 parseFunction (scope
, token
);
1951 parseClass (scope
, token
);
1955 parseVariable (false, false, scope
, token
);
1958 parseVariable (true, false, scope
, token
);
1964 parseDecorator (token
);
1966 case TOKEN_OPEN_CURLY
:
1969 case TOKEN_OPEN_SQUARE
:
1972 case TOKEN_OPEN_PAREN
:
1975 case TOKEN_CLOSE_CURLY
:
1978 case TOKEN_CLOSE_SQUARE
:
1981 case TOKEN_CLOSE_PAREN
:
1987 } while (parsed
&& ! (isType (token
, TOKEN_CLOSE_CURLY
) && parenLvl
<= 0 && squareLvl
<= 0 && curlyLvl
<= 0));
1990 static void parseNamespace (tokenInfo
*const token
)
1992 bool parsed
= false;
1996 clearPoolToken (token
);
1998 parsed
= tryInSequence (token
, false,
2003 } while (parsed
&& token
->type
!= TOKEN_IDENTIFIER
);
2005 if (! parsed
) return;
2007 const int scope
= emitTag (token
, TSTAG_NAMESPACE
);
2009 parseNamespaceBody (scope
, token
);
2012 static void parseTsFile (tokenInfo
*const token
)
2018 clearPoolToken (token
);
2020 parsed
= tryInSequence (token
, true,
2025 parseStringTemplate
,
2027 parseInterfaceKeyword
,
2030 parseFunctionKeyword
,
2032 parseNamespaceKeyword
,
2039 switch (token
->type
)
2042 switch (token
->keyword
)
2044 case KEYWORD_interface
:
2045 parseInterface (CORK_NIL
, token
);
2048 parseType (CORK_NIL
, token
);
2051 parseEnum (CORK_NIL
, token
);
2053 case KEYWORD_function
:
2054 parseFunction (CORK_NIL
, token
);
2057 parseClass (CORK_NIL
, token
);
2059 case KEYWORD_namespace
:
2060 parseNamespace (token
);
2064 parseVariable (false, false, CORK_NIL
, token
);
2067 parseVariable (true, false, CORK_NIL
, token
);
2073 parseDecorator (token
);
2081 static void findTsTags (void)
2085 tokenInfo
*const token
= newToken ();
2087 parseTsFile (token
);
2089 deleteToken (token
);
2091 uwiDeactivate (&tsUwiStats
);
2094 static void initialize (const langType language
)
2098 TokenPool
= objPoolNew (16, newPoolToken
, deletePoolToken
, clearPoolToken
, NULL
);
2101 static void finalize (langType language CTAGS_ATTR_UNUSED
, bool initialized
)
2103 if (! initialized
) return;
2105 objPoolDelete (TokenPool
);
2108 static void initStats (langType language CTAGS_ATTR_UNUSED
)
2110 uwiStatsInit (&tsUwiStats
);
2112 static void printStats (langType language CTAGS_ATTR_UNUSED
)
2114 uwiStatsPrint (&tsUwiStats
);
2117 /* Create parser definition structure */
2118 extern parserDefinition
*TypeScriptParser (void)
2120 static const char *const extensions
[] = { "ts", NULL
};
2121 parserDefinition
*const def
= parserNew ("TypeScript");
2122 def
->extensions
= extensions
;
2123 def
->kindTable
= TsKinds
;
2124 def
->kindCount
= ARRAY_SIZE (TsKinds
);
2125 def
->parser
= findTsTags
;
2126 def
->initialize
= initialize
;
2127 def
->finalize
= finalize
;
2128 def
->keywordTable
= TsKeywordTable
;
2129 def
->keywordCount
= ARRAY_SIZE (TsKeywordTable
);
2130 def
->useCork
= CORK_QUEUE
;
2131 def
->requestAutomaticFQTag
= true;
2133 def
->initStats
= initStats
;
2134 def
->printStats
= printStats
;