pyscriptc 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyscriptc/__init__.py +3 -0
- pyscriptc/__main__.py +3 -0
- pyscriptc/_posthog_token.py +1 -0
- pyscriptc/builtins.py +156 -0
- pyscriptc/canonical.py +167 -0
- pyscriptc/check.py +49 -0
- pyscriptc/cli.py +271 -0
- pyscriptc/coverage.py +388 -0
- pyscriptc/debug.py +120 -0
- pyscriptc/diagnostics.py +179 -0
- pyscriptc/errors.py +56 -0
- pyscriptc/ir.py +365 -0
- pyscriptc/llvm.py +2129 -0
- pyscriptc/log.py +127 -0
- pyscriptc/lower/__init__.py +1071 -0
- pyscriptc/lower/_calls.py +1499 -0
- pyscriptc/lower/_classes.py +969 -0
- pyscriptc/lower/_core.py +301 -0
- pyscriptc/lower/_expr.py +886 -0
- pyscriptc/lower/_stdlib.py +491 -0
- pyscriptc/lower/_stdlib_shared.py +93 -0
- pyscriptc/lower/_stmt.py +1173 -0
- pyscriptc/package.py +249 -0
- pyscriptc/restlower.py +1008 -0
- pyscriptc/runtime/ps_argv.c +28 -0
- pyscriptc/runtime/ps_b64.c +168 -0
- pyscriptc/runtime/ps_coll.c +133 -0
- pyscriptc/runtime/ps_dt.c +388 -0
- pyscriptc/runtime/ps_hash.c +411 -0
- pyscriptc/runtime/ps_help.c +219 -0
- pyscriptc/runtime/ps_hmac.c +120 -0
- pyscriptc/runtime/ps_io.c +198 -0
- pyscriptc/runtime/ps_island.c +272 -0
- pyscriptc/runtime/ps_json.c +402 -0
- pyscriptc/runtime/ps_mix.c +47 -0
- pyscriptc/runtime/ps_more.c +1089 -0
- pyscriptc/runtime/ps_osmore.c +447 -0
- pyscriptc/runtime/ps_path.c +547 -0
- pyscriptc/runtime/ps_re.c +1102 -0
- pyscriptc/runtime/ps_rt.c +1175 -0
- pyscriptc/runtime/ps_rt.h +189 -0
- pyscriptc/runtime/ps_struct.c +291 -0
- pyscriptc/runtime/ps_time.c +207 -0
- pyscriptc/runtime/ps_unicode.c +1521 -0
- pyscriptc/runtime/ps_url.c +327 -0
- pyscriptc/stdlib_queue.py +191 -0
- pyscriptc/stdmore.py +1596 -0
- pyscriptc/telemetry.py +219 -0
- pyscriptc-0.1.0.dist-info/METADATA +187 -0
- pyscriptc-0.1.0.dist-info/RECORD +54 -0
- pyscriptc-0.1.0.dist-info/WHEEL +5 -0
- pyscriptc-0.1.0.dist-info/entry_points.txt +2 -0
- pyscriptc-0.1.0.dist-info/licenses/LICENSE +201 -0
- pyscriptc-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1089 @@
|
|
|
1
|
+
/* R1-R5 helpers: list/dict method cores, str tier-2 methods, scalar casts.
|
|
2
|
+
|
|
3
|
+
All strings and bytes are PsBuf cells ({i64 len, char *data}); comparisons are
|
|
4
|
+
bytewise, which pins the whole surface to ASCII/Latin-1 semantics. Every
|
|
5
|
+
mutating helper works in place on the caller's PsSeq/PsMap.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include "ps_rt.h"
|
|
9
|
+
|
|
10
|
+
#include <stdlib.h>
|
|
11
|
+
#include <string.h>
|
|
12
|
+
|
|
13
|
+
static char *ps_cell(PsSeq *s, int64_t i) {
|
|
14
|
+
return (char *)s->data + (size_t)i * (size_t)s->elem;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static void ps_seq_gap(PsSeq *s) {
|
|
18
|
+
if (s->len == s->cap) {
|
|
19
|
+
int64_t cap = s->cap == 0 ? 4 : s->cap * 2;
|
|
20
|
+
void *data;
|
|
21
|
+
if ((uint64_t)cap > UINT64_MAX / (uint64_t)s->elem) {
|
|
22
|
+
ps_raise_code(PS_OVERFLOW);
|
|
23
|
+
}
|
|
24
|
+
data = realloc(s->data, (size_t)cap * (size_t)s->elem);
|
|
25
|
+
if (data == NULL) {
|
|
26
|
+
abort();
|
|
27
|
+
}
|
|
28
|
+
s->data = data;
|
|
29
|
+
s->cap = cap;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static void ps_push_view(PsSeq *seq, const char *p, int64_t n) {
|
|
34
|
+
PsBuf piece;
|
|
35
|
+
ps_buf_view(&piece, p, n);
|
|
36
|
+
ps_seq_push(seq, &piece);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* list core (R2) */
|
|
40
|
+
|
|
41
|
+
PsSeq *ps_seq_concat(PsSeq *a, PsSeq *b) {
|
|
42
|
+
PsSeq *out;
|
|
43
|
+
if (a->elem != b->elem) {
|
|
44
|
+
ps_raise_cstr(PS_VALUE, "list concat element size mismatch");
|
|
45
|
+
}
|
|
46
|
+
out = ps_seq_new(a->elem, a->len + b->len);
|
|
47
|
+
if (a->len > 0) {
|
|
48
|
+
memcpy(out->data, a->data, (size_t)a->len * (size_t)a->elem);
|
|
49
|
+
}
|
|
50
|
+
if (b->len > 0) {
|
|
51
|
+
memcpy(ps_cell(out, a->len), b->data, (size_t)b->len * (size_t)b->elem);
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
PsSeq *ps_seq_repeat(PsSeq *s, int64_t n) {
|
|
57
|
+
int64_t i;
|
|
58
|
+
PsSeq *out;
|
|
59
|
+
if (n <= 0) {
|
|
60
|
+
return ps_seq_new(s->elem, 0);
|
|
61
|
+
}
|
|
62
|
+
out = ps_seq_new(s->elem, s->len * n);
|
|
63
|
+
for (i = 0; i < n; i++) {
|
|
64
|
+
if (s->len > 0) {
|
|
65
|
+
memcpy(ps_cell(out, i * s->len), s->data, (size_t)s->len * (size_t)s->elem);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
void ps_seq_extend(PsSeq *dst, PsSeq *src) {
|
|
72
|
+
int64_t i;
|
|
73
|
+
if (dst->elem != src->elem) {
|
|
74
|
+
ps_raise_cstr(PS_VALUE, "list extend element size mismatch");
|
|
75
|
+
}
|
|
76
|
+
for (i = 0; i < src->len; i++) {
|
|
77
|
+
ps_seq_push(dst, ps_cell(src, i));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
void ps_seq_insert(PsSeq *s, int64_t i, void *src) {
|
|
82
|
+
if (i < 0) {
|
|
83
|
+
i += s->len;
|
|
84
|
+
if (i < 0) {
|
|
85
|
+
i = 0;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (i > s->len) {
|
|
89
|
+
i = s->len;
|
|
90
|
+
}
|
|
91
|
+
ps_seq_gap(s);
|
|
92
|
+
memmove(ps_cell(s, i + 1), ps_cell(s, i), (size_t)(s->len - i) * (size_t)s->elem);
|
|
93
|
+
memcpy(ps_cell(s, i), src, (size_t)s->elem);
|
|
94
|
+
s->len += 1;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
void ps_seq_reverse(PsSeq *s) {
|
|
98
|
+
char *tmp = malloc((size_t)s->elem);
|
|
99
|
+
int64_t i;
|
|
100
|
+
if (tmp == NULL) {
|
|
101
|
+
abort();
|
|
102
|
+
}
|
|
103
|
+
for (i = 0; i < s->len / 2; i++) {
|
|
104
|
+
char *a = ps_cell(s, i);
|
|
105
|
+
char *b = ps_cell(s, s->len - 1 - i);
|
|
106
|
+
memcpy(tmp, a, (size_t)s->elem);
|
|
107
|
+
memcpy(a, b, (size_t)s->elem);
|
|
108
|
+
memcpy(b, tmp, (size_t)s->elem);
|
|
109
|
+
}
|
|
110
|
+
free(tmp);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
static int ps_cmp_i64(const void *a, const void *b) {
|
|
114
|
+
int64_t x = *(const int64_t *)a, y = *(const int64_t *)b;
|
|
115
|
+
return x < y ? -1 : x > y ? 1 : 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
static int ps_cmp_f64(const void *a, const void *b) {
|
|
119
|
+
double x = *(const double *)a, y = *(const double *)b;
|
|
120
|
+
if (x != x || y != y) {
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
return x < y ? -1 : x > y ? 1 : 0;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
static int ps_cmp_buf(const void *a, const void *b) {
|
|
127
|
+
const PsBuf *x = a, *y = b;
|
|
128
|
+
int64_t n = x->len < y->len ? x->len : y->len;
|
|
129
|
+
int c = n > 0 ? memcmp(x->data, y->data, (size_t)n) : 0;
|
|
130
|
+
if (c != 0) {
|
|
131
|
+
return c;
|
|
132
|
+
}
|
|
133
|
+
return x->len < y->len ? -1 : x->len > y->len ? 1 : 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
void ps_seq_sort_i64(PsSeq *s, int64_t desc) {
|
|
137
|
+
qsort(s->data, (size_t)s->len, (size_t)s->elem, ps_cmp_i64);
|
|
138
|
+
if (desc) {
|
|
139
|
+
ps_seq_reverse(s);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
void ps_seq_sort_f64(PsSeq *s, int64_t desc) {
|
|
144
|
+
qsort(s->data, (size_t)s->len, (size_t)s->elem, ps_cmp_f64);
|
|
145
|
+
if (desc) {
|
|
146
|
+
ps_seq_reverse(s);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
void ps_seq_sort_buf(PsSeq *s, int64_t desc) {
|
|
151
|
+
qsort(s->data, (size_t)s->len, (size_t)s->elem, ps_cmp_buf);
|
|
152
|
+
if (desc) {
|
|
153
|
+
ps_seq_reverse(s);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
int64_t ps_seq_index_i64(PsSeq *s, int64_t needle) {
|
|
158
|
+
int64_t i;
|
|
159
|
+
for (i = 0; i < s->len; i++) {
|
|
160
|
+
if (*(int64_t *)ps_cell(s, i) == needle) {
|
|
161
|
+
return i;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
ps_raise_code(PS_VALUE);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
int64_t ps_seq_index_f64(PsSeq *s, double needle) {
|
|
168
|
+
int64_t i;
|
|
169
|
+
for (i = 0; i < s->len; i++) {
|
|
170
|
+
if (*(double *)ps_cell(s, i) == needle) {
|
|
171
|
+
return i;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
ps_raise_code(PS_VALUE);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
int64_t ps_seq_index_buf(PsSeq *s, int64_t n, char *p) {
|
|
178
|
+
int64_t i;
|
|
179
|
+
for (i = 0; i < s->len; i++) {
|
|
180
|
+
PsBuf *cell = (PsBuf *)ps_cell(s, i);
|
|
181
|
+
if (cell->len == n && (n == 0 || memcmp(cell->data, p, (size_t)n) == 0)) {
|
|
182
|
+
return i;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
ps_raise_code(PS_VALUE);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
int64_t ps_seq_count_i64(PsSeq *s, int64_t needle) {
|
|
189
|
+
int64_t i, hits = 0;
|
|
190
|
+
for (i = 0; i < s->len; i++) {
|
|
191
|
+
if (*(int64_t *)ps_cell(s, i) == needle) {
|
|
192
|
+
hits++;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return hits;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
int64_t ps_seq_count_f64(PsSeq *s, double needle) {
|
|
199
|
+
int64_t i, hits = 0;
|
|
200
|
+
for (i = 0; i < s->len; i++) {
|
|
201
|
+
if (*(double *)ps_cell(s, i) == needle) {
|
|
202
|
+
hits++;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return hits;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
int64_t ps_seq_count_buf(PsSeq *s, int64_t n, char *p) {
|
|
209
|
+
int64_t i, hits = 0;
|
|
210
|
+
for (i = 0; i < s->len; i++) {
|
|
211
|
+
PsBuf *cell = (PsBuf *)ps_cell(s, i);
|
|
212
|
+
if (cell->len == n && (n == 0 || memcmp(cell->data, p, (size_t)n) == 0)) {
|
|
213
|
+
hits++;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return hits;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
static void ps_seq_drop(PsSeq *s, int64_t i) {
|
|
220
|
+
memmove(ps_cell(s, i), ps_cell(s, i + 1), (size_t)(s->len - i - 1) * (size_t)s->elem);
|
|
221
|
+
s->len -= 1;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
void ps_seq_remove_i64(PsSeq *s, int64_t needle) {
|
|
225
|
+
ps_seq_drop(s, ps_seq_index_i64(s, needle));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
void ps_seq_remove_f64(PsSeq *s, double needle) {
|
|
229
|
+
ps_seq_drop(s, ps_seq_index_f64(s, needle));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
void ps_seq_remove_buf(PsSeq *s, int64_t n, char *p) {
|
|
233
|
+
ps_seq_drop(s, ps_seq_index_buf(s, n, p));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* dict core (R1) */
|
|
237
|
+
|
|
238
|
+
void ps_map_del(PsMap *m, void *key) {
|
|
239
|
+
/* key cells are int64_t (key_kind 1) or PsBuf; find inline to avoid an
|
|
240
|
+
extra exported lookup beside ps_map_get/ps_map_has. */
|
|
241
|
+
int64_t i, at = -1;
|
|
242
|
+
for (i = 0; i < m->len; i++) {
|
|
243
|
+
void *cell = (char *)m->keys + (size_t)i * (size_t)m->key_size;
|
|
244
|
+
if (m->key_kind == 1) {
|
|
245
|
+
if (*(int64_t *)cell == *(int64_t *)key) {
|
|
246
|
+
at = i;
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
} else {
|
|
250
|
+
PsBuf *a = cell, *b = key;
|
|
251
|
+
if (a->len == b->len && (a->len == 0 || memcmp(a->data, b->data, (size_t)a->len) == 0)) {
|
|
252
|
+
at = i;
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (at < 0) {
|
|
258
|
+
ps_raise_code(PS_KEY);
|
|
259
|
+
}
|
|
260
|
+
if (at < m->len - 1) {
|
|
261
|
+
memmove(
|
|
262
|
+
(char *)m->keys + (size_t)at * (size_t)m->key_size,
|
|
263
|
+
(char *)m->keys + (size_t)(at + 1) * (size_t)m->key_size,
|
|
264
|
+
(size_t)(m->len - at - 1) * (size_t)m->key_size
|
|
265
|
+
);
|
|
266
|
+
memmove(
|
|
267
|
+
(char *)m->vals + (size_t)at * (size_t)m->val_size,
|
|
268
|
+
(char *)m->vals + (size_t)(at + 1) * (size_t)m->val_size,
|
|
269
|
+
(size_t)(m->len - at - 1) * (size_t)m->val_size
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
m->len -= 1;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
void ps_map_clear(PsMap *m) { m->len = 0; }
|
|
276
|
+
|
|
277
|
+
void ps_map_update(PsMap *dst, PsMap *src) {
|
|
278
|
+
int64_t i;
|
|
279
|
+
if (dst->key_kind != src->key_kind || dst->key_size != src->key_size || dst->val_size != src->val_size) {
|
|
280
|
+
ps_raise_cstr(PS_VALUE, "dict update layout mismatch");
|
|
281
|
+
}
|
|
282
|
+
for (i = 0; i < src->len; i++) {
|
|
283
|
+
ps_map_put(
|
|
284
|
+
dst,
|
|
285
|
+
(char *)src->keys + (size_t)i * (size_t)src->key_size,
|
|
286
|
+
(char *)src->vals + (size_t)i * (size_t)src->val_size
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
PsSeq *ps_dict_values(PsMap *m) {
|
|
292
|
+
PsSeq *seq = ps_seq_new(m->val_size, m->len);
|
|
293
|
+
int64_t i;
|
|
294
|
+
for (i = 0; i < m->len; i++) {
|
|
295
|
+
ps_seq_set(seq, i, (char *)m->vals + (size_t)i * (size_t)m->val_size);
|
|
296
|
+
}
|
|
297
|
+
return seq;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/* seq of {key, val} tuple objects: each cell is a pointer to a heap tuple
|
|
301
|
+
(key at offset 0, val at voff, object size csize), matching the pointer
|
|
302
|
+
layout ps_re_findall_groups uses for list[tuple]. */
|
|
303
|
+
PsSeq *ps_dict_items(PsMap *m, int64_t voff, int64_t csize) {
|
|
304
|
+
PsSeq *seq = ps_seq_new((int64_t)sizeof(void *), m->len);
|
|
305
|
+
int64_t i;
|
|
306
|
+
for (i = 0; i < m->len; i++) {
|
|
307
|
+
char *tup = malloc((size_t)csize);
|
|
308
|
+
if (tup == NULL) {
|
|
309
|
+
abort();
|
|
310
|
+
}
|
|
311
|
+
memcpy(tup, (char *)m->keys + (size_t)i * (size_t)m->key_size, (size_t)m->key_size);
|
|
312
|
+
memcpy(tup + voff, (char *)m->vals + (size_t)i * (size_t)m->val_size, (size_t)m->val_size);
|
|
313
|
+
*(void **)ps_cell(seq, i) = tup;
|
|
314
|
+
}
|
|
315
|
+
return seq;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/* str tier-2 (R3): bytewise ASCII semantics */
|
|
319
|
+
|
|
320
|
+
static int ps_ws(unsigned char c) {
|
|
321
|
+
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f' || c == 0x1c ||
|
|
322
|
+
c == 0x1d || c == 0x1e || c == 0x1f || c == 0x85 || c == 0xa0;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
static int ps_isdig(unsigned char c) { return c >= '0' && c <= '9'; }
|
|
326
|
+
static int ps_islo(unsigned char c) { return (c >= 'a' && c <= 'z') || (c >= 0xe0 && c <= 0xfe && c != 0xf7); }
|
|
327
|
+
static int ps_isup(unsigned char c) { return (c >= 'A' && c <= 'Z') || (c >= 0xc0 && c <= 0xde && c != 0xd7); }
|
|
328
|
+
static int ps_isalpha2(unsigned char c) { return ps_islo(c) || ps_isup(c); }
|
|
329
|
+
static int ps_isalnum2(unsigned char c) { return ps_isalpha2(c) || ps_isdig(c); }
|
|
330
|
+
|
|
331
|
+
int64_t ps_str_count(int64_t n, const char *p, int64_t sn, const char *sp) {
|
|
332
|
+
int64_t i = 0, hits = 0;
|
|
333
|
+
if (sn == 0) {
|
|
334
|
+
return n + 1;
|
|
335
|
+
}
|
|
336
|
+
while (i + sn <= n) {
|
|
337
|
+
if (memcmp(p + i, sp, (size_t)sn) == 0) {
|
|
338
|
+
hits++;
|
|
339
|
+
i += sn;
|
|
340
|
+
} else {
|
|
341
|
+
i++;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return hits;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
int64_t ps_str_index(int64_t n, const char *p, int64_t sn, const char *sp) {
|
|
348
|
+
int64_t i = 0;
|
|
349
|
+
while (i + sn <= n) {
|
|
350
|
+
if (memcmp(p + i, sp, (size_t)sn) == 0) {
|
|
351
|
+
return i;
|
|
352
|
+
}
|
|
353
|
+
i++;
|
|
354
|
+
}
|
|
355
|
+
ps_raise_code(PS_VALUE);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
int64_t ps_str_rfind(int64_t n, const char *p, int64_t sn, const char *sp) {
|
|
359
|
+
int64_t i;
|
|
360
|
+
if (sn == 0) {
|
|
361
|
+
return n;
|
|
362
|
+
}
|
|
363
|
+
for (i = n - sn; i >= 0; i--) {
|
|
364
|
+
if (memcmp(p + i, sp, (size_t)sn) == 0) {
|
|
365
|
+
return i;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return -1;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
/* word scanner: fills lo/hi with word bounds. ascii=1 restricts whitespace
|
|
373
|
+
to the six ASCII bytes (bytes.split); ascii=0 adds the str whitespace set. */
|
|
374
|
+
static int64_t ps_scan_words(int64_t n, const char *p, int64_t *lo, int64_t *hi, int ascii) {
|
|
375
|
+
int64_t i = 0, count = 0;
|
|
376
|
+
while (i < n) {
|
|
377
|
+
int64_t j;
|
|
378
|
+
unsigned char c = (unsigned char)p[i];
|
|
379
|
+
int space = ascii ? (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f')
|
|
380
|
+
: ps_ws(c);
|
|
381
|
+
if (space) {
|
|
382
|
+
i++;
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
j = i + 1;
|
|
386
|
+
while (j < n) {
|
|
387
|
+
unsigned char d = (unsigned char)p[j];
|
|
388
|
+
int gap = ascii ? (d == ' ' || d == '\t' || d == '\n' || d == '\r' || d == '\v' || d == '\f')
|
|
389
|
+
: ps_ws(d);
|
|
390
|
+
if (gap) {
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
j++;
|
|
394
|
+
}
|
|
395
|
+
lo[count] = i;
|
|
396
|
+
hi[count] = j;
|
|
397
|
+
count++;
|
|
398
|
+
i = j;
|
|
399
|
+
}
|
|
400
|
+
return count;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/* generic split driver. mode 0 = separator (str/bytes same), 1 = str
|
|
404
|
+
whitespace, 2 = bytes whitespace. right = rsplit. maxsplit < 0 unlimited. */
|
|
405
|
+
PsSeq *ps_str_split_m(
|
|
406
|
+
int64_t n, const char *p, int64_t sn, const char *sp, int64_t mode, int64_t maxsplit, int64_t right
|
|
407
|
+
) {
|
|
408
|
+
PsSeq *seq;
|
|
409
|
+
if (mode == 0 && sn == 0) {
|
|
410
|
+
ps_raise_cstr(PS_VALUE, "empty separator");
|
|
411
|
+
}
|
|
412
|
+
seq = ps_seq_new(sizeof(PsBuf), 0);
|
|
413
|
+
if (mode == 0) {
|
|
414
|
+
/* separator mode */
|
|
415
|
+
if (maxsplit < 0 || right == 0) {
|
|
416
|
+
int64_t i = 0, left = maxsplit < 0 ? INT64_MAX : maxsplit;
|
|
417
|
+
while (i <= n) {
|
|
418
|
+
int64_t j = i;
|
|
419
|
+
int found = 0;
|
|
420
|
+
if (left == 0) {
|
|
421
|
+
ps_push_view(seq, p + i, n - i);
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
424
|
+
while (j + sn <= n) {
|
|
425
|
+
if (memcmp(p + j, sp, (size_t)sn) == 0) {
|
|
426
|
+
found = 1;
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
j++;
|
|
430
|
+
}
|
|
431
|
+
if (!found) {
|
|
432
|
+
ps_push_view(seq, p + i, n - i);
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
ps_push_view(seq, p + i, j - i);
|
|
436
|
+
left--;
|
|
437
|
+
i = j + sn;
|
|
438
|
+
if (i == n) {
|
|
439
|
+
ps_push_view(seq, p + n, 0);
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return seq;
|
|
444
|
+
}
|
|
445
|
+
/* rsplit with maxsplit: collect match starts, then emit right pieces. */
|
|
446
|
+
{
|
|
447
|
+
int64_t cap = n / (sn > 0 ? sn : 1) + 2;
|
|
448
|
+
int64_t *cuts = malloc((size_t)cap * sizeof(int64_t));
|
|
449
|
+
int64_t count = 0, i = 0, k;
|
|
450
|
+
if (cuts == NULL) {
|
|
451
|
+
abort();
|
|
452
|
+
}
|
|
453
|
+
while (i + sn <= n) {
|
|
454
|
+
if (memcmp(p + i, sp, (size_t)sn) == 0) {
|
|
455
|
+
cuts[count++] = i;
|
|
456
|
+
i += sn;
|
|
457
|
+
} else {
|
|
458
|
+
i++;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
/* head ends at cuts[count - maxsplit]; pieces follow each cut. */
|
|
462
|
+
{
|
|
463
|
+
int64_t head_end = count > maxsplit ? cuts[count - maxsplit] : -1;
|
|
464
|
+
int64_t first = count > maxsplit ? count - maxsplit : 0;
|
|
465
|
+
if (head_end >= 0) {
|
|
466
|
+
ps_push_view(seq, p, head_end);
|
|
467
|
+
}
|
|
468
|
+
for (k = first; k < count; k++) {
|
|
469
|
+
int64_t start = cuts[k] + sn;
|
|
470
|
+
int64_t end = k + 1 < count ? cuts[k + 1] : n;
|
|
471
|
+
ps_push_view(seq, p + start, end - start);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
free(cuts);
|
|
475
|
+
return seq;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
/* whitespace modes */
|
|
479
|
+
{
|
|
480
|
+
int64_t cap = n / 2 + 2;
|
|
481
|
+
int64_t *lo = malloc((size_t)cap * sizeof(int64_t));
|
|
482
|
+
int64_t *hi = malloc((size_t)cap * sizeof(int64_t));
|
|
483
|
+
int64_t count, w;
|
|
484
|
+
if (lo == NULL || hi == NULL) {
|
|
485
|
+
abort();
|
|
486
|
+
}
|
|
487
|
+
count = ps_scan_words(n, p, lo, hi, mode == 2);
|
|
488
|
+
if (maxsplit < 0 || count <= maxsplit || maxsplit == 0) {
|
|
489
|
+
if (maxsplit == 0 && !right && n > 0) {
|
|
490
|
+
/* str.split(None, 0): only leading whitespace is stripped */
|
|
491
|
+
int64_t s = 0;
|
|
492
|
+
while (s < n) {
|
|
493
|
+
unsigned char c = (unsigned char)p[s];
|
|
494
|
+
int space = mode == 2
|
|
495
|
+
? (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f')
|
|
496
|
+
: ps_ws(c);
|
|
497
|
+
if (!space) {
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
s++;
|
|
501
|
+
}
|
|
502
|
+
ps_push_view(seq, p + s, n - s);
|
|
503
|
+
} else if (maxsplit == 0 && right) {
|
|
504
|
+
/* rsplit(None, 0): only trailing whitespace is stripped */
|
|
505
|
+
int64_t e = n;
|
|
506
|
+
while (e > 0) {
|
|
507
|
+
unsigned char c = (unsigned char)p[e - 1];
|
|
508
|
+
int space = mode == 2
|
|
509
|
+
? (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f')
|
|
510
|
+
: ps_ws(c);
|
|
511
|
+
if (!space) {
|
|
512
|
+
break;
|
|
513
|
+
}
|
|
514
|
+
e--;
|
|
515
|
+
}
|
|
516
|
+
ps_push_view(seq, p, e);
|
|
517
|
+
} else {
|
|
518
|
+
for (w = 0; w < count; w++) {
|
|
519
|
+
ps_push_view(seq, p + lo[w], hi[w] - lo[w]);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
} else if (!right) {
|
|
523
|
+
/* split: first maxsplit words, then the rest verbatim minus
|
|
524
|
+
surrounding whitespace. */
|
|
525
|
+
int64_t s, e;
|
|
526
|
+
for (w = 0; w < maxsplit; w++) {
|
|
527
|
+
ps_push_view(seq, p + lo[w], hi[w] - lo[w]);
|
|
528
|
+
}
|
|
529
|
+
s = hi[maxsplit - 1];
|
|
530
|
+
e = n;
|
|
531
|
+
while (s < e && ps_ws((unsigned char)p[s])) {
|
|
532
|
+
s++;
|
|
533
|
+
}
|
|
534
|
+
while (e > s && ps_ws((unsigned char)p[e - 1])) {
|
|
535
|
+
e--;
|
|
536
|
+
}
|
|
537
|
+
ps_push_view(seq, p + s, e - s);
|
|
538
|
+
} else {
|
|
539
|
+
/* rsplit: head verbatim minus surrounding ws + last maxsplit words */
|
|
540
|
+
int64_t e = lo[count - maxsplit];
|
|
541
|
+
int64_t s = 0;
|
|
542
|
+
while (e > s && ps_ws((unsigned char)p[e - 1])) {
|
|
543
|
+
e--;
|
|
544
|
+
}
|
|
545
|
+
while (s < e && ps_ws((unsigned char)p[s])) {
|
|
546
|
+
s++;
|
|
547
|
+
}
|
|
548
|
+
ps_push_view(seq, p + s, e - s);
|
|
549
|
+
for (w = count - maxsplit; w < count; w++) {
|
|
550
|
+
ps_push_view(seq, p + lo[w], hi[w] - lo[w]);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
free(lo);
|
|
554
|
+
free(hi);
|
|
555
|
+
return seq;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/* splitlines: \n \r \r\n \v \f \x1c-\x1e \x85; keepends flag. */
|
|
560
|
+
PsSeq *ps_str_splitlines(int64_t n, const char *p, int64_t keepends) {
|
|
561
|
+
PsSeq *seq = ps_seq_new(sizeof(PsBuf), 0);
|
|
562
|
+
int64_t i = 0, start = 0;
|
|
563
|
+
while (i < n) {
|
|
564
|
+
unsigned char c = (unsigned char)p[i];
|
|
565
|
+
int isbreak = c == '\n' || c == '\r' || c == '\v' || c == '\f' || (c >= 0x1c && c <= 0x1e) || c == 0x85;
|
|
566
|
+
int64_t end;
|
|
567
|
+
if (!isbreak) {
|
|
568
|
+
i++;
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
end = i;
|
|
572
|
+
if (c == '\r' && i + 1 < n && p[i + 1] == '\n') {
|
|
573
|
+
i += 2;
|
|
574
|
+
} else {
|
|
575
|
+
i++;
|
|
576
|
+
}
|
|
577
|
+
if (keepends) {
|
|
578
|
+
ps_push_view(seq, p + start, i - start);
|
|
579
|
+
} else {
|
|
580
|
+
ps_push_view(seq, p + start, end - start);
|
|
581
|
+
}
|
|
582
|
+
start = i;
|
|
583
|
+
}
|
|
584
|
+
if (start < n) {
|
|
585
|
+
ps_push_view(seq, p + start, n - start);
|
|
586
|
+
}
|
|
587
|
+
return seq;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/* predicates: empty -> 0. */
|
|
591
|
+
int64_t ps_str_isdigit(int64_t n, const char *p) {
|
|
592
|
+
int64_t i;
|
|
593
|
+
if (n == 0) {
|
|
594
|
+
return 0;
|
|
595
|
+
}
|
|
596
|
+
for (i = 0; i < n; i++) {
|
|
597
|
+
if (!ps_isdig((unsigned char)p[i])) {
|
|
598
|
+
return 0;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
return 1;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
int64_t ps_str_isalpha(int64_t n, const char *p) {
|
|
605
|
+
int64_t i;
|
|
606
|
+
if (n == 0) {
|
|
607
|
+
return 0;
|
|
608
|
+
}
|
|
609
|
+
for (i = 0; i < n; i++) {
|
|
610
|
+
if (!ps_isalpha2((unsigned char)p[i])) {
|
|
611
|
+
return 0;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return 1;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
int64_t ps_str_isalnum(int64_t n, const char *p) {
|
|
618
|
+
int64_t i;
|
|
619
|
+
if (n == 0) {
|
|
620
|
+
return 0;
|
|
621
|
+
}
|
|
622
|
+
for (i = 0; i < n; i++) {
|
|
623
|
+
if (!ps_isalnum2((unsigned char)p[i])) {
|
|
624
|
+
return 0;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
return 1;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
int64_t ps_str_isspace(int64_t n, const char *p) {
|
|
631
|
+
int64_t i;
|
|
632
|
+
if (n == 0) {
|
|
633
|
+
return 0;
|
|
634
|
+
}
|
|
635
|
+
for (i = 0; i < n; i++) {
|
|
636
|
+
if (!ps_ws((unsigned char)p[i])) {
|
|
637
|
+
return 0;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
return 1;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
int64_t ps_str_isupper(int64_t n, const char *p) {
|
|
644
|
+
int64_t i, any = 0;
|
|
645
|
+
for (i = 0; i < n; i++) {
|
|
646
|
+
unsigned char c = (unsigned char)p[i];
|
|
647
|
+
if (ps_islo(c)) {
|
|
648
|
+
return 0;
|
|
649
|
+
}
|
|
650
|
+
if (ps_isup(c)) {
|
|
651
|
+
any = 1;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return any;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
int64_t ps_str_islower(int64_t n, const char *p) {
|
|
658
|
+
int64_t i, any = 0;
|
|
659
|
+
for (i = 0; i < n; i++) {
|
|
660
|
+
unsigned char c = (unsigned char)p[i];
|
|
661
|
+
if (ps_isup(c)) {
|
|
662
|
+
return 0;
|
|
663
|
+
}
|
|
664
|
+
if (ps_islo(c)) {
|
|
665
|
+
any = 1;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
return any;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
static unsigned char ps_tolower_c(unsigned char c) {
|
|
672
|
+
if (c >= 'A' && c <= 'Z') {
|
|
673
|
+
return (unsigned char)(c + 32);
|
|
674
|
+
}
|
|
675
|
+
if (c >= 0xc0 && c <= 0xde && c != 0xd7) {
|
|
676
|
+
return (unsigned char)(c + 0x20);
|
|
677
|
+
}
|
|
678
|
+
return c;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
static unsigned char ps_toupper_c(unsigned char c) {
|
|
682
|
+
if (c >= 'a' && c <= 'z') {
|
|
683
|
+
return (unsigned char)(c - 32);
|
|
684
|
+
}
|
|
685
|
+
if (c >= 0xe0 && c <= 0xfe && c != 0xf7) {
|
|
686
|
+
return (unsigned char)(c - 0x20);
|
|
687
|
+
}
|
|
688
|
+
return c;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
void ps_str_title(int64_t n, const char *p, PsBuf *out) {
|
|
692
|
+
char *q = malloc((size_t)n + 1);
|
|
693
|
+
int64_t i;
|
|
694
|
+
int prev_alpha = 0;
|
|
695
|
+
if (q == NULL) {
|
|
696
|
+
abort();
|
|
697
|
+
}
|
|
698
|
+
for (i = 0; i < n; i++) {
|
|
699
|
+
unsigned char c = (unsigned char)p[i];
|
|
700
|
+
if (ps_isalpha2(c)) {
|
|
701
|
+
q[i] = (char)(prev_alpha ? ps_tolower_c(c) : ps_toupper_c(c));
|
|
702
|
+
prev_alpha = 1;
|
|
703
|
+
} else {
|
|
704
|
+
q[i] = (char)c;
|
|
705
|
+
prev_alpha = 0;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
out->len = n;
|
|
709
|
+
out->data = q;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
void ps_str_capitalize(int64_t n, const char *p, PsBuf *out) {
|
|
713
|
+
char *q = malloc((size_t)n + 1);
|
|
714
|
+
int64_t i;
|
|
715
|
+
if (q == NULL) {
|
|
716
|
+
abort();
|
|
717
|
+
}
|
|
718
|
+
for (i = 0; i < n; i++) {
|
|
719
|
+
unsigned char c = (unsigned char)p[i];
|
|
720
|
+
q[i] = (char)(i == 0 ? ps_toupper_c(c) : ps_tolower_c(c));
|
|
721
|
+
}
|
|
722
|
+
out->len = n;
|
|
723
|
+
out->data = q;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
void ps_str_casefold(int64_t n, const char *p, PsBuf *out) {
|
|
727
|
+
/* ASCII fold == lower() here */
|
|
728
|
+
char *q = malloc((size_t)n + 1);
|
|
729
|
+
int64_t i;
|
|
730
|
+
if (q == NULL) {
|
|
731
|
+
abort();
|
|
732
|
+
}
|
|
733
|
+
for (i = 0; i < n; i++) {
|
|
734
|
+
q[i] = (char)ps_tolower_c((unsigned char)p[i]);
|
|
735
|
+
}
|
|
736
|
+
out->len = n;
|
|
737
|
+
out->data = q;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
void ps_str_swapcase(int64_t n, const char *p, PsBuf *out) {
|
|
741
|
+
char *q = malloc((size_t)n + 1);
|
|
742
|
+
int64_t i;
|
|
743
|
+
if (q == NULL) {
|
|
744
|
+
abort();
|
|
745
|
+
}
|
|
746
|
+
for (i = 0; i < n; i++) {
|
|
747
|
+
unsigned char c = (unsigned char)p[i];
|
|
748
|
+
if (ps_islo(c)) {
|
|
749
|
+
q[i] = (char)ps_toupper_c(c);
|
|
750
|
+
} else if (ps_isup(c)) {
|
|
751
|
+
q[i] = (char)ps_tolower_c(c);
|
|
752
|
+
} else {
|
|
753
|
+
q[i] = (char)c;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
out->len = n;
|
|
757
|
+
out->data = q;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
void ps_str_zfill(int64_t n, const char *p, int64_t width, PsBuf *out) {
|
|
761
|
+
int64_t pad, s = 0;
|
|
762
|
+
char *q;
|
|
763
|
+
if (width <= n) {
|
|
764
|
+
ps_buf_copy(out, p, n);
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
pad = width - n;
|
|
768
|
+
q = malloc((size_t)width + 1);
|
|
769
|
+
if (q == NULL) {
|
|
770
|
+
abort();
|
|
771
|
+
}
|
|
772
|
+
if (n > 0 && (p[0] == '+' || p[0] == '-')) {
|
|
773
|
+
q[0] = p[0];
|
|
774
|
+
s = 1;
|
|
775
|
+
}
|
|
776
|
+
memset(q + s, '0', (size_t)pad);
|
|
777
|
+
memcpy(q + s + pad, p + s, (size_t)(n - s));
|
|
778
|
+
out->len = width;
|
|
779
|
+
out->data = q;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
/* pad side: 0 = ljust, 1 = rjust, 2 = center */
|
|
783
|
+
void ps_str_justify(int64_t n, const char *p, int64_t width, int64_t fn, const char *fc, int64_t side, PsBuf *out) {
|
|
784
|
+
int64_t pad, left, i;
|
|
785
|
+
char *q;
|
|
786
|
+
if (width <= n) {
|
|
787
|
+
ps_buf_copy(out, p, n);
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
pad = width - n;
|
|
791
|
+
left = side == 0 ? 0 : side == 1 ? pad : pad / 2 + (pad & width & 1);
|
|
792
|
+
q = malloc((size_t)width + 1);
|
|
793
|
+
if (q == NULL) {
|
|
794
|
+
abort();
|
|
795
|
+
}
|
|
796
|
+
if (fn <= 0) {
|
|
797
|
+
memset(q, ' ', (size_t)width);
|
|
798
|
+
} else {
|
|
799
|
+
for (i = 0; i < width; i++) {
|
|
800
|
+
q[i] = fc[i % fn];
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
memcpy(q + left, p, (size_t)n);
|
|
804
|
+
out->len = width;
|
|
805
|
+
out->data = q;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
void ps_str_removeprefix(int64_t n, const char *p, int64_t sn, const char *sp, PsBuf *out) {
|
|
809
|
+
if (sn <= n && memcmp(p, sp, (size_t)sn) == 0) {
|
|
810
|
+
ps_buf_copy(out, p + sn, n - sn);
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
ps_buf_copy(out, p, n);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
void ps_str_removesuffix(int64_t n, const char *p, int64_t sn, const char *sp, PsBuf *out) {
|
|
817
|
+
if (sn <= n && sn > 0 && memcmp(p + n - sn, sp, (size_t)sn) == 0) {
|
|
818
|
+
ps_buf_copy(out, p, n - sn);
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
if (sn == 0) {
|
|
822
|
+
ps_buf_copy(out, p, n);
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
ps_buf_copy(out, p, n);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
void ps_str_expandtabs(int64_t n, const char *p, int64_t tabsize, PsBuf *out) {
|
|
829
|
+
int64_t i, col = 0, total = 0;
|
|
830
|
+
char *q, *w;
|
|
831
|
+
for (i = 0; i < n; i++) {
|
|
832
|
+
unsigned char c = (unsigned char)p[i];
|
|
833
|
+
if (c == '\t') {
|
|
834
|
+
int64_t add = tabsize > 0 ? tabsize - col % tabsize : 0;
|
|
835
|
+
total += add;
|
|
836
|
+
col += add;
|
|
837
|
+
} else {
|
|
838
|
+
total++;
|
|
839
|
+
if (c == '\n' || c == '\r') {
|
|
840
|
+
col = 0;
|
|
841
|
+
} else {
|
|
842
|
+
col++;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
q = malloc((size_t)total + 1);
|
|
847
|
+
if (q == NULL) {
|
|
848
|
+
abort();
|
|
849
|
+
}
|
|
850
|
+
w = q;
|
|
851
|
+
col = 0;
|
|
852
|
+
for (i = 0; i < n; i++) {
|
|
853
|
+
unsigned char c = (unsigned char)p[i];
|
|
854
|
+
if (c == '\t') {
|
|
855
|
+
int64_t add = tabsize > 0 ? tabsize - col % tabsize : 0;
|
|
856
|
+
memset(w, ' ', (size_t)add);
|
|
857
|
+
w += add;
|
|
858
|
+
col += add;
|
|
859
|
+
} else {
|
|
860
|
+
*w++ = (char)c;
|
|
861
|
+
if (c == '\n' || c == '\r') {
|
|
862
|
+
col = 0;
|
|
863
|
+
} else {
|
|
864
|
+
col++;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
out->len = total;
|
|
869
|
+
out->data = q;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/* partition: writes three PsBufs into out (16 bytes each, contiguous).
|
|
873
|
+
right = rpartition. Empty sep raises ValueError. */
|
|
874
|
+
void ps_str_partition(int64_t n, const char *p, int64_t sn, const char *sp, int64_t right, PsBuf *out) {
|
|
875
|
+
int64_t at = -1, i;
|
|
876
|
+
if (sn == 0) {
|
|
877
|
+
ps_raise_cstr(PS_VALUE, "empty separator");
|
|
878
|
+
}
|
|
879
|
+
if (!right) {
|
|
880
|
+
for (i = 0; i + sn <= n; i++) {
|
|
881
|
+
if (memcmp(p + i, sp, (size_t)sn) == 0) {
|
|
882
|
+
at = i;
|
|
883
|
+
break;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
} else {
|
|
887
|
+
for (i = n - sn; i >= 0; i--) {
|
|
888
|
+
if (memcmp(p + i, sp, (size_t)sn) == 0) {
|
|
889
|
+
at = i;
|
|
890
|
+
break;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
if (at < 0) {
|
|
895
|
+
if (!right) {
|
|
896
|
+
ps_buf_copy(&out[0], p, n);
|
|
897
|
+
ps_buf_copy(&out[1], "", 0);
|
|
898
|
+
ps_buf_copy(&out[2], "", 0);
|
|
899
|
+
} else {
|
|
900
|
+
ps_buf_copy(&out[0], "", 0);
|
|
901
|
+
ps_buf_copy(&out[1], "", 0);
|
|
902
|
+
ps_buf_copy(&out[2], p, n);
|
|
903
|
+
}
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
ps_buf_copy(&out[0], p, at);
|
|
907
|
+
ps_buf_copy(&out[1], sp, sn);
|
|
908
|
+
ps_buf_copy(&out[2], p + at + sn, n - at - sn);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
/* R4/R5: repr of a bytes value (b'...' with escapes) and float(str). */
|
|
912
|
+
void ps_repr_bytes(int64_t n, const char *p, PsBuf *out) {
|
|
913
|
+
/* worst case: each byte -> \xNN (4) plus b'' quotes */
|
|
914
|
+
char *q = malloc((size_t)n * 4 + 4);
|
|
915
|
+
char *w = q;
|
|
916
|
+
int64_t i;
|
|
917
|
+
int quote = '\'';
|
|
918
|
+
if (q == NULL) {
|
|
919
|
+
abort();
|
|
920
|
+
}
|
|
921
|
+
for (i = 0; i < n; i++) {
|
|
922
|
+
if (p[i] == '"' && memchr(p, '\'', (size_t)n) == NULL) {
|
|
923
|
+
quote = '"';
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
*w++ = 'b';
|
|
927
|
+
*w++ = (char)quote;
|
|
928
|
+
for (i = 0; i < n; i++) {
|
|
929
|
+
unsigned char c = (unsigned char)p[i];
|
|
930
|
+
if (c == (unsigned char)quote || c == '\\') {
|
|
931
|
+
*w++ = '\\';
|
|
932
|
+
*w++ = (char)c;
|
|
933
|
+
} else if (c == '\n') {
|
|
934
|
+
*w++ = '\\';
|
|
935
|
+
*w++ = 'n';
|
|
936
|
+
} else if (c == '\r') {
|
|
937
|
+
*w++ = '\\';
|
|
938
|
+
*w++ = 'r';
|
|
939
|
+
} else if (c == '\t') {
|
|
940
|
+
*w++ = '\\';
|
|
941
|
+
*w++ = 't';
|
|
942
|
+
} else if (c >= 0x20 && c < 0x7f) {
|
|
943
|
+
*w++ = (char)c;
|
|
944
|
+
} else {
|
|
945
|
+
static const char hex[] = "0123456789abcdef";
|
|
946
|
+
*w++ = '\\';
|
|
947
|
+
*w++ = 'x';
|
|
948
|
+
*w++ = hex[c >> 4];
|
|
949
|
+
*w++ = hex[c & 15];
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
*w++ = (char)quote;
|
|
953
|
+
out->len = w - q;
|
|
954
|
+
out->data = q;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
/* strict float(str): [ws] sign (digits [.digits] [. digits] | inf | nan)
|
|
958
|
+
[e sign digits] [ws]; underscores and trailing junk -> ValueError. */
|
|
959
|
+
double ps_float_from_str(int64_t n, const char *p) {
|
|
960
|
+
int64_t i = 0, e = n;
|
|
961
|
+
int sign = 1, any = 0, anyfrac = 0, anyexp = 0;
|
|
962
|
+
double val = 0.0, frac = 0.0, scale = 0.1;
|
|
963
|
+
int64_t exp = 0;
|
|
964
|
+
int expsign = 1;
|
|
965
|
+
while (i < e && ps_ws((unsigned char)p[i])) {
|
|
966
|
+
i++;
|
|
967
|
+
}
|
|
968
|
+
while (e > i && ps_ws((unsigned char)p[e - 1])) {
|
|
969
|
+
e--;
|
|
970
|
+
}
|
|
971
|
+
if (i < e && (p[i] == '+' || p[i] == '-')) {
|
|
972
|
+
if (p[i] == '-') {
|
|
973
|
+
sign = -1;
|
|
974
|
+
}
|
|
975
|
+
i++;
|
|
976
|
+
}
|
|
977
|
+
if (i + 3 <= e && (p[i] == 'i' || p[i] == 'I')) {
|
|
978
|
+
/* inf / infinity */
|
|
979
|
+
if ((p[i + 1] == 'n' || p[i + 1] == 'N') && (p[i + 2] == 'f' || p[i + 2] == 'F')) {
|
|
980
|
+
i += 3;
|
|
981
|
+
if (i + 5 <= e && (p[i] == 'i' || p[i] == 'I')) {
|
|
982
|
+
i += 5;
|
|
983
|
+
}
|
|
984
|
+
if (i != e) {
|
|
985
|
+
ps_raise_code(PS_VALUE);
|
|
986
|
+
}
|
|
987
|
+
return sign > 0 ? 1.0 / 0.0 : -1.0 / 0.0;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
if (i + 3 <= e && (p[i] == 'n' || p[i] == 'N') && (p[i + 1] == 'a' || p[i + 1] == 'A') &&
|
|
991
|
+
(p[i + 2] == 'n' || p[i + 2] == 'N')) {
|
|
992
|
+
i += 3;
|
|
993
|
+
if (i != e) {
|
|
994
|
+
ps_raise_code(PS_VALUE);
|
|
995
|
+
}
|
|
996
|
+
return 0.0 / 0.0;
|
|
997
|
+
}
|
|
998
|
+
while (i < e && ps_isdig((unsigned char)p[i])) {
|
|
999
|
+
val = val * 10.0 + (double)(p[i] - '0');
|
|
1000
|
+
i++;
|
|
1001
|
+
any = 1;
|
|
1002
|
+
}
|
|
1003
|
+
if (i < e && p[i] == '.') {
|
|
1004
|
+
i++;
|
|
1005
|
+
while (i < e && ps_isdig((unsigned char)p[i])) {
|
|
1006
|
+
frac += scale * (double)(p[i] - '0');
|
|
1007
|
+
scale /= 10.0;
|
|
1008
|
+
i++;
|
|
1009
|
+
anyfrac = 1;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
if (!any && !anyfrac) {
|
|
1013
|
+
ps_raise_code(PS_VALUE);
|
|
1014
|
+
}
|
|
1015
|
+
val += frac;
|
|
1016
|
+
if (i < e && (p[i] == 'e' || p[i] == 'E')) {
|
|
1017
|
+
i++;
|
|
1018
|
+
if (i < e && (p[i] == '+' || p[i] == '-')) {
|
|
1019
|
+
if (p[i] == '-') {
|
|
1020
|
+
expsign = -1;
|
|
1021
|
+
}
|
|
1022
|
+
i++;
|
|
1023
|
+
}
|
|
1024
|
+
while (i < e && ps_isdig((unsigned char)p[i])) {
|
|
1025
|
+
exp = exp * 10 + (p[i] - '0');
|
|
1026
|
+
i++;
|
|
1027
|
+
anyexp = 1;
|
|
1028
|
+
}
|
|
1029
|
+
if (!anyexp) {
|
|
1030
|
+
ps_raise_code(PS_VALUE);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
if (i != e) {
|
|
1034
|
+
ps_raise_code(PS_VALUE);
|
|
1035
|
+
}
|
|
1036
|
+
if (exp != 0) {
|
|
1037
|
+
double mult = 1.0;
|
|
1038
|
+
int64_t k;
|
|
1039
|
+
for (k = 0; k < exp && k < 400; k++) {
|
|
1040
|
+
mult *= 10.0;
|
|
1041
|
+
}
|
|
1042
|
+
if (expsign < 0) {
|
|
1043
|
+
val /= mult;
|
|
1044
|
+
} else {
|
|
1045
|
+
val *= mult;
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
return sign > 0 ? val : -val;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
/* by-kind list.insert/pop wrappers (generic _c_pieces arg marshaling) */
|
|
1052
|
+
void ps_seq_insert_i64(PsSeq *s, int64_t i, int64_t v) { ps_seq_insert(s, i, &v); }
|
|
1053
|
+
void ps_seq_insert_f64(PsSeq *s, int64_t i, double v) { ps_seq_insert(s, i, &v); }
|
|
1054
|
+
void ps_seq_insert_buf(PsSeq *s, int64_t i, int64_t n, char *p) {
|
|
1055
|
+
PsBuf b;
|
|
1056
|
+
b.len = n;
|
|
1057
|
+
b.data = p;
|
|
1058
|
+
ps_seq_insert(s, i, &b);
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
static int64_t ps_pop_index(PsSeq *s, int64_t i) {
|
|
1062
|
+
if (i < 0) {
|
|
1063
|
+
i += s->len;
|
|
1064
|
+
}
|
|
1065
|
+
if (i < 0 || i >= s->len) {
|
|
1066
|
+
ps_raise_code(PS_INDEX);
|
|
1067
|
+
}
|
|
1068
|
+
return i;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
int64_t ps_seq_pop_i64(PsSeq *s, int64_t i) {
|
|
1072
|
+
i = ps_pop_index(s, i);
|
|
1073
|
+
int64_t v = *(int64_t *)ps_cell(s, i);
|
|
1074
|
+
ps_seq_drop(s, i);
|
|
1075
|
+
return v;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
double ps_seq_pop_f64(PsSeq *s, int64_t i) {
|
|
1079
|
+
i = ps_pop_index(s, i);
|
|
1080
|
+
double v = *(double *)ps_cell(s, i);
|
|
1081
|
+
ps_seq_drop(s, i);
|
|
1082
|
+
return v;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
void ps_seq_pop_buf(PsSeq *s, int64_t i, PsBuf *out) {
|
|
1086
|
+
i = ps_pop_index(s, i);
|
|
1087
|
+
*out = *(PsBuf *)ps_cell(s, i);
|
|
1088
|
+
ps_seq_drop(s, i);
|
|
1089
|
+
}
|