Determine anonymous tags based on name only when necessary
[geany-mirror.git] / src / tagmanager / tm_parser.c
blobe4c91fc66e3c81047cd014aeb1056128c4f777d2
1 /*
2 * tm_parser.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2016 The Geany contributors
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "tm_parser.h"
22 #include "tm_ctags.h"
24 #include <string.h>
27 typedef struct
29 const gchar kind;
30 TMTagType type;
31 } TMParserMapEntry;
33 /* Allows remapping a subparser tag type to another type if there's a clash with
34 * the master parser tag type. Only subparser tag types explicitly listed within
35 * TMSubparserMapEntry maps are added to tag manager - tags with types not listed
36 * are discarded to prevent uncontrolled merging of tags from master parser and
37 * subparsers. */
38 typedef struct
40 TMTagType orig_type;
41 TMTagType new_type;
42 } TMSubparserMapEntry;
45 static GHashTable *subparser_map = NULL;
47 #define COMMON_C \
48 {'d', tm_tag_macro_t}, \
49 {'e', tm_tag_enumerator_t}, \
50 {'f', tm_tag_function_t}, \
51 {'g', tm_tag_enum_t}, \
52 {'m', tm_tag_member_t}, \
53 {'p', tm_tag_prototype_t}, \
54 {'s', tm_tag_struct_t}, \
55 {'t', tm_tag_typedef_t}, \
56 {'u', tm_tag_union_t}, \
57 {'v', tm_tag_variable_t}, \
58 {'x', tm_tag_externvar_t},
60 /* Old C parser, also used by GLSL and Ferite */
61 static TMParserMapEntry map_C_old_parser[] = {
62 COMMON_C
63 {'c', tm_tag_class_t},
64 {'n', tm_tag_namespace_t},
67 # define COMMON_C_NEW_PARSER \
68 {'h', tm_tag_undef_t}, \
69 {'l', tm_tag_undef_t}, \
70 {'z', tm_tag_undef_t}, \
71 {'L', tm_tag_undef_t}, \
72 {'D', tm_tag_undef_t},
74 static TMParserMapEntry map_C[] = {
75 COMMON_C
76 COMMON_C_NEW_PARSER
79 static TMParserMapEntry map_CPP[] = {
80 COMMON_C
81 COMMON_C_NEW_PARSER
83 {'c', tm_tag_class_t},
84 {'n', tm_tag_namespace_t},
85 {'A', tm_tag_undef_t},
86 {'N', tm_tag_undef_t},
87 {'U', tm_tag_undef_t},
88 {'Z', tm_tag_undef_t},
91 static TMParserMapEntry map_JAVA[] = {
92 {'c', tm_tag_class_t},
93 {'f', tm_tag_field_t},
94 {'i', tm_tag_interface_t},
95 {'m', tm_tag_method_t},
96 {'p', tm_tag_package_t},
97 {'e', tm_tag_enumerator_t},
98 {'g', tm_tag_enum_t},
101 static TMParserMapEntry map_MAKEFILE[] = {
102 {'m', tm_tag_macro_t},
103 {'t', tm_tag_function_t},
104 {'I', tm_tag_undef_t},
107 static TMParserMapEntry map_PASCAL[] = {
108 {'f', tm_tag_function_t},
109 {'p', tm_tag_function_t},
112 static TMParserMapEntry map_PERL[] = {
113 {'c', tm_tag_enum_t},
114 {'f', tm_tag_other_t},
115 {'l', tm_tag_macro_t},
116 {'p', tm_tag_package_t},
117 {'s', tm_tag_function_t},
118 {'d', tm_tag_prototype_t},
119 {'M', tm_tag_undef_t},
122 static TMParserMapEntry map_PHP[] = {
123 {'c', tm_tag_class_t},
124 {'d', tm_tag_macro_t},
125 {'f', tm_tag_function_t},
126 {'i', tm_tag_interface_t},
127 {'l', tm_tag_undef_t},
128 {'n', tm_tag_namespace_t},
129 {'t', tm_tag_struct_t},
130 {'v', tm_tag_variable_t},
131 {'a', tm_tag_undef_t},
134 static TMParserMapEntry map_PYTHON[] = {
135 {'c', tm_tag_class_t},
136 {'f', tm_tag_function_t},
137 {'m', tm_tag_method_t},
138 {'v', tm_tag_variable_t},
139 /* defined as externvar to get those excluded as forward type in symbols.c:goto_tag()
140 * so we can jump to the real implementation (if known) instead of to the import statement */
141 {'x', tm_tag_externvar_t},
144 /* different parser than tex.c from universal-ctags */
145 static TMParserMapEntry map_LATEX[] = {
146 {'f', tm_tag_function_t},
147 {'c', tm_tag_class_t},
148 {'m', tm_tag_member_t},
149 {'d', tm_tag_macro_t},
150 {'v', tm_tag_variable_t},
151 {'n', tm_tag_namespace_t},
152 {'s', tm_tag_struct_t},
154 static TMParserMapEntry map_BIBTEX[] = {
155 {'a', tm_tag_function_t},
156 {'b', tm_tag_class_t},
157 {'B', tm_tag_class_t},
158 {'c', tm_tag_member_t},
159 {'i', tm_tag_macro_t},
160 {'I', tm_tag_macro_t},
161 {'j', tm_tag_member_t},
162 {'m', tm_tag_other_t},
163 {'M', tm_tag_variable_t},
164 {'n', tm_tag_other_t},
165 {'p', tm_tag_variable_t},
166 {'P', tm_tag_class_t},
167 {'s', tm_tag_namespace_t},
168 {'t', tm_tag_other_t},
169 {'u', tm_tag_externvar_t},
172 static TMParserMapEntry map_ASM[] = {
173 {'d', tm_tag_macro_t},
174 {'l', tm_tag_namespace_t},
175 {'m', tm_tag_function_t},
176 {'t', tm_tag_struct_t},
179 /* not in universal-ctags */
180 static TMParserMapEntry map_CONF[] = {
181 {'s', tm_tag_namespace_t},
182 {'k', tm_tag_macro_t},
185 static TMParserMapEntry map_SQL[] = {
186 {'c', tm_tag_undef_t},
187 {'d', tm_tag_prototype_t},
188 {'f', tm_tag_function_t},
189 {'E', tm_tag_field_t},
190 {'l', tm_tag_undef_t},
191 {'L', tm_tag_undef_t},
192 {'P', tm_tag_package_t},
193 {'p', tm_tag_namespace_t},
194 {'r', tm_tag_undef_t},
195 {'s', tm_tag_undef_t},
196 {'t', tm_tag_class_t},
197 {'T', tm_tag_macro_t},
198 {'v', tm_tag_variable_t},
199 {'i', tm_tag_struct_t},
200 {'e', tm_tag_undef_t},
201 {'U', tm_tag_undef_t},
202 {'R', tm_tag_undef_t},
203 {'D', tm_tag_undef_t},
204 {'V', tm_tag_member_t},
205 {'n', tm_tag_undef_t},
206 {'x', tm_tag_undef_t},
207 {'y', tm_tag_undef_t},
208 {'z', tm_tag_undef_t},
209 {'C', tm_tag_undef_t},
212 /* not in universal-ctags */
213 static TMParserMapEntry map_DOCBOOK[] = {
214 {'f', tm_tag_function_t},
215 {'c', tm_tag_class_t},
216 {'m', tm_tag_member_t},
217 {'d', tm_tag_macro_t},
218 {'v', tm_tag_variable_t},
219 {'s', tm_tag_struct_t},
222 static TMParserMapEntry map_ERLANG[] = {
223 {'d', tm_tag_macro_t},
224 {'f', tm_tag_function_t},
225 {'m', tm_tag_undef_t},
226 {'r', tm_tag_struct_t},
227 {'t', tm_tag_typedef_t},
230 static TMParserMapEntry map_CSS[] = {
231 {'c', tm_tag_class_t},
232 {'s', tm_tag_struct_t},
233 {'i', tm_tag_variable_t},
236 static TMParserMapEntry map_RUBY[] = {
237 {'c', tm_tag_class_t},
238 {'f', tm_tag_method_t},
239 {'m', tm_tag_namespace_t},
240 {'S', tm_tag_member_t},
241 {'C', tm_tag_undef_t},
242 {'A', tm_tag_undef_t},
243 {'a', tm_tag_undef_t},
244 {'L', tm_tag_undef_t},
247 static TMParserMapEntry map_TCL[] = {
248 {'c', tm_tag_class_t},
249 {'m', tm_tag_member_t},
250 {'p', tm_tag_function_t},
251 {'n', tm_tag_namespace_t},
254 static TMParserMapEntry map_SH[] = {
255 {'f', tm_tag_function_t},
258 static TMParserMapEntry map_D[] = {
259 {'c', tm_tag_class_t},
260 {'e', tm_tag_enumerator_t},
261 {'f', tm_tag_function_t},
262 {'g', tm_tag_enum_t},
263 {'i', tm_tag_interface_t},
264 {'m', tm_tag_member_t},
265 {'n', tm_tag_namespace_t},
266 {'p', tm_tag_prototype_t},
267 {'s', tm_tag_struct_t},
268 {'t', tm_tag_typedef_t},
269 {'u', tm_tag_union_t},
270 {'v', tm_tag_variable_t},
271 {'x', tm_tag_externvar_t},
274 static TMParserMapEntry map_DIFF[] = {
275 {'m', tm_tag_function_t},
276 {'n', tm_tag_function_t},
277 {'d', tm_tag_function_t},
278 {'h', tm_tag_undef_t},
281 /* different parser than in universal-ctags */
282 static TMParserMapEntry map_VHDL[] = {
283 {'c', tm_tag_variable_t},
284 {'t', tm_tag_typedef_t},
285 {'v', tm_tag_variable_t},
286 {'a', tm_tag_undef_t},
287 {'s', tm_tag_variable_t},
288 {'f', tm_tag_function_t},
289 {'p', tm_tag_function_t},
290 {'k', tm_tag_member_t},
291 {'l', tm_tag_namespace_t},
292 {'m', tm_tag_member_t},
293 {'n', tm_tag_class_t},
294 {'o', tm_tag_struct_t},
295 {'u', tm_tag_undef_t},
296 {'b', tm_tag_member_t},
297 {'A', tm_tag_typedef_t},
300 static TMParserMapEntry map_LUA[] = {
301 {'f', tm_tag_function_t},
302 {'X', tm_tag_undef_t},
305 static TMParserMapEntry map_JAVASCRIPT[] = {
306 {'f', tm_tag_function_t},
307 {'c', tm_tag_class_t},
308 {'m', tm_tag_method_t},
309 {'p', tm_tag_member_t},
310 {'C', tm_tag_macro_t},
311 {'v', tm_tag_variable_t},
312 {'g', tm_tag_function_t},
313 {'G', tm_tag_undef_t},
314 {'S', tm_tag_undef_t},
315 {'M', tm_tag_undef_t},
318 static TMParserMapEntry map_HASKELL[] = {
319 {'t', tm_tag_typedef_t},
320 {'c', tm_tag_macro_t},
321 {'f', tm_tag_function_t},
322 {'m', tm_tag_namespace_t},
325 static TMParserMapEntry map_CSHARP[] = {
326 {'c', tm_tag_class_t},
327 {'d', tm_tag_macro_t},
328 {'e', tm_tag_enumerator_t},
329 {'E', tm_tag_undef_t},
330 {'f', tm_tag_field_t},
331 {'g', tm_tag_enum_t},
332 {'i', tm_tag_interface_t},
333 {'l', tm_tag_undef_t},
334 {'m', tm_tag_method_t},
335 {'n', tm_tag_namespace_t},
336 {'p', tm_tag_undef_t},
337 {'s', tm_tag_struct_t},
338 {'t', tm_tag_typedef_t},
341 static TMParserMapEntry map_FREEBASIC[] = {
342 {'c', tm_tag_macro_t},
343 {'f', tm_tag_function_t},
344 {'l', tm_tag_namespace_t},
345 {'t', tm_tag_struct_t},
346 {'v', tm_tag_variable_t},
347 {'g', tm_tag_externvar_t},
350 static TMParserMapEntry map_HAXE[] = {
351 {'m', tm_tag_method_t},
352 {'c', tm_tag_class_t},
353 {'e', tm_tag_enum_t},
354 {'v', tm_tag_variable_t},
355 {'i', tm_tag_interface_t},
356 {'t', tm_tag_typedef_t},
359 static TMParserMapEntry map_REST[] = {
360 {'c', tm_tag_namespace_t},
361 {'s', tm_tag_member_t},
362 {'S', tm_tag_macro_t},
363 {'t', tm_tag_variable_t},
364 {'C', tm_tag_undef_t},
365 {'T', tm_tag_undef_t},
366 {'d', tm_tag_undef_t},
369 static TMParserMapEntry map_HTML[] = {
370 {'a', tm_tag_member_t},
371 {'c', tm_tag_undef_t},
372 {'h', tm_tag_namespace_t},
373 {'i', tm_tag_class_t},
374 {'j', tm_tag_variable_t},
375 {'C', tm_tag_undef_t},
376 {'I', tm_tag_undef_t},
377 {'J', tm_tag_undef_t},
380 static TMSubparserMapEntry subparser_HTML_javascript_map[] = {
381 {tm_tag_function_t, tm_tag_function_t},
384 static TMParserMapEntry map_F77[] = {
385 {'b', tm_tag_undef_t},
386 {'c', tm_tag_macro_t},
387 {'e', tm_tag_undef_t},
388 {'f', tm_tag_function_t},
389 {'i', tm_tag_interface_t},
390 {'k', tm_tag_member_t},
391 {'l', tm_tag_undef_t},
392 {'L', tm_tag_undef_t},
393 {'m', tm_tag_namespace_t},
394 {'n', tm_tag_undef_t},
395 {'p', tm_tag_struct_t},
396 {'s', tm_tag_method_t},
397 {'t', tm_tag_class_t},
398 {'v', tm_tag_variable_t},
399 {'E', tm_tag_enum_t},
400 {'N', tm_tag_enumerator_t},
403 #define map_FORTRAN map_F77
405 #define map_FERITE map_C_old_parser
407 /* different parser than in universal-ctags */
408 static TMParserMapEntry map_MATLAB[] = {
409 {'f', tm_tag_function_t},
410 {'s', tm_tag_struct_t},
413 #define map_GLSL map_C_old_parser
415 /* not in universal-ctags */
416 static TMParserMapEntry map_VALA[] = {
417 {'c', tm_tag_class_t},
418 {'d', tm_tag_macro_t},
419 {'e', tm_tag_enumerator_t},
420 {'f', tm_tag_field_t},
421 {'g', tm_tag_enum_t},
422 {'i', tm_tag_interface_t},
423 {'l', tm_tag_undef_t},
424 {'m', tm_tag_method_t},
425 {'n', tm_tag_namespace_t},
426 {'p', tm_tag_undef_t},
427 {'S', tm_tag_undef_t},
428 {'s', tm_tag_struct_t},
431 /* not in universal-ctags */
432 static TMParserMapEntry map_ACTIONSCRIPT[] = {
433 {'f', tm_tag_function_t},
434 {'c', tm_tag_class_t},
435 {'i', tm_tag_interface_t},
436 {'P', tm_tag_package_t},
437 {'m', tm_tag_method_t},
438 {'p', tm_tag_member_t},
439 {'v', tm_tag_variable_t},
440 {'l', tm_tag_variable_t},
441 {'C', tm_tag_macro_t},
442 {'I', tm_tag_externvar_t},
443 {'x', tm_tag_other_t},
446 static TMParserMapEntry map_NSIS[] = {
447 {'s', tm_tag_namespace_t},
448 {'f', tm_tag_function_t},
449 {'v', tm_tag_variable_t},
450 {'d', tm_tag_undef_t},
451 {'m', tm_tag_undef_t},
452 {'S', tm_tag_undef_t},
453 {'p', tm_tag_undef_t},
454 {'l', tm_tag_undef_t},
455 {'i', tm_tag_undef_t},
458 /* not in universal-ctags */
459 static TMParserMapEntry map_MARKDOWN[] = {
460 {'v', tm_tag_variable_t},
463 static TMParserMapEntry map_TXT2TAGS[] = {
464 {'s', tm_tag_member_t},
467 static TMParserMapEntry map_ABC[] = {
468 {'s', tm_tag_member_t},
471 static TMParserMapEntry map_VERILOG[] = {
472 {'c', tm_tag_variable_t},
473 {'e', tm_tag_typedef_t},
474 {'f', tm_tag_function_t},
475 {'m', tm_tag_class_t},
476 {'n', tm_tag_variable_t},
477 {'p', tm_tag_variable_t},
478 {'r', tm_tag_variable_t},
479 {'t', tm_tag_function_t},
482 static TMParserMapEntry map_R[] = {
483 {'f', tm_tag_function_t},
484 {'l', tm_tag_other_t},
485 {'s', tm_tag_other_t},
488 static TMParserMapEntry map_COBOL[] = {
489 {'d', tm_tag_variable_t},
490 {'D', tm_tag_interface_t},
491 {'f', tm_tag_function_t},
492 {'g', tm_tag_struct_t},
493 {'p', tm_tag_macro_t},
494 {'P', tm_tag_class_t},
495 {'s', tm_tag_namespace_t},
496 {'S', tm_tag_externvar_t},
499 static TMParserMapEntry map_OBJC[] = {
500 {'i', tm_tag_interface_t},
501 {'I', tm_tag_undef_t},
502 {'P', tm_tag_undef_t},
503 {'m', tm_tag_method_t},
504 {'c', tm_tag_class_t},
505 {'v', tm_tag_variable_t},
506 {'E', tm_tag_field_t},
507 {'f', tm_tag_function_t},
508 {'p', tm_tag_undef_t},
509 {'t', tm_tag_typedef_t},
510 {'s', tm_tag_struct_t},
511 {'e', tm_tag_enum_t},
512 {'M', tm_tag_macro_t},
513 {'C', tm_tag_undef_t},
516 static TMParserMapEntry map_ASCIIDOC[] = {
517 {'c', tm_tag_namespace_t},
518 {'s', tm_tag_member_t},
519 {'S', tm_tag_macro_t},
520 {'t', tm_tag_variable_t},
521 {'T', tm_tag_struct_t},
522 {'u', tm_tag_undef_t},
523 {'a', tm_tag_undef_t},
526 static TMParserMapEntry map_ABAQUS[] = {
527 {'p', tm_tag_class_t},
528 {'a', tm_tag_member_t},
529 {'s', tm_tag_interface_t},
532 static TMParserMapEntry map_RUST[] = {
533 {'n', tm_tag_namespace_t},
534 {'s', tm_tag_struct_t},
535 {'i', tm_tag_interface_t},
536 {'c', tm_tag_class_t},
537 {'f', tm_tag_function_t},
538 {'g', tm_tag_enum_t},
539 {'t', tm_tag_typedef_t},
540 {'v', tm_tag_variable_t},
541 {'M', tm_tag_macro_t},
542 {'m', tm_tag_field_t},
543 {'e', tm_tag_enumerator_t},
544 {'P', tm_tag_method_t},
547 static TMParserMapEntry map_GO[] = {
548 {'p', tm_tag_namespace_t},
549 {'f', tm_tag_function_t},
550 {'c', tm_tag_macro_t},
551 {'t', tm_tag_typedef_t},
552 {'v', tm_tag_variable_t},
553 {'s', tm_tag_struct_t},
554 {'i', tm_tag_interface_t},
555 {'m', tm_tag_member_t},
556 {'M', tm_tag_undef_t},
557 {'n', tm_tag_undef_t},
558 {'u', tm_tag_undef_t},
559 {'P', tm_tag_undef_t},
560 {'a', tm_tag_undef_t},
561 {'R', tm_tag_undef_t},
564 static TMParserMapEntry map_JSON[] = {
565 {'o', tm_tag_member_t},
566 {'a', tm_tag_member_t},
567 {'n', tm_tag_member_t},
568 {'s', tm_tag_member_t},
569 {'b', tm_tag_member_t},
570 {'z', tm_tag_member_t},
573 /* Zephir, same as PHP */
574 #define map_ZEPHIR map_PHP
576 /* not in universal-ctags */
577 static TMParserMapEntry map_POWERSHELL[] = {
578 {'f', tm_tag_function_t},
579 {'v', tm_tag_variable_t},
582 static TMParserMapEntry map_JULIA[] = {
583 {'c', tm_tag_variable_t},
584 {'f', tm_tag_function_t},
585 {'g', tm_tag_member_t},
586 {'m', tm_tag_macro_t},
587 {'n', tm_tag_namespace_t},
588 {'s', tm_tag_struct_t},
589 {'t', tm_tag_typedef_t},
590 /* defined as externvar to get those excluded as forward type in symbols.c:goto_tag()
591 * so we can jump to the real implementation (if known) instead of to the import statement */
592 {'x', tm_tag_externvar_t},
595 static TMParserMapEntry map_CPREPROCESSOR[] = {
596 {'d', tm_tag_undef_t},
597 {'h', tm_tag_undef_t},
598 {'D', tm_tag_undef_t},
601 typedef struct
603 TMParserMapEntry *entries;
604 guint size;
605 } TMParserMap;
607 #define MAP_ENTRY(lang) [TM_PARSER_##lang] = {map_##lang, G_N_ELEMENTS(map_##lang)}
609 /* keep in sync with TM_PARSER_* definitions in the header */
610 static TMParserMap parser_map[] = {
611 MAP_ENTRY(C),
612 MAP_ENTRY(CPP),
613 MAP_ENTRY(JAVA),
614 MAP_ENTRY(MAKEFILE),
615 MAP_ENTRY(PASCAL),
616 MAP_ENTRY(PERL),
617 MAP_ENTRY(PHP),
618 MAP_ENTRY(PYTHON),
619 MAP_ENTRY(LATEX),
620 MAP_ENTRY(BIBTEX),
621 MAP_ENTRY(ASM),
622 MAP_ENTRY(CONF),
623 MAP_ENTRY(SQL),
624 MAP_ENTRY(DOCBOOK),
625 MAP_ENTRY(ERLANG),
626 MAP_ENTRY(CSS),
627 MAP_ENTRY(RUBY),
628 MAP_ENTRY(TCL),
629 MAP_ENTRY(SH),
630 MAP_ENTRY(D),
631 MAP_ENTRY(FORTRAN),
632 MAP_ENTRY(FERITE),
633 MAP_ENTRY(DIFF),
634 MAP_ENTRY(VHDL),
635 MAP_ENTRY(LUA),
636 MAP_ENTRY(JAVASCRIPT),
637 MAP_ENTRY(HASKELL),
638 MAP_ENTRY(CSHARP),
639 MAP_ENTRY(FREEBASIC),
640 MAP_ENTRY(HAXE),
641 MAP_ENTRY(REST),
642 MAP_ENTRY(HTML),
643 MAP_ENTRY(F77),
644 MAP_ENTRY(GLSL),
645 MAP_ENTRY(MATLAB),
646 MAP_ENTRY(VALA),
647 MAP_ENTRY(ACTIONSCRIPT),
648 MAP_ENTRY(NSIS),
649 MAP_ENTRY(MARKDOWN),
650 MAP_ENTRY(TXT2TAGS),
651 MAP_ENTRY(ABC),
652 MAP_ENTRY(VERILOG),
653 MAP_ENTRY(R),
654 MAP_ENTRY(COBOL),
655 MAP_ENTRY(OBJC),
656 MAP_ENTRY(ASCIIDOC),
657 MAP_ENTRY(ABAQUS),
658 MAP_ENTRY(RUST),
659 MAP_ENTRY(GO),
660 MAP_ENTRY(JSON),
661 MAP_ENTRY(ZEPHIR),
662 MAP_ENTRY(POWERSHELL),
663 MAP_ENTRY(JULIA),
664 MAP_ENTRY(CPREPROCESSOR),
666 /* make sure the parser map is consistent and complete */
667 G_STATIC_ASSERT(G_N_ELEMENTS(parser_map) == TM_PARSER_COUNT);
670 TMTagType tm_parser_get_tag_type(gchar kind, TMParserType lang)
672 TMParserMap *map = &parser_map[lang];
673 guint i;
675 for (i = 0; i < map->size; i++)
677 TMParserMapEntry *entry = &map->entries[i];
679 if (entry->kind == kind)
680 return entry->type;
682 return tm_tag_undef_t;
686 gchar tm_parser_get_tag_kind(TMTagType type, TMParserType lang)
688 TMParserMap *map = &parser_map[lang];
689 guint i;
691 for (i = 0; i < map->size; i++)
693 TMParserMapEntry *entry = &map->entries[i];
695 if (entry->type == type)
696 return entry->kind;
698 return '\0';
702 static void add_subparser(TMParserType lang, TMParserType sublang, TMSubparserMapEntry *map, guint map_size)
704 guint i;
705 GPtrArray *mapping;
706 GHashTable *lang_map = g_hash_table_lookup(subparser_map, GINT_TO_POINTER(lang));
708 if (!lang_map)
710 lang_map = g_hash_table_new(g_direct_hash, g_direct_equal);
711 g_hash_table_insert(subparser_map, GINT_TO_POINTER(lang), lang_map);
714 mapping = g_ptr_array_new();
715 for (i = 0; i < map_size; i++)
716 g_ptr_array_add(mapping, &map[i]);
718 g_hash_table_insert(lang_map, GINT_TO_POINTER(sublang), mapping);
722 #define SUBPARSER_MAP_ENTRY(lang, sublang, map) add_subparser(TM_PARSER_##lang, TM_PARSER_##sublang, map, G_N_ELEMENTS(map))
724 static void init_subparser_map(void)
726 SUBPARSER_MAP_ENTRY(HTML, JAVASCRIPT, subparser_HTML_javascript_map);
730 TMTagType tm_parser_get_subparser_type(TMParserType lang, TMParserType sublang, TMTagType type)
732 guint i;
733 GHashTable *lang_map;
734 GPtrArray *mapping;
736 if (!subparser_map)
738 subparser_map = g_hash_table_new(g_direct_hash, g_direct_equal);
739 init_subparser_map();
742 lang_map = g_hash_table_lookup(subparser_map, GINT_TO_POINTER(lang));
743 if (!lang_map)
744 return tm_tag_undef_t;
746 mapping = g_hash_table_lookup(lang_map, GINT_TO_POINTER(sublang));
747 if (!mapping)
748 return tm_tag_undef_t;
750 for (i = 0; i < mapping->len; i++)
752 TMSubparserMapEntry *entry = mapping->pdata[i];
753 if (entry->orig_type == type)
754 return entry->new_type;
757 return tm_tag_undef_t;
761 void tm_parser_verify_type_mappings(void)
763 TMParserType lang;
765 if (TM_PARSER_COUNT > tm_ctags_get_lang_count())
766 g_error("More parsers defined in Geany than in ctags");
768 for (lang = 0; lang < TM_PARSER_COUNT; lang++)
770 const gchar *kinds = tm_ctags_get_lang_kinds(lang);
771 TMParserMap *map = &parser_map[lang];
772 gchar presence_map[256];
773 guint i;
775 if (! map->entries || map->size < 1)
776 g_error("No tag types in TM for %s, is the language listed in parser_map?",
777 tm_ctags_get_lang_name(lang));
779 if (map->size != strlen(kinds))
780 g_error("Different number of tag types in TM (%d) and ctags (%d) for %s",
781 map->size, (int)strlen(kinds), tm_ctags_get_lang_name(lang));
783 memset(presence_map, 0, sizeof(presence_map));
784 for (i = 0; i < map->size; i++)
786 gboolean ctags_found = FALSE;
787 gboolean tm_found = FALSE;
788 guint j;
790 for (j = 0; j < map->size; j++)
792 /* check that for every type in TM there's a type in ctags */
793 if (map->entries[i].kind == kinds[j])
794 ctags_found = TRUE;
795 /* check that for every type in ctags there's a type in TM */
796 if (map->entries[j].kind == kinds[i])
797 tm_found = TRUE;
798 if (ctags_found && tm_found)
799 break;
801 if (!ctags_found)
802 g_error("Tag type '%c' found in TM but not in ctags for %s",
803 map->entries[i].kind, tm_ctags_get_lang_name(lang));
804 if (!tm_found)
805 g_error("Tag type '%c' found in ctags but not in TM for %s",
806 kinds[i], tm_ctags_get_lang_name(lang));
808 presence_map[(unsigned char) map->entries[i].kind]++;
811 for (i = 0; i < sizeof(presence_map); i++)
813 if (presence_map[i] > 1)
814 g_error("Duplicate tag type '%c' found for %s",
815 (gchar)i, tm_ctags_get_lang_name(lang));
821 /* When the suffix of 'str' is an operator that should trigger scope
822 * autocompletion, this function should return the length of the operator,
823 * zero otherwise. */
824 gint tm_parser_scope_autocomplete_suffix(TMParserType lang, const gchar *str)
826 const gchar *sep = tm_parser_context_separator(lang);
828 if (g_str_has_suffix(str, sep))
829 return strlen(sep);
831 switch (lang)
833 case TM_PARSER_C:
834 case TM_PARSER_CPP:
835 if (g_str_has_suffix(str, "."))
836 return 1;
837 else if (g_str_has_suffix(str, "->"))
838 return 2;
839 else if (lang == TM_PARSER_CPP && g_str_has_suffix(str, "->*"))
840 return 3;
841 default:
842 break;
844 return 0;
848 /* Get the name of constructor method. Arguments of this method will be used
849 * for calltips when creating an object using the class name
850 * (e.g. after the opening brace in 'c = MyClass()' in Python) */
851 const gchar *tm_parser_get_constructor_method(TMParserType lang)
853 switch (lang)
855 case TM_PARSER_D:
856 return "this";
857 case TM_PARSER_PYTHON:
858 return "__init__";
859 default:
860 return NULL;
865 /* determine anonymous tags from tag names only when corresponding
866 * ctags information is not available */
867 gboolean tm_parser_is_anon_name(TMParserType lang, gchar *name)
869 guint i;
870 char dummy;
872 if (sscanf(name, "__anon%u%c", &i, &dummy) == 1) /* uctags tags files */
873 return TRUE;
874 else if (lang == TM_PARSER_C || lang == TM_PARSER_CPP) /* legacy Geany tags files */
875 return sscanf(name, "anon_%*[a-z]_%u%c", &i, &dummy) == 1;
876 else if (lang == TM_PARSER_FORTRAN || lang == TM_PARSER_F77) /* legacy Geany tags files */
878 return sscanf(name, "Structure#%u%c", &i, &dummy) == 1 ||
879 sscanf(name, "Interface#%u%c", &i, &dummy) == 1 ||
880 sscanf(name, "Enum#%u%c", &i, &dummy) == 1;
882 return FALSE;
886 static gchar *replace_string_if_present(gchar *haystack, gchar *needle, gchar *subst)
888 if (strstr(haystack, needle))
890 gchar **split = g_strsplit(haystack, needle, -1);
891 gchar *ret = g_strjoinv(subst, split);
892 g_strfreev(split);
893 return ret;
895 return haystack;
899 /* return updated scope or original scope if no change needed */
900 gchar *tm_parser_update_scope(TMParserType lang, gchar *scope)
902 switch (lang)
904 case TM_PARSER_PHP:
905 case TM_PARSER_ZEPHIR:
906 /* PHP parser uses two different scope separators but this would
907 * complicate things in Geany so make sure there's just one type */
908 return replace_string_if_present(scope, "\\", "::");
910 return scope;
914 /* whether or not to enable ctags roles for the given language and kind */
915 gboolean tm_parser_enable_role(TMParserType lang, gchar kind)
917 switch (lang)
919 case TM_PARSER_GO:
920 /* 'p' is used both for package definition tags and imported package
921 * tags and we can't tell which is which just by kind. By disabling
922 * roles for this kind, we only get package definition tags. */
923 return kind == 'p' ? FALSE : TRUE;
925 return TRUE;
929 /* whether or not to enable ctags kinds for the given language */
930 gboolean tm_parser_enable_kind(TMParserType lang, gchar kind)
932 TMParserMap *map;
933 guint i;
935 if (lang >= TM_PARSER_COUNT)
936 /* Fatal error but tm_parser_verify_type_mappings() will provide
937 * better message later */
938 return FALSE;
940 map = &parser_map[lang];
941 for (i = 0; i < map->size; i++)
943 if (map->entries[i].kind == kind)
944 return map->entries[i].type != tm_tag_undef_t;
946 return FALSE;
950 gchar *tm_parser_format_variable(TMParserType lang, const gchar *name, const gchar *type)
952 if (!type)
953 return NULL;
955 switch (lang)
957 case TM_PARSER_GO:
958 return g_strconcat(name, " ", type, NULL);
959 case TM_PARSER_PASCAL:
960 case TM_PARSER_PYTHON:
961 return g_strconcat(name, ": ", type, NULL);
962 default:
963 return g_strconcat(type, " ", name, NULL);
968 gchar *tm_parser_format_function(TMParserType lang, const gchar *fname, const gchar *args,
969 const gchar *retval, const gchar *scope)
971 GString *str;
973 if (!args) /* not a function */
974 return NULL;
976 str = g_string_new(NULL);
978 if (scope)
980 g_string_append(str, scope);
981 g_string_append(str, tm_parser_context_separator(lang));
983 g_string_append(str, fname);
984 g_string_append_c(str, ' ');
985 g_string_append(str, args);
987 if (retval)
989 switch (lang)
991 case TM_PARSER_GO:
992 case TM_PARSER_PASCAL:
993 case TM_PARSER_PYTHON:
995 /* retval after function */
996 const gchar *sep;
997 switch (lang)
999 case TM_PARSER_PASCAL:
1000 sep = ": ";
1001 break;
1002 case TM_PARSER_PYTHON:
1003 sep = " -> ";
1004 break;
1005 default:
1006 sep = " ";
1007 break;
1009 g_string_append(str, sep);
1010 g_string_append(str, retval);
1011 break;
1013 default:
1014 /* retval before function */
1015 g_string_prepend_c(str, ' ');
1016 g_string_prepend(str, retval);
1017 break;
1021 return g_string_free(str, FALSE);
1025 const gchar *tm_parser_context_separator(TMParserType lang)
1027 switch (lang)
1029 case TM_PARSER_C: /* for C++ .h headers or C structs */
1030 case TM_PARSER_CPP:
1031 case TM_PARSER_GLSL: /* for structs */
1032 case TM_PARSER_PHP:
1033 case TM_PARSER_POWERSHELL:
1034 case TM_PARSER_RUST:
1035 case TM_PARSER_ZEPHIR:
1036 return "::";
1038 case TM_PARSER_TXT2TAGS:
1039 return "\"\"";
1041 /* these parsers don't report nested scopes but default "." for scope separator
1042 * might appear in the text so use something more improbable */
1043 case TM_PARSER_ASCIIDOC:
1044 case TM_PARSER_CONF:
1045 case TM_PARSER_REST:
1046 return "\x3";
1048 default:
1049 return ".";
1054 gboolean tm_parser_has_full_context(TMParserType lang)
1056 switch (lang)
1058 /* These parsers include full hierarchy in the tag scope, separated by tm_parser_context_separator() */
1059 case TM_PARSER_ACTIONSCRIPT:
1060 case TM_PARSER_C:
1061 case TM_PARSER_CPP:
1062 case TM_PARSER_CSHARP:
1063 case TM_PARSER_COBOL:
1064 case TM_PARSER_D:
1065 case TM_PARSER_FERITE:
1066 case TM_PARSER_GLSL:
1067 case TM_PARSER_GO:
1068 case TM_PARSER_JAVA:
1069 case TM_PARSER_JAVASCRIPT:
1070 case TM_PARSER_JSON:
1071 case TM_PARSER_LUA:
1072 case TM_PARSER_PHP:
1073 case TM_PARSER_POWERSHELL:
1074 case TM_PARSER_PYTHON:
1075 case TM_PARSER_RUBY:
1076 case TM_PARSER_RUST:
1077 case TM_PARSER_SQL:
1078 case TM_PARSER_TXT2TAGS:
1079 case TM_PARSER_VALA:
1080 case TM_PARSER_ZEPHIR:
1081 return TRUE;
1083 /* These make use of the scope, but don't include nested hierarchy
1084 * (either as a parser limitation or a language semantic) */
1085 case TM_PARSER_ASCIIDOC:
1086 case TM_PARSER_CONF:
1087 case TM_PARSER_ERLANG:
1088 case TM_PARSER_F77:
1089 case TM_PARSER_FORTRAN:
1090 case TM_PARSER_OBJC:
1091 case TM_PARSER_REST:
1092 /* Other parsers don't use scope at all (or should be somewhere above) */
1093 default:
1094 return FALSE;
1099 gboolean tm_parser_langs_compatible(TMParserType lang, TMParserType other)
1101 if (lang == TM_PARSER_NONE || other == TM_PARSER_NONE)
1102 return FALSE;
1103 if (lang == other)
1104 return TRUE;
1105 /* Accept CPP tags for C lang and vice versa */
1106 else if (lang == TM_PARSER_C && other == TM_PARSER_CPP)
1107 return TRUE;
1108 else if (lang == TM_PARSER_CPP && other == TM_PARSER_C)
1109 return TRUE;
1111 return FALSE;