Merge pull request #3062 from techee/asm_parser
[geany-mirror.git] / src / tagmanager / tm_parser.c
blob289f438cfd02108fc52b2de024ab2d0afc984f88
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 #define map_FERITE map_C_old_parser
408 /* different parser than in universal-ctags */
409 static TMParserMapEntry map_MATLAB[] = {
410 {'f', tm_tag_function_t},
411 {'s', tm_tag_struct_t},
414 #define map_GLSL map_C_old_parser
416 /* not in universal-ctags */
417 static TMParserMapEntry map_VALA[] = {
418 {'c', tm_tag_class_t},
419 {'d', tm_tag_macro_t},
420 {'e', tm_tag_enumerator_t},
421 {'f', tm_tag_field_t},
422 {'g', tm_tag_enum_t},
423 {'i', tm_tag_interface_t},
424 {'l', tm_tag_undef_t},
425 {'m', tm_tag_method_t},
426 {'n', tm_tag_namespace_t},
427 {'p', tm_tag_undef_t},
428 {'S', tm_tag_undef_t},
429 {'s', tm_tag_struct_t},
432 /* not in universal-ctags */
433 static TMParserMapEntry map_ACTIONSCRIPT[] = {
434 {'f', tm_tag_function_t},
435 {'c', tm_tag_class_t},
436 {'i', tm_tag_interface_t},
437 {'P', tm_tag_package_t},
438 {'m', tm_tag_method_t},
439 {'p', tm_tag_member_t},
440 {'v', tm_tag_variable_t},
441 {'l', tm_tag_variable_t},
442 {'C', tm_tag_macro_t},
443 {'I', tm_tag_externvar_t},
444 {'x', tm_tag_other_t},
447 static TMParserMapEntry map_NSIS[] = {
448 {'s', tm_tag_namespace_t},
449 {'f', tm_tag_function_t},
450 {'v', tm_tag_variable_t},
451 {'d', tm_tag_undef_t},
452 {'m', tm_tag_undef_t},
453 {'S', tm_tag_undef_t},
454 {'p', tm_tag_undef_t},
455 {'l', tm_tag_undef_t},
456 {'i', tm_tag_undef_t},
459 /* not in universal-ctags */
460 static TMParserMapEntry map_MARKDOWN[] = {
461 {'v', tm_tag_variable_t},
464 static TMParserMapEntry map_TXT2TAGS[] = {
465 {'s', tm_tag_member_t},
468 static TMParserMapEntry map_ABC[] = {
469 {'s', tm_tag_member_t},
472 static TMParserMapEntry map_VERILOG[] = {
473 {'c', tm_tag_variable_t},
474 {'e', tm_tag_typedef_t},
475 {'f', tm_tag_function_t},
476 {'m', tm_tag_class_t},
477 {'n', tm_tag_variable_t},
478 {'p', tm_tag_variable_t},
479 {'r', tm_tag_variable_t},
480 {'t', tm_tag_function_t},
483 static TMParserMapEntry map_R[] = {
484 {'f', tm_tag_function_t},
485 {'l', tm_tag_other_t},
486 {'s', tm_tag_other_t},
489 static TMParserMapEntry map_COBOL[] = {
490 {'d', tm_tag_variable_t},
491 {'D', tm_tag_interface_t},
492 {'f', tm_tag_function_t},
493 {'g', tm_tag_struct_t},
494 {'p', tm_tag_macro_t},
495 {'P', tm_tag_class_t},
496 {'s', tm_tag_namespace_t},
497 {'S', tm_tag_externvar_t},
500 static TMParserMapEntry map_OBJC[] = {
501 {'i', tm_tag_interface_t},
502 {'I', tm_tag_undef_t},
503 {'P', tm_tag_undef_t},
504 {'m', tm_tag_method_t},
505 {'c', tm_tag_class_t},
506 {'v', tm_tag_variable_t},
507 {'E', tm_tag_field_t},
508 {'f', tm_tag_function_t},
509 {'p', tm_tag_undef_t},
510 {'t', tm_tag_typedef_t},
511 {'s', tm_tag_struct_t},
512 {'e', tm_tag_enum_t},
513 {'M', tm_tag_macro_t},
514 {'C', tm_tag_undef_t},
517 static TMParserMapEntry map_ASCIIDOC[] = {
518 {'c', tm_tag_namespace_t},
519 {'s', tm_tag_member_t},
520 {'S', tm_tag_macro_t},
521 {'t', tm_tag_variable_t},
522 {'T', tm_tag_struct_t},
523 {'u', tm_tag_undef_t},
524 {'a', tm_tag_undef_t},
527 static TMParserMapEntry map_ABAQUS[] = {
528 {'p', tm_tag_class_t},
529 {'a', tm_tag_member_t},
530 {'s', tm_tag_interface_t},
533 static TMParserMapEntry map_RUST[] = {
534 {'n', tm_tag_namespace_t},
535 {'s', tm_tag_struct_t},
536 {'i', tm_tag_interface_t},
537 {'c', tm_tag_class_t},
538 {'f', tm_tag_function_t},
539 {'g', tm_tag_enum_t},
540 {'t', tm_tag_typedef_t},
541 {'v', tm_tag_variable_t},
542 {'M', tm_tag_macro_t},
543 {'m', tm_tag_field_t},
544 {'e', tm_tag_enumerator_t},
545 {'P', tm_tag_method_t},
548 static TMParserMapEntry map_GO[] = {
549 {'p', tm_tag_namespace_t},
550 {'f', tm_tag_function_t},
551 {'c', tm_tag_macro_t},
552 {'t', tm_tag_typedef_t},
553 {'v', tm_tag_variable_t},
554 {'s', tm_tag_struct_t},
555 {'i', tm_tag_interface_t},
556 {'m', tm_tag_member_t},
557 {'M', tm_tag_undef_t},
558 {'n', tm_tag_undef_t},
559 {'u', tm_tag_undef_t},
560 {'P', tm_tag_undef_t},
561 {'a', tm_tag_undef_t},
562 {'R', tm_tag_undef_t},
565 static TMParserMapEntry map_JSON[] = {
566 {'o', tm_tag_member_t},
567 {'a', tm_tag_member_t},
568 {'n', tm_tag_member_t},
569 {'s', tm_tag_member_t},
570 {'b', tm_tag_member_t},
571 {'z', tm_tag_member_t},
574 /* Zephir, same as PHP */
575 #define map_ZEPHIR map_PHP
577 /* not in universal-ctags */
578 static TMParserMapEntry map_POWERSHELL[] = {
579 {'f', tm_tag_function_t},
580 {'v', tm_tag_variable_t},
583 static TMParserMapEntry map_JULIA[] = {
584 {'c', tm_tag_variable_t},
585 {'f', tm_tag_function_t},
586 {'g', tm_tag_member_t},
587 {'m', tm_tag_macro_t},
588 {'n', tm_tag_namespace_t},
589 {'s', tm_tag_struct_t},
590 {'t', tm_tag_typedef_t},
591 /* defined as externvar to get those excluded as forward type in symbols.c:goto_tag()
592 * so we can jump to the real implementation (if known) instead of to the import statement */
593 {'x', tm_tag_externvar_t},
596 static TMParserMapEntry map_CPREPROCESSOR[] = {
597 {'d', tm_tag_undef_t},
598 {'h', tm_tag_undef_t},
599 {'D', tm_tag_undef_t},
601 static TMParserMapEntry map_GDSCRIPT[] = {
602 {'c', tm_tag_class_t},
603 {'m', tm_tag_method_t},
604 {'v', tm_tag_variable_t},
605 {'C', tm_tag_variable_t},
606 {'g', tm_tag_enum_t},
607 {'e', tm_tag_variable_t},
608 {'z', tm_tag_other_t},
609 {'l', tm_tag_other_t},
610 {'s', tm_tag_variable_t},
613 typedef struct
615 TMParserMapEntry *entries;
616 guint size;
617 } TMParserMap;
619 #define MAP_ENTRY(lang) [TM_PARSER_##lang] = {map_##lang, G_N_ELEMENTS(map_##lang)}
621 /* keep in sync with TM_PARSER_* definitions in the header */
622 static TMParserMap parser_map[] = {
623 MAP_ENTRY(C),
624 MAP_ENTRY(CPP),
625 MAP_ENTRY(JAVA),
626 MAP_ENTRY(MAKEFILE),
627 MAP_ENTRY(PASCAL),
628 MAP_ENTRY(PERL),
629 MAP_ENTRY(PHP),
630 MAP_ENTRY(PYTHON),
631 MAP_ENTRY(LATEX),
632 MAP_ENTRY(BIBTEX),
633 MAP_ENTRY(ASM),
634 MAP_ENTRY(CONF),
635 MAP_ENTRY(SQL),
636 MAP_ENTRY(DOCBOOK),
637 MAP_ENTRY(ERLANG),
638 MAP_ENTRY(CSS),
639 MAP_ENTRY(RUBY),
640 MAP_ENTRY(TCL),
641 MAP_ENTRY(SH),
642 MAP_ENTRY(D),
643 MAP_ENTRY(FORTRAN),
644 MAP_ENTRY(FERITE),
645 MAP_ENTRY(DIFF),
646 MAP_ENTRY(VHDL),
647 MAP_ENTRY(LUA),
648 MAP_ENTRY(JAVASCRIPT),
649 MAP_ENTRY(HASKELL),
650 MAP_ENTRY(CSHARP),
651 MAP_ENTRY(FREEBASIC),
652 MAP_ENTRY(HAXE),
653 MAP_ENTRY(REST),
654 MAP_ENTRY(HTML),
655 MAP_ENTRY(F77),
656 MAP_ENTRY(GLSL),
657 MAP_ENTRY(MATLAB),
658 MAP_ENTRY(VALA),
659 MAP_ENTRY(ACTIONSCRIPT),
660 MAP_ENTRY(NSIS),
661 MAP_ENTRY(MARKDOWN),
662 MAP_ENTRY(TXT2TAGS),
663 MAP_ENTRY(ABC),
664 MAP_ENTRY(VERILOG),
665 MAP_ENTRY(R),
666 MAP_ENTRY(COBOL),
667 MAP_ENTRY(OBJC),
668 MAP_ENTRY(ASCIIDOC),
669 MAP_ENTRY(ABAQUS),
670 MAP_ENTRY(RUST),
671 MAP_ENTRY(GO),
672 MAP_ENTRY(JSON),
673 MAP_ENTRY(ZEPHIR),
674 MAP_ENTRY(POWERSHELL),
675 MAP_ENTRY(JULIA),
676 MAP_ENTRY(CPREPROCESSOR),
677 MAP_ENTRY(GDSCRIPT),
679 /* make sure the parser map is consistent and complete */
680 G_STATIC_ASSERT(G_N_ELEMENTS(parser_map) == TM_PARSER_COUNT);
683 TMTagType tm_parser_get_tag_type(gchar kind, TMParserType lang)
685 TMParserMap *map = &parser_map[lang];
686 guint i;
688 for (i = 0; i < map->size; i++)
690 TMParserMapEntry *entry = &map->entries[i];
692 if (entry->kind == kind)
693 return entry->type;
695 return tm_tag_undef_t;
699 gchar tm_parser_get_tag_kind(TMTagType type, TMParserType lang)
701 TMParserMap *map = &parser_map[lang];
702 guint i;
704 for (i = 0; i < map->size; i++)
706 TMParserMapEntry *entry = &map->entries[i];
708 if (entry->type == type)
709 return entry->kind;
711 return '\0';
715 static void add_subparser(TMParserType lang, TMParserType sublang, TMSubparserMapEntry *map, guint map_size)
717 guint i;
718 GPtrArray *mapping;
719 GHashTable *lang_map = g_hash_table_lookup(subparser_map, GINT_TO_POINTER(lang));
721 if (!lang_map)
723 lang_map = g_hash_table_new(g_direct_hash, g_direct_equal);
724 g_hash_table_insert(subparser_map, GINT_TO_POINTER(lang), lang_map);
727 mapping = g_ptr_array_new();
728 for (i = 0; i < map_size; i++)
729 g_ptr_array_add(mapping, &map[i]);
731 g_hash_table_insert(lang_map, GINT_TO_POINTER(sublang), mapping);
735 #define SUBPARSER_MAP_ENTRY(lang, sublang, map) add_subparser(TM_PARSER_##lang, TM_PARSER_##sublang, map, G_N_ELEMENTS(map))
737 static void init_subparser_map(void)
739 SUBPARSER_MAP_ENTRY(HTML, JAVASCRIPT, subparser_HTML_javascript_map);
743 TMTagType tm_parser_get_subparser_type(TMParserType lang, TMParserType sublang, TMTagType type)
745 guint i;
746 GHashTable *lang_map;
747 GPtrArray *mapping;
749 if (!subparser_map)
751 subparser_map = g_hash_table_new(g_direct_hash, g_direct_equal);
752 init_subparser_map();
755 lang_map = g_hash_table_lookup(subparser_map, GINT_TO_POINTER(lang));
756 if (!lang_map)
757 return tm_tag_undef_t;
759 mapping = g_hash_table_lookup(lang_map, GINT_TO_POINTER(sublang));
760 if (!mapping)
761 return tm_tag_undef_t;
763 for (i = 0; i < mapping->len; i++)
765 TMSubparserMapEntry *entry = mapping->pdata[i];
766 if (entry->orig_type == type)
767 return entry->new_type;
770 return tm_tag_undef_t;
774 void tm_parser_verify_type_mappings(void)
776 TMParserType lang;
778 if (TM_PARSER_COUNT > tm_ctags_get_lang_count())
779 g_error("More parsers defined in Geany than in ctags");
781 for (lang = 0; lang < TM_PARSER_COUNT; lang++)
783 const gchar *kinds = tm_ctags_get_lang_kinds(lang);
784 TMParserMap *map = &parser_map[lang];
785 gchar presence_map[256];
786 guint i;
788 if (! map->entries || map->size < 1)
789 g_error("No tag types in TM for %s, is the language listed in parser_map?",
790 tm_ctags_get_lang_name(lang));
792 if (map->size != strlen(kinds))
793 g_error("Different number of tag types in TM (%d) and ctags (%d) for %s",
794 map->size, (int)strlen(kinds), tm_ctags_get_lang_name(lang));
796 memset(presence_map, 0, sizeof(presence_map));
797 for (i = 0; i < map->size; i++)
799 gboolean ctags_found = FALSE;
800 gboolean tm_found = FALSE;
801 guint j;
803 for (j = 0; j < map->size; j++)
805 /* check that for every type in TM there's a type in ctags */
806 if (map->entries[i].kind == kinds[j])
807 ctags_found = TRUE;
808 /* check that for every type in ctags there's a type in TM */
809 if (map->entries[j].kind == kinds[i])
810 tm_found = TRUE;
811 if (ctags_found && tm_found)
812 break;
814 if (!ctags_found)
815 g_error("Tag type '%c' found in TM but not in ctags for %s",
816 map->entries[i].kind, tm_ctags_get_lang_name(lang));
817 if (!tm_found)
818 g_error("Tag type '%c' found in ctags but not in TM for %s",
819 kinds[i], tm_ctags_get_lang_name(lang));
821 presence_map[(unsigned char) map->entries[i].kind]++;
824 for (i = 0; i < sizeof(presence_map); i++)
826 if (presence_map[i] > 1)
827 g_error("Duplicate tag type '%c' found for %s",
828 (gchar)i, tm_ctags_get_lang_name(lang));
834 /* When the suffix of 'str' is an operator that should trigger scope
835 * autocompletion, this function should return the length of the operator,
836 * zero otherwise. */
837 gint tm_parser_scope_autocomplete_suffix(TMParserType lang, const gchar *str)
839 const gchar *sep = tm_parser_scope_separator(lang);
841 if (g_str_has_suffix(str, sep))
842 return strlen(sep);
844 switch (lang)
846 case TM_PARSER_C:
847 case TM_PARSER_CPP:
848 if (g_str_has_suffix(str, "."))
849 return 1;
850 else if (g_str_has_suffix(str, "->"))
851 return 2;
852 else if (lang == TM_PARSER_CPP && g_str_has_suffix(str, "->*"))
853 return 3;
854 default:
855 break;
857 return 0;
861 /* Get the name of constructor method. Arguments of this method will be used
862 * for calltips when creating an object using the class name
863 * (e.g. after the opening brace in 'c = MyClass()' in Python) */
864 const gchar *tm_parser_get_constructor_method(TMParserType lang)
866 switch (lang)
868 case TM_PARSER_D:
869 return "this";
870 case TM_PARSER_PYTHON:
871 return "__init__";
872 default:
873 return NULL;
878 /* determine anonymous tags from tag names only when corresponding
879 * ctags information is not available */
880 gboolean tm_parser_is_anon_name(TMParserType lang, gchar *name)
882 guint i;
883 char dummy;
885 if (sscanf(name, "__anon%u%c", &i, &dummy) == 1) /* uctags tags files */
886 return TRUE;
887 else if (lang == TM_PARSER_C || lang == TM_PARSER_CPP) /* legacy Geany tags files */
888 return sscanf(name, "anon_%*[a-z]_%u%c", &i, &dummy) == 1;
889 else if (lang == TM_PARSER_FORTRAN || lang == TM_PARSER_F77) /* legacy Geany tags files */
891 return sscanf(name, "Structure#%u%c", &i, &dummy) == 1 ||
892 sscanf(name, "Interface#%u%c", &i, &dummy) == 1 ||
893 sscanf(name, "Enum#%u%c", &i, &dummy) == 1;
895 return FALSE;
899 static gchar *replace_string_if_present(gchar *haystack, gchar *needle, gchar *subst)
901 if (strstr(haystack, needle))
903 gchar **split = g_strsplit(haystack, needle, -1);
904 gchar *ret = g_strjoinv(subst, split);
905 g_strfreev(split);
906 return ret;
908 return haystack;
912 /* return updated scope or original scope if no change needed */
913 gchar *tm_parser_update_scope(TMParserType lang, gchar *scope)
915 switch (lang)
917 case TM_PARSER_PHP:
918 case TM_PARSER_ZEPHIR:
919 /* PHP parser uses two different scope separators but this would
920 * complicate things in Geany so make sure there's just one type */
921 return replace_string_if_present(scope, "\\", "::");
923 return scope;
927 /* whether or not to enable ctags roles for the given language and kind */
928 gboolean tm_parser_enable_role(TMParserType lang, gchar kind)
930 switch (lang)
932 case TM_PARSER_GDSCRIPT:
933 return kind == 'c' ? FALSE : TRUE;
934 case TM_PARSER_GO:
935 /* 'p' is used both for package definition tags and imported package
936 * tags and we can't tell which is which just by kind. By disabling
937 * roles for this kind, we only get package definition tags. */
938 return kind == 'p' ? FALSE : TRUE;
940 return TRUE;
944 /* whether or not to enable ctags kinds for the given language */
945 gboolean tm_parser_enable_kind(TMParserType lang, gchar kind)
947 TMParserMap *map;
948 guint i;
950 if (lang >= TM_PARSER_COUNT)
951 /* Fatal error but tm_parser_verify_type_mappings() will provide
952 * better message later */
953 return FALSE;
955 map = &parser_map[lang];
956 for (i = 0; i < map->size; i++)
958 if (map->entries[i].kind == kind)
959 return map->entries[i].type != tm_tag_undef_t;
961 return FALSE;
965 gchar *tm_parser_format_variable(TMParserType lang, const gchar *name, const gchar *type)
967 if (!type)
968 return NULL;
970 switch (lang)
972 case TM_PARSER_GO:
973 return g_strconcat(name, " ", type, NULL);
974 case TM_PARSER_PASCAL:
975 case TM_PARSER_PYTHON:
976 return g_strconcat(name, ": ", type, NULL);
977 default:
978 return g_strconcat(type, " ", name, NULL);
983 gchar *tm_parser_format_function(TMParserType lang, const gchar *fname, const gchar *args,
984 const gchar *retval, const gchar *scope)
986 GString *str;
988 if (!args) /* not a function */
989 return NULL;
991 str = g_string_new(NULL);
993 if (scope)
995 g_string_append(str, scope);
996 g_string_append(str, tm_parser_scope_separator_printable(lang));
998 g_string_append(str, fname);
999 g_string_append_c(str, ' ');
1000 g_string_append(str, args);
1002 if (retval)
1004 switch (lang)
1006 case TM_PARSER_GDSCRIPT:
1007 case TM_PARSER_GO:
1008 case TM_PARSER_PASCAL:
1009 case TM_PARSER_PYTHON:
1011 /* retval after function */
1012 const gchar *sep;
1013 switch (lang)
1015 case TM_PARSER_PASCAL:
1016 sep = ": ";
1017 break;
1018 case TM_PARSER_GDSCRIPT:
1019 case TM_PARSER_PYTHON:
1020 sep = " -> ";
1021 break;
1022 default:
1023 sep = " ";
1024 break;
1026 g_string_append(str, sep);
1027 g_string_append(str, retval);
1028 break;
1030 default:
1031 /* retval before function */
1032 g_string_prepend_c(str, ' ');
1033 g_string_prepend(str, retval);
1034 break;
1038 return g_string_free(str, FALSE);
1042 const gchar *tm_parser_scope_separator(TMParserType lang)
1044 switch (lang)
1046 case TM_PARSER_C: /* for C++ .h headers or C structs */
1047 case TM_PARSER_CPP:
1048 case TM_PARSER_GLSL: /* for structs */
1049 case TM_PARSER_PHP:
1050 case TM_PARSER_POWERSHELL:
1051 case TM_PARSER_RUST:
1052 case TM_PARSER_ZEPHIR:
1053 return "::";
1055 case TM_PARSER_TXT2TAGS:
1056 return "\"\"";
1058 /* these parsers don't report nested scopes but default "." for scope separator
1059 * might appear in the text so use something more improbable */
1060 case TM_PARSER_ASCIIDOC:
1061 case TM_PARSER_CONF:
1062 case TM_PARSER_REST:
1063 return "\x3";
1065 default:
1066 return ".";
1071 const gchar *tm_parser_scope_separator_printable(TMParserType lang)
1073 switch (lang)
1075 case TM_PARSER_TXT2TAGS:
1076 case TM_PARSER_ASCIIDOC:
1077 case TM_PARSER_CONF:
1078 case TM_PARSER_REST:
1079 return " > ";
1081 default:
1082 return tm_parser_scope_separator(lang);
1087 gboolean tm_parser_has_full_scope(TMParserType lang)
1089 switch (lang)
1091 /* These parsers include full hierarchy in the tag scope, separated by tm_parser_scope_separator() */
1092 case TM_PARSER_ACTIONSCRIPT:
1093 case TM_PARSER_C:
1094 case TM_PARSER_CPP:
1095 case TM_PARSER_CSHARP:
1096 case TM_PARSER_COBOL:
1097 case TM_PARSER_D:
1098 case TM_PARSER_FERITE:
1099 case TM_PARSER_GDSCRIPT:
1100 case TM_PARSER_GLSL:
1101 case TM_PARSER_GO:
1102 case TM_PARSER_JAVA:
1103 case TM_PARSER_JAVASCRIPT:
1104 case TM_PARSER_JSON:
1105 case TM_PARSER_LUA:
1106 case TM_PARSER_PHP:
1107 case TM_PARSER_POWERSHELL:
1108 case TM_PARSER_PYTHON:
1109 case TM_PARSER_RUBY:
1110 case TM_PARSER_RUST:
1111 case TM_PARSER_SQL:
1112 case TM_PARSER_TXT2TAGS:
1113 case TM_PARSER_VALA:
1114 case TM_PARSER_ZEPHIR:
1115 return TRUE;
1117 /* These make use of the scope, but don't include nested hierarchy
1118 * (either as a parser limitation or a language semantic) */
1119 case TM_PARSER_ASCIIDOC:
1120 case TM_PARSER_CONF:
1121 case TM_PARSER_ERLANG:
1122 case TM_PARSER_F77:
1123 case TM_PARSER_FORTRAN:
1124 case TM_PARSER_OBJC:
1125 case TM_PARSER_REST:
1126 /* Other parsers don't use scope at all (or should be somewhere above) */
1127 default:
1128 return FALSE;
1133 gboolean tm_parser_langs_compatible(TMParserType lang, TMParserType other)
1135 if (lang == TM_PARSER_NONE || other == TM_PARSER_NONE)
1136 return FALSE;
1137 if (lang == other)
1138 return TRUE;
1139 /* Accept CPP tags for C lang and vice versa */
1140 else if (lang == TM_PARSER_C && other == TM_PARSER_CPP)
1141 return TRUE;
1142 else if (lang == TM_PARSER_CPP && other == TM_PARSER_C)
1143 return TRUE;
1145 return FALSE;