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.
Files changed (54) hide show
  1. pyscriptc/__init__.py +3 -0
  2. pyscriptc/__main__.py +3 -0
  3. pyscriptc/_posthog_token.py +1 -0
  4. pyscriptc/builtins.py +156 -0
  5. pyscriptc/canonical.py +167 -0
  6. pyscriptc/check.py +49 -0
  7. pyscriptc/cli.py +271 -0
  8. pyscriptc/coverage.py +388 -0
  9. pyscriptc/debug.py +120 -0
  10. pyscriptc/diagnostics.py +179 -0
  11. pyscriptc/errors.py +56 -0
  12. pyscriptc/ir.py +365 -0
  13. pyscriptc/llvm.py +2129 -0
  14. pyscriptc/log.py +127 -0
  15. pyscriptc/lower/__init__.py +1071 -0
  16. pyscriptc/lower/_calls.py +1499 -0
  17. pyscriptc/lower/_classes.py +969 -0
  18. pyscriptc/lower/_core.py +301 -0
  19. pyscriptc/lower/_expr.py +886 -0
  20. pyscriptc/lower/_stdlib.py +491 -0
  21. pyscriptc/lower/_stdlib_shared.py +93 -0
  22. pyscriptc/lower/_stmt.py +1173 -0
  23. pyscriptc/package.py +249 -0
  24. pyscriptc/restlower.py +1008 -0
  25. pyscriptc/runtime/ps_argv.c +28 -0
  26. pyscriptc/runtime/ps_b64.c +168 -0
  27. pyscriptc/runtime/ps_coll.c +133 -0
  28. pyscriptc/runtime/ps_dt.c +388 -0
  29. pyscriptc/runtime/ps_hash.c +411 -0
  30. pyscriptc/runtime/ps_help.c +219 -0
  31. pyscriptc/runtime/ps_hmac.c +120 -0
  32. pyscriptc/runtime/ps_io.c +198 -0
  33. pyscriptc/runtime/ps_island.c +272 -0
  34. pyscriptc/runtime/ps_json.c +402 -0
  35. pyscriptc/runtime/ps_mix.c +47 -0
  36. pyscriptc/runtime/ps_more.c +1089 -0
  37. pyscriptc/runtime/ps_osmore.c +447 -0
  38. pyscriptc/runtime/ps_path.c +547 -0
  39. pyscriptc/runtime/ps_re.c +1102 -0
  40. pyscriptc/runtime/ps_rt.c +1175 -0
  41. pyscriptc/runtime/ps_rt.h +189 -0
  42. pyscriptc/runtime/ps_struct.c +291 -0
  43. pyscriptc/runtime/ps_time.c +207 -0
  44. pyscriptc/runtime/ps_unicode.c +1521 -0
  45. pyscriptc/runtime/ps_url.c +327 -0
  46. pyscriptc/stdlib_queue.py +191 -0
  47. pyscriptc/stdmore.py +1596 -0
  48. pyscriptc/telemetry.py +219 -0
  49. pyscriptc-0.1.0.dist-info/METADATA +187 -0
  50. pyscriptc-0.1.0.dist-info/RECORD +54 -0
  51. pyscriptc-0.1.0.dist-info/WHEEL +5 -0
  52. pyscriptc-0.1.0.dist-info/entry_points.txt +2 -0
  53. pyscriptc-0.1.0.dist-info/licenses/LICENSE +201 -0
  54. pyscriptc-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1175 @@
