| 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/numtostr.h" | ||
| 8 | #include "util/string-view.h" | ||
| 9 | #include "util/xmalloc.h" | ||
| 10 | #include "util/xstring.h" | ||
| 11 | |||
| 12 | enum { | ||
| 13 | FIXBUF_SIZE = 512 | ||
| 14 | }; | ||
| 15 | |||
| 16 | 4401 | static const char *fix_name(char *buf, StringView prefix, const char *name) | |
| 17 | { | ||
| 18 | 4401 | size_t plen = prefix.length; | |
| 19 | 4401 | BUG_ON(plen >= FIXBUF_SIZE); | |
| 20 | 4401 | size_t avail = FIXBUF_SIZE - plen; | |
| 21 | 4401 | char *end = memccpy(xmempcpy(buf, prefix.data, plen), name, '\0', avail); | |
| 22 |
1/2✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 4401 times.
|
4401 | FATAL_ERROR_ON(!end, ENOBUFS); |
| 23 | 4401 | return buf; | |
| 24 | } | ||
| 25 | |||
| 26 | 3635 | static void fix_action(const Syntax *syn, Action *a, StringView prefix, char *buf) | |
| 27 | { | ||
| 28 |
2/2✓ Branch 2 → 3 taken 2821 times.
✓ Branch 2 → 6 taken 814 times.
|
3635 | if (a->destination) { |
| 29 | 2821 | const char *name = fix_name(buf, prefix, a->destination->name); | |
| 30 | 2821 | a->destination = find_state(syn, name); | |
| 31 | } | ||
| 32 | 3635 | } | |
| 33 | |||
| 34 | 1405 | static void fix_conditions ( | |
| 35 | const Syntax *syn, | ||
| 36 | State *s, | ||
| 37 | const SyntaxMerge *m, | ||
| 38 | StringView prefix, | ||
| 39 | char *buf | ||
| 40 | ) { | ||
| 41 | 1405 | BUG_ON(!s); // Silence spurious `-Wnull-dereference` warning in GCC 9 | |
| 42 |
2/2✓ Branch 13 → 5 taken 2230 times.
✓ Branch 13 → 14 taken 1405 times.
|
3635 | for (size_t i = 0, n = s->conds.count; i < n; i++) { |
| 43 | 2230 | Condition *c = s->conds.ptrs[i]; | |
| 44 | 2230 | fix_action(syn, &c->a, prefix, buf); | |
| 45 |
4/4✓ Branch 6 → 7 taken 411 times.
✓ Branch 6 → 9 taken 1819 times.
✓ Branch 7 → 8 taken 324 times.
✓ Branch 7 → 9 taken 87 times.
|
2230 | if (!c->a.destination && cond_type_has_destination(c->type)) { |
| 46 | 324 | c->a.destination = m->return_state; | |
| 47 | } | ||
| 48 |
1/4✗ Branch 9 → 10 not taken.
✓ Branch 9 → 12 taken 2230 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
|
2230 | if (m->delim && c->type == COND_HEREDOCEND) { |
| 49 | ✗ | c->u.heredocend = string_view(m->delim, m->delim_len); | |
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | 1405 | fix_action(syn, &s->default_action, prefix, buf); | |
| 54 |
2/2✓ Branch 15 → 16 taken 403 times.
✓ Branch 15 → 17 taken 1002 times.
|
1405 | if (!s->default_action.destination) { |
| 55 | 403 | s->default_action.destination = m->return_state; | |
| 56 | } | ||
| 57 | 1405 | } | |
| 58 | |||
| 59 | // Generate a prefix for merged state names, to avoid clashes | ||
| 60 | 175 | static StringView make_prefix_str(char *buf) | |
| 61 | { | ||
| 62 | 175 | static unsigned int counter; | |
| 63 | 175 | size_t n = 0; | |
| 64 | 175 | buf[n++] = 'm'; | |
| 65 | 175 | n += buf_uint_to_str(counter++, buf + n); | |
| 66 | 175 | buf[n++] = '-'; | |
| 67 | 175 | return string_view(buf, n); | |
| 68 | } | ||
| 69 | |||
| 70 | // Merge a sub-syntax into another syntax, copying or updating | ||
| 71 | // pointers and strings as appropriate. | ||
| 72 | // NOTE: string_lists is owned by Syntax, so there's no need to | ||
| 73 | // copy it. Freeing Condition does not free any string lists. | ||
| 74 | 175 | State *merge_syntax(Syntax *syn, SyntaxMerge *merge, const StyleMap *styles) | |
| 75 | { | ||
| 76 | 175 | const HashMap *subsyn_states = &merge->subsyn->states; | |
| 77 | 175 | HashMap *states = &syn->states; | |
| 78 | 175 | char prefix_buf[64]; | |
| 79 | 175 | StringView prefix = make_prefix_str(prefix_buf); | |
| 80 | 175 | char buf[FIXBUF_SIZE]; | |
| 81 | |||
| 82 |
2/2✓ Branch 20 → 4 taken 1405 times.
✓ Branch 20 → 21 taken 175 times.
|
1580 | for (HashMapIter it = hashmap_iter(subsyn_states); hashmap_next(&it); ) { |
| 83 | 1405 | State *s = xmemdup(it.entry->value, sizeof(State)); | |
| 84 | 1405 | s->name = xmemjoin(prefix.data, prefix.length, s->name, strlen(s->name) + 1); | |
| 85 | 1405 | hashmap_insert(states, s->name, s); | |
| 86 | |||
| 87 |
2/2✓ Branch 7 → 8 taken 1385 times.
✓ Branch 7 → 16 taken 20 times.
|
1405 | if (s->conds.count > 0) { |
| 88 | // Deep copy conds PointerArray | ||
| 89 | 1385 | BUG_ON(s->conds.alloc < s->conds.count); | |
| 90 | 1385 | void **ptrs = xmallocarray(s->conds.alloc, sizeof(*ptrs)); | |
| 91 |
2/2✓ Branch 14 → 12 taken 2230 times.
✓ Branch 14 → 15 taken 1385 times.
|
3615 | for (size_t i = 0, n = s->conds.count; i < n; i++) { |
| 92 | 2230 | ptrs[i] = xmemdup(s->conds.ptrs[i], sizeof(Condition)); | |
| 93 | } | ||
| 94 | 1385 | s->conds.ptrs = ptrs; | |
| 95 | } else { | ||
| 96 | 20 | BUG_ON(s->conds.alloc != 0); | |
| 97 | } | ||
| 98 | |||
| 99 | // Mark unvisited, so that return-only states get visited | ||
| 100 | 1405 | s->visited = false; | |
| 101 | |||
| 102 | // Don't complain about unvisited, copied states | ||
| 103 | 1405 | s->copied = true; | |
| 104 | } | ||
| 105 | |||
| 106 | // Fix conditions and update styles for newly merged states | ||
| 107 |
2/2✓ Branch 31 → 22 taken 1405 times.
✓ Branch 31 → 32 taken 175 times.
|
1755 | for (HashMapIter it = hashmap_iter(subsyn_states); hashmap_next(&it); ) { |
| 108 | 1405 | const State *subsyn_state = it.entry->value; | |
| 109 | 1405 | BUG_ON(!subsyn_state); | |
| 110 | 1405 | const char *new_name = fix_name(buf, prefix, subsyn_state->name); | |
| 111 | 1405 | State *new_state = hashmap_xget(states, new_name); | |
| 112 | 1405 | fix_conditions(syn, new_state, merge, prefix, buf); | |
| 113 |
1/2✗ Branch 27 → 28 not taken.
✓ Branch 27 → 30 taken 1405 times.
|
1405 | if (merge->delim) { |
| 114 | ✗ | update_state_styles(syn, new_state, styles); | |
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | 175 | const char *name = fix_name(buf, prefix, merge->subsyn->start_state->name); | |
| 119 | 175 | State *start_state = hashmap_xget(states, name); | |
| 120 | 175 | merge->subsyn->used = true; | |
| 121 | 175 | return start_state; | |
| 122 | } | ||
| 123 |