Line | Branch | Exec | Source |
---|---|---|---|
1 | #include <errno.h> | ||
2 | #include <stdbool.h> | ||
3 | #include <string.h> | ||
4 | #include "merge.h" | ||
5 | #include "util/debug.h" | ||
6 | #include "util/hashmap.h" | ||
7 | #include "util/string-view.h" | ||
8 | #include "util/xmalloc.h" | ||
9 | #include "util/xsnprintf.h" | ||
10 | |||
11 | enum { | ||
12 | FIXBUF_SIZE = 512 | ||
13 | }; | ||
14 | |||
15 | 4335 | static const char *fix_name(char *buf, StringView prefix, const char *name) | |
16 | { | ||
17 | 4335 | size_t plen = prefix.length; | |
18 | 4335 | BUG_ON(plen >= FIXBUF_SIZE); | |
19 | 4335 | memcpy(buf, prefix.data, plen); | |
20 | 4335 | char *end = memccpy(buf + plen, name, '\0', FIXBUF_SIZE - plen); | |
21 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4335 times.
|
4335 | if (unlikely(!end)) { |
22 | − | fatal_error(__func__, ENOBUFS); | |
23 | } | ||
24 | 4335 | return buf; | |
25 | } | ||
26 | |||
27 | 3581 | static void fix_action(const Syntax *syn, Action *a, StringView prefix, char *buf) | |
28 | { | ||
29 |
2/2✓ Branch 0 taken 2783 times.
✓ Branch 1 taken 798 times.
|
3581 | if (a->destination) { |
30 | 2783 | const char *name = fix_name(buf, prefix, a->destination->name); | |
31 | 2783 | a->destination = find_state(syn, name); | |
32 | } | ||
33 |
2/2✓ Branch 0 taken 1219 times.
✓ Branch 1 taken 2362 times.
|
3581 | if (a->emit_name) { |
34 | 1219 | a->emit_name = xstrdup(a->emit_name); | |
35 | } | ||
36 | 3581 | } | |
37 | |||
38 | 1383 | static void fix_conditions ( | |
39 | const Syntax *syn, | ||
40 | State *s, | ||
41 | const SyntaxMerge *m, | ||
42 | StringView prefix, | ||
43 | char *buf | ||
44 | ) { | ||
45 |
2/2✓ Branch 0 taken 2198 times.
✓ Branch 1 taken 1383 times.
|
3581 | for (size_t i = 0, n = s->conds.count; i < n; i++) { |
46 | 2198 | Condition *c = s->conds.ptrs[i]; | |
47 | 2198 | fix_action(syn, &c->a, prefix, buf); | |
48 |
4/4✓ Branch 0 taken 405 times.
✓ Branch 1 taken 1793 times.
✓ Branch 2 taken 318 times.
✓ Branch 3 taken 87 times.
|
2198 | if (!c->a.destination && cond_type_has_destination(c->type)) { |
49 | 318 | c->a.destination = m->return_state; | |
50 | } | ||
51 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 2198 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
2198 | if (m->delim && c->type == COND_HEREDOCEND) { |
52 | ✗ | c->u.heredocend = string_view(m->delim, m->delim_len); | |
53 | } | ||
54 | } | ||
55 | |||
56 | 1383 | fix_action(syn, &s->default_action, prefix, buf); | |
57 |
2/2✓ Branch 0 taken 393 times.
✓ Branch 1 taken 990 times.
|
1383 | if (!s->default_action.destination) { |
58 | 393 | s->default_action.destination = m->return_state; | |
59 | } | ||
60 | 1383 | } | |
61 | |||
62 | // Merge a sub-syntax into another syntax, copying or updating | ||
63 | // pointers and strings as appropriate. | ||
64 | // NOTE: string_lists is owned by Syntax, so there's no need to | ||
65 | // copy it. Freeing Condition does not free any string lists. | ||
66 | 169 | State *merge_syntax(Syntax *syn, SyntaxMerge *merge, const StyleMap *styles) | |
67 | { | ||
68 | // Generate a prefix for merged state names, to avoid clashes | ||
69 | 169 | static unsigned int counter; | |
70 | 169 | char prefix_buf[DECIMAL_STR_MAX(counter) + 2]; | |
71 | 169 | size_t prefix_len = xsnprintf(prefix_buf, sizeof prefix_buf, "m%u-", counter++); | |
72 | 169 | StringView prefix = string_view(prefix_buf, prefix_len); | |
73 | |||
74 | 169 | const HashMap *subsyn_states = &merge->subsyn->states; | |
75 | 169 | HashMap *states = &syn->states; | |
76 | 169 | char buf[FIXBUF_SIZE]; | |
77 | |||
78 |
2/2✓ Branch 0 taken 1383 times.
✓ Branch 1 taken 169 times.
|
1552 | for (HashMapIter it = hashmap_iter(subsyn_states); hashmap_next(&it); ) { |
79 | 1383 | State *s = xmemdup(it.entry->value, sizeof(State)); | |
80 | 1383 | s->name = xstrjoin(prefix_buf, s->name); | |
81 | 1383 | s->emit_name = xstrdup(s->emit_name); | |
82 | 1383 | hashmap_insert(states, s->name, s); | |
83 | |||
84 |
2/2✓ Branch 0 taken 1363 times.
✓ Branch 1 taken 20 times.
|
1383 | if (s->conds.count > 0) { |
85 | // Deep copy conds PointerArray | ||
86 | 1363 | BUG_ON(s->conds.alloc < s->conds.count); | |
87 | 1363 | void **ptrs = xnew(void*, s->conds.alloc); | |
88 |
2/2✓ Branch 0 taken 2198 times.
✓ Branch 1 taken 1363 times.
|
3561 | for (size_t i = 0, n = s->conds.count; i < n; i++) { |
89 | 2198 | ptrs[i] = xmemdup(s->conds.ptrs[i], sizeof(Condition)); | |
90 | } | ||
91 | 1363 | s->conds.ptrs = ptrs; | |
92 | } else { | ||
93 | 20 | BUG_ON(s->conds.alloc != 0); | |
94 | } | ||
95 | |||
96 | // Mark unvisited so that state that is used only as a return | ||
97 | // state gets visited | ||
98 | 1383 | s->visited = false; | |
99 | |||
100 | // Don't complain about unvisited copied states | ||
101 | 1383 | s->copied = true; | |
102 | } | ||
103 | |||
104 | // Fix conditions and update styles for newly merged states | ||
105 |
2/2✓ Branch 0 taken 1383 times.
✓ Branch 1 taken 169 times.
|
1721 | for (HashMapIter it = hashmap_iter(subsyn_states); hashmap_next(&it); ) { |
106 | 1383 | const State *subsyn_state = it.entry->value; | |
107 | 1383 | BUG_ON(!subsyn_state); | |
108 | 1383 | const char *new_name = fix_name(buf, prefix, subsyn_state->name); | |
109 | 1383 | State *new_state = hashmap_get(states, new_name); | |
110 | 1383 | BUG_ON(!new_state); | |
111 | 1383 | fix_conditions(syn, new_state, merge, prefix, buf); | |
112 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1383 times.
|
1383 | if (merge->delim) { |
113 | ✗ | update_state_styles(syn, new_state, styles); | |
114 | } | ||
115 | } | ||
116 | |||
117 | 169 | const char *name = fix_name(buf, prefix, merge->subsyn->start_state->name); | |
118 | 169 | State *start_state = hashmap_get(states, name); | |
119 | 169 | BUG_ON(!start_state); | |
120 | 169 | merge->subsyn->used = true; | |
121 | 169 | return start_state; | |
122 | } | ||
123 |