dte test coverage


Directory: ./
File: src/syntax/syntax.c
Date: 2024-12-21 16:03:22
Exec Total Coverage
Lines: 98 118 83.1%
Functions: 18 20 90.0%
Branches: 49 62 79.0%

Line Branch Exec Source
1 #include <stdlib.h>
2 #include "syntax.h"
3 #include "error.h"
4 #include "util/xsnprintf.h"
5
6 197 StringList *find_string_list(const Syntax *syn, const char *name)
7 {
8 197 return hashmap_get(&syn->string_lists, name);
9 }
10
11 5406 State *find_state(const Syntax *syn, const char *name)
12 {
13 5406 return hashmap_get(&syn->states, name);
14 }
15
16 560 Syntax *find_any_syntax(const HashMap *syntaxes, const char *name)
17 {
18 560 return hashmap_get(syntaxes, name);
19 }
20
21 // NOLINTNEXTLINE(misc-no-recursion)
22 5945 static void visit(State *s)
23 {
24
2/2
✓ Branch 0 taken 2264 times.
✓ Branch 1 taken 3681 times.
5945 if (s->visited) {
25 return;
26 }
27 2264 s->visited = true;
28
2/2
✓ Branch 0 taken 4033 times.
✓ Branch 1 taken 2264 times.
6297 for (size_t i = 0, n = s->conds.count; i < n; i++) {
29 4033 const Condition *cond = s->conds.ptrs[i];
30
2/2
✓ Branch 0 taken 3709 times.
✓ Branch 1 taken 324 times.
4033 if (cond->a.destination) {
31 3709 visit(cond->a.destination);
32 }
33 }
34
2/2
✓ Branch 0 taken 2106 times.
✓ Branch 1 taken 158 times.
2264 if (s->default_action.destination) {
35 2106 visit(s->default_action.destination);
36 }
37 }
38
39 4033 static void free_condition(Condition *cond)
40 {
41 4033 free(cond->a.emit_name);
42 4033 free(cond);
43 4033 }
44
45 static void free_heredoc_state(HeredocState *s)
46 {
47 free(s);
48 }
49
50 2264 static void free_state(State *s)
51 {
52 2264 free(s->emit_name);
53 2264 ptr_array_free_cb(&s->conds, FREE_FUNC(free_condition));
54 2264 ptr_array_free_cb(&s->heredoc.states, FREE_FUNC(free_heredoc_state));
55 2264 free(s->default_action.emit_name);
56 2264 free(s);
57 2264 }
58
59 97 static void free_string_list(StringList *list)
60 {
61 97 hashset_free(&list->strings);
62 97 free(list);
63 97 }
64
65 130 static void free_syntax_contents(Syntax *syn)
66 {
67 130 hashmap_free(&syn->states, FREE_FUNC(free_state));
68 130 hashmap_free(&syn->string_lists, FREE_FUNC(free_string_list));
69 130 hashmap_free(&syn->default_styles, NULL);
70 130 }
71
72 static void free_syntax(Syntax *syn)
73 {
74 free_syntax_contents(syn);
75 free(syn->name);
76 free(syn);
77 }
78
79 130 static void free_syntax_cb(Syntax *syn)
80 {
81 130 free_syntax_contents(syn);
82 130 free(syn);
83 130 }
84
85 8 void free_syntaxes(HashMap *syntaxes)
86 {
87 8 hashmap_free(syntaxes, FREE_FUNC(free_syntax_cb));
88 8 }
89
90 130 void finalize_syntax(HashMap *syntaxes, Syntax *syn, unsigned int saved_nr_errors)
91 {
92
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 130 times.
130 if (syn->states.count == 0) {
93 error_msg("Empty syntax");
94 }
95
96
2/2
✓ Branch 0 taken 2264 times.
✓ Branch 1 taken 130 times.
2524 for (HashMapIter it = hashmap_iter(&syn->states); hashmap_next(&it); ) {
97 2264 const State *s = it.entry->value;
98
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2264 times.
2264 if (!s->defined) {
99 // This state has been referenced but not defined
100 error_msg("No such state %s", it.entry->key);
101 }
102 }
103
2/2
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 130 times.
357 for (HashMapIter it = hashmap_iter(&syn->string_lists); hashmap_next(&it); ) {
104 97 const StringList *list = it.entry->value;
105
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 if (!list->defined) {
106 error_msg("No such list %s", it.entry->key);
107 }
108 }
109
110
3/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 121 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
130 if (syn->heredoc && !is_subsyntax(syn)) {
111 error_msg("heredocend can be used only in subsyntaxes");
112 }
113
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 130 times.
130 if (find_any_syntax(syntaxes, syn->name)) {
115 error_msg("Syntax %s already exists", syn->name);
116 }
117
118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 130 times.
130 if (get_nr_errors() != saved_nr_errors) {
119 free_syntax(syn);
120 return;
121 }
122
123 // Unused states and lists cause warnings only (to make loading WIP
124 // syntax files less annoying)
125 130 visit(syn->start_state);
126
2/2
✓ Branch 0 taken 2264 times.
✓ Branch 1 taken 130 times.
2394 for (HashMapIter it = hashmap_iter(&syn->states); hashmap_next(&it); ) {
127 2264 const State *s = it.entry->value;
128
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2264 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2264 if (!s->visited && !s->copied) {
129 error_msg("State %s is unreachable", it.entry->key);
130 }
131 }
132
2/2
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 130 times.
357 for (HashMapIter it = hashmap_iter(&syn->string_lists); hashmap_next(&it); ) {
133 97 const StringList *list = it.entry->value;
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 if (!list->used) {
135 error_msg("List %s never used", it.entry->key);
136 }
137 }
138
139 130 hashmap_insert(syntaxes, syn->name, syn);
140 }
141
142 248 Syntax *find_syntax(const HashMap *syntaxes, const char *name)
143 {
144 248 Syntax *syn = find_any_syntax(syntaxes, name);
145
3/4
✓ Branch 0 taken 105 times.
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 105 times.
248 if (syn && is_subsyntax(syn)) {
146 return NULL;
147 }
148 return syn;
149 }
150
151 625 static const char *find_default_style(const Syntax *syn, const char *name)
152 {
153 625 return hashmap_get(&syn->default_styles, name);
154 }
155
156 4139 static void update_action_style(const Syntax *syn, Action *a, const StyleMap *styles)
157 {
158 4139 const char *name = a->emit_name;
159
2/2
✓ Branch 0 taken 3011 times.
✓ Branch 1 taken 1128 times.
4139 if (!name) {
160 3011 name = a->destination->emit_name;
161 }
162
163 4139 char full[256];
164 4139 xsnprintf(full, sizeof full, "%s.%s", syn->name, name);
165 4139 a->emit_style = find_style(styles, full);
166
2/2
✓ Branch 0 taken 625 times.
✓ Branch 1 taken 3514 times.
4139 if (a->emit_style) {
167 3829 return;
168 }
169
170 625 const char *def = find_default_style(syn, name);
171
2/2
✓ Branch 0 taken 310 times.
✓ Branch 1 taken 315 times.
625 if (!def) {
172 return;
173 }
174
175 310 xsnprintf(full, sizeof full, "%s.%s", syn->name, def);
176 310 a->emit_style = find_style(styles, full);
177 }
178
179 1442 void update_state_styles(const Syntax *syn, State *s, const StyleMap *styles)
180 {
181
2/2
✓ Branch 0 taken 2697 times.
✓ Branch 1 taken 1442 times.
4139 for (size_t i = 0, n = s->conds.count; i < n; i++) {
182 2697 Condition *c = s->conds.ptrs[i];
183 2697 update_action_style(syn, &c->a, styles);
184 }
185 1442 update_action_style(syn, &s->default_action, styles);
186 1442 }
187
188 127 void update_syntax_styles(Syntax *syn, const StyleMap *styles)
189 {
190
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 77 times.
127 if (is_subsyntax(syn)) {
191 // No point in updating styles of a sub-syntax
192 return;
193 }
194
2/2
✓ Branch 0 taken 1442 times.
✓ Branch 1 taken 50 times.
1492 for (HashMapIter it = hashmap_iter(&syn->states); hashmap_next(&it); ) {
195 1442 update_state_styles(syn, it.entry->value, styles);
196 }
197 }
198
199 7 void update_all_syntax_styles(const HashMap *syntaxes, const StyleMap *styles)
200 {
201
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 7 times.
134 for (HashMapIter it = hashmap_iter(syntaxes); hashmap_next(&it); ) {
202 127 update_syntax_styles(it.entry->value, styles);
203 }
204 7 }
205
206 51 void find_unused_subsyntaxes(const HashMap *syntaxes)
207 {
208
2/2
✓ Branch 0 taken 3194 times.
✓ Branch 1 taken 51 times.
3245 for (HashMapIter it = hashmap_iter(syntaxes); hashmap_next(&it); ) {
209 3194 Syntax *s = it.entry->value;
210
4/6
✓ Branch 0 taken 1276 times.
✓ Branch 1 taken 1918 times.
✓ Branch 2 taken 1276 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1276 times.
3194 if (!s->used && !s->warned_unused_subsyntax && is_subsyntax(s)) {
211 error_msg("Subsyntax %s is unused", s->name);
212 // Don't complain multiple times about the same unused subsyntaxes
213 s->warned_unused_subsyntax = true;
214 }
215 }
216 51 }
217