Merge pull request #3035 from techee/different_parsers
[geany-mirror.git] / src / tagmanager / tm_parser.c
bloba1bc1d1f7872fd4d30e3d5cd60467ad097ed0759
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 {'a', tm_tag_undef_t},
257 {'f', tm_tag_function_t},
258 {'s', tm_tag_undef_t},
259 {'h', tm_tag_undef_t},
262 static TMParserMapEntry map_D[] = {
263 {'c', tm_tag_class_t},
264 {'e', tm_tag_enumerator_t},
265 {'f', tm_tag_function_t},
266 {'g', tm_tag_enum_t},
267 {'i', tm_tag_interface_t},
268 {'m', tm_tag_member_t},
269 {'n', tm_tag_namespace_t},
270 {'p', tm_tag_prototype_t},
271 {'s', tm_tag_struct_t},
272 {'t', tm_tag_typedef_t},
273 {'u', tm_tag_union_t},
274 {'v', tm_tag_variable_t},
275 {'x', tm_tag_externvar_t},
278 static TMParserMapEntry map_DIFF[] = {
279 {'m', tm_tag_function_t},
280 {'n', tm_tag_function_t},
281 {'d', tm_tag_function_t},
282 {'h', tm_tag_undef_t},
285 /* different parser than in universal-ctags */
286 static TMParserMapEntry map_VHDL[] = {
287 {'c', tm_tag_variable_t},
288 {'t', tm_tag_typedef_t},
289 {'v', tm_tag_variable_t},
290 {'a', tm_tag_undef_t},
291 {'s', tm_tag_variable_t},
292 {'f', tm_tag_function_t},
293 {'p', tm_tag_function_t},
294 {'k', tm_tag_member_t},
295 {'l', tm_tag_namespace_t},
296 {'m', tm_tag_member_t},
297 {'n', tm_tag_class_t},
298 {'o', tm_tag_struct_t},
299 {'u', tm_tag_undef_t},
300 {'b', tm_tag_member_t},
301 {'A', tm_tag_typedef_t},
304 static TMParserMapEntry map_LUA[] = {
305 {'f', tm_tag_function_t},
306 {'X', tm_tag_undef_t},
309 static TMParserMapEntry map_JAVASCRIPT[] = {
310 {'f', tm_tag_function_t},
311 {'c', tm_tag_class_t},
312 {'m', tm_tag_method_t},
313 {'p', tm_tag_member_t},
314 {'C', tm_tag_macro_t},
315 {'v', tm_tag_variable_t},
316 {'g', tm_tag_function_t},
317 {'G', tm_tag_undef_t},
318 {'S', tm_tag_undef_t},
319 {'M', tm_tag_undef_t},
322 static TMParserMapEntry map_HASKELL[] = {
323 {'t', tm_tag_typedef_t},
324 {'c', tm_tag_macro_t},
325 {'f', tm_tag_function_t},
326 {'m', tm_tag_namespace_t},
329 static TMParserMapEntry map_CSHARP[] = {
330 {'c', tm_tag_class_t},
331 {'d', tm_tag_macro_t},
332 {'e', tm_tag_enumerator_t},
333 {'E', tm_tag_undef_t},
334 {'f', tm_tag_field_t},
335 {'g', tm_tag_enum_t},
336 {'i', tm_tag_interface_t},
337 {'l', tm_tag_undef_t},
338 {'m', tm_tag_method_t},
339 {'n', tm_tag_namespace_t},
340 {'p', tm_tag_undef_t},
341 {'s', tm_tag_struct_t},
342 {'t', tm_tag_typedef_t},
345 static TMParserMapEntry map_FREEBASIC[] = {
346 {'c', tm_tag_macro_t},
347 {'f', tm_tag_function_t},
348 {'l', tm_tag_namespace_t},
349 {'t', tm_tag_struct_t},
350 {'v', tm_tag_variable_t},
351 {'g', tm_tag_externvar_t},
354 static TMParserMapEntry map_HAXE[] = {
355 {'m', tm_tag_method_t},
356 {'c', tm_tag_class_t},
357 {'e', tm_tag_enum_t},
358 {'v', tm_tag_variable_t},
359 {'i', tm_tag_interface_t},
360 {'t', tm_tag_typedef_t},
363 static TMParserMapEntry map_REST[] = {
364 {'c', tm_tag_namespace_t},
365 {'s', tm_tag_member_t},
366 {'S', tm_tag_macro_t},
367 {'t', tm_tag_variable_t},
368 {'C', tm_tag_undef_t},
369 {'T', tm_tag_undef_t},
370 {'d', tm_tag_undef_t},
373 static TMParserMapEntry map_HTML[] = {
374 {'a', tm_tag_member_t},
375 {'c', tm_tag_undef_t},
376 {'h', tm_tag_namespace_t},
377 {'i', tm_tag_class_t},
378 {'j', tm_tag_variable_t},
379 {'C', tm_tag_undef_t},
380 {'I', tm_tag_undef_t},
381 {'J', tm_tag_undef_t},
384 static TMSubparserMapEntry subparser_HTML_javascript_map[] = {
385 {tm_tag_function_t, tm_tag_function_t},
388 static TMParserMapEntry map_F77[] = {
389 {'b', tm_tag_undef_t},
390 {'c', tm_tag_macro_t},
391 {'e', tm_tag_undef_t},
392 {'f', tm_tag_function_t},
393 {'i', tm_tag_interface_t},
394 {'k', tm_tag_member_t},
395 {'l', tm_tag_undef_t},
396 {'L', tm_tag_undef_t},
397 {'m', tm_tag_namespace_t},
398 {'n', tm_tag_undef_t},
399 {'p', tm_tag_struct_t},
400 {'s', tm_tag_method_t},
401 {'t', tm_tag_class_t},
402 {'v', tm_tag_variable_t},
403 {'E', tm_tag_enum_t},
404 {'N', tm_tag_enumerator_t},
407 #define map_FORTRAN map_F77
409 /* different parser than in universal-ctags */
410 static TMParserMapEntry map_MATLAB[] = {
411 {'f', tm_tag_function_t},
412 {'s', tm_tag_struct_t},
415 #define map_CUDA map_C
417 /* not in universal-ctags */
418 static TMParserMapEntry map_VALA[] = {
419 {'c', tm_tag_class_t},
420 {'d', tm_tag_macro_t},
421 {'e', tm_tag_enumerator_t},
422 {'f', tm_tag_field_t},
423 {'g', tm_tag_enum_t},
424 {'i', tm_tag_interface_t},
425 {'l', tm_tag_undef_t},
426 {'m', tm_tag_method_t},
427 {'n', tm_tag_namespace_t},
428 {'p', tm_tag_undef_t},
429 {'S', tm_tag_undef_t},
430 {'s', tm_tag_struct_t},
433 /* not in universal-ctags */
434 static TMParserMapEntry map_ACTIONSCRIPT[] = {
435 {'f', tm_tag_function_t},
436 {'c', tm_tag_class_t},
437 {'i', tm_tag_interface_t},
438 {'P', tm_tag_package_t},
439 {'m', tm_tag_method_t},
440 {'p', tm_tag_member_t},
441 {'v', tm_tag_variable_t},
442 {'l', tm_tag_variable_t},
443 {'C', tm_tag_macro_t},
444 {'I', tm_tag_externvar_t},
445 {'x', tm_tag_other_t},
448 static TMParserMapEntry map_NSIS[] = {
449 {'s', tm_tag_namespace_t},
450 {'f', tm_tag_function_t},
451 {'v', tm_tag_variable_t},
452 {'d', tm_tag_undef_t},
453 {'m', tm_tag_undef_t},
454 {'S', tm_tag_undef_t},
455 {'p', tm_tag_undef_t},
456 {'l', tm_tag_undef_t},
457 {'i', tm_tag_undef_t},
460 /* not in universal-ctags */
461 static TMParserMapEntry map_MARKDOWN[] = {
462 {'v', tm_tag_variable_t},
465 static TMParserMapEntry map_TXT2TAGS[] = {
466 {'s', tm_tag_member_t},
469 static TMParserMapEntry map_ABC[] = {
470 {'s', tm_tag_member_t},
473 static TMParserMapEntry map_VERILOG[] = {
474 {'c', tm_tag_variable_t},
475 {'e', tm_tag_typedef_t},
476 {'f', tm_tag_function_t},
477 {'m', tm_tag_class_t},
478 {'n', tm_tag_variable_t},
479 {'p', tm_tag_variable_t},
480 {'r', tm_tag_variable_t},
481 {'t', tm_tag_function_t},
482 {'b', tm_tag_undef_t},
483 {'i', tm_tag_undef_t},
486 static TMParserMapEntry map_R[] = {
487 {'f', tm_tag_function_t},
488 {'l', tm_tag_other_t},
489 {'s', tm_tag_other_t},
490 {'g', tm_tag_undef_t},
491 {'v', tm_tag_undef_t},
492 {'z', tm_tag_undef_t},
493 {'c', tm_tag_undef_t},
494 {'L', tm_tag_undef_t},
495 {'d', tm_tag_undef_t},
496 {'n', tm_tag_undef_t},
499 static TMParserMapEntry map_COBOL[] = {
500 {'d', tm_tag_variable_t},
501 {'D', tm_tag_interface_t},
502 {'f', tm_tag_function_t},
503 {'g', tm_tag_struct_t},
504 {'p', tm_tag_macro_t},
505 {'P', tm_tag_class_t},
506 {'s', tm_tag_namespace_t},
507 {'S', tm_tag_externvar_t},
510 static TMParserMapEntry map_OBJC[] = {
511 {'i', tm_tag_interface_t},
512 {'I', tm_tag_undef_t},
513 {'P', tm_tag_undef_t},
514 {'m', tm_tag_method_t},
515 {'c', tm_tag_class_t},
516 {'v', tm_tag_variable_t},
517 {'E', tm_tag_field_t},
518 {'f', tm_tag_function_t},
519 {'p', tm_tag_undef_t},
520 {'t', tm_tag_typedef_t},
521 {'s', tm_tag_struct_t},
522 {'e', tm_tag_enum_t},
523 {'M', tm_tag_macro_t},
524 {'C', tm_tag_undef_t},
527 static TMParserMapEntry map_ASCIIDOC[] = {
528 {'c', tm_tag_namespace_t},
529 {'s', tm_tag_member_t},
530 {'S', tm_tag_macro_t},
531 {'t', tm_tag_variable_t},
532 {'T', tm_tag_struct_t},
533 {'u', tm_tag_undef_t},
534 {'a', tm_tag_undef_t},
537 static TMParserMapEntry map_ABAQUS[] = {
538 {'p', tm_tag_class_t},
539 {'a', tm_tag_member_t},
540 {'s', tm_tag_interface_t},
543 static TMParserMapEntry map_RUST[] = {
544 {'n', tm_tag_namespace_t},
545 {'s', tm_tag_struct_t},
546 {'i', tm_tag_interface_t},
547 {'c', tm_tag_class_t},
548 {'f', tm_tag_function_t},
549 {'g', tm_tag_enum_t},
550 {'t', tm_tag_typedef_t},
551 {'v', tm_tag_variable_t},
552 {'M', tm_tag_macro_t},
553 {'m', tm_tag_field_t},
554 {'e', tm_tag_enumerator_t},
555 {'P', tm_tag_method_t},
558 static TMParserMapEntry map_GO[] = {
559 {'p', tm_tag_namespace_t},
560 {'f', tm_tag_function_t},
561 {'c', tm_tag_macro_t},
562 {'t', tm_tag_typedef_t},
563 {'v', tm_tag_variable_t},
564 {'s', tm_tag_struct_t},
565 {'i', tm_tag_interface_t},
566 {'m', tm_tag_member_t},
567 {'M', tm_tag_undef_t},
568 {'n', tm_tag_undef_t},
569 {'u', tm_tag_undef_t},
570 {'P', tm_tag_undef_t},
571 {'a', tm_tag_undef_t},
572 {'R', tm_tag_undef_t},
575 static TMParserMapEntry map_JSON[] = {
576 {'o', tm_tag_member_t},
577 {'a', tm_tag_member_t},
578 {'n', tm_tag_member_t},
579 {'s', tm_tag_member_t},
580 {'b', tm_tag_member_t},
581 {'z', tm_tag_member_t},
584 /* Zephir, same as PHP */
585 #define map_ZEPHIR map_PHP
587 /* not in universal-ctags */
588 static TMParserMapEntry map_POWERSHELL[] = {
589 {'f', tm_tag_function_t},
590 {'v', tm_tag_variable_t},
593 static TMParserMapEntry map_JULIA[] = {
594 {'c', tm_tag_variable_t},
595 {'f', tm_tag_function_t},
596 {'g', tm_tag_member_t},
597 {'m', tm_tag_macro_t},
598 {'n', tm_tag_namespace_t},
599 {'s', tm_tag_struct_t},
600 {'t', tm_tag_typedef_t},
601 /* defined as externvar to get those excluded as forward type in symbols.c:goto_tag()
602 * so we can jump to the real implementation (if known) instead of to the import statement */
603 {'x', tm_tag_externvar_t},
606 static TMParserMapEntry map_CPREPROCESSOR[] = {
607 {'d', tm_tag_undef_t},
608 {'h', tm_tag_undef_t},
609 {'D', tm_tag_undef_t},
611 static TMParserMapEntry map_GDSCRIPT[] = {
612 {'c', tm_tag_class_t},
613 {'m', tm_tag_method_t},
614 {'v', tm_tag_variable_t},
615 {'C', tm_tag_variable_t},
616 {'g', tm_tag_enum_t},
617 {'e', tm_tag_variable_t},
618 {'z', tm_tag_other_t},
619 {'l', tm_tag_other_t},
620 {'s', tm_tag_variable_t},
623 typedef struct
625 TMParserMapEntry *entries;
626 guint size;
627 } TMParserMap;
629 #define MAP_ENTRY(lang) [TM_PARSER_##lang] = {map_##lang, G_N_ELEMENTS(map_##lang)}
631 /* keep in sync with TM_PARSER_* definitions in the header */
632 static TMParserMap parser_map[] = {
633 MAP_ENTRY(C),
634 MAP_ENTRY(CPP),
635 MAP_ENTRY(JAVA),
636 MAP_ENTRY(MAKEFILE),
637 MAP_ENTRY(PASCAL),
638 MAP_ENTRY(PERL),
639 MAP_ENTRY(PHP),
640 MAP_ENTRY(PYTHON),
641 MAP_ENTRY(LATEX),
642 MAP_ENTRY(BIBTEX),
643 MAP_ENTRY(ASM),
644 MAP_ENTRY(CONF),
645 MAP_ENTRY(SQL),
646 MAP_ENTRY(DOCBOOK),
647 MAP_ENTRY(ERLANG),
648 MAP_ENTRY(CSS),
649 MAP_ENTRY(RUBY),
650 MAP_ENTRY(TCL),
651 MAP_ENTRY(SH),
652 MAP_ENTRY(D),
653 MAP_ENTRY(FORTRAN),
654 MAP_ENTRY(GDSCRIPT),
655 MAP_ENTRY(DIFF),
656 MAP_ENTRY(VHDL),
657 MAP_ENTRY(LUA),
658 MAP_ENTRY(JAVASCRIPT),
659 MAP_ENTRY(HASKELL),
660 MAP_ENTRY(CSHARP),
661 MAP_ENTRY(FREEBASIC),
662 MAP_ENTRY(HAXE),
663 MAP_ENTRY(REST),
664 MAP_ENTRY(HTML),
665 MAP_ENTRY(F77),
666 MAP_ENTRY(CUDA),
667 MAP_ENTRY(MATLAB),
668 MAP_ENTRY(VALA),
669 MAP_ENTRY(ACTIONSCRIPT),
670 MAP_ENTRY(NSIS),
671 MAP_ENTRY(MARKDOWN),
672 MAP_ENTRY(TXT2TAGS),
673 MAP_ENTRY(ABC),
674 MAP_ENTRY(VERILOG),
675 MAP_ENTRY(R),
676 MAP_ENTRY(COBOL),
677 MAP_ENTRY(OBJC),
678 MAP_ENTRY(ASCIIDOC),
679 MAP_ENTRY(ABAQUS),
680 MAP_ENTRY(RUST),
681 MAP_ENTRY(GO),
682 MAP_ENTRY(JSON),
683 MAP_ENTRY(ZEPHIR),
684 MAP_ENTRY(POWERSHELL),
685 MAP_ENTRY(JULIA),
686 MAP_ENTRY(CPREPROCESSOR),
688 /* make sure the parser map is consistent and complete */
689 G_STATIC_ASSERT(G_N_ELEMENTS(parser_map) == TM_PARSER_COUNT);
692 TMTagType tm_parser_get_tag_type(gchar kind, TMParserType lang)
694 TMParserMap *map = &parser_map[lang];
695 guint i;
697 for (i = 0; i < map->size; i++)
699 TMParserMapEntry *entry = &map->entries[i];
701 if (entry->kind == kind)
702 return entry->type;
704 return tm_tag_undef_t;
708 gchar tm_parser_get_tag_kind(TMTagType type, TMParserType lang)
710 TMParserMap *map = &parser_map[lang];
711 guint i;
713 for (i = 0; i < map->size; i++)
715 TMParserMapEntry *entry = &map->entries[i];
717 if (entry->type == type)
718 return entry->kind;
720 return '\0';
724 static void add_subparser(TMParserType lang, TMParserType sublang, TMSubparserMapEntry *map, guint map_size)
726 guint i;
727 GPtrArray *mapping;
728 GHashTable *lang_map = g_hash_table_lookup(subparser_map, GINT_TO_POINTER(lang));
730 if (!lang_map)
732 lang_map = g_hash_table_new(g_direct_hash, g_direct_equal);
733 g_hash_table_insert(subparser_map, GINT_TO_POINTER(lang), lang_map);
736 mapping = g_ptr_array_new();
737 for (i = 0; i < map_size; i++)
738 g_ptr_array_add(mapping, &map[i]);
740 g_hash_table_insert(lang_map, GINT_TO_POINTER(sublang), mapping);
744 #define SUBPARSER_MAP_ENTRY(lang, sublang, map) add_subparser(TM_PARSER_##lang, TM_PARSER_##sublang, map, G_N_ELEMENTS(map))
746 static void init_subparser_map(void)
748 SUBPARSER_MAP_ENTRY(HTML, JAVASCRIPT, subparser_HTML_javascript_map);
752 TMTagType tm_parser_get_subparser_type(TMParserType lang, TMParserType sublang, TMTagType type)
754 guint i;
755 GHashTable *lang_map;
756 GPtrArray *mapping;
758 if (!subparser_map)
760 subparser_map = g_hash_table_new(g_direct_hash, g_direct_equal);
761 init_subparser_map();
764 lang_map = g_hash_table_lookup(subparser_map, GINT_TO_POINTER(lang));
765 if (!lang_map)
766 return tm_tag_undef_t;
768 mapping = g_hash_table_lookup(lang_map, GINT_TO_POINTER(sublang));
769 if (!mapping)
770 return tm_tag_undef_t;
772 for (i = 0; i < mapping->len; i++)
774 TMSubparserMapEntry *entry = mapping->pdata[i];
775 if (entry->orig_type == type)
776 return entry->new_type;
779 return tm_tag_undef_t;
783 void tm_parser_verify_type_mappings(void)
785 TMParserType lang;
787 if (TM_PARSER_COUNT > tm_ctags_get_lang_count())
788 g_error("More parsers defined in Geany than in ctags");
790 for (lang = 0; lang < TM_PARSER_COUNT; lang++)
792 const gchar *kinds = tm_ctags_get_lang_kinds(lang);
793 TMParserMap *map = &parser_map[lang];
794 gchar presence_map[256];
795 guint i;
797 if (! map->entries || map->size < 1)
798 g_error("No tag types in TM for %s, is the language listed in parser_map?",
799 tm_ctags_get_lang_name(lang));
801 if (map->size != strlen(kinds))
802 g_error("Different number of tag types in TM (%d) and ctags (%d) for %s",
803 map->size, (int)strlen(kinds), tm_ctags_get_lang_name(lang));
805 memset(presence_map, 0, sizeof(presence_map));
806 for (i = 0; i < map->size; i++)
808 gboolean ctags_found = FALSE;
809 gboolean tm_found = FALSE;
810 guint j;
812 for (j = 0; j < map->size; j++)
814 /* check that for every type in TM there's a type in ctags */
815 if (map->entries[i].kind == kinds[j])
816 ctags_found = TRUE;
817 /* check that for every type in ctags there's a type in TM */
818 if (map->entries[j].kind == kinds[i])
819 tm_found = TRUE;
820 if (ctags_found && tm_found)
821 break;
823 if (!ctags_found)
824 g_error("Tag type '%c' found in TM but not in ctags for %s",
825 map->entries[i].kind, tm_ctags_get_lang_name(lang));
826 if (!tm_found)
827 g_error("Tag type '%c' found in ctags but not in TM for %s",
828 kinds[i], tm_ctags_get_lang_name(lang));
830 presence_map[(unsigned char) map->entries[i].kind]++;
833 for (i = 0; i < sizeof(presence_map); i++)
835 if (presence_map[i] > 1)
836 g_error("Duplicate tag type '%c' found for %s",
837 (gchar)i, tm_ctags_get_lang_name(lang));
843 /* When the suffix of 'str' is an operator that should trigger scope
844 * autocompletion, this function should return the length of the operator,
845 * zero otherwise. */
846 gint tm_parser_scope_autocomplete_suffix(TMParserType lang, const gchar *str)
848 const gchar *sep = tm_parser_scope_separator(lang);
850 if (g_str_has_suffix(str, sep))
851 return strlen(sep);
853 switch (lang)
855 case TM_PARSER_C:
856 case TM_PARSER_CPP:
857 if (g_str_has_suffix(str, "."))
858 return 1;
859 else if (g_str_has_suffix(str, "->"))
860 return 2;
861 else if (lang == TM_PARSER_CPP && g_str_has_suffix(str, "->*"))
862 return 3;
863 default:
864 break;
866 return 0;
870 /* Get the name of constructor method. Arguments of this method will be used
871 * for calltips when creating an object using the class name
872 * (e.g. after the opening brace in 'c = MyClass()' in Python) */
873 const gchar *tm_parser_get_constructor_method(TMParserType lang)
875 switch (lang)
877 case TM_PARSER_D:
878 return "this";
879 case TM_PARSER_PYTHON:
880 return "__init__";
881 default:
882 return NULL;
887 /* determine anonymous tags from tag names only when corresponding
888 * ctags information is not available */
889 gboolean tm_parser_is_anon_name(TMParserType lang, gchar *name)
891 guint i;
892 char dummy;
894 if (sscanf(name, "__anon%u%c", &i, &dummy) == 1) /* uctags tags files */
895 return TRUE;
896 else if (lang == TM_PARSER_C || lang == TM_PARSER_CPP) /* legacy Geany tags files */
897 return sscanf(name, "anon_%*[a-z]_%u%c", &i, &dummy) == 1;
898 else if (lang == TM_PARSER_FORTRAN || lang == TM_PARSER_F77) /* legacy Geany tags files */
900 return sscanf(name, "Structure#%u%c", &i, &dummy) == 1 ||
901 sscanf(name, "Interface#%u%c", &i, &dummy) == 1 ||
902 sscanf(name, "Enum#%u%c", &i, &dummy) == 1;
904 return FALSE;
908 static gchar *replace_string_if_present(gchar *haystack, gchar *needle, gchar *subst)
910 if (strstr(haystack, needle))
912 gchar **split = g_strsplit(haystack, needle, -1);
913 gchar *ret = g_strjoinv(subst, split);
914 g_strfreev(split);
915 return ret;
917 return haystack;
921 /* return updated scope or original scope if no change needed */
922 gchar *tm_parser_update_scope(TMParserType lang, gchar *scope)
924 switch (lang)
926 case TM_PARSER_PHP:
927 case TM_PARSER_ZEPHIR:
928 /* PHP parser uses two different scope separators but this would
929 * complicate things in Geany so make sure there's just one type */
930 return replace_string_if_present(scope, "\\", "::");
932 return scope;
936 /* whether or not to enable ctags roles for the given language and kind */
937 gboolean tm_parser_enable_role(TMParserType lang, gchar kind)
939 switch (lang)
941 case TM_PARSER_GDSCRIPT:
942 return kind == 'c' ? FALSE : TRUE;
943 case TM_PARSER_GO:
944 /* 'p' is used both for package definition tags and imported package
945 * tags and we can't tell which is which just by kind. By disabling
946 * roles for this kind, we only get package definition tags. */
947 return kind == 'p' ? FALSE : TRUE;
949 return TRUE;
953 /* whether or not to enable ctags kinds for the given language */
954 gboolean tm_parser_enable_kind(TMParserType lang, gchar kind)
956 TMParserMap *map;
957 guint i;
959 if (lang >= TM_PARSER_COUNT)
960 /* Fatal error but tm_parser_verify_type_mappings() will provide
961 * better message later */
962 return FALSE;
964 map = &parser_map[lang];
965 for (i = 0; i < map->size; i++)
967 if (map->entries[i].kind == kind)
968 return map->entries[i].type != tm_tag_undef_t;
970 return FALSE;
974 gchar *tm_parser_format_variable(TMParserType lang, const gchar *name, const gchar *type)
976 if (!type)
977 return NULL;
979 switch (lang)
981 case TM_PARSER_GO:
982 return g_strconcat(name, " ", type, NULL);
983 case TM_PARSER_PASCAL:
984 case TM_PARSER_PYTHON:
985 return g_strconcat(name, ": ", type, NULL);
986 default:
987 return g_strconcat(type, " ", name, NULL);
992 gchar *tm_parser_format_function(TMParserType lang, const gchar *fname, const gchar *args,
993 const gchar *retval, const gchar *scope)
995 GString *str;
997 if (!args) /* not a function */
998 return NULL;
1000 str = g_string_new(NULL);
1002 if (scope)
1004 g_string_append(str, scope);
1005 g_string_append(str, tm_parser_scope_separator_printable(lang));
1007 g_string_append(str, fname);
1008 g_string_append_c(str, ' ');
1009 g_string_append(str, args);
1011 if (retval)
1013 switch (lang)
1015 case TM_PARSER_GDSCRIPT:
1016 case TM_PARSER_GO:
1017 case TM_PARSER_PASCAL:
1018 case TM_PARSER_PYTHON:
1020 /* retval after function */
1021 const gchar *sep;
1022 switch (lang)
1024 case TM_PARSER_PASCAL:
1025 sep = ": ";
1026 break;
1027 case TM_PARSER_GDSCRIPT:
1028 case TM_PARSER_PYTHON:
1029 sep = " -> ";
1030 break;
1031 default:
1032 sep = " ";
1033 break;
1035 g_string_append(str, sep);
1036 g_string_append(str, retval);
1037 break;
1039 default:
1040 /* retval before function */
1041 g_string_prepend_c(str, ' ');
1042 g_string_prepend(str, retval);
1043 break;
1047 return g_string_free(str, FALSE);
1051 const gchar *tm_parser_scope_separator(TMParserType lang)
1053 switch (lang)
1055 case TM_PARSER_C: /* for C++ .h headers or C structs */
1056 case TM_PARSER_CPP:
1057 case TM_PARSER_CUDA:
1058 case TM_PARSER_PHP:
1059 case TM_PARSER_POWERSHELL:
1060 case TM_PARSER_RUST:
1061 case TM_PARSER_ZEPHIR:
1062 return "::";
1064 case TM_PARSER_TXT2TAGS:
1065 return "\"\"";
1067 /* these parsers don't report nested scopes but default "." for scope separator
1068 * might appear in the text so use something more improbable */
1069 case TM_PARSER_ASCIIDOC:
1070 case TM_PARSER_CONF:
1071 case TM_PARSER_REST:
1072 return "\x3";
1074 default:
1075 return ".";
1080 const gchar *tm_parser_scope_separator_printable(TMParserType lang)
1082 switch (lang)
1084 case TM_PARSER_TXT2TAGS:
1085 case TM_PARSER_ASCIIDOC:
1086 case TM_PARSER_CONF:
1087 case TM_PARSER_REST:
1088 return " > ";
1090 default:
1091 return tm_parser_scope_separator(lang);
1096 gboolean tm_parser_has_full_scope(TMParserType lang)
1098 switch (lang)
1100 /* These parsers include full hierarchy in the tag scope, separated by tm_parser_scope_separator() */
1101 case TM_PARSER_ACTIONSCRIPT:
1102 case TM_PARSER_C:
1103 case TM_PARSER_CPP:
1104 case TM_PARSER_CUDA:
1105 case TM_PARSER_CSHARP:
1106 case TM_PARSER_COBOL:
1107 case TM_PARSER_D:
1108 case TM_PARSER_GDSCRIPT:
1109 case TM_PARSER_GO:
1110 case TM_PARSER_JAVA:
1111 case TM_PARSER_JAVASCRIPT:
1112 case TM_PARSER_JSON:
1113 case TM_PARSER_LUA:
1114 case TM_PARSER_PHP:
1115 case TM_PARSER_POWERSHELL:
1116 case TM_PARSER_PYTHON:
1117 case TM_PARSER_R:
1118 case TM_PARSER_RUBY:
1119 case TM_PARSER_RUST:
1120 case TM_PARSER_SQL:
1121 case TM_PARSER_TXT2TAGS:
1122 case TM_PARSER_VALA:
1123 case TM_PARSER_VERILOG:
1124 case TM_PARSER_ZEPHIR:
1125 return TRUE;
1127 /* These make use of the scope, but don't include nested hierarchy
1128 * (either as a parser limitation or a language semantic) */
1129 case TM_PARSER_ASCIIDOC:
1130 case TM_PARSER_CONF:
1131 case TM_PARSER_ERLANG:
1132 case TM_PARSER_F77:
1133 case TM_PARSER_FORTRAN:
1134 case TM_PARSER_OBJC:
1135 case TM_PARSER_REST:
1136 /* Other parsers don't use scope at all (or should be somewhere above) */
1137 default:
1138 return FALSE;
1143 gboolean tm_parser_langs_compatible(TMParserType lang, TMParserType other)
1145 if (lang == TM_PARSER_NONE || other == TM_PARSER_NONE)
1146 return FALSE;
1147 if (lang == other)
1148 return TRUE;
1149 /* Accept CPP tags for C lang and vice versa */
1150 else if (lang == TM_PARSER_C && other == TM_PARSER_CPP)
1151 return TRUE;
1152 else if (lang == TM_PARSER_CPP && other == TM_PARSER_C)
1153 return TRUE;
1155 return FALSE;