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,28 @@
|
|
|
1
|
+
/* sys.argv: the process argv materialized once as a list[str] (PsSeq of
|
|
2
|
+
PsBuf). The emitted main hands argc/argv to ps_argv_init before running user
|
|
3
|
+
code; sys.argv reads come back through ps_argv_get. */
|
|
4
|
+
|
|
5
|
+
#include "ps_rt.h"
|
|
6
|
+
|
|
7
|
+
#include <string.h>
|
|
8
|
+
|
|
9
|
+
static PsSeq *ps_argv_seq;
|
|
10
|
+
|
|
11
|
+
void ps_argv_init(int32_t argc, char **argv) {
|
|
12
|
+
PsSeq *seq = ps_seq_new((int64_t)sizeof(PsBuf), 0);
|
|
13
|
+
for (int32_t i = 0; i < argc; i++) {
|
|
14
|
+
PsBuf b;
|
|
15
|
+
b.len = (int64_t)strlen(argv[i]);
|
|
16
|
+
b.data = ps_alloc(b.len + 1);
|
|
17
|
+
memcpy(b.data, argv[i], (size_t)b.len + 1);
|
|
18
|
+
ps_seq_push(seq, &b);
|
|
19
|
+
}
|
|
20
|
+
ps_argv_seq = seq;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
PsSeq *ps_argv_get(void) {
|
|
24
|
+
if (ps_argv_seq == NULL) {
|
|
25
|
+
ps_argv_seq = ps_seq_new((int64_t)sizeof(PsBuf), 0);
|
|
26
|
+
}
|
|
27
|
+
return ps_argv_seq;
|
|
28
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/* base64 and urlsafe base64. Padding is required. Characters outside the
|
|
2
|
+
alphabet are ignored, matching CPython's default validate=False. binascii.Error
|
|
3
|
+
is reported as ValueError. */
|
|
4
|
+
|
|
5
|
+
#include "ps_rt.h"
|
|
6
|
+
|
|
7
|
+
#include <stdlib.h>
|
|
8
|
+
#include <string.h>
|
|
9
|
+
|
|
10
|
+
static int ps_b64_val(unsigned char c, int *out) {
|
|
11
|
+
if (c >= 'A' && c <= 'Z') {
|
|
12
|
+
*out = c - 'A';
|
|
13
|
+
return 1;
|
|
14
|
+
}
|
|
15
|
+
if (c >= 'a' && c <= 'z') {
|
|
16
|
+
*out = c - 'a' + 26;
|
|
17
|
+
return 1;
|
|
18
|
+
}
|
|
19
|
+
if (c >= '0' && c <= '9') {
|
|
20
|
+
*out = c - '0' + 52;
|
|
21
|
+
return 1;
|
|
22
|
+
}
|
|
23
|
+
if (c == '+' || c == '-') {
|
|
24
|
+
*out = 62;
|
|
25
|
+
return 1;
|
|
26
|
+
}
|
|
27
|
+
if (c == '/' || c == '_') {
|
|
28
|
+
*out = 63;
|
|
29
|
+
return 1;
|
|
30
|
+
}
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static void ps_b64_encode(int64_t n, const char *p, int url, PsBuf *out) {
|
|
35
|
+
static const char kStd[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
36
|
+
static const char kUrl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
37
|
+
const char *alpha = url ? kUrl : kStd;
|
|
38
|
+
if (n < 0) {
|
|
39
|
+
ps_raise_cstr(PS_VALUE, "base64 length is negative");
|
|
40
|
+
}
|
|
41
|
+
int64_t groups = (n + 2) / 3;
|
|
42
|
+
if (groups > INT64_MAX / 4) {
|
|
43
|
+
ps_raise_cstr(PS_OVERFLOW, "base64 result does not fit");
|
|
44
|
+
}
|
|
45
|
+
int64_t total = groups * 4;
|
|
46
|
+
char *q = malloc((size_t)total + 1);
|
|
47
|
+
if (q == NULL) {
|
|
48
|
+
abort();
|
|
49
|
+
}
|
|
50
|
+
int64_t w = 0;
|
|
51
|
+
int64_t i = 0;
|
|
52
|
+
while (i + 3 <= n) {
|
|
53
|
+
unsigned int v = ((unsigned char)p[i] << 16) | ((unsigned char)p[i + 1] << 8) | (unsigned char)p[i + 2];
|
|
54
|
+
q[w++] = alpha[(v >> 18) & 63];
|
|
55
|
+
q[w++] = alpha[(v >> 12) & 63];
|
|
56
|
+
q[w++] = alpha[(v >> 6) & 63];
|
|
57
|
+
q[w++] = alpha[v & 63];
|
|
58
|
+
i += 3;
|
|
59
|
+
}
|
|
60
|
+
if (i < n) {
|
|
61
|
+
unsigned int v = (unsigned char)p[i] << 16;
|
|
62
|
+
if (i + 1 < n) {
|
|
63
|
+
v |= (unsigned char)p[i + 1] << 8;
|
|
64
|
+
}
|
|
65
|
+
q[w++] = alpha[(v >> 18) & 63];
|
|
66
|
+
q[w++] = alpha[(v >> 12) & 63];
|
|
67
|
+
if (i + 1 < n) {
|
|
68
|
+
q[w++] = alpha[(v >> 6) & 63];
|
|
69
|
+
q[w++] = '=';
|
|
70
|
+
} else {
|
|
71
|
+
q[w++] = '=';
|
|
72
|
+
q[w++] = '=';
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
q[w] = '\0';
|
|
76
|
+
out->len = w;
|
|
77
|
+
out->data = q;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static void ps_b64_decode(int64_t n, const char *p, int url, PsBuf *out) {
|
|
81
|
+
char *filtered = malloc((size_t)n + 1);
|
|
82
|
+
if (filtered == NULL && n > 0) {
|
|
83
|
+
abort();
|
|
84
|
+
}
|
|
85
|
+
int64_t m = 0;
|
|
86
|
+
for (int64_t i = 0; i < n; i++) {
|
|
87
|
+
unsigned char c = (unsigned char)p[i];
|
|
88
|
+
int dummy = 0;
|
|
89
|
+
if (c == '=') {
|
|
90
|
+
filtered[m++] = '=';
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (!ps_b64_val(c, &dummy)) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (!url && (c == '-' || c == '_')) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
filtered[m++] = (char)c;
|
|
100
|
+
}
|
|
101
|
+
if (m % 4 != 0) {
|
|
102
|
+
free(filtered);
|
|
103
|
+
ps_raise_cstr(PS_VALUE, "incorrect base64 padding");
|
|
104
|
+
}
|
|
105
|
+
int64_t pad = 0;
|
|
106
|
+
if (m >= 1 && filtered[m - 1] == '=') {
|
|
107
|
+
pad++;
|
|
108
|
+
}
|
|
109
|
+
if (m >= 2 && filtered[m - 2] == '=') {
|
|
110
|
+
pad++;
|
|
111
|
+
}
|
|
112
|
+
for (int64_t i = 0; i < m - pad; i++) {
|
|
113
|
+
if (filtered[i] == '=') {
|
|
114
|
+
free(filtered);
|
|
115
|
+
ps_raise_cstr(PS_VALUE, "incorrect base64 padding");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
int64_t data_chars = m - pad;
|
|
119
|
+
if (data_chars % 4 == 1) {
|
|
120
|
+
free(filtered);
|
|
121
|
+
ps_raise_cstr(PS_VALUE, "incorrect base64 padding");
|
|
122
|
+
}
|
|
123
|
+
int64_t total = m == 0 ? 0 : (m / 4) * 3 - pad;
|
|
124
|
+
char *q = malloc((size_t)total + 1);
|
|
125
|
+
if (q == NULL) {
|
|
126
|
+
free(filtered);
|
|
127
|
+
abort();
|
|
128
|
+
}
|
|
129
|
+
int64_t w = 0;
|
|
130
|
+
for (int64_t i = 0; i < m; i += 4) {
|
|
131
|
+
int v0 = 0;
|
|
132
|
+
int v1 = 0;
|
|
133
|
+
int v2 = 0;
|
|
134
|
+
int v3 = 0;
|
|
135
|
+
if (!ps_b64_val((unsigned char)filtered[i], &v0) || !ps_b64_val((unsigned char)filtered[i + 1], &v1)) {
|
|
136
|
+
free(filtered);
|
|
137
|
+
free(q);
|
|
138
|
+
ps_raise_cstr(PS_VALUE, "incorrect base64 padding");
|
|
139
|
+
}
|
|
140
|
+
if (filtered[i + 2] != '=' && !ps_b64_val((unsigned char)filtered[i + 2], &v2)) {
|
|
141
|
+
free(filtered);
|
|
142
|
+
free(q);
|
|
143
|
+
ps_raise_cstr(PS_VALUE, "incorrect base64 padding");
|
|
144
|
+
}
|
|
145
|
+
if (filtered[i + 3] != '=' && !ps_b64_val((unsigned char)filtered[i + 3], &v3)) {
|
|
146
|
+
free(filtered);
|
|
147
|
+
free(q);
|
|
148
|
+
ps_raise_cstr(PS_VALUE, "incorrect base64 padding");
|
|
149
|
+
}
|
|
150
|
+
unsigned int v = ((unsigned int)v0 << 18) | ((unsigned int)v1 << 12) | ((unsigned int)v2 << 6) | (unsigned int)v3;
|
|
151
|
+
q[w++] = (char)((v >> 16) & 0xff);
|
|
152
|
+
if (filtered[i + 2] != '=') {
|
|
153
|
+
q[w++] = (char)((v >> 8) & 0xff);
|
|
154
|
+
}
|
|
155
|
+
if (filtered[i + 3] != '=') {
|
|
156
|
+
q[w++] = (char)(v & 0xff);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
free(filtered);
|
|
160
|
+
q[w] = '\0';
|
|
161
|
+
out->len = w;
|
|
162
|
+
out->data = q;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
void ps_b64_std_encode(int64_t n, char *p, PsBuf *out) { ps_b64_encode(n, p, 0, out); }
|
|
166
|
+
void ps_b64_url_encode(int64_t n, char *p, PsBuf *out) { ps_b64_encode(n, p, 1, out); }
|
|
167
|
+
void ps_b64_std_decode(int64_t n, char *p, PsBuf *out) { ps_b64_decode(n, p, 0, out); }
|
|
168
|
+
void ps_b64_url_decode(int64_t n, char *p, PsBuf *out) { ps_b64_decode(n, p, 1, out); }
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/* collections.deque. The value is this struct, not a field object.
|
|
2
|
+
|
|
3
|
+
Indexing follows Python: negative indexes count from the end, and an empty
|
|
4
|
+
pop raises IndexError.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
#include "ps_rt.h"
|
|
8
|
+
|
|
9
|
+
#include <stdlib.h>
|
|
10
|
+
#include <string.h>
|
|
11
|
+
|
|
12
|
+
typedef struct {
|
|
13
|
+
int64_t len;
|
|
14
|
+
int64_t cap;
|
|
15
|
+
int64_t start;
|
|
16
|
+
int64_t elem;
|
|
17
|
+
char *data;
|
|
18
|
+
} PsDeque;
|
|
19
|
+
|
|
20
|
+
static char *ps_at(PsDeque *d, int64_t i) {
|
|
21
|
+
int64_t at = d->start + i;
|
|
22
|
+
if (d->cap > 0 && at >= d->cap) {
|
|
23
|
+
at -= d->cap;
|
|
24
|
+
}
|
|
25
|
+
return d->data + (size_t)at * (size_t)d->elem;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static void ps_grow(PsDeque *d) {
|
|
29
|
+
int64_t cap = d->cap == 0 ? 4 : d->cap * 2;
|
|
30
|
+
char *data;
|
|
31
|
+
int64_t i;
|
|
32
|
+
if (cap < d->len + 1) {
|
|
33
|
+
ps_raise_code(PS_OVERFLOW);
|
|
34
|
+
}
|
|
35
|
+
data = calloc((size_t)cap, (size_t)d->elem);
|
|
36
|
+
if (data == NULL) {
|
|
37
|
+
abort();
|
|
38
|
+
}
|
|
39
|
+
for (i = 0; i < d->len; i++) {
|
|
40
|
+
memcpy(data + (size_t)i * (size_t)d->elem, ps_at(d, i), (size_t)d->elem);
|
|
41
|
+
}
|
|
42
|
+
free(d->data);
|
|
43
|
+
d->data = data;
|
|
44
|
+
d->start = 0;
|
|
45
|
+
d->cap = cap;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static PsDeque *ps_new(int64_t elem) {
|
|
49
|
+
PsDeque *d;
|
|
50
|
+
if (elem <= 0) {
|
|
51
|
+
ps_raise_code(PS_VALUE);
|
|
52
|
+
}
|
|
53
|
+
d = calloc(1, sizeof(PsDeque));
|
|
54
|
+
if (d == NULL) {
|
|
55
|
+
abort();
|
|
56
|
+
}
|
|
57
|
+
d->elem = elem;
|
|
58
|
+
return d;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
PsDeque *ps_deque_empty(int64_t elem) { return ps_new(elem); }
|
|
62
|
+
|
|
63
|
+
PsDeque *ps_deque_from(int64_t elem, PsSeq *src) {
|
|
64
|
+
PsDeque *d = ps_new(elem);
|
|
65
|
+
int64_t i;
|
|
66
|
+
if (src->elem != elem) {
|
|
67
|
+
ps_raise_cstr(PS_VALUE, "deque element size does not match");
|
|
68
|
+
}
|
|
69
|
+
for (i = 0; i < src->len; i++) {
|
|
70
|
+
if (d->len == d->cap) {
|
|
71
|
+
ps_grow(d);
|
|
72
|
+
}
|
|
73
|
+
memcpy(ps_at(d, d->len), (char *)src->data + (size_t)i * (size_t)elem, (size_t)elem);
|
|
74
|
+
d->len += 1;
|
|
75
|
+
}
|
|
76
|
+
return d;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
int64_t ps_deque_len(PsDeque *d) { return d->len; }
|
|
80
|
+
|
|
81
|
+
void ps_deque_append(PsDeque *d, void *src) {
|
|
82
|
+
if (d->len == d->cap) {
|
|
83
|
+
ps_grow(d);
|
|
84
|
+
}
|
|
85
|
+
memcpy(ps_at(d, d->len), src, (size_t)d->elem);
|
|
86
|
+
d->len += 1;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
void ps_deque_appendleft(PsDeque *d, void *src) {
|
|
90
|
+
if (d->len == d->cap) {
|
|
91
|
+
ps_grow(d);
|
|
92
|
+
}
|
|
93
|
+
d->start = d->start == 0 ? d->cap - 1 : d->start - 1;
|
|
94
|
+
memcpy(ps_at(d, 0), src, (size_t)d->elem);
|
|
95
|
+
d->len += 1;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static int64_t ps_index(int64_t len, int64_t i) {
|
|
99
|
+
if (i < 0) {
|
|
100
|
+
i += len;
|
|
101
|
+
}
|
|
102
|
+
if (i < 0 || i >= len) {
|
|
103
|
+
ps_raise_code(PS_INDEX);
|
|
104
|
+
}
|
|
105
|
+
return i;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
void ps_deque_get(PsDeque *d, int64_t i, void *out) {
|
|
109
|
+
i = ps_index(d->len, i);
|
|
110
|
+
memcpy(out, ps_at(d, i), (size_t)d->elem);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
void ps_deque_pop(PsDeque *d, void *out) {
|
|
114
|
+
if (d->len == 0) {
|
|
115
|
+
ps_raise_code(PS_INDEX);
|
|
116
|
+
}
|
|
117
|
+
d->len -= 1;
|
|
118
|
+
memcpy(out, ps_at(d, d->len), (size_t)d->elem);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
void ps_deque_popleft(PsDeque *d, void *out) {
|
|
122
|
+
if (d->len == 0) {
|
|
123
|
+
ps_raise_code(PS_INDEX);
|
|
124
|
+
}
|
|
125
|
+
memcpy(out, ps_at(d, 0), (size_t)d->elem);
|
|
126
|
+
d->len -= 1;
|
|
127
|
+
if (d->cap > 0) {
|
|
128
|
+
d->start += 1;
|
|
129
|
+
if (d->start == d->cap) {
|
|
130
|
+
d->start = 0;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
/* datetime.date, datetime.datetime, datetime.time, and timedelta.
|
|
2
|
+
|
|
3
|
+
Field order matches the synthetic classes: Date is year, month, day.
|
|
4
|
+
DateTime adds hour, minute, second, microsecond. TimeDelta is days, seconds,
|
|
5
|
+
microseconds, normalized the way CPython normalizes them.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include "ps_rt.h"
|
|
9
|
+
|
|
10
|
+
#include <stdint.h>
|
|
11
|
+
|
|
12
|
+
typedef struct {
|
|
13
|
+
int64_t year;
|
|
14
|
+
int64_t month;
|
|
15
|
+
int64_t day;
|
|
16
|
+
} PsDate;
|
|
17
|
+
|
|
18
|
+
typedef struct {
|
|
19
|
+
int64_t year;
|
|
20
|
+
int64_t month;
|
|
21
|
+
int64_t day;
|
|
22
|
+
int64_t hour;
|
|
23
|
+
int64_t minute;
|
|
24
|
+
int64_t second;
|
|
25
|
+
int64_t microsecond;
|
|
26
|
+
} PsDateTime;
|
|
27
|
+
|
|
28
|
+
typedef struct {
|
|
29
|
+
int64_t hour;
|
|
30
|
+
int64_t minute;
|
|
31
|
+
int64_t second;
|
|
32
|
+
int64_t microsecond;
|
|
33
|
+
} PsTod;
|
|
34
|
+
|
|
35
|
+
typedef struct {
|
|
36
|
+
int64_t days;
|
|
37
|
+
int64_t seconds;
|
|
38
|
+
int64_t microseconds;
|
|
39
|
+
} PsDelta;
|
|
40
|
+
|
|
41
|
+
static const int64_t PS_DAY_US = 86400000000LL;
|
|
42
|
+
|
|
43
|
+
static int ps_leap(int64_t year) {
|
|
44
|
+
return (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static int ps_valid_ymd(int64_t y, int64_t m, int64_t d) {
|
|
48
|
+
static const int mdays[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
49
|
+
int dim;
|
|
50
|
+
if (y < 1 || y > 9999 || m < 1 || m > 12 || d < 1) {
|
|
51
|
+
return 0;
|
|
52
|
+
}
|
|
53
|
+
dim = mdays[m];
|
|
54
|
+
if (m == 2 && ps_leap(y)) {
|
|
55
|
+
dim = 29;
|
|
56
|
+
}
|
|
57
|
+
return d <= dim;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static int64_t ps_ymd_ord(int64_t y, int64_t m, int64_t d) {
|
|
61
|
+
static const int before[] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
|
|
62
|
+
int64_t y1 = y - 1;
|
|
63
|
+
int64_t days = before[m];
|
|
64
|
+
if (m > 2 && ps_leap(y)) {
|
|
65
|
+
days += 1;
|
|
66
|
+
}
|
|
67
|
+
return y1 * 365 + y1 / 4 - y1 / 100 + y1 / 400 + days + d;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static void ps_ord_ymd(int64_t ordinal, int64_t *year, int64_t *month, int64_t *day) {
|
|
71
|
+
static const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
72
|
+
int64_t n = ordinal - 1;
|
|
73
|
+
int64_t n400 = n / 146097;
|
|
74
|
+
int64_t n100;
|
|
75
|
+
int64_t n4;
|
|
76
|
+
int64_t n1;
|
|
77
|
+
int leap;
|
|
78
|
+
int m;
|
|
79
|
+
n %= 146097;
|
|
80
|
+
n100 = n / 36524;
|
|
81
|
+
n %= 36524;
|
|
82
|
+
n4 = n / 1461;
|
|
83
|
+
n %= 1461;
|
|
84
|
+
n1 = n / 365;
|
|
85
|
+
n %= 365;
|
|
86
|
+
*year = n400 * 400 + n100 * 100 + n4 * 4 + n1 + 1;
|
|
87
|
+
if (n1 == 4 || n100 == 4) {
|
|
88
|
+
*year -= 1;
|
|
89
|
+
*month = 12;
|
|
90
|
+
*day = 31;
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
leap = n1 == 3 && (n4 != 24 || n100 == 3);
|
|
94
|
+
for (m = 1; m <= 12; m++) {
|
|
95
|
+
int dim = mdays[m - 1];
|
|
96
|
+
if (m == 2 && leap) {
|
|
97
|
+
dim += 1;
|
|
98
|
+
}
|
|
99
|
+
if (n < dim) {
|
|
100
|
+
*month = m;
|
|
101
|
+
*day = n + 1;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
n -= dim;
|
|
105
|
+
}
|
|
106
|
+
ps_raise_cstr(PS_VALUE, "date out of range");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
static void ps_put_ord(int64_t ordinal, PsDate *out) {
|
|
110
|
+
int64_t max_ord = ps_ymd_ord(9999, 12, 31);
|
|
111
|
+
if (ordinal < 1 || ordinal > max_ord) {
|
|
112
|
+
ps_raise_cstr(PS_VALUE, "date out of range");
|
|
113
|
+
}
|
|
114
|
+
ps_ord_ymd(ordinal, &out->year, &out->month, &out->day);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
static void ps_pad(char *dst, int width, int64_t value) {
|
|
118
|
+
int i;
|
|
119
|
+
for (i = width - 1; i >= 0; i--) {
|
|
120
|
+
dst[i] = (char)('0' + (value % 10));
|
|
121
|
+
value /= 10;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static void ps_iso_date(int64_t y, int64_t m, int64_t d, PsBuf *out) {
|
|
126
|
+
char buf[16];
|
|
127
|
+
ps_pad(buf, 4, y);
|
|
128
|
+
buf[4] = '-';
|
|
129
|
+
ps_pad(buf + 5, 2, m);
|
|
130
|
+
buf[7] = '-';
|
|
131
|
+
ps_pad(buf + 8, 2, d);
|
|
132
|
+
ps_buf_copy(out, buf, 10);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
static void ps_iso_tod(int64_t h, int64_t m, int64_t s, int64_t us, PsBuf *out) {
|
|
136
|
+
char buf[24];
|
|
137
|
+
int n = 8;
|
|
138
|
+
ps_pad(buf, 2, h);
|
|
139
|
+
buf[2] = ':';
|
|
140
|
+
ps_pad(buf + 3, 2, m);
|
|
141
|
+
buf[5] = ':';
|
|
142
|
+
ps_pad(buf + 6, 2, s);
|
|
143
|
+
if (us != 0) {
|
|
144
|
+
buf[8] = '.';
|
|
145
|
+
ps_pad(buf + 9, 6, us);
|
|
146
|
+
n = 15;
|
|
147
|
+
}
|
|
148
|
+
ps_buf_copy(out, buf, n);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static int ps_digits(const char *s, int64_t n, int64_t at, int width, int64_t *out) {
|
|
152
|
+
int64_t value = 0;
|
|
153
|
+
int i;
|
|
154
|
+
if (at + width > n) {
|
|
155
|
+
return 0;
|
|
156
|
+
}
|
|
157
|
+
for (i = 0; i < width; i++) {
|
|
158
|
+
char c = s[at + i];
|
|
159
|
+
if (c < '0' || c > '9') {
|
|
160
|
+
return 0;
|
|
161
|
+
}
|
|
162
|
+
value = value * 10 + (c - '0');
|
|
163
|
+
}
|
|
164
|
+
*out = value;
|
|
165
|
+
return 1;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
static void ps_delta_norm(__int128 us, PsDelta *out) {
|
|
169
|
+
__int128 day;
|
|
170
|
+
__int128 rem;
|
|
171
|
+
day = us / PS_DAY_US;
|
|
172
|
+
rem = us - day * PS_DAY_US;
|
|
173
|
+
if (rem < 0) {
|
|
174
|
+
rem += PS_DAY_US;
|
|
175
|
+
day -= 1;
|
|
176
|
+
}
|
|
177
|
+
if (day > INT64_MAX || day < INT64_MIN) {
|
|
178
|
+
ps_raise_cstr(PS_OVERFLOW, "timedelta out of range");
|
|
179
|
+
}
|
|
180
|
+
out->days = (int64_t)day;
|
|
181
|
+
out->seconds = (int64_t)(rem / 1000000);
|
|
182
|
+
out->microseconds = (int64_t)(rem % 1000000);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
static __int128 ps_delta_us(const PsDelta *d) {
|
|
186
|
+
return (__int128)d->days * PS_DAY_US + (__int128)d->seconds * 1000000 + d->microseconds;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
void ps_date_ymd(int64_t y, int64_t m, int64_t d, PsDate *out) {
|
|
190
|
+
if (!ps_valid_ymd(y, m, d)) {
|
|
191
|
+
ps_raise_cstr(PS_VALUE, "date out of range");
|
|
192
|
+
}
|
|
193
|
+
out->year = y;
|
|
194
|
+
out->month = m;
|
|
195
|
+
out->day = d;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
void ps_date_today(PsDate *out) {
|
|
199
|
+
/* Filled by ps_time via a local date. Implemented here with time.h. */
|
|
200
|
+
extern void ps_date_today_fill(PsDate *out);
|
|
201
|
+
ps_date_today_fill(out);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
void ps_date_fromiso(int64_t n, const char *s, PsDate *out) {
|
|
205
|
+
int64_t y, m, d;
|
|
206
|
+
if (n != 10 || s[4] != '-' || s[7] != '-' || !ps_digits(s, n, 0, 4, &y) || !ps_digits(s, n, 5, 2, &m) ||
|
|
207
|
+
!ps_digits(s, n, 8, 2, &d)) {
|
|
208
|
+
ps_raise_cstr(PS_VALUE, "invalid isoformat date");
|
|
209
|
+
}
|
|
210
|
+
ps_date_ymd(y, m, d, out);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
void ps_date_fromord(int64_t ordinal, PsDate *out) { ps_put_ord(ordinal, out); }
|
|
214
|
+
|
|
215
|
+
void ps_date_iso(PsDate *d, PsBuf *out) { ps_iso_date(d->year, d->month, d->day, out); }
|
|
216
|
+
|
|
217
|
+
int64_t ps_date_ord(PsDate *d) { return ps_ymd_ord(d->year, d->month, d->day); }
|
|
218
|
+
|
|
219
|
+
int64_t ps_date_weekday(PsDate *d) { return (ps_ymd_ord(d->year, d->month, d->day) + 6) % 7; }
|
|
220
|
+
|
|
221
|
+
void ps_date_add(PsDate *d, PsDelta *delta, int32_t sign, PsDate *out) {
|
|
222
|
+
int64_t ord = ps_ymd_ord(d->year, d->month, d->day);
|
|
223
|
+
__int128 days = delta->days;
|
|
224
|
+
__int128 sum;
|
|
225
|
+
if (sign < 0) {
|
|
226
|
+
days = -days;
|
|
227
|
+
}
|
|
228
|
+
sum = (__int128)ord + days;
|
|
229
|
+
if (sum < 1 || sum > ps_ymd_ord(9999, 12, 31)) {
|
|
230
|
+
ps_raise_cstr(PS_VALUE, "date out of range");
|
|
231
|
+
}
|
|
232
|
+
ps_put_ord((int64_t)sum, out);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
void ps_date_diff(PsDate *a, PsDate *b, PsDelta *out) {
|
|
236
|
+
out->days = ps_ymd_ord(a->year, a->month, a->day) - ps_ymd_ord(b->year, b->month, b->day);
|
|
237
|
+
out->seconds = 0;
|
|
238
|
+
out->microseconds = 0;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
static void ps_check_tod(int64_t h, int64_t mi, int64_t s, int64_t us) {
|
|
242
|
+
if (h < 0 || h > 23 || mi < 0 || mi > 59 || s < 0 || s > 59 || us < 0 || us > 999999) {
|
|
243
|
+
ps_raise_cstr(PS_VALUE, "time out of range");
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
void ps_dt_new(int64_t y, int64_t m, int64_t d, int64_t h, int64_t mi, int64_t s, int64_t us, PsDateTime *out) {
|
|
248
|
+
if (!ps_valid_ymd(y, m, d)) {
|
|
249
|
+
ps_raise_cstr(PS_VALUE, "date out of range");
|
|
250
|
+
}
|
|
251
|
+
ps_check_tod(h, mi, s, us);
|
|
252
|
+
out->year = y;
|
|
253
|
+
out->month = m;
|
|
254
|
+
out->day = d;
|
|
255
|
+
out->hour = h;
|
|
256
|
+
out->minute = mi;
|
|
257
|
+
out->second = s;
|
|
258
|
+
out->microsecond = us;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
void ps_dt_now(PsDateTime *out) {
|
|
262
|
+
extern void ps_dt_now_fill(PsDateTime *out);
|
|
263
|
+
ps_dt_now_fill(out);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
void ps_dt_fromiso(int64_t n, const char *s, PsDateTime *out) {
|
|
267
|
+
int64_t y, m, d, h = 0, mi = 0, sec = 0, us = 0;
|
|
268
|
+
if (n != 10 && n != 19 && n != 26) {
|
|
269
|
+
ps_raise_cstr(PS_VALUE, "invalid isoformat datetime");
|
|
270
|
+
}
|
|
271
|
+
if (s[4] != '-' || s[7] != '-' || !ps_digits(s, n, 0, 4, &y) || !ps_digits(s, n, 5, 2, &m) ||
|
|
272
|
+
!ps_digits(s, n, 8, 2, &d)) {
|
|
273
|
+
ps_raise_cstr(PS_VALUE, "invalid isoformat datetime");
|
|
274
|
+
}
|
|
275
|
+
if (n >= 19) {
|
|
276
|
+
if ((s[10] != 'T' && s[10] != ' ') || s[13] != ':' || s[16] != ':' || !ps_digits(s, n, 11, 2, &h) ||
|
|
277
|
+
!ps_digits(s, n, 14, 2, &mi) || !ps_digits(s, n, 17, 2, &sec)) {
|
|
278
|
+
ps_raise_cstr(PS_VALUE, "invalid isoformat datetime");
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (n == 26) {
|
|
282
|
+
if (s[19] != '.' || !ps_digits(s, n, 20, 6, &us)) {
|
|
283
|
+
ps_raise_cstr(PS_VALUE, "invalid isoformat datetime");
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
ps_dt_new(y, m, d, h, mi, sec, us, out);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
void ps_dt_iso(PsDateTime *d, PsBuf *out) {
|
|
290
|
+
char buf[40];
|
|
291
|
+
int n = 19;
|
|
292
|
+
ps_pad(buf, 4, d->year);
|
|
293
|
+
buf[4] = '-';
|
|
294
|
+
ps_pad(buf + 5, 2, d->month);
|
|
295
|
+
buf[7] = '-';
|
|
296
|
+
ps_pad(buf + 8, 2, d->day);
|
|
297
|
+
buf[10] = 'T';
|
|
298
|
+
ps_pad(buf + 11, 2, d->hour);
|
|
299
|
+
buf[13] = ':';
|
|
300
|
+
ps_pad(buf + 14, 2, d->minute);
|
|
301
|
+
buf[16] = ':';
|
|
302
|
+
ps_pad(buf + 17, 2, d->second);
|
|
303
|
+
if (d->microsecond != 0) {
|
|
304
|
+
buf[19] = '.';
|
|
305
|
+
ps_pad(buf + 20, 6, d->microsecond);
|
|
306
|
+
n = 26;
|
|
307
|
+
}
|
|
308
|
+
ps_buf_copy(out, buf, n);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
void ps_dt_date(PsDateTime *d, PsDate *out) { ps_date_ymd(d->year, d->month, d->day, out); }
|
|
312
|
+
|
|
313
|
+
void ps_dt_time(PsDateTime *d, PsTod *out) {
|
|
314
|
+
ps_check_tod(d->hour, d->minute, d->second, d->microsecond);
|
|
315
|
+
out->hour = d->hour;
|
|
316
|
+
out->minute = d->minute;
|
|
317
|
+
out->second = d->second;
|
|
318
|
+
out->microsecond = d->microsecond;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
static void ps_dt_parts(const PsDateTime *a, int64_t *ord, __int128 *us) {
|
|
322
|
+
*ord = ps_ymd_ord(a->year, a->month, a->day);
|
|
323
|
+
*us = (((__int128)a->hour * 3600 + a->minute * 60 + a->second) * 1000000) + a->microsecond;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
void ps_dt_add(PsDateTime *a, PsDelta *delta, int32_t sign, PsDateTime *out) {
|
|
327
|
+
int64_t ord;
|
|
328
|
+
__int128 us;
|
|
329
|
+
__int128 extra;
|
|
330
|
+
__int128 rem;
|
|
331
|
+
__int128 add = ps_delta_us(delta);
|
|
332
|
+
if (sign < 0) {
|
|
333
|
+
add = -add;
|
|
334
|
+
}
|
|
335
|
+
ps_dt_parts(a, &ord, &us);
|
|
336
|
+
us += add;
|
|
337
|
+
extra = us / PS_DAY_US;
|
|
338
|
+
rem = us - extra * PS_DAY_US;
|
|
339
|
+
if (rem < 0) {
|
|
340
|
+
rem += PS_DAY_US;
|
|
341
|
+
extra -= 1;
|
|
342
|
+
}
|
|
343
|
+
if (extra > INT64_MAX || extra < INT64_MIN || (extra > 0 && ord > INT64_MAX - (int64_t)extra) ||
|
|
344
|
+
(extra < 0 && ord < (int64_t)(-extra))) {
|
|
345
|
+
ps_raise_cstr(PS_VALUE, "datetime out of range");
|
|
346
|
+
}
|
|
347
|
+
ps_put_ord(ord + (int64_t)extra, (PsDate *)out);
|
|
348
|
+
out->hour = (int64_t)(rem / 3600000000LL);
|
|
349
|
+
rem %= 3600000000LL;
|
|
350
|
+
out->minute = (int64_t)(rem / 60000000LL);
|
|
351
|
+
rem %= 60000000LL;
|
|
352
|
+
out->second = (int64_t)(rem / 1000000LL);
|
|
353
|
+
out->microsecond = (int64_t)(rem % 1000000LL);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
void ps_dt_diff(PsDateTime *a, PsDateTime *b, PsDelta *out) {
|
|
357
|
+
int64_t oa, ob;
|
|
358
|
+
__int128 ua, ub;
|
|
359
|
+
ps_dt_parts(a, &oa, &ua);
|
|
360
|
+
ps_dt_parts(b, &ob, &ub);
|
|
361
|
+
ps_delta_norm(((__int128)oa - ob) * PS_DAY_US + (ua - ub), out);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
void ps_tod_new(int64_t h, int64_t mi, int64_t s, int64_t us, PsTod *out) {
|
|
365
|
+
ps_check_tod(h, mi, s, us);
|
|
366
|
+
out->hour = h;
|
|
367
|
+
out->minute = mi;
|
|
368
|
+
out->second = s;
|
|
369
|
+
out->microsecond = us;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
void ps_tod_iso(PsTod *t, PsBuf *out) { ps_iso_tod(t->hour, t->minute, t->second, t->microsecond, out); }
|
|
373
|
+
|
|
374
|
+
void ps_delta_new(int64_t days, int64_t seconds, int64_t microseconds, PsDelta *out) {
|
|
375
|
+
ps_delta_norm((__int128)days * PS_DAY_US + (__int128)seconds * 1000000 + microseconds, out);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
void ps_delta_neg(PsDelta *d, PsDelta *out) { ps_delta_norm(-ps_delta_us(d), out); }
|
|
379
|
+
|
|
380
|
+
void ps_delta_add(PsDelta *a, PsDelta *b, int32_t sign, PsDelta *out) {
|
|
381
|
+
__int128 add = ps_delta_us(b);
|
|
382
|
+
if (sign < 0) {
|
|
383
|
+
add = -add;
|
|
384
|
+
}
|
|
385
|
+
ps_delta_norm(ps_delta_us(a) + add, out);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
double ps_delta_total(PsDelta *d) { return (double)ps_delta_us(d) / 1000000.0; }
|