Merge pull request #3075 from techee/remove_ferite_parser
[geany-mirror.git] / src / tagmanager / tm_parser.c
blob2a317ceab32dcd60a8e250ed9938003776ce6bad
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},
177 {'s', tm_tag_undef_t},
180 /* not in universal-ctags */
181 static TMParserMapEntry map_CONF[] = {
182 {'s', tm_tag_namespace_t},
183 {'k', tm_tag_macro_t},
186 static TMParserMapEntry map_SQL[] = {
187 {'c', tm_tag_undef_t},
188 {'d', tm_tag_prototype_t},
189 {'f', tm_tag_function_t},
190 {'E', tm_tag_field_t},
191 {'l', tm_tag_undef_t},
192 {'L', tm_tag_undef_t},
193 {'P', tm_tag_package_t},
194 {'p', tm_tag_namespace_t},
195 {'r', tm_tag_undef_t},
196 {'s', tm_tag_undef_t},
197 {'t', tm_tag_class_t},
198 {'T', tm_tag_macro_t},
199 {'v', tm_tag_variable_t},
200 {'i', tm_tag_struct_t},
201 {'e', tm_tag_undef_t},
202 {'U', tm_tag_undef_t},
203 {'R', tm_tag_undef_t},
204 {'D', tm_tag_undef_t},
205 {'V', tm_tag_member_t},
206 {'n', tm_tag_undef_t},
207 {'x', tm_tag_undef_t},
208 {'y', tm_tag_undef_t},
209 {'z', tm_tag_undef_t},
210 {'C', tm_tag_undef_t},
213 /* not in universal-ctags */
214 static TMParserMapEntry map_DOCBOOK[] = {
215 {'f', tm_tag_function_t},
216 {'c', tm_tag_class_t},
217 {'m', tm_tag_member_t},
218 {'d', tm_tag_macro_t},
219 {'v', tm_tag_variable_t},
220 {'s', tm_tag_struct_t},
223 static TMParserMapEntry map_ERLANG[] = {
224 {'d', tm_tag_macro_t},
225 {'f', tm_tag_function_t},
226 {'m', tm_tag_undef_t},
227 {'r', tm_tag_struct_t},
228 {'t', tm_tag_typedef_t},
231 static TMParserMapEntry map_CSS[] = {
232 {'c', tm_tag_class_t},
233 {'s', tm_tag_struct_t},
234 {'i', tm_tag_variable_t},
237 static TMParserMapEntry map_RUBY[] = {
238 {'c', tm_tag_class_t},
239 {'f', tm_tag_method_t},
240 {'m', tm_tag_namespace_t},
241 {'S', tm_tag_member_t},
242 {'C', tm_tag_undef_t},
243 {'A', tm_tag_undef_t},
244 {'a', tm_tag_undef_t},
245 {'L', tm_tag_undef_t},
248 static TMParserMapEntry map_TCL[] = {
249 {'c', tm_tag_class_t},
250 {'m', tm_tag_member_t},
251 {'p', tm_tag_function_t},
252 {'n', tm_tag_namespace_t},
255 static TMParserMapEntry map_SH[] = {
256 {'f', tm_tag_function_t},
259 static TMParserMapEntry map_D[] = {
260 {'c', tm_tag_class_t},
261 {'e', tm_tag_enumerator_t},
262 {'f', tm_tag_function_t},
263 {'g', tm_tag_enum_t},
264 {'i', tm_tag_interface_t},
265 {'m', tm_tag_member_t},
266 {'n', tm_tag_namespace_t},
267 {'p', tm_tag_prototype_t},
268 {'s', tm_tag_struct_t},
269 {'t', tm_tag_typedef_t},
270 {'u', tm_tag_union_t},
271 {'v', tm_tag_variable_t},
272 {'x', tm_tag_externvar_t},
275 static TMParserMapEntry map_DIFF[] = {
276 {'m', tm_tag_function_t},
277 {'n', tm_tag_function_t},
278 {'d', tm_tag_function_t},
279 {'h', tm_tag_undef_t},
282 /* different parser than in universal-ctags */
283 static TMParserMapEntry map_VHDL[] = {
284 {'c', tm_tag_variable_t},
285 {'t', tm_tag_typedef_t},
286 {'v', tm_tag_variable_t},
287 {'a', tm_tag_undef_t},
288 {'s', tm_tag_variable_t},
289 {'f', tm_tag_function_t},
290 {'p', tm_tag_function_t},
291 {'k', tm_tag_member_t},
292 {'l', tm_tag_namespace_t},
293 {'m', tm_tag_member_t},
294 {'n', tm_tag_class_t},
295 {'o', tm_tag_struct_t},
296 {'u', tm_tag_undef_t},
297 {'b', tm_tag_member_t},
298 {'A', tm_tag_typedef_t},
301 static TMParserMapEntry map_LUA[] = {
302 {'f', tm_tag_function_t},
303 {'X', tm_tag_undef_t},
306 static TMParserMapEntry map_JAVASCRIPT[] = {
307 {'f', tm_tag_function_t},
308 {'c', tm_tag_class_t},
309 {'m', tm_tag_method_t},
310 {'p', tm_tag_member_t},
311 {'C', tm_tag_macro_t},
312 {'v', tm_tag_variable_t},
313 {'g', tm_tag_function_t},
314 {'G', tm_tag_undef_t},
315 {'S', tm_tag_undef_t},
316 {'M', tm_tag_undef_t},
319 static TMParserMapEntry map_HASKELL[] = {
320 {'t', tm_tag_typedef_t},
321 {'c', tm_tag_macro_t},
322 {'f', tm_tag_function_t},
323 {'m', tm_tag_namespace_t},
326 static TMParserMapEntry map_CSHARP[] = {
327 {'c', tm_tag_class_t},
328 {'d', tm_tag_macro_t},
329 {'e', tm_tag_enumerator_t},
330 {'E', tm_tag_undef_t},
331 {'f', tm_tag_field_t},
332 {'g', tm_tag_enum_t},
333 {'i', tm_tag_interface_t},
334 {'l', tm_tag_undef_t},
335 {'m', tm_tag_method_t},
336 {'n', tm_tag_namespace_t},
337 {'p', tm_tag_undef_t},
338 {'s', tm_tag_struct_t},
339 {'t', tm_tag_typedef_t},
342 static TMParserMapEntry map_FREEBASIC[] = {
343 {'c', tm_tag_macro_t},
344 {'f', tm_tag_function_t},
345 {'l', tm_tag_namespace_t},
346 {'t', tm_tag_struct_t},
347 {'v', tm_tag_variable_t},
348 {'g', tm_tag_externvar_t},
351 static TMParserMapEntry map_HAXE[] = {
352 {'m', tm_tag_method_t},
353 {'c', tm_tag_class_t},
354 {'e', tm_tag_enum_t},
355 {'v', tm_tag_variable_t},
356 {'i', tm_tag_interface_t},
357 {'t', tm_tag_typedef_t},
360 static TMParserMapEntry map_REST[] = {
361 {'c', tm_tag_namespace_t},
362 {'s', tm_tag_member_t},
363 {'S', tm_tag_macro_t},
364 {'t', tm_tag_variable_t},
365 {'C', tm_tag_undef_t},
366 {'T', tm_tag_undef_t},
367 {'d', tm_tag_undef_t},
370 static TMParserMapEntry map_HTML[] = {
371 {'a', tm_tag_member_t},
372 {'c', tm_tag_undef_t},
373 {'h', tm_tag_namespace_t},
374 {'i', tm_tag_class_t},
375 {'j', tm_tag_variable_t},
376 {'C', tm_tag_undef_t},
377 {'I', tm_tag_undef_t},
378 {'J', tm_tag_undef_t},
381 static TMSubparserMapEntry subparser_HTML_javascript_map[] = {
382 {tm_tag_function_t, tm_tag_function_t},
385 static TMParserMapEntry map_F77[] = {
386 {'b', tm_tag_undef_t},
387 {'c', tm_tag_macro_t},
388 {'e', tm_tag_undef_t},
389 {'f', tm_tag_function_t},
390 {'i', tm_tag_interface_t},
391 {'k', tm_tag_member_t},
392 {'l', tm_tag_undef_t},
393 {'L', tm_tag_undef_t},
394 {'m', tm_tag_namespace_t},
395 {'n', tm_tag_undef_t},
396 {'p', tm_tag_struct_t},
397 {'s', tm_tag_method_t},
398 {'t', tm_tag_class_t},
399 {'v', tm_tag_variable_t},
400 {'E', tm_tag_enum_t},
401 {'N', tm_tag_enumerator_t},
404 #define map_FORTRAN map_F77
406 /* different parser than in universal-ctags */
407 static TMParserMapEntry map_MATLAB[] = {
408 {'f', tm_tag_function_t},
409 {'s', tm_tag_struct_t},
412 #define map_GLSL map_C_old_parser
414 /* not in universal-ctags */
415 static TMParserMapEntry map_VALA[] = {
416 {'c', tm_tag_class_t},
417 {'d', tm_tag_macro_t},
418 {'e', tm_tag_enumerator_t},
419 {'f', tm_tag_field_t},
420 {'g', tm_tag_enum_t},
421 {'i', tm_tag_interface_t},
422 {'l', tm_tag_undef_t},
423 {'m', tm_tag_method_t},
424 {'n', tm_tag_namespace_t},
425 {'p', tm_tag_undef_t},
426 {'S', tm_tag_undef_t},
427 {'s', tm_tag_struct_t},
430 /* not in universal-ctags */
431 static TMParserMapEntry map_ACTIONSCRIPT[] = {
432 {'f', tm_tag_function_t},
433 {'c', tm_tag_class_t},
434 {'i', tm_tag_interface_t},
435 {'P', tm_tag_package_t},
436 {'m', tm_tag_method_t},
437 {'p', tm_tag_member_t},
438 {'v', tm_tag_variable_t},
439 {'l', tm_tag_variable_t},
440 {'C', tm_tag_macro_t},
441 {'I', tm_tag_externvar_t},
442 {'x', tm_tag_other_t},
445 static TMParserMapEntry map_NSIS[] = {
446 {'s', tm_tag_namespace_t},
447 {'f', tm_tag_function_t},
448 {'v', tm_tag_variable_t},
449 {'d', tm_tag_undef_t},
450 {'m', tm_tag_undef_t},
451 {'S', tm_tag_undef_t},
452 {'p', tm_tag_undef_t},
453 {'l', tm_tag_undef_t},
454 {'i', tm_tag_undef_t},
457 /* not in universal-ctags */
458 static TMParserMapEntry map_MARKDOWN[] = {
459 {'v', tm_tag_variable_t},
462 static TMParserMapEntry map_TXT2TAGS[] = {
463 {'s', tm_tag_member_t},
466 static TMParserMapEntry map_ABC[] = {
467 {'s', tm_tag_member_t},
470 static TMParserMapEntry map_VERILOG[] = {
471 {'c', tm_tag_variable_t},
472 {'e', tm_tag_typedef_t},
473 {'f', tm_tag_function_t},
474 {'m', tm_tag_class_t},
475 {'n', tm_tag_variable_t},
476 {'p', tm_tag_variable_t},
477 {'r', tm_tag_variable_t},
478 {'t', tm_tag_function_t},
481 static TMParserMapEntry map_R[] = {
482 {'f', tm_tag_function_t},
483 {'l', tm_tag_other_t},
484 {'s', tm_tag_other_t},
487 static TMParserMapEntry map_COBOL[] = {
488 {'d', tm_tag_variable_t},
489 {'D', tm_tag_interface_t},
490 {'f', tm_tag_function_t},
491 {'g', tm_tag_struct_t},
492 {'p', tm_tag_macro_t},
493 {'P', tm_tag_class_t},
494 {'s', tm_tag_namespace_t},
495 {'S', tm_tag_externvar_t},
498 static TMParserMapEntry map_OBJC[] = {
499 {'i', tm_tag_interface_t},
500 {'I', tm_tag_undef_t},
501 {'P', tm_tag_undef_t},
502 {'m', tm_tag_method_t},
503 {'c', tm_tag_class_t},
504 {'v', tm_tag_variable_t},
505 {'E', tm_tag_field_t},
506 {'f', tm_tag_function_t},
507 {'p', tm_tag_undef_t},
508 {'t', tm_tag_typedef_t},
509 {'s', tm_tag_struct_t},
510 {'e', tm_tag_enum_t},
511 {'M', tm_tag_macro_t},
512 {'C', tm_tag_undef_t},
515 static TMParserMapEntry map_ASCIIDOC[] = {
516 {'c', tm_tag_namespace_t},
517 {'s', tm_tag_member_t},
518 {'S', tm_tag_macro_t},
519 {'t', tm_tag_variable_t},
520 {'T', tm_tag_struct_t},
521 {'u', tm_tag_undef_t},
522 {'a', tm_tag_undef_t},
525 static TMParserMapEntry map_ABAQUS[] = {
526 {'p', tm_tag_class_t},
527 {'a', tm_tag_member_t},
528 {'s', tm_tag_interface_t},
531 static TMParserMapEntry map_RUST[] = {
532 {'n', tm_tag_namespace_t},
533 {'s', tm_tag_struct_t},
534 {'i', tm_tag_interface_t},
535 {'c', tm_tag_class_t},
536 {'f', tm_tag_function_t},
537 {'g', tm_tag_enum_t},
538 {'t', tm_tag_typedef_t},
539 {'v', tm_tag_variable_t},
540 {'M', tm_tag_macro_t},
541 {'m', tm_tag_field_t},
542 {'e', tm_tag_enumerator_t},
543 {'P', tm_tag_method_t},
546 static TMParserMapEntry map_GO[] = {
547 {'p', tm_tag_namespace_t},
548 {'f', tm_tag_function_t},
549 {'c', tm_tag_macro_t},
550 {'t', tm_tag_typedef_t},
551 {'v', tm_tag_variable_t},
552 {'s', tm_tag_struct_t},
553 {'i', tm_tag_interface_t},
554 {'m', tm_tag_member_t},
555 {'M', tm_tag_undef_t},
556 {'n', tm_tag_undef_t},
557 {'u', tm_tag_undef_t},
558 {'P', tm_tag_undef_t},
559 {'a', tm_tag_undef_t},
560 {'R', tm_tag_undef_t},
563 static TMParserMapEntry map_JSON[] = {
564 {'o', tm_tag_member_t},
565 {'a', tm_tag_member_t},
566 {'n', tm_tag_member_t},
567 {'s', tm_tag_member_t},
568 {'b', tm_tag_member_t},
569 {'z', tm_tag_member_t},
572 /* Zephir, same as PHP */
573 #define map_ZEPHIR map_PHP
575 /* not in universal-ctags */
576 static TMParserMapEntry map_POWERSHELL[] = {
577 {'f', tm_tag_function_t},
578 {'v', tm_tag_variable_t},
581 static TMParserMapEntry map_JULIA[] = {
582 {'c', tm_tag_variable_t},
583 {'f', tm_tag_function_t},
584 {'g', tm_tag_member_t},
585 {'m', tm_tag_macro_t},
586 {'n', tm_tag_namespace_t},
587 {'s', tm_tag_struct_t},
588 {'t', tm_tag_typedef_t},
589 /* defined as externvar to get those excluded as forward type in symbols.c:goto_tag()
590 * so we can jump to the real implementation (if known) instead of to the import statement */
591 {'x', tm_tag_externvar_t},
594 static TMParserMapEntry map_CPREPROCESSOR[] = {
595 {'d', tm_tag_undef_t},
596 {'h', tm_tag_undef_t},
597 {'D', tm_tag_undef_t},
599 static TMParserMapEntry map_GDSCRIPT[] = {
600 {'c', tm_tag_class_t},
601 {'m', tm_tag_method_t},
602 {'v', tm_tag_variable_t},
603 {'C', tm_tag_variable_t},
604 {'g', tm_tag_enum_t},
605 {'e', tm_tag_variable_t},
606 {'z', tm_tag_other_t},
607 {'l', tm_tag_other_t},
608 {'s', tm_tag_variable_t},
611 typedef struct
613 TMParserMapEntry *entries;
614 guint size;
615 } TMParserMap;
617 #define MAP_ENTRY(lang) [TM_PARSER_##lang] = {map_##lang, G_N_ELEMENTS(map_##lang)}
619 /* keep in sync with TM_PARSER_* definitions in the header */
620 static TMParserMap parser_map[] = {
621 MAP_ENTRY(C),
622 MAP_ENTRY(CPP),
623 MAP_ENTRY(JAVA),
624 MAP_ENTRY(MAKEFILE),
625 MAP_ENTRY(PASCAL),
626 MAP_ENTRY(PERL),
627 MAP_ENTRY(PHP),
628 MAP_ENTRY(PYTHON),
629 MAP_ENTRY(LATEX),
630 MAP_ENTRY(BIBTEX),
631 MAP_ENTRY(ASM),
632 MAP_ENTRY(CONF),
633 MAP_ENTRY(SQL),
634 MAP_ENTRY(DOCBOOK),
635 MAP_ENTRY(ERLANG),
636 MAP_ENTRY(CSS),
637 MAP_ENTRY(RUBY),
638 MAP_ENTRY(TCL),
639 MAP_ENTRY(SH),
640 MAP_ENTRY(D),
641 MAP_ENTRY(FORTRAN),
642 MAP_ENTRY(GDSCRIPT),
643 MAP_ENTRY(DIFF),
644 MAP_ENTRY(VHDL),
645 MAP_ENTRY(LUA),
646 MAP_ENTRY(JAVASCRIPT),
647 MAP_ENTRY(HASKELL),
648 MAP_ENTRY(CSHARP),
649 MAP_ENTRY(FREEBASIC),
650 MAP_ENTRY(HAXE),
651 MAP_ENTRY(REST),
652 MAP_ENTRY(HTML),
653 MAP_ENTRY(F77),
654 MAP_ENTRY(GLSL),
655 MAP_ENTRY(MATLAB),
656 MAP_ENTRY(VALA),
657 MAP_ENTRY(ACTIONSCRIPT),
658 MAP_ENTRY(NSIS),
659 MAP_ENTRY(MARKDOWN),
660 MAP_ENTRY(TXT2TAGS),
661 MAP_ENTRY(ABC),
662 MAP_ENTRY(VERILOG),
663 MAP_ENTRY(R),
664 MAP_ENTRY(COBOL),
665 MAP_ENTRY(OBJC),
666 MAP_ENTRY(ASCIIDOC),
667 MAP_ENTRY(ABAQUS),
668 MAP_ENTRY(RUST),
669 MAP_ENTRY(GO),
670 MAP_ENTRY(JSON),
671 MAP_ENTRY(ZEPHIR),
672 MAP_ENTRY(POWERSHELL),
673 MAP_ENTRY(JULIA),
674 MAP_ENTRY(CPREPROCESSOR),
676 /* make sure the parser map is consistent and complete */
677 G_STATIC_ASSERT(G_N_ELEMENTS(parser_map) == TM_PARSER_COUNT);
680 TMTagType tm_parser_get_tag_type(gchar kind, TMParserType lang)
682 TMParserMap *map = &parser_map[lang];
683 guint i;
685 for (i = 0; i < map->size; i++)
687 TMParserMapEntry *entry = &map->entries[i];
689 if (entry->kind == kind)
690 return entry->type;
692 return tm_tag_undef_t;
696 gchar tm_parser_get_tag_kind(TMTagType type, TMParserType lang)
698 TMParserMap *map = &parser_map[lang];
699 guint i;
701 for (i = 0; i < map->size; i++)
703 TMParserMapEntry *entry = &map->entries[i];
705 if (entry->type == type)
706 return entry->kind;
708 return '\0';
712 static void add_subparser(TMParserType lang, TMParserType sublang, TMSubparserMapEntry *map, guint map_size)
714 guint i;
715 GPtrArray *mapping;
716 GHashTable *lang_map = g_hash_table_lookup(subparser_map, GINT_TO_POINTER(lang));
718 if (!lang_map)
720 lang_map = g_hash_table_new(g_direct_hash, g_direct_equal);
721 g_hash_table_insert(subparser_map, GINT_TO_POINTER(lang), lang_map);
724 mapping = g_ptr_array_new();
725 for (i = 0; i < map_size; i++)
726 g_ptr_array_add(mapping, &map[i]);
728 g_hash_table_insert(lang_map, GINT_TO_POINTER(sublang), mapping);
732 #define SUBPARSER_MAP_ENTRY(lang, sublang, map) add_subparser(TM_PARSER_##lang, TM_PARSER_##sublang, map, G_N_ELEMENTS(map))
734 static void init_subparser_map(void)
736 SUBPARSER_MAP_ENTRY(HTML, JAVASCRIPT, subparser_HTML_javascript_map);
740 TMTagType tm_parser_get_subparser_type(TMParserType lang, TMParserType sublang, TMTagType type)
742 guint i;
743 GHashTable *lang_map;
744 GPtrArray *mapping;
746 if (!subparser_map)
748 subparser_map = g_hash_table_new(g_direct_hash, g_direct_equal);
749 init_subparser_map();
752 lang_map = g_hash_table_lookup(subparser_map, GINT_TO_POINTER(lang));
753 if (!lang_map)
754 return tm_tag_undef_t;
756 mapping = g_hash_table_lookup(lang_map, GINT_TO_POINTER(sublang));
757 if (!mapping)
758 return tm_tag_undef_t;
760 for (i = 0; i < mapping->len; i++)
762 TMSubparserMapEntry *entry = mapping->pdata[i];
763 if (entry->orig_type == type)
764 return entry->new_type;
767 return tm_tag_undef_t;
771 void tm_parser_verify_type_mappings(void)
773 TMParserType lang;
775 if (TM_PARSER_COUNT > tm_ctags_get_lang_count())
776 g_error("More parsers defined in Geany than in ctags");
778 for (lang = 0; lang < TM_PARSER_COUNT; lang++)
780 const gchar *kinds = tm_ctags_get_lang_kinds(lang);
781 TMParserMap *map = &parser_map[lang];
782 gchar presence_map[256];
783 guint i;
785 if (! map->entries || map->size < 1)
786 g_error("No tag types in TM for %s, is the language listed in parser_map?",
787 tm_ctags_get_lang_name(lang));
789 if (map->size != strlen(kinds))
790 g_error("Different number of tag types in TM (%d) and ctags (%d) for %s",
791 map->size, (int)strlen(kinds), tm_ctags_get_lang_name(lang));
793 memset(presence_map, 0, sizeof(presence_map));
794 for (i = 0; i < map->size; i++)
796 gboolean ctags_found = FALSE;
797 gboolean tm_found = FALSE;
798 guint j;
800 for (j = 0; j < map->size; j++)
802 /* check that for every type in TM there's a type in ctags */
803 if (map->entries[i].kind == kinds[j])
804 ctags_found = TRUE;
805 /* check that for every type in ctags there's a type in TM */
806 if (map->entries[j].kind == kinds[i])
807 tm_found = TRUE;
808 if (ctags_found && tm_found)
809 break;
811 if (!ctags_found)
812 g_error("Tag type '%c' found in TM but not in ctags for %s",
813 map->entries[i].kind, tm_ctags_get_lang_name(lang));
814 if (!tm_found)
815 g_error("Tag type '%c' found in ctags but not in TM for %s",
816 kinds[i], tm_ctags_get_lang_name(lang));
818 presence_map[(unsigned char) map->entries[i].kind]++;
821 for (i = 0; i < sizeof(presence_map); i++)
823 if (presence_map[i] > 1)
824 g_error("Duplicate tag type '%c' found for %s",
825 (gchar)i, tm_ctags_get_lang_name(lang));
831 /* When the suffix of 'str' is an operator that should trigger scope
832 * autocompletion, this function should return the length of the operator,
833 * zero otherwise. */
834 gint tm_parser_scope_autocomplete_suffix(TMParserType lang, const gchar *str)
836 const gchar *sep = tm_parser_scope_separator(lang);
838 if (g_str_has_suffix(str, sep))
839 return strlen(sep);
841 switch (lang)
843 case TM_PARSER_C:
844 case TM_PARSER_CPP:
845 if (g_str_has_suffix(str, "."))
846 return 1;
847 else if (g_str_has_suffix(str, "->"))
848 return 2;
849 else if (lang == TM_PARSER_CPP && g_str_has_suffix(str, "->*"))
850 return 3;
851 default:
852 break;
854 return 0;
858 /* Get the name of constructor method. Arguments of this method will be used
859 * for calltips when creating an object using the class name
860 * (e.g. after the opening brace in 'c = MyClass()' in Python) */
861 const gchar *tm_parser_get_constructor_method(TMParserType lang)
863 switch (lang)
865 case TM_PARSER_D:
866 return "this";
867 case TM_PARSER_PYTHON:
868 return "__init__";
869 default:
870 return NULL;
875 /* determine anonymous tags from tag names only when corresponding
876 * ctags information is not available */
877 gboolean tm_parser_is_anon_name(TMParserType lang, gchar *name)
879 guint i;
880 char dummy;
882 if (sscanf(name, "__anon%u%c", &i, &dummy) == 1) /* uctags tags files */
883 return TRUE;
884 else if (lang == TM_PARSER_C || lang == TM_PARSER_CPP) /* legacy Geany tags files */
885 return sscanf(name, "anon_%*[a-z]_%u%c", &i, &dummy) == 1;
886 else if (lang == TM_PARSER_FORTRAN || lang == TM_PARSER_F77) /* legacy Geany tags files */
888 return sscanf(name, "Structure#%u%c", &i, &dummy) == 1 ||
889 sscanf(name, "Interface#%u%c", &i, &dummy) == 1 ||
890 sscanf(name, "Enum#%u%c", &i, &dummy) == 1;
892 return FALSE;
896 static gchar *replace_string_if_present(gchar *haystack, gchar *needle, gchar *subst)
898 if (strstr(haystack, needle))
900 gchar **split = g_strsplit(haystack, needle, -1);
901 gchar *ret = g_strjoinv(subst, split);
902 g_strfreev(split);
903 return ret;
905 return haystack;
909 /* return updated scope or original scope if no change needed */
910 gchar *tm_parser_update_scope(TMParserType lang, gchar *scope)
912 switch (lang)
914 case TM_PARSER_PHP:
915 case TM_PARSER_ZEPHIR:
916 /* PHP parser uses two different scope separators but this would
917 * complicate things in Geany so make sure there's just one type */
918 return replace_string_if_present(scope, "\\", "::");
920 return scope;
924 /* whether or not to enable ctags roles for the given language and kind */
925 gboolean tm_parser_enable_role(TMParserType lang, gchar kind)
927 switch (lang)
929 case TM_PARSER_GDSCRIPT:
930 return kind == 'c' ? FALSE : TRUE;
931 case TM_PARSER_GO:
932 /* 'p' is used both for package definition tags and imported package
933 * tags and we can't tell which is which just by kind. By disabling
934 * roles for this kind, we only get package definition tags. */
935 return kind == 'p' ? FALSE : TRUE;
937 return TRUE;
941 /* whether or not to enable ctags kinds for the given language */
942 gboolean tm_parser_enable_kind(TMParserType lang, gchar kind)
944 TMParserMap *map;
945 guint i;
947 if (lang >= TM_PARSER_COUNT)
948 /* Fatal error but tm_parser_verify_type_mappings() will provide
949 * better message later */
950 return FALSE;
952 map = &parser_map[lang];
953 for (i = 0; i < map->size; i++)
955 if (map->entries[i].kind == kind)
956 return map->entries[i].type != tm_tag_undef_t;
958 return FALSE;
962 gchar *tm_parser_format_variable(TMParserType lang, const gchar *name, const gchar *type)
964 if (!type)
965 return NULL;
967 switch (lang)
969 case TM_PARSER_GO:
970 return g_strconcat(name, " ", type, NULL);
971 case TM_PARSER_PASCAL:
972 case TM_PARSER_PYTHON:
973 return g_strconcat(name, ": ", type, NULL);
974 default:
975 return g_strconcat(type, " ", name, NULL);
980 gchar *tm_parser_format_function(TMParserType lang, const gchar *fname, const gchar *args,
981 const gchar *retval, const gchar *scope)
983 GString *str;
985 if (!args) /* not a function */
986 return NULL;
988 str = g_string_new(NULL);
990 if (scope)
992 g_string_append(str, scope);
993 g_string_append(str, tm_parser_scope_separator_printable(lang));
995 g_string_append(str, fname);
996 g_string_append_c(str, ' ');
997 g_string_append(str, args);
999 if (retval)
1001 switch (lang)
1003 case TM_PARSER_GDSCRIPT:
1004 case TM_PARSER_GO:
1005 case TM_PARSER_PASCAL:
1006 case TM_PARSER_PYTHON:
1008 /* retval after function */
1009 const gchar *sep;
1010 switch (lang)
1012 case TM_PARSER_PASCAL:
1013 sep = ": ";
1014 break;
1015 case TM_PARSER_GDSCRIPT:
1016 case TM_PARSER_PYTHON:
1017 sep = " -> ";
1018 break;
1019 default:
1020 sep = " ";
1021 break;
1023 g_string_append(str, sep);
1024 g_string_append(str, retval);
1025 break;
1027 default:
1028 /* retval before function */
1029 g_string_prepend_c(str, ' ');
1030 g_string_prepend(str, retval);
1031 break;
1035 return g_string_free(str, FALSE);
1039 const gchar *tm_parser_scope_separator(TMParserType lang)
1041 switch (lang)
1043 case TM_PARSER_C: /* for C++ .h headers or C structs */
1044 case TM_PARSER_CPP:
1045 case TM_PARSER_GLSL: /* for structs */
1046 case TM_PARSER_PHP:
1047 case TM_PARSER_POWERSHELL:
1048 case TM_PARSER_RUST:
1049 case TM_PARSER_ZEPHIR:
1050 return "::";
1052 case TM_PARSER_TXT2TAGS:
1053 return "\"\"";
1055 /* these parsers don't report nested scopes but default "." for scope separator
1056 * might appear in the text so use something more improbable */
1057 case TM_PARSER_ASCIIDOC:
1058 case TM_PARSER_CONF:
1059 case TM_PARSER_REST:
1060 return "\x3";
1062 default:
1063 return ".";
1068 const gchar *tm_parser_scope_separator_printable(TMParserType lang)
1070 switch (lang)
1072 case TM_PARSER_TXT2TAGS:
1073 case TM_PARSER_ASCIIDOC:
1074 case TM_PARSER_CONF:
1075 case TM_PARSER_REST:
1076 return " > ";
1078 default:
1079 return tm_parser_scope_separator(lang);
1084 gboolean tm_parser_has_full_scope(TMParserType lang)
1086 switch (lang)
1088 /* These parsers include full hierarchy in the tag scope, separated by tm_parser_scope_separator() */
1089 case TM_PARSER_ACTIONSCRIPT:
1090 case TM_PARSER_C:
1091 case TM_PARSER_CPP:
1092 case TM_PARSER_CSHARP:
1093 case TM_PARSER_COBOL:
1094 case TM_PARSER_D:
1095 case TM_PARSER_GDSCRIPT:
1096 case TM_PARSER_GLSL:
1097 case TM_PARSER_GO:
1098 case TM_PARSER_JAVA:
1099 case TM_PARSER_JAVASCRIPT:
1100 case TM_PARSER_JSON:
1101 case TM_PARSER_LUA:
1102 case TM_PARSER_PHP:
1103 case TM_PARSER_POWERSHELL:
1104 case TM_PARSER_PYTHON:
1105 case TM_PARSER_RUBY:
1106 case TM_PARSER_RUST:
1107 case TM_PARSER_SQL:
1108 case TM_PARSER_TXT2TAGS:
1109 case TM_PARSER_VALA:
1110 case TM_PARSER_ZEPHIR:
1111 return TRUE;
1113 /* These make use of the scope, but don't include nested hierarchy
1114 * (either as a parser limitation or a language semantic) */
1115 case TM_PARSER_ASCIIDOC:
1116 case TM_PARSER_CONF:
1117 case TM_PARSER_ERLANG:
1118 case TM_PARSER_F77:
1119 case TM_PARSER_FORTRAN:
1120 case TM_PARSER_OBJC:
1121 case TM_PARSER_REST:
1122 /* Other parsers don't use scope at all (or should be somewhere above) */
1123 default:
1124 return FALSE;
1129 gboolean tm_parser_langs_compatible(TMParserType lang, TMParserType other)
1131 if (lang == TM_PARSER_NONE || other == TM_PARSER_NONE)
1132 return FALSE;
1133 if (lang == other)
1134 return TRUE;
1135 /* Accept CPP tags for C lang and vice versa */
1136 else if (lang == TM_PARSER_C && other == TM_PARSER_CPP)
1137 return TRUE;
1138 else if (lang == TM_PARSER_CPP && other == TM_PARSER_C)
1139 return TRUE;
1141 return FALSE;