/home/runner/work/panackelty/panackelty/src/vm/builtins_text.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "builtins_internal.h" |
2 | | #include "utf8.h" |
3 | | #include "value.h" |
4 | | |
5 | | #include <stdlib.h> |
6 | | #include <string.h> |
7 | | |
8 | | /* Text and byte operations preserve code-point semantics and runtime bounds checks. */ |
9 | | |
10 | | Value *builtins_text_call(VM *vm, const char *name, Value **a) |
11 | 6.15M | { |
12 | 6.15M | if (!strcmp(name, "len")) { Branch (12:9): [True: 1.64M, False: 1.42M]
Branch (12:9): [True: 1.64M, False: 1.42M]
|
13 | 3.29M | REQUIRE(a[0]->kind == V_STR || a[0]->kind == V_BYTES || a[0]->kind == V_ARRAY, |
14 | 3.29M | "VM trap: len requires Str, Bytes, or Array"); |
15 | 3.29M | size_t n = a[0]->kind == V_STR ? a[0]->as.bytes.characters Branch (15:20): [True: 992k, False: 654k]
Branch (15:20): [True: 992k, False: 654k]
|
16 | 3.29M | : a[0]->kind == V_BYTES ? a[0]->as.bytes.length Branch (16:22): [True: 0, False: 654k]
Branch (16:22): [True: 0, False: 654k]
|
17 | 1.30M | : a[0]->as.sequence.count; |
18 | 3.29M | return value_size(n); |
19 | 3.29M | } |
20 | | |
21 | 2.85M | if (!strcmp(name, "concat")) { Branch (21:9): [True: 138k, False: 1.28M]
Branch (21:9): [True: 138k, False: 1.28M]
|
22 | 276k | REQUIRE(a[0]->kind == V_ARRAY && a[1]->kind == V_ARRAY, "VM trap: concat requires arrays"); |
23 | 276k | size_t n = a[0]->as.sequence.count, m = a[1]->as.sequence.count; |
24 | 276k | Value **items = malloc((n + m) * sizeof(Value *)); |
25 | 276k | if (!items && n + m) { Branch (25:13): [True: 0, False: 138k]
Branch (25:23): [True: 0, False: 0]
Branch (25:13): [True: 0, False: 138k]
Branch (25:23): [True: 0, False: 0]
|
26 | 0 | return NULL; |
27 | 0 | } |
28 | 276k | memcpy(items, a[0]->as.sequence.items, n * sizeof(Value *)); |
29 | 276k | memcpy(items + n, a[1]->as.sequence.items, m * sizeof(Value *)); |
30 | 276k | Value *v = value_sequence(V_ARRAY, items, n + m); |
31 | 276k | free(items); |
32 | 276k | return v; |
33 | 276k | } |
34 | | |
35 | 2.57M | if (!strcmp(name, "slice")) { Branch (35:9): [True: 53.1k, False: 1.23M]
Branch (35:9): [True: 53.1k, False: 1.23M]
|
36 | 106k | REQUIRE(a[0]->kind == V_STR && a[1]->kind == V_NAT && a[2]->kind == V_NAT, |
37 | 106k | "VM trap: slice requires Str and Nat bounds"); |
38 | 106k | size_t start, end, bs, be; |
39 | 106k | if (!value_index(a[1], &start) || !value_index(a[2], &end) || start > end) { Branch (39:13): [True: 0, False: 53.1k]
Branch (39:43): [True: 0, False: 53.1k]
Branch (39:71): [True: 1, False: 53.1k]
Branch (39:13): [True: 0, False: 53.1k]
Branch (39:43): [True: 0, False: 53.1k]
Branch (39:71): [True: 1, False: 53.1k]
|
40 | 2 | vm->error = "VM trap: invalid string slice"; |
41 | 2 | return NULL; |
42 | 2 | } |
43 | 106k | size_t count = a[0]->as.bytes.characters; |
44 | 106k | if (end > count) { Branch (44:13): [True: 3, False: 53.1k]
Branch (44:13): [True: 3, False: 53.1k]
|
45 | 6 | vm->error = "VM trap: invalid string slice"; |
46 | 6 | return NULL; |
47 | 6 | } |
48 | 106k | if (start == count) { Branch (48:13): [True: 344, False: 52.8k]
Branch (48:13): [True: 344, False: 52.8k]
|
49 | 688 | bs = a[0]->as.bytes.length; |
50 | 105k | } else if (!utf8_offset(a[0], start, &bs, &be)) { Branch (50:20): [True: 0, False: 52.8k]
Branch (50:20): [True: 0, False: 52.8k]
|
51 | 0 | return NULL; |
52 | 0 | } |
53 | 106k | if (end == count) { Branch (53:13): [True: 4.30k, False: 48.8k]
Branch (53:13): [True: 4.30k, False: 48.8k]
|
54 | 8.61k | be = a[0]->as.bytes.length; |
55 | 97.7k | } else { |
56 | 97.7k | size_t ignored; |
57 | 97.7k | if (!utf8_offset(a[0], end, &be, &ignored)) { Branch (57:17): [True: 0, False: 48.8k]
Branch (57:17): [True: 0, False: 48.8k]
|
58 | 0 | return NULL; |
59 | 0 | } |
60 | 97.7k | } |
61 | 106k | return value_data(V_STR, a[0]->as.bytes.data + bs, be - bs); |
62 | 106k | } |
63 | | |
64 | 2.47M | if (!strcmp(name, "starts_with") || !strcmp(name, "starts_with_at")) { Branch (64:9): [True: 26.1k, False: 1.21M]
Branch (64:41): [True: 487k, False: 723k]
Branch (64:9): [True: 26.1k, False: 1.21M]
Branch (64:41): [True: 487k, False: 723k]
|
65 | 1.02M | REQUIRE(a[0]->kind == V_STR && a[1]->kind == V_STR, "VM trap: starts_with requires Str"); |
66 | 1.02M | if (!strcmp(name, "starts_with_at")) { Branch (66:13): [True: 487k, False: 26.1k]
Branch (66:13): [True: 487k, False: 26.1k]
|
67 | 974k | REQUIRE(a[2]->kind == V_NAT, "VM trap: starts_with_at requires Nat offset"); |
68 | 974k | } |
69 | 1.02M | size_t offset = 0, bs = 0, be; |
70 | 1.02M | if (!strcmp(name, "starts_with_at")) { Branch (70:13): [True: 487k, False: 26.1k]
Branch (70:13): [True: 487k, False: 26.1k]
|
71 | 974k | if (!value_index(a[2], &offset)) { Branch (71:17): [True: 1, False: 487k]
Branch (71:17): [True: 1, False: 487k]
|
72 | 2 | return value_bool(false); |
73 | 2 | } |
74 | 974k | if (offset == a[0]->as.bytes.characters) { Branch (74:17): [True: 3, False: 487k]
Branch (74:17): [True: 3, False: 487k]
|
75 | 6 | bs = a[0]->as.bytes.length; |
76 | 974k | } else if (!utf8_offset(a[0], offset, &bs, &be)) { Branch (76:24): [True: 2, False: 487k]
Branch (76:24): [True: 2, False: 487k]
|
77 | 4 | return value_bool(false); |
78 | 4 | } |
79 | 974k | } |
80 | 1.02M | bool result = a[1]->as.bytes.length <= a[0]->as.bytes.length - bs && Branch (80:23): [True: 489k, False: 23.4k]
Branch (80:23): [True: 489k, False: 23.4k]
|
81 | 1.02M | !memcmp(a[0]->as.bytes.data + bs, a[1]->as.bytes.data, a[1]->as.bytes.length); Branch (81:23): [True: 3.86k, False: 485k]
Branch (81:23): [True: 3.86k, False: 485k]
|
82 | 1.02M | return value_bool(result); |
83 | 1.02M | } |
84 | | |
85 | 1.44M | if (!strcmp(name, "reverse")) { Branch (85:9): [True: 6, False: 723k]
Branch (85:9): [True: 6, False: 723k]
|
86 | 12 | REQUIRE(a[0]->kind == V_STR, "VM trap: reverse requires Str"); |
87 | 12 | size_t n = a[0]->as.bytes.length, source = 0, destination = n; |
88 | 12 | uint8_t *data = malloc(n ? n : 1); Branch (88:32): [True: 6, False: 0]
Branch (88:32): [True: 6, False: 0]
|
89 | 12 | if (!data) { Branch (89:13): [True: 0, False: 6]
Branch (89:13): [True: 0, False: 6]
|
90 | 0 | return NULL; |
91 | 0 | } |
92 | 52 | while (source < n) { Branch (92:16): [True: 20, False: 6]
Branch (92:16): [True: 20, False: 6]
|
93 | 40 | uint8_t c = a[0]->as.bytes.data[source]; |
94 | 40 | size_t width = c < 0x80 ? 1 : (c & 0xe0) == 0xc0 ? 2 : (c & 0xf0) == 0xe0 ? 3 : 4; Branch (94:28): [True: 8, False: 12]
Branch (94:43): [True: 6, False: 6]
Branch (94:68): [True: 1, False: 5]
Branch (94:28): [True: 8, False: 12]
Branch (94:43): [True: 6, False: 6]
Branch (94:68): [True: 1, False: 5]
|
95 | 40 | destination -= width; |
96 | 40 | memcpy(data + destination, a[0]->as.bytes.data + source, width); |
97 | 40 | source += width; |
98 | 40 | } |
99 | 12 | Value *v = value_data(V_STR, data, n); |
100 | 12 | free(data); |
101 | 12 | return v; |
102 | 12 | } |
103 | | |
104 | 1.44M | if (!strcmp(name, "is_digit") || !strcmp(name, "is_letter") || !strcmp(name, "is_whitespace")) { Branch (104:9): [True: 109k, False: 613k]
Branch (104:38): [True: 252k, False: 360k]
Branch (104:68): [True: 158k, False: 202k]
Branch (104:9): [True: 109k, False: 613k]
Branch (104:38): [True: 252k, False: 360k]
Branch (104:68): [True: 158k, False: 202k]
|
105 | 1.04M | REQUIRE(a[0]->kind == V_STR, "VM trap: character class requires Str"); |
106 | 1.04M | uint8_t c = a[0]->as.bytes.length == 1 ? a[0]->as.bytes.data[0] : 0; Branch (106:21): [True: 520k, False: 1]
Branch (106:21): [True: 520k, False: 1]
|
107 | 1.04M | bool result = !strcmp(name, "is_digit") ? c >= '0' && c <= '9' Branch (107:23): [True: 109k, False: 411k]
Branch (107:51): [True: 64.2k, False: 45.2k]
Branch (107:63): [True: 12.4k, False: 51.7k]
Branch (107:23): [True: 109k, False: 411k]
Branch (107:51): [True: 64.2k, False: 45.2k]
Branch (107:63): [True: 12.4k, False: 51.7k]
|
108 | 1.04M | : !strcmp(name, "is_letter") Branch (108:25): [True: 252k, False: 158k]
Branch (108:25): [True: 252k, False: 158k]
|
109 | 822k | ? (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') Branch (109:30): [True: 201k, False: 51.3k]
Branch (109:42): [True: 11.8k, False: 189k]
Branch (109:56): [True: 177k, False: 63.9k]
Branch (109:68): [True: 171k, False: 5.78k]
Branch (109:30): [True: 201k, False: 51.3k]
Branch (109:42): [True: 11.8k, False: 189k]
Branch (109:56): [True: 177k, False: 63.9k]
Branch (109:68): [True: 171k, False: 5.78k]
|
110 | 822k | : c == ' ' || c == '\t' || c == '\r' || c == '\n'; Branch (110:29): [True: 55.8k, False: 102k]
Branch (110:41): [True: 0, False: 102k]
Branch (110:54): [True: 0, False: 102k]
Branch (110:67): [True: 173, False: 102k]
Branch (110:29): [True: 55.8k, False: 102k]
Branch (110:41): [True: 0, False: 102k]
Branch (110:54): [True: 0, False: 102k]
Branch (110:67): [True: 173, False: 102k]
|
111 | 1.04M | return value_bool(result); |
112 | 1.04M | } |
113 | | |
114 | 404k | if (!strcmp(name, "byte_append")) { Branch (114:9): [True: 97.9k, False: 104k]
Branch (114:9): [True: 97.9k, False: 104k]
|
115 | 195k | REQUIRE(a[0]->kind == V_BYTES && a[1]->kind == V_NAT, |
116 | 195k | "VM trap: byte_append requires Bytes and Nat"); |
117 | 195k | size_t byte; |
118 | 195k | if (!value_index(a[1], &byte) || byte > 255) { Branch (118:13): [True: 0, False: 97.9k]
Branch (118:42): [True: 2, False: 97.9k]
Branch (118:13): [True: 0, False: 97.9k]
Branch (118:42): [True: 2, False: 97.9k]
|
119 | 4 | vm->error = "VM trap: byte value is outside 0..255"; |
120 | 4 | return NULL; |
121 | 4 | } |
122 | 195k | size_t n = a[0]->as.bytes.length; |
123 | 195k | uint8_t *data = malloc(n + 1); |
124 | 195k | if (!data) { Branch (124:13): [True: 0, False: 97.9k]
Branch (124:13): [True: 0, False: 97.9k]
|
125 | 0 | return NULL; |
126 | 0 | } |
127 | 195k | memcpy(data, a[0]->as.bytes.data, n); |
128 | 195k | data[n] = (uint8_t)byte; |
129 | 195k | Value *v = value_data(V_BYTES, data, n + 1); |
130 | 195k | free(data); |
131 | 195k | return v; |
132 | 195k | } |
133 | | |
134 | 208k | if (!strcmp(name, "bytes_concat")) { Branch (134:9): [True: 62.0k, False: 42.3k]
Branch (134:9): [True: 62.0k, False: 42.3k]
|
135 | 124k | REQUIRE(a[0]->kind == V_BYTES && a[1]->kind == V_BYTES, |
136 | 124k | "VM trap: bytes_concat requires Bytes"); |
137 | 124k | size_t n = a[0]->as.bytes.length, m = a[1]->as.bytes.length; |
138 | 124k | uint8_t *data = malloc(n + m); |
139 | 124k | if (!data && n + m) { Branch (139:13): [True: 0, False: 62.0k]
Branch (139:22): [True: 0, False: 0]
Branch (139:13): [True: 0, False: 62.0k]
Branch (139:22): [True: 0, False: 0]
|
140 | 0 | return NULL; |
141 | 0 | } |
142 | 124k | memcpy(data, a[0]->as.bytes.data, n); |
143 | 124k | memcpy(data + n, a[1]->as.bytes.data, m); |
144 | 124k | Value *v = value_data(V_BYTES, data, n + m); |
145 | 124k | free(data); |
146 | 124k | return v; |
147 | 124k | } |
148 | | |
149 | 84.6k | if (!strcmp(name, "byte_len")) { Branch (149:9): [True: 18.8k, False: 23.4k]
Branch (149:9): [True: 18.8k, False: 23.4k]
|
150 | 37.7k | REQUIRE(a[0]->kind == V_BYTES, "VM trap: byte_len requires Bytes"); |
151 | 37.7k | return value_size(a[0]->as.bytes.length); |
152 | 37.7k | } |
153 | | |
154 | 46.9k | if (!strcmp(name, "byte_get")) { Branch (154:9): [True: 5.55k, False: 17.9k]
Branch (154:9): [True: 5.55k, False: 17.9k]
|
155 | 11.1k | REQUIRE(a[0]->kind == V_BYTES && a[1]->kind == V_NAT, |
156 | 11.1k | "VM trap: byte_get requires Bytes and Nat"); |
157 | 11.1k | size_t i; |
158 | 11.1k | if (!value_index(a[1], &i) || i >= a[0]->as.bytes.length) { Branch (158:13): [True: 0, False: 5.55k]
Branch (158:39): [True: 0, False: 5.55k]
Branch (158:13): [True: 0, False: 5.55k]
Branch (158:39): [True: 0, False: 5.55k]
|
159 | 0 | vm->error = "VM trap: byte index is out of bounds"; |
160 | 0 | return NULL; |
161 | 0 | } |
162 | 11.1k | return value_size(a[0]->as.bytes.data[i]); |
163 | 11.1k | } |
164 | | |
165 | 35.8k | if (!strcmp(name, "utf8_encode")) { Branch (165:9): [True: 14.3k, False: 3.55k]
Branch (165:9): [True: 14.3k, False: 3.55k]
|
166 | 28.7k | REQUIRE(a[0]->kind == V_STR, "VM trap: utf8_encode requires Str"); |
167 | 28.7k | return value_data(V_BYTES, a[0]->as.bytes.data, a[0]->as.bytes.length); |
168 | 28.7k | } |
169 | | |
170 | 7.11k | if (!strcmp(name, "utf8_decode")) { Branch (170:9): [True: 550, False: 3.00k]
Branch (170:9): [True: 550, False: 3.00k]
|
171 | 1.10k | REQUIRE(a[0]->kind == V_BYTES, "VM trap: utf8_decode requires Bytes"); |
172 | 1.09k | if (!utf8(a[0]->as.bytes.data, a[0]->as.bytes.length)) { Branch (172:13): [True: 2, False: 547]
Branch (172:13): [True: 2, False: 547]
|
173 | 4 | vm->error = "VM trap: invalid UTF-8"; |
174 | 4 | return NULL; |
175 | 4 | } |
176 | 1.09k | return value_data(V_STR, a[0]->as.bytes.data, a[0]->as.bytes.length); |
177 | 1.09k | } |
178 | | |
179 | 6.01k | if (!strcmp(name, "nat_from_str")) { Branch (179:9): [True: 3.00k, False: 0]
Branch (179:9): [True: 3.00k, False: 0]
|
180 | 6.01k | REQUIRE(a[0]->kind == V_STR, "VM trap: nat_from_str requires Str"); |
181 | 6.01k | if (!a[0]->as.bytes.length) { Branch (181:13): [True: 0, False: 3.00k]
Branch (181:13): [True: 0, False: 3.00k]
|
182 | 0 | vm->error = "VM trap: text is not a Nat"; |
183 | 0 | return NULL; |
184 | 0 | } |
185 | 27.6k | for (size_t i = 0; i < a[0]->as.bytes.length; i++) { Branch (185:28): [True: 10.8k, False: 3.00k]
Branch (185:28): [True: 10.8k, False: 3.00k]
|
186 | 21.6k | if (a[0]->as.bytes.data[i] < '0' || a[0]->as.bytes.data[i] > '9') { Branch (186:17): [True: 0, False: 10.8k]
Branch (186:49): [True: 0, False: 10.8k]
Branch (186:17): [True: 0, False: 10.8k]
Branch (186:49): [True: 0, False: 10.8k]
|
187 | 0 | vm->error = "VM trap: text is not a Nat"; |
188 | 0 | return NULL; |
189 | 0 | } |
190 | 21.6k | } |
191 | 6.01k | PnBigInt n; |
192 | 6.01k | if (!pn_big_from_digits(&n, (char *)a[0]->as.bytes.data, a[0]->as.bytes.length, 1)) { Branch (192:13): [True: 0, False: 3.00k]
Branch (192:13): [True: 0, False: 3.00k]
|
193 | 0 | return NULL; |
194 | 0 | } |
195 | 6.01k | Value *v = value_big(V_NAT, &n); |
196 | 6.01k | pn_big_free(&n); |
197 | 6.01k | return v; |
198 | 6.01k | } |
199 | 0 | vm->error = "VM trap: unknown builtin"; |
200 | 0 | return NULL; |
201 | 6.01k | } Line | Count | Source | 11 | 3.07M | { | 12 | 3.07M | if (!strcmp(name, "len")) { Branch (12:9): [True: 1.64M, False: 1.42M]
| 13 | 1.64M | REQUIRE(a[0]->kind == V_STR || a[0]->kind == V_BYTES || a[0]->kind == V_ARRAY, | 14 | 1.64M | "VM trap: len requires Str, Bytes, or Array"); | 15 | 1.64M | size_t n = a[0]->kind == V_STR ? a[0]->as.bytes.characters Branch (15:20): [True: 992k, False: 654k]
| 16 | 1.64M | : a[0]->kind == V_BYTES ? a[0]->as.bytes.length Branch (16:22): [True: 0, False: 654k]
| 17 | 654k | : a[0]->as.sequence.count; | 18 | 1.64M | return value_size(n); | 19 | 1.64M | } | 20 | | | 21 | 1.42M | if (!strcmp(name, "concat")) { Branch (21:9): [True: 138k, False: 1.28M]
| 22 | 138k | REQUIRE(a[0]->kind == V_ARRAY && a[1]->kind == V_ARRAY, "VM trap: concat requires arrays"); | 23 | 138k | size_t n = a[0]->as.sequence.count, m = a[1]->as.sequence.count; | 24 | 138k | Value **items = malloc((n + m) * sizeof(Value *)); | 25 | 138k | if (!items && n + m) { Branch (25:13): [True: 0, False: 138k]
Branch (25:23): [True: 0, False: 0]
| 26 | 0 | return NULL; | 27 | 0 | } | 28 | 138k | memcpy(items, a[0]->as.sequence.items, n * sizeof(Value *)); | 29 | 138k | memcpy(items + n, a[1]->as.sequence.items, m * sizeof(Value *)); | 30 | 138k | Value *v = value_sequence(V_ARRAY, items, n + m); | 31 | 138k | free(items); | 32 | 138k | return v; | 33 | 138k | } | 34 | | | 35 | 1.28M | if (!strcmp(name, "slice")) { Branch (35:9): [True: 53.1k, False: 1.23M]
| 36 | 53.1k | REQUIRE(a[0]->kind == V_STR && a[1]->kind == V_NAT && a[2]->kind == V_NAT, | 37 | 53.1k | "VM trap: slice requires Str and Nat bounds"); | 38 | 53.1k | size_t start, end, bs, be; | 39 | 53.1k | if (!value_index(a[1], &start) || !value_index(a[2], &end) || start > end) { Branch (39:13): [True: 0, False: 53.1k]
Branch (39:43): [True: 0, False: 53.1k]
Branch (39:71): [True: 1, False: 53.1k]
| 40 | 1 | vm->error = "VM trap: invalid string slice"; | 41 | 1 | return NULL; | 42 | 1 | } | 43 | 53.1k | size_t count = a[0]->as.bytes.characters; | 44 | 53.1k | if (end > count) { Branch (44:13): [True: 3, False: 53.1k]
| 45 | 3 | vm->error = "VM trap: invalid string slice"; | 46 | 3 | return NULL; | 47 | 3 | } | 48 | 53.1k | if (start == count) { Branch (48:13): [True: 344, False: 52.8k]
| 49 | 344 | bs = a[0]->as.bytes.length; | 50 | 52.8k | } else if (!utf8_offset(a[0], start, &bs, &be)) { Branch (50:20): [True: 0, False: 52.8k]
| 51 | 0 | return NULL; | 52 | 0 | } | 53 | 53.1k | if (end == count) { Branch (53:13): [True: 4.30k, False: 48.8k]
| 54 | 4.30k | be = a[0]->as.bytes.length; | 55 | 48.8k | } else { | 56 | 48.8k | size_t ignored; | 57 | 48.8k | if (!utf8_offset(a[0], end, &be, &ignored)) { Branch (57:17): [True: 0, False: 48.8k]
| 58 | 0 | return NULL; | 59 | 0 | } | 60 | 48.8k | } | 61 | 53.1k | return value_data(V_STR, a[0]->as.bytes.data + bs, be - bs); | 62 | 53.1k | } | 63 | | | 64 | 1.23M | if (!strcmp(name, "starts_with") || !strcmp(name, "starts_with_at")) { Branch (64:9): [True: 26.1k, False: 1.21M]
Branch (64:41): [True: 487k, False: 723k]
| 65 | 513k | REQUIRE(a[0]->kind == V_STR && a[1]->kind == V_STR, "VM trap: starts_with requires Str"); | 66 | 513k | if (!strcmp(name, "starts_with_at")) { Branch (66:13): [True: 487k, False: 26.1k]
| 67 | 487k | REQUIRE(a[2]->kind == V_NAT, "VM trap: starts_with_at requires Nat offset"); | 68 | 487k | } | 69 | 513k | size_t offset = 0, bs = 0, be; | 70 | 513k | if (!strcmp(name, "starts_with_at")) { Branch (70:13): [True: 487k, False: 26.1k]
| 71 | 487k | if (!value_index(a[2], &offset)) { Branch (71:17): [True: 1, False: 487k]
| 72 | 1 | return value_bool(false); | 73 | 1 | } | 74 | 487k | if (offset == a[0]->as.bytes.characters) { Branch (74:17): [True: 3, False: 487k]
| 75 | 3 | bs = a[0]->as.bytes.length; | 76 | 487k | } else if (!utf8_offset(a[0], offset, &bs, &be)) { Branch (76:24): [True: 2, False: 487k]
| 77 | 2 | return value_bool(false); | 78 | 2 | } | 79 | 487k | } | 80 | 513k | bool result = a[1]->as.bytes.length <= a[0]->as.bytes.length - bs && Branch (80:23): [True: 489k, False: 23.4k]
| 81 | 513k | !memcmp(a[0]->as.bytes.data + bs, a[1]->as.bytes.data, a[1]->as.bytes.length); Branch (81:23): [True: 3.86k, False: 485k]
| 82 | 513k | return value_bool(result); | 83 | 513k | } | 84 | | | 85 | 723k | if (!strcmp(name, "reverse")) { Branch (85:9): [True: 6, False: 723k]
| 86 | 6 | REQUIRE(a[0]->kind == V_STR, "VM trap: reverse requires Str"); | 87 | 6 | size_t n = a[0]->as.bytes.length, source = 0, destination = n; | 88 | 6 | uint8_t *data = malloc(n ? n : 1); Branch (88:32): [True: 6, False: 0]
| 89 | 6 | if (!data) { Branch (89:13): [True: 0, False: 6]
| 90 | 0 | return NULL; | 91 | 0 | } | 92 | 26 | while (source < n) { Branch (92:16): [True: 20, False: 6]
| 93 | 20 | uint8_t c = a[0]->as.bytes.data[source]; | 94 | 20 | size_t width = c < 0x80 ? 1 : (c & 0xe0) == 0xc0 ? 2 : (c & 0xf0) == 0xe0 ? 3 : 4; Branch (94:28): [True: 8, False: 12]
Branch (94:43): [True: 6, False: 6]
Branch (94:68): [True: 1, False: 5]
| 95 | 20 | destination -= width; | 96 | 20 | memcpy(data + destination, a[0]->as.bytes.data + source, width); | 97 | 20 | source += width; | 98 | 20 | } | 99 | 6 | Value *v = value_data(V_STR, data, n); | 100 | 6 | free(data); | 101 | 6 | return v; | 102 | 6 | } | 103 | | | 104 | 723k | if (!strcmp(name, "is_digit") || !strcmp(name, "is_letter") || !strcmp(name, "is_whitespace")) { Branch (104:9): [True: 109k, False: 613k]
Branch (104:38): [True: 252k, False: 360k]
Branch (104:68): [True: 158k, False: 202k]
| 105 | 520k | REQUIRE(a[0]->kind == V_STR, "VM trap: character class requires Str"); | 106 | 520k | uint8_t c = a[0]->as.bytes.length == 1 ? a[0]->as.bytes.data[0] : 0; Branch (106:21): [True: 520k, False: 1]
| 107 | 520k | bool result = !strcmp(name, "is_digit") ? c >= '0' && c <= '9' Branch (107:23): [True: 109k, False: 411k]
Branch (107:51): [True: 64.2k, False: 45.2k]
Branch (107:63): [True: 12.4k, False: 51.7k]
| 108 | 520k | : !strcmp(name, "is_letter") Branch (108:25): [True: 252k, False: 158k]
| 109 | 411k | ? (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') Branch (109:30): [True: 201k, False: 51.3k]
Branch (109:42): [True: 11.8k, False: 189k]
Branch (109:56): [True: 177k, False: 63.9k]
Branch (109:68): [True: 171k, False: 5.78k]
| 110 | 411k | : c == ' ' || c == '\t' || c == '\r' || c == '\n'; Branch (110:29): [True: 55.8k, False: 102k]
Branch (110:41): [True: 0, False: 102k]
Branch (110:54): [True: 0, False: 102k]
Branch (110:67): [True: 173, False: 102k]
| 111 | 520k | return value_bool(result); | 112 | 520k | } | 113 | | | 114 | 202k | if (!strcmp(name, "byte_append")) { Branch (114:9): [True: 97.9k, False: 104k]
| 115 | 97.9k | REQUIRE(a[0]->kind == V_BYTES && a[1]->kind == V_NAT, | 116 | 97.9k | "VM trap: byte_append requires Bytes and Nat"); | 117 | 97.9k | size_t byte; | 118 | 97.9k | if (!value_index(a[1], &byte) || byte > 255) { Branch (118:13): [True: 0, False: 97.9k]
Branch (118:42): [True: 2, False: 97.9k]
| 119 | 2 | vm->error = "VM trap: byte value is outside 0..255"; | 120 | 2 | return NULL; | 121 | 2 | } | 122 | 97.9k | size_t n = a[0]->as.bytes.length; | 123 | 97.9k | uint8_t *data = malloc(n + 1); | 124 | 97.9k | if (!data) { Branch (124:13): [True: 0, False: 97.9k]
| 125 | 0 | return NULL; | 126 | 0 | } | 127 | 97.9k | memcpy(data, a[0]->as.bytes.data, n); | 128 | 97.9k | data[n] = (uint8_t)byte; | 129 | 97.9k | Value *v = value_data(V_BYTES, data, n + 1); | 130 | 97.9k | free(data); | 131 | 97.9k | return v; | 132 | 97.9k | } | 133 | | | 134 | 104k | if (!strcmp(name, "bytes_concat")) { Branch (134:9): [True: 62.0k, False: 42.3k]
| 135 | 62.0k | REQUIRE(a[0]->kind == V_BYTES && a[1]->kind == V_BYTES, | 136 | 62.0k | "VM trap: bytes_concat requires Bytes"); | 137 | 62.0k | size_t n = a[0]->as.bytes.length, m = a[1]->as.bytes.length; | 138 | 62.0k | uint8_t *data = malloc(n + m); | 139 | 62.0k | if (!data && n + m) { Branch (139:13): [True: 0, False: 62.0k]
Branch (139:22): [True: 0, False: 0]
| 140 | 0 | return NULL; | 141 | 0 | } | 142 | 62.0k | memcpy(data, a[0]->as.bytes.data, n); | 143 | 62.0k | memcpy(data + n, a[1]->as.bytes.data, m); | 144 | 62.0k | Value *v = value_data(V_BYTES, data, n + m); | 145 | 62.0k | free(data); | 146 | 62.0k | return v; | 147 | 62.0k | } | 148 | | | 149 | 42.3k | if (!strcmp(name, "byte_len")) { Branch (149:9): [True: 18.8k, False: 23.4k]
| 150 | 18.8k | REQUIRE(a[0]->kind == V_BYTES, "VM trap: byte_len requires Bytes"); | 151 | 18.8k | return value_size(a[0]->as.bytes.length); | 152 | 18.8k | } | 153 | | | 154 | 23.4k | if (!strcmp(name, "byte_get")) { Branch (154:9): [True: 5.55k, False: 17.9k]
| 155 | 5.55k | REQUIRE(a[0]->kind == V_BYTES && a[1]->kind == V_NAT, | 156 | 5.55k | "VM trap: byte_get requires Bytes and Nat"); | 157 | 5.55k | size_t i; | 158 | 5.55k | if (!value_index(a[1], &i) || i >= a[0]->as.bytes.length) { Branch (158:13): [True: 0, False: 5.55k]
Branch (158:39): [True: 0, False: 5.55k]
| 159 | 0 | vm->error = "VM trap: byte index is out of bounds"; | 160 | 0 | return NULL; | 161 | 0 | } | 162 | 5.55k | return value_size(a[0]->as.bytes.data[i]); | 163 | 5.55k | } | 164 | | | 165 | 17.9k | if (!strcmp(name, "utf8_encode")) { Branch (165:9): [True: 14.3k, False: 3.55k]
| 166 | 14.3k | REQUIRE(a[0]->kind == V_STR, "VM trap: utf8_encode requires Str"); | 167 | 14.3k | return value_data(V_BYTES, a[0]->as.bytes.data, a[0]->as.bytes.length); | 168 | 14.3k | } | 169 | | | 170 | 3.55k | if (!strcmp(name, "utf8_decode")) { Branch (170:9): [True: 550, False: 3.00k]
| 171 | 550 | REQUIRE(a[0]->kind == V_BYTES, "VM trap: utf8_decode requires Bytes"); | 172 | 549 | if (!utf8(a[0]->as.bytes.data, a[0]->as.bytes.length)) { Branch (172:13): [True: 2, False: 547]
| 173 | 2 | vm->error = "VM trap: invalid UTF-8"; | 174 | 2 | return NULL; | 175 | 2 | } | 176 | 547 | return value_data(V_STR, a[0]->as.bytes.data, a[0]->as.bytes.length); | 177 | 549 | } | 178 | | | 179 | 3.00k | if (!strcmp(name, "nat_from_str")) { Branch (179:9): [True: 3.00k, False: 0]
| 180 | 3.00k | REQUIRE(a[0]->kind == V_STR, "VM trap: nat_from_str requires Str"); | 181 | 3.00k | if (!a[0]->as.bytes.length) { Branch (181:13): [True: 0, False: 3.00k]
| 182 | 0 | vm->error = "VM trap: text is not a Nat"; | 183 | 0 | return NULL; | 184 | 0 | } | 185 | 13.8k | for (size_t i = 0; i < a[0]->as.bytes.length; i++) { Branch (185:28): [True: 10.8k, False: 3.00k]
| 186 | 10.8k | if (a[0]->as.bytes.data[i] < '0' || a[0]->as.bytes.data[i] > '9') { Branch (186:17): [True: 0, False: 10.8k]
Branch (186:49): [True: 0, False: 10.8k]
| 187 | 0 | vm->error = "VM trap: text is not a Nat"; | 188 | 0 | return NULL; | 189 | 0 | } | 190 | 10.8k | } | 191 | 3.00k | PnBigInt n; | 192 | 3.00k | if (!pn_big_from_digits(&n, (char *)a[0]->as.bytes.data, a[0]->as.bytes.length, 1)) { Branch (192:13): [True: 0, False: 3.00k]
| 193 | 0 | return NULL; | 194 | 0 | } | 195 | 3.00k | Value *v = value_big(V_NAT, &n); | 196 | 3.00k | pn_big_free(&n); | 197 | 3.00k | return v; | 198 | 3.00k | } | 199 | 0 | vm->error = "VM trap: unknown builtin"; | 200 | 0 | return NULL; | 201 | 3.00k | } |
Line | Count | Source | 11 | 3.07M | { | 12 | 3.07M | if (!strcmp(name, "len")) { Branch (12:9): [True: 1.64M, False: 1.42M]
| 13 | 1.64M | REQUIRE(a[0]->kind == V_STR || a[0]->kind == V_BYTES || a[0]->kind == V_ARRAY, | 14 | 1.64M | "VM trap: len requires Str, Bytes, or Array"); | 15 | 1.64M | size_t n = a[0]->kind == V_STR ? a[0]->as.bytes.characters Branch (15:20): [True: 992k, False: 654k]
| 16 | 1.64M | : a[0]->kind == V_BYTES ? a[0]->as.bytes.length Branch (16:22): [True: 0, False: 654k]
| 17 | 654k | : a[0]->as.sequence.count; | 18 | 1.64M | return value_size(n); | 19 | 1.64M | } | 20 | | | 21 | 1.42M | if (!strcmp(name, "concat")) { Branch (21:9): [True: 138k, False: 1.28M]
| 22 | 138k | REQUIRE(a[0]->kind == V_ARRAY && a[1]->kind == V_ARRAY, "VM trap: concat requires arrays"); | 23 | 138k | size_t n = a[0]->as.sequence.count, m = a[1]->as.sequence.count; | 24 | 138k | Value **items = malloc((n + m) * sizeof(Value *)); | 25 | 138k | if (!items && n + m) { Branch (25:13): [True: 0, False: 138k]
Branch (25:23): [True: 0, False: 0]
| 26 | 0 | return NULL; | 27 | 0 | } | 28 | 138k | memcpy(items, a[0]->as.sequence.items, n * sizeof(Value *)); | 29 | 138k | memcpy(items + n, a[1]->as.sequence.items, m * sizeof(Value *)); | 30 | 138k | Value *v = value_sequence(V_ARRAY, items, n + m); | 31 | 138k | free(items); | 32 | 138k | return v; | 33 | 138k | } | 34 | | | 35 | 1.28M | if (!strcmp(name, "slice")) { Branch (35:9): [True: 53.1k, False: 1.23M]
| 36 | 53.1k | REQUIRE(a[0]->kind == V_STR && a[1]->kind == V_NAT && a[2]->kind == V_NAT, | 37 | 53.1k | "VM trap: slice requires Str and Nat bounds"); | 38 | 53.1k | size_t start, end, bs, be; | 39 | 53.1k | if (!value_index(a[1], &start) || !value_index(a[2], &end) || start > end) { Branch (39:13): [True: 0, False: 53.1k]
Branch (39:43): [True: 0, False: 53.1k]
Branch (39:71): [True: 1, False: 53.1k]
| 40 | 1 | vm->error = "VM trap: invalid string slice"; | 41 | 1 | return NULL; | 42 | 1 | } | 43 | 53.1k | size_t count = a[0]->as.bytes.characters; | 44 | 53.1k | if (end > count) { Branch (44:13): [True: 3, False: 53.1k]
| 45 | 3 | vm->error = "VM trap: invalid string slice"; | 46 | 3 | return NULL; | 47 | 3 | } | 48 | 53.1k | if (start == count) { Branch (48:13): [True: 344, False: 52.8k]
| 49 | 344 | bs = a[0]->as.bytes.length; | 50 | 52.8k | } else if (!utf8_offset(a[0], start, &bs, &be)) { Branch (50:20): [True: 0, False: 52.8k]
| 51 | 0 | return NULL; | 52 | 0 | } | 53 | 53.1k | if (end == count) { Branch (53:13): [True: 4.30k, False: 48.8k]
| 54 | 4.30k | be = a[0]->as.bytes.length; | 55 | 48.8k | } else { | 56 | 48.8k | size_t ignored; | 57 | 48.8k | if (!utf8_offset(a[0], end, &be, &ignored)) { Branch (57:17): [True: 0, False: 48.8k]
| 58 | 0 | return NULL; | 59 | 0 | } | 60 | 48.8k | } | 61 | 53.1k | return value_data(V_STR, a[0]->as.bytes.data + bs, be - bs); | 62 | 53.1k | } | 63 | | | 64 | 1.23M | if (!strcmp(name, "starts_with") || !strcmp(name, "starts_with_at")) { Branch (64:9): [True: 26.1k, False: 1.21M]
Branch (64:41): [True: 487k, False: 723k]
| 65 | 513k | REQUIRE(a[0]->kind == V_STR && a[1]->kind == V_STR, "VM trap: starts_with requires Str"); | 66 | 513k | if (!strcmp(name, "starts_with_at")) { Branch (66:13): [True: 487k, False: 26.1k]
| 67 | 487k | REQUIRE(a[2]->kind == V_NAT, "VM trap: starts_with_at requires Nat offset"); | 68 | 487k | } | 69 | 513k | size_t offset = 0, bs = 0, be; | 70 | 513k | if (!strcmp(name, "starts_with_at")) { Branch (70:13): [True: 487k, False: 26.1k]
| 71 | 487k | if (!value_index(a[2], &offset)) { Branch (71:17): [True: 1, False: 487k]
| 72 | 1 | return value_bool(false); | 73 | 1 | } | 74 | 487k | if (offset == a[0]->as.bytes.characters) { Branch (74:17): [True: 3, False: 487k]
| 75 | 3 | bs = a[0]->as.bytes.length; | 76 | 487k | } else if (!utf8_offset(a[0], offset, &bs, &be)) { Branch (76:24): [True: 2, False: 487k]
| 77 | 2 | return value_bool(false); | 78 | 2 | } | 79 | 487k | } | 80 | 513k | bool result = a[1]->as.bytes.length <= a[0]->as.bytes.length - bs && Branch (80:23): [True: 489k, False: 23.4k]
| 81 | 513k | !memcmp(a[0]->as.bytes.data + bs, a[1]->as.bytes.data, a[1]->as.bytes.length); Branch (81:23): [True: 3.86k, False: 485k]
| 82 | 513k | return value_bool(result); | 83 | 513k | } | 84 | | | 85 | 723k | if (!strcmp(name, "reverse")) { Branch (85:9): [True: 6, False: 723k]
| 86 | 6 | REQUIRE(a[0]->kind == V_STR, "VM trap: reverse requires Str"); | 87 | 6 | size_t n = a[0]->as.bytes.length, source = 0, destination = n; | 88 | 6 | uint8_t *data = malloc(n ? n : 1); Branch (88:32): [True: 6, False: 0]
| 89 | 6 | if (!data) { Branch (89:13): [True: 0, False: 6]
| 90 | 0 | return NULL; | 91 | 0 | } | 92 | 26 | while (source < n) { Branch (92:16): [True: 20, False: 6]
| 93 | 20 | uint8_t c = a[0]->as.bytes.data[source]; | 94 | 20 | size_t width = c < 0x80 ? 1 : (c & 0xe0) == 0xc0 ? 2 : (c & 0xf0) == 0xe0 ? 3 : 4; Branch (94:28): [True: 8, False: 12]
Branch (94:43): [True: 6, False: 6]
Branch (94:68): [True: 1, False: 5]
| 95 | 20 | destination -= width; | 96 | 20 | memcpy(data + destination, a[0]->as.bytes.data + source, width); | 97 | 20 | source += width; | 98 | 20 | } | 99 | 6 | Value *v = value_data(V_STR, data, n); | 100 | 6 | free(data); | 101 | 6 | return v; | 102 | 6 | } | 103 | | | 104 | 723k | if (!strcmp(name, "is_digit") || !strcmp(name, "is_letter") || !strcmp(name, "is_whitespace")) { Branch (104:9): [True: 109k, False: 613k]
Branch (104:38): [True: 252k, False: 360k]
Branch (104:68): [True: 158k, False: 202k]
| 105 | 520k | REQUIRE(a[0]->kind == V_STR, "VM trap: character class requires Str"); | 106 | 520k | uint8_t c = a[0]->as.bytes.length == 1 ? a[0]->as.bytes.data[0] : 0; Branch (106:21): [True: 520k, False: 1]
| 107 | 520k | bool result = !strcmp(name, "is_digit") ? c >= '0' && c <= '9' Branch (107:23): [True: 109k, False: 411k]
Branch (107:51): [True: 64.2k, False: 45.2k]
Branch (107:63): [True: 12.4k, False: 51.7k]
| 108 | 520k | : !strcmp(name, "is_letter") Branch (108:25): [True: 252k, False: 158k]
| 109 | 411k | ? (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') Branch (109:30): [True: 201k, False: 51.3k]
Branch (109:42): [True: 11.8k, False: 189k]
Branch (109:56): [True: 177k, False: 63.9k]
Branch (109:68): [True: 171k, False: 5.78k]
| 110 | 411k | : c == ' ' || c == '\t' || c == '\r' || c == '\n'; Branch (110:29): [True: 55.8k, False: 102k]
Branch (110:41): [True: 0, False: 102k]
Branch (110:54): [True: 0, False: 102k]
Branch (110:67): [True: 173, False: 102k]
| 111 | 520k | return value_bool(result); | 112 | 520k | } | 113 | | | 114 | 202k | if (!strcmp(name, "byte_append")) { Branch (114:9): [True: 97.9k, False: 104k]
| 115 | 97.9k | REQUIRE(a[0]->kind == V_BYTES && a[1]->kind == V_NAT, | 116 | 97.9k | "VM trap: byte_append requires Bytes and Nat"); | 117 | 97.9k | size_t byte; | 118 | 97.9k | if (!value_index(a[1], &byte) || byte > 255) { Branch (118:13): [True: 0, False: 97.9k]
Branch (118:42): [True: 2, False: 97.9k]
| 119 | 2 | vm->error = "VM trap: byte value is outside 0..255"; | 120 | 2 | return NULL; | 121 | 2 | } | 122 | 97.9k | size_t n = a[0]->as.bytes.length; | 123 | 97.9k | uint8_t *data = malloc(n + 1); | 124 | 97.9k | if (!data) { Branch (124:13): [True: 0, False: 97.9k]
| 125 | 0 | return NULL; | 126 | 0 | } | 127 | 97.9k | memcpy(data, a[0]->as.bytes.data, n); | 128 | 97.9k | data[n] = (uint8_t)byte; | 129 | 97.9k | Value *v = value_data(V_BYTES, data, n + 1); | 130 | 97.9k | free(data); | 131 | 97.9k | return v; | 132 | 97.9k | } | 133 | | | 134 | 104k | if (!strcmp(name, "bytes_concat")) { Branch (134:9): [True: 62.0k, False: 42.3k]
| 135 | 62.0k | REQUIRE(a[0]->kind == V_BYTES && a[1]->kind == V_BYTES, | 136 | 62.0k | "VM trap: bytes_concat requires Bytes"); | 137 | 62.0k | size_t n = a[0]->as.bytes.length, m = a[1]->as.bytes.length; | 138 | 62.0k | uint8_t *data = malloc(n + m); | 139 | 62.0k | if (!data && n + m) { Branch (139:13): [True: 0, False: 62.0k]
Branch (139:22): [True: 0, False: 0]
| 140 | 0 | return NULL; | 141 | 0 | } | 142 | 62.0k | memcpy(data, a[0]->as.bytes.data, n); | 143 | 62.0k | memcpy(data + n, a[1]->as.bytes.data, m); | 144 | 62.0k | Value *v = value_data(V_BYTES, data, n + m); | 145 | 62.0k | free(data); | 146 | 62.0k | return v; | 147 | 62.0k | } | 148 | | | 149 | 42.3k | if (!strcmp(name, "byte_len")) { Branch (149:9): [True: 18.8k, False: 23.4k]
| 150 | 18.8k | REQUIRE(a[0]->kind == V_BYTES, "VM trap: byte_len requires Bytes"); | 151 | 18.8k | return value_size(a[0]->as.bytes.length); | 152 | 18.8k | } | 153 | | | 154 | 23.4k | if (!strcmp(name, "byte_get")) { Branch (154:9): [True: 5.55k, False: 17.9k]
| 155 | 5.55k | REQUIRE(a[0]->kind == V_BYTES && a[1]->kind == V_NAT, | 156 | 5.55k | "VM trap: byte_get requires Bytes and Nat"); | 157 | 5.55k | size_t i; | 158 | 5.55k | if (!value_index(a[1], &i) || i >= a[0]->as.bytes.length) { Branch (158:13): [True: 0, False: 5.55k]
Branch (158:39): [True: 0, False: 5.55k]
| 159 | 0 | vm->error = "VM trap: byte index is out of bounds"; | 160 | 0 | return NULL; | 161 | 0 | } | 162 | 5.55k | return value_size(a[0]->as.bytes.data[i]); | 163 | 5.55k | } | 164 | | | 165 | 17.9k | if (!strcmp(name, "utf8_encode")) { Branch (165:9): [True: 14.3k, False: 3.55k]
| 166 | 14.3k | REQUIRE(a[0]->kind == V_STR, "VM trap: utf8_encode requires Str"); | 167 | 14.3k | return value_data(V_BYTES, a[0]->as.bytes.data, a[0]->as.bytes.length); | 168 | 14.3k | } | 169 | | | 170 | 3.55k | if (!strcmp(name, "utf8_decode")) { Branch (170:9): [True: 550, False: 3.00k]
| 171 | 550 | REQUIRE(a[0]->kind == V_BYTES, "VM trap: utf8_decode requires Bytes"); | 172 | 549 | if (!utf8(a[0]->as.bytes.data, a[0]->as.bytes.length)) { Branch (172:13): [True: 2, False: 547]
| 173 | 2 | vm->error = "VM trap: invalid UTF-8"; | 174 | 2 | return NULL; | 175 | 2 | } | 176 | 547 | return value_data(V_STR, a[0]->as.bytes.data, a[0]->as.bytes.length); | 177 | 549 | } | 178 | | | 179 | 3.00k | if (!strcmp(name, "nat_from_str")) { Branch (179:9): [True: 3.00k, False: 0]
| 180 | 3.00k | REQUIRE(a[0]->kind == V_STR, "VM trap: nat_from_str requires Str"); | 181 | 3.00k | if (!a[0]->as.bytes.length) { Branch (181:13): [True: 0, False: 3.00k]
| 182 | 0 | vm->error = "VM trap: text is not a Nat"; | 183 | 0 | return NULL; | 184 | 0 | } | 185 | 13.8k | for (size_t i = 0; i < a[0]->as.bytes.length; i++) { Branch (185:28): [True: 10.8k, False: 3.00k]
| 186 | 10.8k | if (a[0]->as.bytes.data[i] < '0' || a[0]->as.bytes.data[i] > '9') { Branch (186:17): [True: 0, False: 10.8k]
Branch (186:49): [True: 0, False: 10.8k]
| 187 | 0 | vm->error = "VM trap: text is not a Nat"; | 188 | 0 | return NULL; | 189 | 0 | } | 190 | 10.8k | } | 191 | 3.00k | PnBigInt n; | 192 | 3.00k | if (!pn_big_from_digits(&n, (char *)a[0]->as.bytes.data, a[0]->as.bytes.length, 1)) { Branch (192:13): [True: 0, False: 3.00k]
| 193 | 0 | return NULL; | 194 | 0 | } | 195 | 3.00k | Value *v = value_big(V_NAT, &n); | 196 | 3.00k | pn_big_free(&n); | 197 | 3.00k | return v; | 198 | 3.00k | } | 199 | 0 | vm->error = "VM trap: unknown builtin"; | 200 | 0 | return NULL; | 201 | 3.00k | } |
|