1
+ /* Small runtime linked beside emitted LLVM.
2
+
3
+ Lists and dicts are pointers, so assignment shares the buffer the way Python
4
+ does. A try runs its body as a callback: setjmp stays in ps_try_call, whose
5
+ frame is still live if the body raises. Arithmetic overflow stays an LLVM trap.
6
+ */
7
+
8
+ #include "ps_rt.h"
9
+
10
+ #include <math.h>
11
+ #include <setjmp.h>
12
+ #include <stdint.h>
13
+ #include <stdio.h>
14
+ #include <stdlib.h>
15
+ #include <string.h>
16
+
17
+ typedef struct PsJmp {
18
+ jmp_buf buf;
19
+ struct PsJmp *prev;
20
+ } PsJmp;
21
+
22
+ static _Thread_local PsJmp *ps_top;
23
+ static _Thread_local PsExc *ps_current;
24
+ char ps_empty_byte;
25
+
26
+ /* Parent chain for the 7 existing codes: every builtin is a child of
27
+ Exception. User codes (>= PS_USER_BASE) have no runtime parent yet; the
28
+ emitted handler precomputes their matches (E3 registers them here). */
29
+ static const int32_t ps_exc_parent[PS_USER_BASE] = {
30
+ 0,
31
+ PS_EXCEPTION,
32
+ PS_EXCEPTION,
33
+ PS_EXCEPTION,
34
+ PS_EXCEPTION,
35
+ PS_EXCEPTION,
36
+ PS_EXCEPTION,
37
+ 0,
38
+ };
39
+
40
+ _Static_assert(sizeof(PsBuf) == 16, "PsBuf must match %ps.str");
41
+
42
+ static const char *ps_exc_name(int code) {
43
+ switch (code) {
44
+ case PS_VALUE:
45
+ return "ValueError";
46
+ case PS_INDEX:
47
+ return "IndexError";
48
+ case PS_KEY:
49
+ return "KeyError";
50
+ case PS_OVERFLOW:
51
+ return "OverflowError";
52
+ case PS_ZERO_DIV:
53
+ return "ZeroDivisionError";
54
+ case PS_EXCEPTION:
55
+ return "Exception";
56
+ default:
57
+ return "RuntimeError";
58
+ }
59
+ }
60
+
61
+ static PsExc *ps_exc_new(int32_t code) {
62
+ PsExc *e = calloc(1, sizeof(PsExc));
63
+ if (e == NULL) {
64
+ abort();
65
+ }
66
+ e->code = code;
67
+ e->name.data = (char *)ps_exc_name(code);
68
+ e->name.len = (int64_t)strlen(e->name.data);
69
+ e->message.data = calloc(256, 1);
70
+ if (e->message.data == NULL) {
71
+ abort();
72
+ }
73
+ return e;
74
+ }
75
+
76
+ /* Deliver ps_current: unwind to the innermost handler, or report and exit. */
77
+ __attribute__((noinline, noreturn)) static void ps_deliver(void) {
78
+ PsExc *e = ps_current;
79
+ if (ps_top == NULL) {
80
+ if (e != NULL && e->message.len > 0) {
81
+ fprintf(stderr, "%s: %s\n", ps_exc_name(e->code), e->message.data);
82
+ } else {
83
+ fprintf(stderr, "%s\n", ps_exc_name(e != NULL ? e->code : PS_RUNTIME));
84
+ }
85
+ exit(1);
86
+ }
87
+ longjmp(ps_top->buf, PS_RAISED);
88
+ }
89
+
90
+ __attribute__((noinline, noreturn)) void ps_raise(int32_t code) {
91
+ if (code == 0) {
92
+ code = PS_RUNTIME;
93
+ }
94
+ if (ps_current == NULL || ps_current->code != code) {
95
+ ps_current = ps_exc_new(code);
96
+ }
97
+ ps_deliver();
98
+ }
99
+
100
+ __attribute__((noinline, noreturn)) void ps_raise_code(int32_t code) {
101
+ if (code == 0) {
102
+ code = PS_RUNTIME;
103
+ }
104
+ ps_current = ps_exc_new(code);
105
+ ps_deliver();
106
+ }
107
+
108
+ __attribute__((noinline, noreturn)) void ps_reraise(void) {
109
+ if (ps_current == NULL) {
110
+ ps_current = ps_exc_new(PS_RUNTIME);
111
+ }
112
+ ps_deliver();
113
+ }
114
+
115
+ int32_t ps_exc_code(void) {
116
+ return ps_current != NULL ? ps_current->code : 0;
117
+ }
118
+
119
+ int32_t ps_exc_isa(int32_t raised, int32_t wanted) {
120
+ int32_t code = raised;
121
+ while (code > 0) {
122
+ if (code == wanted) {
123
+ return 1;
124
+ }
125
+ if (code >= PS_USER_BASE) {
126
+ return 0;
127
+ }
128
+ code = ps_exc_parent[code];
129
+ }
130
+ return 0;
131
+ }
132
+
133
+ __attribute__((noreturn)) void ps_raise_cstr(int32_t code, const char *msg) {
134
+ PsExc *e = ps_exc_new(code == 0 ? PS_RUNTIME : code);
135
+ snprintf(e->message.data, 256, "%s", msg);
136
+ e->message.len = (int64_t)strlen(e->message.data);
137
+ ps_current = e;
138
+ ps_deliver();
139
+ }
140
+
141
+ typedef int32_t (*ps_try_fn)(void *);
142
+
143
+ /* `fn` runs the try body. 0 means the body fell through; 1 means it returned.
144
+ The longjmp target is this frame, so `fn` must be called before we return. */
145
+ __attribute__((noinline)) int32_t ps_try_call(ps_try_fn fn, void *env, int32_t *flow) {
146
+ PsJmp *slot = malloc(sizeof(PsJmp));
147
+ if (slot == NULL) {
148
+ abort();
149
+ }
150
+ slot->prev = ps_top;
151
+ ps_top = slot;
152
+ int code = setjmp(slot->buf);
153
+ if (code != 0) {
154
+ PsJmp *cur = ps_top;
155
+ ps_top = cur->prev;
156
+ free(cur);
157
+ return (int32_t)code;
158
+ }
159
+ int32_t status = fn(env);
160
+ PsJmp *cur = ps_top;
161
+ ps_top = cur->prev;
162
+ free(cur);
163
+ *flow = status;
164
+ return 0;
165
+ }
166
+
167
+ void ps_raise_msg(int32_t code, int64_t n, const char *data) {
168
+ if (n < 0) {
169
+ n = 0;
170
+ }
171
+ size_t take = (size_t)n;
172
+ if (take > 255) {
173
+ take = 255;
174
+ }
175
+ PsExc *e = ps_exc_new(code == 0 ? PS_RUNTIME : code);
176
+ memcpy(e->message.data, data, take);
177
+ e->message.data[take] = '\0';
178
+ e->message.len = (int64_t)take;
179
+ ps_current = e;
180
+ ps_deliver();
181
+ }
182
+
183
+ void *ps_alloc(int64_t n) {
184
+ if (n < 1) {
185
+ n = 1;
186
+ }
187
+ void *p = calloc(1, (size_t)n);
188
+ if (p == NULL) {
189
+ abort();
190
+ }
191
+ return p;
192
+ }
193
+
194
+ static int64_t ps_index(int64_t len, int64_t i) {
195
+ if (i < 0) {
196
+ i += len;
197
+ }
198
+ if (i < 0 || i >= len) {
199
+ ps_raise_code(PS_INDEX);
200
+ }
201
+ return i;
202
+ }
203
+
204
+ PsSeq *ps_seq_new(int64_t elem, int64_t n) {
205
+ if (elem <= 0 || n < 0) {
206
+ ps_raise_code(PS_OVERFLOW);
207
+ }
208
+ if (n > 0 && (uint64_t)n > UINT64_MAX / (uint64_t)elem) {
209
+ ps_raise_code(PS_OVERFLOW);
210
+ }
211
+ PsSeq *s = calloc(1, sizeof(PsSeq));
212
+ if (s == NULL) {
213
+ abort();
214
+ }
215
+ s->len = n;
216
+ s->elem = elem;
217
+ s->cap = n;
218
+ if (n == 0) {
219
+ s->data = NULL;
220
+ return s;
221
+ }
222
+ s->data = calloc((size_t)n, (size_t)elem);
223
+ if (s->data == NULL) {
224
+ abort();
225
+ }
226
+ return s;
227
+ }
228
+
229
+ int64_t ps_seq_len(PsSeq *s) { return s->len; }
230
+
231
+ void ps_seq_get(PsSeq *s, int64_t i, void *out) {
232
+ i = ps_index(s->len, i);
233
+ memcpy(out, (char *)s->data + (size_t)i * (size_t)s->elem, (size_t)s->elem);
234
+ }
235
+
236
+ void ps_seq_push(PsSeq *s, const void *src) {
237
+ if (s->len == s->cap) {
238
+ int64_t cap = s->cap == 0 ? 4 : s->cap * 2;
239
+ if (cap < s->len + 1) {
240
+ ps_raise_code(PS_OVERFLOW);
241
+ }
242
+ if ((uint64_t)cap > UINT64_MAX / (uint64_t)s->elem) {
243
+ ps_raise_code(PS_OVERFLOW);
244
+ }
245
+ void *data = realloc(s->data, (size_t)cap * (size_t)s->elem);
246
+ if (data == NULL) {
247
+ abort();
248
+ }
249
+ s->data = data;
250
+ s->cap = cap;
251
+ }
252
+ memcpy((char *)s->data + (size_t)s->len * (size_t)s->elem, src, (size_t)s->elem);
253
+ s->len += 1;
254
+ }
255
+
256
+ void ps_seq_set(PsSeq *s, int64_t i, void *src) {
257
+ i = ps_index(s->len, i);
258
+ memcpy((char *)s->data + (size_t)i * (size_t)s->elem, src, (size_t)s->elem);
259
+ }
260
+
261
+ static int ps_buf_eq(PsBuf a, PsBuf b) {
262
+ if (a.len != b.len) {
263
+ return 0;
264
+ }
265
+ if (a.len == 0) {
266
+ return 1;
267
+ }
268
+ return memcmp(a.data, b.data, (size_t)a.len) == 0;
269
+ }
270
+
271
+ int32_t ps_seq_has_i64(PsSeq *s, int64_t needle) {
272
+ for (int64_t i = 0; i < s->len; i++) {
273
+ int64_t cur = 0;
274
+ memcpy(&cur, (char *)s->data + (size_t)i * (size_t)s->elem, 8);
275
+ if (cur == needle) {
276
+ return 1;
277
+ }
278
+ }
279
+ return 0;
280
+ }
281
+
282
+ int32_t ps_seq_has_f64(PsSeq *s, double needle) {
283
+ for (int64_t i = 0; i < s->len; i++) {
284
+ double cur = 0;
285
+ memcpy(&cur, (char *)s->data + (size_t)i * (size_t)s->elem, 8);
286
+ if (cur == needle) {
287
+ return 1;
288
+ }
289
+ }
290
+ return 0;
291
+ }
292
+
293
+ int32_t ps_seq_has_buf(PsSeq *s, int64_t n, char *p) {
294
+ PsBuf needle = {n, p};
295
+ for (int64_t i = 0; i < s->len; i++) {
296
+ PsBuf cur;
297
+ memcpy(&cur, (char *)s->data + (size_t)i * (size_t)s->elem, 16);
298
+ if (ps_buf_eq(cur, needle)) {
299
+ return 1;
300
+ }
301
+ }
302
+ return 0;
303
+ }
304
+
305
+ PsMap *ps_map_new(int32_t key_kind, int64_t key_size, int64_t val_size, int64_t cap) {
306
+ if (cap < 0 || key_size <= 0 || val_size <= 0) {
307
+ ps_raise_code(PS_OVERFLOW);
308
+ }
309
+ PsMap *m = calloc(1, sizeof(PsMap));
310
+ if (m == NULL) {
311
+ abort();
312
+ }
313
+ m->key_kind = key_kind;
314
+ m->key_size = key_size;
315
+ m->val_size = val_size;
316
+ m->cap = cap;
317
+ m->len = 0;
318
+ if (cap > 0) {
319
+ m->keys = calloc((size_t)cap, (size_t)key_size);
320
+ m->vals = calloc((size_t)cap, (size_t)val_size);
321
+ if (m->keys == NULL || m->vals == NULL) {
322
+ abort();
323
+ }
324
+ }
325
+ return m;
326
+ }
327
+
328
+ int64_t ps_map_len(PsMap *m) { return m->len; }
329
+
330
+ static int ps_key_eq(PsMap *m, const void *a, const void *b) {
331
+ if (m->key_kind == 1) {
332
+ int64_t ka = 0;
333
+ int64_t kb = 0;
334
+ memcpy(&ka, a, 8);
335
+ memcpy(&kb, b, 8);
336
+ return ka == kb;
337
+ }
338
+ PsBuf ba;
339
+ PsBuf bb;
340
+ memcpy(&ba, a, 16);
341
+ memcpy(&bb, b, 16);
342
+ return ps_buf_eq(ba, bb);
343
+ }
344
+
345
+ static int64_t ps_map_find(PsMap *m, const void *key) {
346
+ for (int64_t i = 0; i < m->len; i++) {
347
+ if (ps_key_eq(m, (char *)m->keys + (size_t)i * (size_t)m->key_size, key)) {
348
+ return i;
349
+ }
350
+ }
351
+ return -1;
352
+ }
353
+
354
+ static void ps_map_grow(PsMap *m) {
355
+ int64_t cap = m->cap == 0 ? 4 : m->cap * 2;
356
+ void *keys = realloc(m->keys, (size_t)cap * (size_t)m->key_size);
357
+ void *vals = realloc(m->vals, (size_t)cap * (size_t)m->val_size);
358
+ if (keys == NULL || vals == NULL) {
359
+ abort();
360
+ }
361
+ m->keys = keys;
362
+ m->vals = vals;
363
+ m->cap = cap;
364
+ }
365
+
366
+ void ps_map_put(PsMap *m, void *key, void *val) {
367
+ int64_t at = ps_map_find(m, key);
368
+ if (at < 0) {
369
+ if (m->len == m->cap) {
370
+ ps_map_grow(m);
371
+ }
372
+ at = m->len;
373
+ m->len += 1;
374
+ memcpy((char *)m->keys + (size_t)at * (size_t)m->key_size, key, (size_t)m->key_size);
375
+ }
376
+ memcpy((char *)m->vals + (size_t)at * (size_t)m->val_size, val, (size_t)m->val_size);
377
+ }
378
+
379
+ void ps_map_get(PsMap *m, void *key, void *out) {
380
+ int64_t at = ps_map_find(m, key);
381
+ if (at < 0) {
382
+ ps_raise_code(PS_KEY);
383
+ }
384
+ memcpy(out, (char *)m->vals + (size_t)at * (size_t)m->val_size, (size_t)m->val_size);
385
+ }
386
+
387
+ int32_t ps_map_has(PsMap *m, void *key) { return ps_map_find(m, key) >= 0; }
388
+
389
+ void ps_map_key_at(PsMap *m, int64_t i, void *out) {
390
+ if (i < 0 || i >= m->len) {
391
+ ps_raise_code(PS_INDEX);
392
+ }
393
+ memcpy(out, (char *)m->keys + (size_t)i * (size_t)m->key_size, (size_t)m->key_size);
394
+ }
395
+
396
+ PsSeq *ps_dict_keys(PsMap *m) {
397
+ PsSeq *seq = ps_seq_new(m->key_size, m->len);
398
+ for (int64_t i = 0; i < m->len; i++) {
399
+ ps_seq_set(seq, i, (char *)m->keys + (size_t)i * (size_t)m->key_size);
400
+ }
401
+ return seq;
402
+ }
403
+
404
+ void ps_map_val_at(PsMap *m, int64_t i, void *out) {
405
+ if (i < 0 || i >= m->len) {
406
+ ps_raise_code(PS_INDEX);
407
+ }
408
+ memcpy(out, (char *)m->vals + (size_t)i * (size_t)m->val_size, (size_t)m->val_size);
409
+ }
410
+
411
+ static int ps_space(unsigned char c) {
412
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f' || c == 0x1c ||
413
+ c == 0x1d || c == 0x1e || c == 0x1f;
414
+ }
415
+
416
+ static void ps_view(PsBuf *out, const char *p, int64_t n) {
417
+ out->len = n;
418
+ out->data = n == 0 ? &ps_empty_byte : (char *)p;
419
+ }
420
+
421
+ void ps_buf_view(PsBuf *out, const char *p, int64_t n) { ps_view(out, p, n); }
422
+
423
+ void ps_buf_copy(PsBuf *out, const char *p, int64_t n) {
424
+ if (n < 0) {
425
+ ps_raise_code(PS_OVERFLOW);
426
+ }
427
+ char *q = malloc((size_t)n + 1);
428
+ if (q == NULL) {
429
+ abort();
430
+ }
431
+ if (n > 0) {
432
+ memcpy(q, p, (size_t)n);
433
+ }
434
+ q[n] = '\0';
435
+ out->len = n;
436
+ out->data = q;
437
+ }
438
+
439
+ void ps_grow_init(PsGrow *g) {
440
+ g->data = NULL;
441
+ g->len = 0;
442
+ g->cap = 0;
443
+ }
444
+
445
+ void ps_grow_add(PsGrow *g, const char *p, int64_t n) {
446
+ if (n < 0) {
447
+ ps_raise_code(PS_OVERFLOW);
448
+ }
449
+ if (n > INT64_MAX - g->len - 1) {
450
+ ps_raise_code(PS_OVERFLOW);
451
+ }
452
+ if (g->len + n + 1 > g->cap) {
453
+ int64_t cap = g->cap == 0 ? 32 : g->cap;
454
+ while (cap < g->len + n + 1) {
455
+ if (cap > INT64_MAX / 2) {
456
+ ps_raise_code(PS_OVERFLOW);
457
+ }
458
+ cap *= 2;
459
+ }
460
+ char *data = realloc(g->data, (size_t)cap);
461
+ if (data == NULL) {
462
+ abort();
463
+ }
464
+ g->data = data;
465
+ g->cap = cap;
466
+ }
467
+ if (n > 0) {
468
+ memcpy(g->data + g->len, p, (size_t)n);
469
+ }
470
+ g->len += n;
471
+ g->data[g->len] = '\0';
472
+ }
473
+
474
+ void ps_grow_byte(PsGrow *g, unsigned char c) {
475
+ char ch = (char)c;
476
+ ps_grow_add(g, &ch, 1);
477
+ }
478
+
479
+ void ps_grow_finish(PsGrow *g, PsBuf *out) {
480
+ if (g->data == NULL) {
481
+ ps_buf_copy(out, "", 0);
482
+ return;
483
+ }
484
+ out->len = g->len;
485
+ out->data = g->data;
486
+ g->data = NULL;
487
+ g->len = 0;
488
+ g->cap = 0;
489
+ }
490
+
491
+ void ps_str_get(int64_t n, char *p, int64_t i, PsBuf *out) {
492
+ i = ps_index(n, i);
493
+ ps_view(out, p + i, 1);
494
+ }
495
+
496
+ int64_t ps_buf_at(int64_t n, char *p, int64_t i) {
497
+ i = ps_index(n, i);
498
+ return (unsigned char)p[i];
499
+ }
500
+
501
+ static void ps_trim(int64_t n, const char *p, int which, PsBuf *out) {
502
+ int64_t i = 0;
503
+ int64_t j = n;
504
+ if (which != 2) {
505
+ while (i < j && ps_space((unsigned char)p[i])) {
506
+ i++;
507
+ }
508
+ }
509
+ if (which != 1) {
510
+ while (j > i && ps_space((unsigned char)p[j - 1])) {
511
+ j--;
512
+ }
513
+ }
514
+ ps_view(out, p + i, j - i);
515
+ }
516
+
517
+ void ps_str_strip(int64_t n, char *p, PsBuf *out) { ps_trim(n, p, 0, out); }
518
+ void ps_str_lstrip(int64_t n, char *p, PsBuf *out) { ps_trim(n, p, 1, out); }
519
+ void ps_str_rstrip(int64_t n, char *p, PsBuf *out) { ps_trim(n, p, 2, out); }
520
+
521
+ int32_t ps_str_startswith(int64_t n, char *p, int64_t pn, char *pp) {
522
+ if (pn > n) {
523
+ return 0;
524
+ }
525
+ if (pn == 0) {
526
+ return 1;
527
+ }
528
+ return memcmp(p, pp, (size_t)pn) == 0;
529
+ }
530
+
531
+ int32_t ps_str_endswith(int64_t n, char *p, int64_t pn, char *pp) {
532
+ if (pn > n) {
533
+ return 0;
534
+ }
535
+ if (pn == 0) {
536
+ return 1;
537
+ }
538
+ return memcmp(p + (n - pn), pp, (size_t)pn) == 0;
539
+ }
540
+
541
+ int64_t ps_str_find(int64_t n, char *p, int64_t pn, char *pp) {
542
+ if (pn == 0) {
543
+ return 0;
544
+ }
545
+ if (pn > n) {
546
+ return -1;
547
+ }
548
+ for (int64_t i = 0; i + pn <= n; i++) {
549
+ if (memcmp(p + i, pp, (size_t)pn) == 0) {
550
+ return i;
551
+ }
552
+ }
553
+ return -1;
554
+ }
555
+
556
+ int32_t ps_str_eq(int64_t an, char *ap, int64_t bn, char *bp) {
557
+ PsBuf a = {an, ap};
558
+ PsBuf b = {bn, bp};
559
+ return ps_buf_eq(a, b);
560
+ }
561
+
562
+ int32_t ps_str_cmp(int64_t an, char *ap, int64_t bn, char *bp) {
563
+ int64_t n = an < bn ? an : bn;
564
+ int cmp = n == 0 ? 0 : memcmp(ap, bp, (size_t)n);
565
+ if (cmp < 0) {
566
+ return -1;
567
+ }
568
+ if (cmp > 0) {
569
+ return 1;
570
+ }
571
+ if (an < bn) {
572
+ return -1;
573
+ }
574
+ if (an > bn) {
575
+ return 1;
576
+ }
577
+ return 0;
578
+ }
579
+
580
+ static void ps_case(int64_t n, const char *p, int upper, PsBuf *out) {
581
+ char *q = malloc((size_t)n + 1);
582
+ if (q == NULL) {
583
+ abort();
584
+ }
585
+ for (int64_t i = 0; i < n; i++) {
586
+ unsigned char c = (unsigned char)p[i];
587
+ if (upper && c >= 'a' && c <= 'z') {
588
+ c = (unsigned char)(c - 'a' + 'A');
589
+ }
590
+ if (!upper && c >= 'A' && c <= 'Z') {
591
+ c = (unsigned char)(c - 'A' + 'a');
592
+ }
593
+ q[i] = (char)c;
594
+ }
595
+ q[n] = '\0';
596
+ out->len = n;
597
+ out->data = q;
598
+ }
599
+
600
+ void ps_str_upper(int64_t n, char *p, PsBuf *out) { ps_case(n, p, 1, out); }
601
+ void ps_str_lower(int64_t n, char *p, PsBuf *out) { ps_case(n, p, 0, out); }
602
+
603
+ void ps_str_replace(int64_t n, char *p, int64_t on, char *op, int64_t nn, char *np, PsBuf *out) {
604
+ if (on == 0) {
605
+ if (n > INT64_MAX - 1 || (nn > 0 && (n + 1) > INT64_MAX / nn)) {
606
+ ps_raise_code(PS_OVERFLOW);
607
+ }
608
+ int64_t total = (n + 1) * nn + n;
609
+ char *q = malloc((size_t)total + 1);
610
+ if (q == NULL) {
611
+ abort();
612
+ }
613
+ char *w = q;
614
+ for (int64_t i = 0; i < n; i++) {
615
+ if (nn > 0) {
616
+ memcpy(w, np, (size_t)nn);
617
+ w += nn;
618
+ }
619
+ *w++ = p[i];
620
+ }
621
+ if (nn > 0) {
622
+ memcpy(w, np, (size_t)nn);
623
+ w += nn;
624
+ }
625
+ *w = '\0';
626
+ out->len = total;
627
+ out->data = q;
628
+ return;
629
+ }
630
+ int64_t count = 0;
631
+ for (int64_t i = 0; i + on <= n;) {
632
+ if (memcmp(p + i, op, (size_t)on) == 0) {
633
+ count++;
634
+ i += on;
635
+ } else {
636
+ i++;
637
+ }
638
+ }
639
+ int64_t total = n + count * (nn - on);
640
+ if (total < 0) {
641
+ ps_raise_code(PS_OVERFLOW);
642
+ }
643
+ char *q = malloc((size_t)total + 1);
644
+ if (q == NULL) {
645
+ abort();
646
+ }
647
+ char *w = q;
648
+ for (int64_t i = 0; i < n;) {
649
+ if (i + on <= n && memcmp(p + i, op, (size_t)on) == 0) {
650
+ if (nn > 0) {
651
+ memcpy(w, np, (size_t)nn);
652
+ w += nn;
653
+ }
654
+ i += on;
655
+ } else {
656
+ *w++ = p[i++];
657
+ }
658
+ }
659
+ *w = '\0';
660
+ out->len = total;
661
+ out->data = q;
662
+ }
663
+
664
+ static int64_t ps_double_to_i64(double y) {
665
+ if (isnan(y)) {
666
+ ps_raise_cstr(PS_VALUE, "cannot convert float NaN to integer");
667
+ }
668
+ if (isinf(y) || y >= 9223372036854775808.0 || y < -9223372036854775808.0) {
669
+ ps_raise_cstr(PS_OVERFLOW, "cannot convert float to i64");
670
+ }
671
+ return (int64_t)y;
672
+ }
673
+
674
+ int64_t ps_float_to_int(double x) { return ps_double_to_i64(trunc(x)); }
675
+
676
+ int64_t ps_math_floor(double x) { return ps_double_to_i64(floor(x)); }
677
+ int64_t ps_math_ceil(double x) { return ps_double_to_i64(ceil(x)); }
678
+ int64_t ps_math_trunc(double x) { return ps_double_to_i64(trunc(x)); }
679
+
680
+ double ps_math_sqrt(double x) {
681
+ if (isnan(x)) {
682
+ return x;
683
+ }
684
+ if (x < 0) {
685
+ ps_raise_cstr(PS_VALUE, "math domain error");
686
+ }
687
+ return sqrt(x);
688
+ }
689
+
690
+ double ps_math_fabs(double x) { return fabs(x); }
691
+
692
+ static double ps_finite(double x, double (*fn)(double)) {
693
+ if (isinf(x)) {
694
+ ps_raise_cstr(PS_VALUE, "expected a finite input");
695
+ }
696
+ return fn(x);
697
+ }
698
+
699
+ double ps_math_sin(double x) { return ps_finite(x, sin); }
700
+ double ps_math_cos(double x) { return ps_finite(x, cos); }
701
+ double ps_math_tan(double x) { return ps_finite(x, tan); }
702
+
703
+ double ps_math_exp(double x) {
704
+ if (isnan(x)) {
705
+ return x;
706
+ }
707
+ double r = exp(x);
708
+ if (isinf(r)) {
709
+ ps_raise_cstr(PS_OVERFLOW, "math range error");
710
+ }
711
+ return r;
712
+ }
713
+
714
+ static double ps_positive(double x, double (*fn)(double)) {
715
+ if (isnan(x)) {
716
+ return x;
717
+ }
718
+ if (!(x > 0.0)) {
719
+ ps_raise_cstr(PS_VALUE, "expected a positive input");
720
+ }
721
+ return fn(x);
722
+ }
723
+
724
+ double ps_math_log(double x) { return ps_positive(x, log); }
725
+ double ps_math_log2(double x) { return ps_positive(x, log2); }
726
+ double ps_math_log10(double x) { return ps_positive(x, log10); }
727
+
728
+ double ps_math_hypot(double x, double y) {
729
+ double r = hypot(x, y);
730
+ if (isfinite(x) && isfinite(y) && isinf(r)) {
731
+ ps_raise_cstr(PS_OVERFLOW, "math range error");
732
+ }
733
+ return r;
734
+ }
735
+
736
+ double ps_math_pow(double x, double y) {
737
+ if (isnan(x)) {
738
+ return pow(x, y);
739
+ }
740
+ if (x == 0.0 && y < 0.0 && !isnan(y)) {
741
+ ps_raise_cstr(PS_VALUE, "math domain error");
742
+ }
743
+ if (x < 0.0 && !isnan(y)) {
744
+ double t = trunc(y);
745
+ if (t != y) {
746
+ ps_raise_cstr(PS_VALUE, "math domain error");
747
+ }
748
+ }
749
+ double r = pow(x, y);
750
+ if (isfinite(x) && isfinite(y) && isinf(r)) {
751
+ ps_raise_cstr(PS_OVERFLOW, "math range error");
752
+ }
753
+ return r;
754
+ }
755
+
756
+ static int64_t ps_slice_at(int64_t n, int64_t i, int64_t present, int64_t fallback) {
757
+ if (!present) {
758
+ return fallback;
759
+ }
760
+ if (i < 0) {
761
+ if (n == 0 || i < -n) {
762
+ return 0;
763
+ }
764
+ i += n;
765
+ }
766
+ if (i < 0) {
767
+ return 0;
768
+ }
769
+ if (i > n) {
770
+ return n;
771
+ }
772
+ return i;
773
+ }
774
+
775
+ static void ps_slice_bounds(
776
+ int64_t n, int64_t start, int64_t stop, int64_t has_start, int64_t has_stop, int64_t *lo, int64_t *hi
777
+ ) {
778
+ int64_t left = ps_slice_at(n, start, has_start, 0);
779
+ int64_t right = ps_slice_at(n, stop, has_stop, n);
780
+ if (right < left) {
781
+ right = left;
782
+ }
783
+ *lo = left;
784
+ *hi = right;
785
+ }
786
+
787
+ static void ps_slice_step_ok(int64_t step) {
788
+ if (step == 0) {
789
+ ps_raise_cstr(PS_VALUE, "slice step cannot be zero");
790
+ }
791
+ }
792
+
793
+ static int64_t ps_slice_count(int64_t lo, int64_t hi, int64_t step) {
794
+ if (hi <= lo) {
795
+ return 0;
796
+ }
797
+ int64_t span = hi - lo;
798
+ int64_t count = span / step;
799
+ if (span % step != 0) {
800
+ count++;
801
+ }
802
+ return count;
803
+ }
804
+
805
+ /* Negative steps clamp like CPython: wrap negatives, then pin to [-1, n-1].
806
+ Missing start defaults to n-1, missing stop to -1 (walk through index 0). */
807
+ static int64_t ps_slice_at_neg(int64_t n, int64_t i, int64_t present, int64_t fallback) {
808
+ if (!present) {
809
+ return fallback;
810
+ }
811
+ if (i < 0) {
812
+ i += n;
813
+ }
814
+ if (i < 0) {
815
+ return -1;
816
+ }
817
+ if (i > n - 1) {
818
+ return n - 1;
819
+ }
820
+ return i;
821
+ }
822
+
823
+ static void ps_slice_bounds_neg(
824
+ int64_t n, int64_t start, int64_t stop, int64_t has_start, int64_t has_stop, int64_t *lo, int64_t *hi
825
+ ) {
826
+ *lo = ps_slice_at_neg(n, start, has_start, n - 1);
827
+ *hi = ps_slice_at_neg(n, stop, has_stop, -1);
828
+ }
829
+
830
+ static int64_t ps_slice_count_neg(int64_t from, int64_t to, int64_t step) {
831
+ if (from <= to) {
832
+ return 0;
833
+ }
834
+ return (from - to - 1) / (-step) + 1;
835
+ }
836
+
837
+ void ps_str_slice(
838
+ int64_t n, const char *p, int64_t start, int64_t stop, int64_t has_start, int64_t has_stop, int64_t step, PsBuf *out
839
+ ) {
840
+ ps_slice_step_ok(step);
841
+ int64_t lo = 0;
842
+ int64_t hi = 0;
843
+ if (step < 0) {
844
+ ps_slice_bounds_neg(n, start, stop, has_start, has_stop, &lo, &hi);
845
+ } else {
846
+ ps_slice_bounds(n, start, stop, has_start, has_stop, &lo, &hi);
847
+ }
848
+ if (step == 1) {
849
+ ps_view(out, p + lo, hi - lo);
850
+ return;
851
+ }
852
+ int64_t count = step < 0 ? ps_slice_count_neg(lo, hi, step) : ps_slice_count(lo, hi, step);
853
+ if (count == 0) {
854
+ ps_view(out, "", 0);
855
+ return;
856
+ }
857
+ char *q = malloc((size_t)count + 1);
858
+ if (q == NULL) {
859
+ abort();
860
+ }
861
+ int64_t i = lo;
862
+ for (int64_t w = 0; w < count; w++) {
863
+ q[w] = p[i];
864
+ i += step;
865
+ }
866
+ q[count] = '\0';
867
+ out->len = count;
868
+ out->data = q;
869
+ }
870
+
871
+ PsSeq *ps_seq_slice(PsSeq *s, int64_t start, int64_t stop, int64_t has_start, int64_t has_stop, int64_t step) {
872
+ ps_slice_step_ok(step);
873
+ int64_t lo = 0;
874
+ int64_t hi = 0;
875
+ if (step < 0) {
876
+ ps_slice_bounds_neg(s->len, start, stop, has_start, has_stop, &lo, &hi);
877
+ } else {
878
+ ps_slice_bounds(s->len, start, stop, has_start, has_stop, &lo, &hi);
879
+ }
880
+ if (step == 1) {
881
+ int64_t count = hi - lo;
882
+ PsSeq *out = ps_seq_new(s->elem, count);
883
+ if (count > 0 && s->data != NULL) {
884
+ memcpy(out->data, (char *)s->data + (size_t)lo * (size_t)s->elem, (size_t)count * (size_t)s->elem);
885
+ }
886
+ return out;
887
+ }
888
+ int64_t count = step < 0 ? ps_slice_count_neg(lo, hi, step) : ps_slice_count(lo, hi, step);
889
+ PsSeq *out = ps_seq_new(s->elem, count);
890
+ if (count > 0 && s->data != NULL) {
891
+ int64_t i = lo;
892
+ for (int64_t w = 0; w < count; w++) {
893
+ memcpy(
894
+ (char *)out->data + (size_t)w * (size_t)s->elem,
895
+ (char *)s->data + (size_t)i * (size_t)s->elem,
896
+ (size_t)s->elem
897
+ );
898
+ i += step;
899
+ }
900
+ }
901
+ return out;
902
+ }
903
+
904
+ static int ps_ascii_space(unsigned char c) {
905
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f';
906
+ }
907
+
908
+ static int ps_text_space(unsigned char c) { return ps_space(c) || c == 0x85 || c == 0xa0; }
909
+
910
+ static void ps_push_view(PsSeq *seq, const char *p, int64_t n) {
911
+ PsBuf piece;
912
+ ps_view(&piece, p, n);
913
+ ps_seq_push(seq, &piece);
914
+ }
915
+
916
+ PsSeq *ps_str_split(int64_t n, const char *p, int64_t sn, const char *sp, int64_t mode) {
917
+ PsSeq *seq = ps_seq_new(sizeof(PsBuf), 0);
918
+ if (mode == 0 && sn == 0) {
919
+ ps_raise_cstr(PS_VALUE, "empty separator");
920
+ }
921
+ if (mode != 0) {
922
+ int64_t i = 0;
923
+ while (i < n) {
924
+ unsigned char c = (unsigned char)p[i];
925
+ int space = mode == 2 ? ps_ascii_space(c) : ps_text_space(c);
926
+ if (space) {
927
+ i++;
928
+ continue;
929
+ }
930
+ int64_t j = i + 1;
931
+ while (j < n) {
932
+ unsigned char d = (unsigned char)p[j];
933
+ int gap = mode == 2 ? ps_ascii_space(d) : ps_text_space(d);
934
+ if (gap) {
935
+ break;
936
+ }
937
+ j++;
938
+ }
939
+ ps_push_view(seq, p + i, j - i);
940
+ i = j;
941
+ }
942
+ return seq;
943
+ }
944
+ int64_t i = 0;
945
+ while (i <= n) {
946
+ int64_t j = i;
947
+ int found = 0;
948
+ while (j + sn <= n) {
949
+ if (memcmp(p + j, sp, (size_t)sn) == 0) {
950
+ found = 1;
951
+ break;
952
+ }
953
+ j++;
954
+ }
955
+ if (!found) {
956
+ ps_push_view(seq, p + i, n - i);
957
+ break;
958
+ }
959
+ ps_push_view(seq, p + i, j - i);
960
+ i = j + sn;
961
+ if (i == n) {
962
+ ps_push_view(seq, p + n, 0);
963
+ break;
964
+ }
965
+ }
966
+ return seq;
967
+ }
968
+
969
+ void ps_str_join(int64_t n, const char *sep, PsSeq *parts, PsBuf *out) {
970
+ if (parts->elem != (int64_t)sizeof(PsBuf)) {
971
+ ps_raise_cstr(PS_VALUE, "join takes a list of str or bytes");
972
+ }
973
+ if (parts->len == 0) {
974
+ ps_buf_copy(out, "", 0);
975
+ return;
976
+ }
977
+ int64_t total = 0;
978
+ for (int64_t i = 0; i < parts->len; i++) {
979
+ PsBuf piece;
980
+ memcpy(&piece, (char *)parts->data + (size_t)i * sizeof(PsBuf), sizeof(PsBuf));
981
+ if (i > 0) {
982
+ if (n < 0 || total > INT64_MAX - n) {
983
+ ps_raise_code(PS_OVERFLOW);
984
+ }
985
+ total += n;
986
+ }
987
+ if (piece.len < 0 || total > INT64_MAX - piece.len) {
988
+ ps_raise_code(PS_OVERFLOW);
989
+ }
990
+ total += piece.len;
991
+ }
992
+ char *q = malloc((size_t)total + 1);
993
+ if (q == NULL) {
994
+ abort();
995
+ }
996
+ char *w = q;
997
+ for (int64_t i = 0; i < parts->len; i++) {
998
+ PsBuf piece;
999
+ memcpy(&piece, (char *)parts->data + (size_t)i * sizeof(PsBuf), sizeof(PsBuf));
1000
+ if (i > 0 && n > 0) {
1001
+ memcpy(w, sep, (size_t)n);
1002
+ w += n;
1003
+ }
1004
+ if (piece.len > 0) {
1005
+ memcpy(w, piece.data, (size_t)piece.len);
1006
+ w += piece.len;
1007
+ }
1008
+ }
1009
+ *w = '\0';
1010
+ out->len = total;
1011
+ out->data = q;
1012
+ }
1013
+
1014
+ void ps_utf8_encode(int64_t n, const char *p, PsBuf *out) {
1015
+ PsGrow grow;
1016
+ ps_grow_init(&grow);
1017
+ for (int64_t i = 0; i < n; i++) {
1018
+ unsigned char c = (unsigned char)p[i];
1019
+ if (c < 0x80) {
1020
+ ps_grow_byte(&grow, c);
1021
+ } else {
1022
+ ps_grow_byte(&grow, (unsigned char)(0xC0 | (c >> 6)));
1023
+ ps_grow_byte(&grow, (unsigned char)(0x80 | (c & 0x3F)));
1024
+ }
1025
+ }
1026
+ ps_grow_finish(&grow, out);
1027
+ }
1028
+
1029
+ void ps_utf8_decode(int64_t n, const char *p, PsBuf *out) {
1030
+ PsGrow grow;
1031
+ ps_grow_init(&grow);
1032
+ for (int64_t i = 0; i < n;) {
1033
+ unsigned char c = (unsigned char)p[i];
1034
+ if (c < 0x80) {
1035
+ ps_grow_byte(&grow, c);
1036
+ i++;
1037
+ continue;
1038
+ }
1039
+ if (c < 0xC2 || c > 0xC3 || i + 1 >= n) {
1040
+ ps_raise_cstr(PS_VALUE, "utf-8 decode failed");
1041
+ }
1042
+ unsigned char d = (unsigned char)p[i + 1];
1043
+ if ((d & 0xC0) != 0x80) {
1044
+ ps_raise_cstr(PS_VALUE, "utf-8 decode failed");
1045
+ }
1046
+ unsigned int cp = ((unsigned int)(c & 0x1F) << 6) | (unsigned int)(d & 0x3F);
1047
+ if (cp > 255) {
1048
+ ps_raise_cstr(PS_VALUE, "utf-8 decode failed");
1049
+ }
1050
+ ps_grow_byte(&grow, (unsigned char)cp);
1051
+ i += 2;
1052
+ }
1053
+ ps_grow_finish(&grow, out);
1054
+ }
1055
+
1056
+ void ps_i64_str(int64_t v, PsBuf *out) {
1057
+ char tmp[32];
1058
+ int wrote = snprintf(tmp, sizeof tmp, "%lld", (long long)v);
1059
+ if (wrote < 0) {
1060
+ ps_raise_cstr(PS_VALUE, "int to str failed");
1061
+ }
1062
+ ps_buf_copy(out, tmp, wrote);
1063
+ }
1064
+
1065
+ static void ps_normalize_exp(char *tmp) {
1066
+ char *exp = strchr(tmp, 'e');
1067
+ if (exp == NULL) {
1068
+ exp = strchr(tmp, 'E');
1069
+ }
1070
+ if (exp == NULL) {
1071
+ return;
1072
+ }
1073
+ *exp = 'e';
1074
+ char *digits = exp + 1;
1075
+ int sign = 1;
1076
+ if (*digits == '+') {
1077
+ digits++;
1078
+ } else if (*digits == '-') {
1079
+ sign = -1;
1080
+ digits++;
1081
+ }
1082
+ int value = 0;
1083
+ while (*digits >= '0' && *digits <= '9') {
1084
+ value = value * 10 + (*digits - '0');
1085
+ digits++;
1086
+ }
1087
+ snprintf(exp, 8, "e%c%02d", sign < 0 ? '-' : '+', value);
1088
+ }
1089
+
1090
+ void ps_f64_str(double v, PsBuf *out) {
1091
+ char tmp[128];
1092
+ if (isnan(v)) {
1093
+ ps_buf_copy(out, "nan", 3);
1094
+ return;
1095
+ }
1096
+ if (isinf(v)) {
1097
+ ps_buf_copy(out, signbit(v) ? "-inf" : "inf", signbit(v) ? 4 : 3);
1098
+ return;
1099
+ }
1100
+ if (v == 0.0) {
1101
+ ps_buf_copy(out, signbit(v) ? "-0.0" : "0.0", signbit(v) ? 4 : 3);
1102
+ return;
1103
+ }
1104
+ int prec = 1;
1105
+ for (; prec <= 17; prec++) {
1106
+ snprintf(tmp, sizeof tmp, "%.*g", prec, v);
1107
+ char *end = NULL;
1108
+ double back = strtod(tmp, &end);
1109
+ if (end != tmp && end != NULL && *end == '\0' && back == v) {
1110
+ break;
1111
+ }
1112
+ }
1113
+ int has_dot = 0;
1114
+ int has_exp = 0;
1115
+ for (char *cursor = tmp; *cursor != '\0'; cursor++) {
1116
+ if (*cursor == '.') {
1117
+ has_dot = 1;
1118
+ }
1119
+ if (*cursor == 'e' || *cursor == 'E') {
1120
+ has_exp = 1;
1121
+ }
1122
+ }
1123
+ if (!has_dot && !has_exp) {
1124
+ size_t len = strlen(tmp);
1125
+ if (len + 3 < sizeof tmp) {
1126
+ tmp[len] = '.';
1127
+ tmp[len + 1] = '0';
1128
+ tmp[len + 2] = '\0';
1129
+ }
1130
+ }
1131
+ if (has_exp) {
1132
+ ps_normalize_exp(tmp);
1133
+ }
1134
+ ps_buf_copy(out, tmp, (int64_t)strlen(tmp));
1135
+ }
1136
+
1137
+ static int64_t ps_seq_i64(PsSeq *s, int64_t index) {
1138
+ int64_t value = 0;
1139
+ memcpy(&value, (char *)s->data + (size_t)index * (size_t)s->elem, sizeof(int64_t));
1140
+ return value;
1141
+ }
1142
+
1143
+ int64_t ps_bisect_left(PsSeq *s, int64_t key) {
1144
+ if (s->elem != (int64_t)sizeof(int64_t)) {
1145
+ ps_raise_cstr(PS_VALUE, "bisect takes a list of int");
1146
+ }
1147
+ int64_t lo = 0;
1148
+ int64_t hi = s->len;
1149
+ while (lo < hi) {
1150
+ int64_t mid = lo + (hi - lo) / 2;
1151
+ if (ps_seq_i64(s, mid) < key) {
1152
+ lo = mid + 1;
1153
+ } else {
1154
+ hi = mid;
1155
+ }
1156
+ }
1157
+ return lo;
1158
+ }
1159
+
1160
+ int64_t ps_bisect_right(PsSeq *s, int64_t key) {
1161
+ if (s->elem != (int64_t)sizeof(int64_t)) {
1162
+ ps_raise_cstr(PS_VALUE, "bisect takes a list of int");
1163
+ }
1164
+ int64_t lo = 0;
1165
+ int64_t hi = s->len;
1166
+ while (lo < hi) {
1167
+ int64_t mid = lo + (hi - lo) / 2;
1168
+ if (ps_seq_i64(s, mid) <= key) {
1169
+ lo = mid + 1;
1170
+ } else {
1171
+ hi = mid;
1172
+ }
1173
+ }
1174
+ return lo;
1175
+ }