slovo/runtime/runtime.c
2026-05-22 08:38:43 +02:00

1115 lines
27 KiB
C

#define _POSIX_C_SOURCE 200809L
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
typedef struct {
int32_t len;
int32_t *data;
} __glagol_vec_i32;
typedef struct {
int32_t len;
int64_t *data;
} __glagol_vec_i64;
typedef struct {
int32_t len;
double *data;
} __glagol_vec_f64;
typedef struct {
int32_t len;
bool *data;
} __glagol_vec_bool;
typedef struct {
int32_t len;
char **data;
} __glagol_vec_string;
static int32_t __glagol_process_argc_value = 0;
static char **__glagol_process_argv_value = NULL;
static bool __glagol_time_base_initialized = false;
static struct timespec __glagol_time_base;
void print_i32(int32_t value) {
printf("%d\n", value);
}
void print_i64(int64_t value) {
printf("%" PRId64 "\n", value);
}
void print_u32(uint32_t value) {
printf("%" PRIu32 "\n", value);
}
void print_u64(uint64_t value) {
printf("%" PRIu64 "\n", value);
}
void print_f64(double value) {
printf("%.17g\n", value);
}
void print_string(const char *value) {
puts(value);
}
void print_bool(bool value) {
puts(value ? "true" : "false");
}
int32_t string_len(const char *value) {
return (int32_t)strlen(value);
}
void __glagol_io_eprint(const char *value) {
fputs(value, stderr);
}
char *__glagol_io_read_stdin_result(void) {
size_t capacity = 1024;
size_t length = 0;
char *value = malloc(capacity);
if (value == NULL) {
return NULL;
}
for (;;) {
if (length == capacity) {
if (capacity > SIZE_MAX / 2) {
free(value);
return NULL;
}
size_t next_capacity = capacity * 2;
char *next = realloc(value, next_capacity);
if (next == NULL) {
free(value);
return NULL;
}
value = next;
capacity = next_capacity;
}
size_t available = capacity - length;
size_t read_count = fread(value + length, 1, available, stdin);
length += read_count;
if (read_count < available) {
if (ferror(stdin)) {
free(value);
return NULL;
}
break;
}
}
if (length == capacity) {
if (capacity == SIZE_MAX) {
free(value);
return NULL;
}
char *next = realloc(value, capacity + 1);
if (next == NULL) {
free(value);
return NULL;
}
value = next;
}
value[length] = '\0';
return value;
}
void __glagol_process_init(int32_t argc, char **argv) {
__glagol_process_argc_value = argc;
__glagol_process_argv_value = argv;
}
int32_t __glagol_process_argc(void) {
return __glagol_process_argc_value;
}
static void __glagol_process_arg_trap(void) {
fputs("slovo runtime error: process argument index out of bounds\n", stderr);
exit(1);
}
char *__glagol_process_arg(int32_t index) {
if (index < 0 || index >= __glagol_process_argc_value || __glagol_process_argv_value == NULL) {
__glagol_process_arg_trap();
}
return __glagol_process_argv_value[index];
}
char *__glagol_process_arg_result(int32_t index) {
if (index < 0 || index >= __glagol_process_argc_value || __glagol_process_argv_value == NULL) {
return NULL;
}
return __glagol_process_argv_value[index];
}
char *__glagol_env_get(const char *name) {
char *value = getenv(name);
return value == NULL ? "" : value;
}
char *__glagol_env_get_result(const char *name) {
return getenv(name);
}
static void __glagol_fs_read_trap(void) {
fputs("slovo runtime error: file read failed\n", stderr);
exit(1);
}
char *__glagol_fs_read_text(const char *path) {
FILE *file = fopen(path, "rb");
if (file == NULL) {
__glagol_fs_read_trap();
}
if (fseek(file, 0, SEEK_END) != 0) {
fclose(file);
__glagol_fs_read_trap();
}
long length = ftell(file);
if (length < 0) {
fclose(file);
__glagol_fs_read_trap();
}
if (fseek(file, 0, SEEK_SET) != 0) {
fclose(file);
__glagol_fs_read_trap();
}
size_t size = (size_t)length;
char *value = malloc(size + 1);
if (value == NULL) {
fclose(file);
__glagol_fs_read_trap();
}
if (size > 0 && fread(value, 1, size, file) != size) {
free(value);
fclose(file);
__glagol_fs_read_trap();
}
if (fclose(file) != 0) {
free(value);
__glagol_fs_read_trap();
}
value[size] = '\0';
return value;
}
char *__glagol_fs_read_text_result(const char *path) {
FILE *file = fopen(path, "rb");
if (file == NULL) {
return NULL;
}
if (fseek(file, 0, SEEK_END) != 0) {
fclose(file);
return NULL;
}
long length = ftell(file);
if (length < 0) {
fclose(file);
return NULL;
}
if (fseek(file, 0, SEEK_SET) != 0) {
fclose(file);
return NULL;
}
size_t size = (size_t)length;
char *value = malloc(size + 1);
if (value == NULL) {
fclose(file);
return NULL;
}
if (size > 0 && fread(value, 1, size, file) != size) {
free(value);
fclose(file);
return NULL;
}
if (fclose(file) != 0) {
free(value);
return NULL;
}
value[size] = '\0';
return value;
}
int32_t __glagol_fs_write_text(const char *path, const char *text) {
FILE *file = fopen(path, "wb");
if (file == NULL) {
return 1;
}
size_t len = strlen(text);
if (len > 0 && fwrite(text, 1, len, file) != len) {
fclose(file);
return 1;
}
if (fclose(file) != 0) {
return 1;
}
return 0;
}
int32_t __glagol_fs_write_text_result(const char *path, const char *text) {
return __glagol_fs_write_text(path, text);
}
static void __glagol_allocation_trap(void) {
fputs("slovo runtime error: string allocation failed\n", stderr);
exit(1);
}
char *__glagol_string_concat(const char *left, const char *right) {
size_t left_len = strlen(left);
size_t right_len = strlen(right);
if (left_len > SIZE_MAX - right_len - 1) {
__glagol_allocation_trap();
}
char *value = malloc(left_len + right_len + 1);
if (value == NULL) {
__glagol_allocation_trap();
}
memcpy(value, left, left_len);
memcpy(value + left_len, right, right_len + 1);
return value;
}
static char *__glagol_num_u64_to_string_impl(uint64_t magnitude, bool negative) {
char reversed[20];
size_t digit_count = 0;
do {
reversed[digit_count] = (char)(0x30u + (magnitude % 10u));
digit_count++;
magnitude /= 10u;
} while (magnitude != 0u);
size_t sign_count = negative ? 1u : 0u;
char *value = malloc(sign_count + digit_count + 1u);
if (value == NULL) {
__glagol_allocation_trap();
}
size_t cursor = 0;
if (negative) {
value[cursor] = (char)0x2du;
cursor++;
}
for (size_t i = 0; i < digit_count; i++) {
value[cursor + i] = reversed[digit_count - i - 1u];
}
value[cursor + digit_count] = '\0';
return value;
}
static char *__glagol_num_i64_to_string_impl(int64_t value) {
bool negative = value < 0;
uint64_t magnitude = negative
? (uint64_t)(-(value + 1)) + 1u
: (uint64_t)value;
return __glagol_num_u64_to_string_impl(magnitude, negative);
}
char *__glagol_num_i32_to_string(int32_t value) {
return __glagol_num_i64_to_string_impl((int64_t)value);
}
char *__glagol_num_u32_to_string(uint32_t value) {
return __glagol_num_u64_to_string_impl((uint64_t)value, false);
}
char *__glagol_num_i64_to_string(int64_t value) {
return __glagol_num_i64_to_string_impl(value);
}
char *__glagol_num_u64_to_string(uint64_t value) {
return __glagol_num_u64_to_string_impl(value, false);
}
char *__glagol_num_f64_to_string(double value) {
int length = snprintf(NULL, 0, "%.17f", value);
if (length < 0) {
__glagol_allocation_trap();
}
char *text = malloc((size_t)length + 1u);
if (text == NULL) {
__glagol_allocation_trap();
}
int written = snprintf(text, (size_t)length + 1u, "%.17f", value);
if (written != length) {
free(text);
__glagol_allocation_trap();
}
char *dot = strchr(text, '.');
if (dot != NULL) {
char *last = text + strlen(text) - 1u;
while (last > dot + 1 && *last == '0') {
*last = '\0';
last--;
}
}
return text;
}
bool __glagol_string_eq(const char *left, const char *right) {
return strcmp(left, right) == 0;
}
static int64_t __glagol_string_parse_i32_result_encode(uint32_t status, int32_t payload) {
uint64_t encoded = ((uint64_t)status << 32) | (uint32_t)payload;
return (int64_t)encoded;
}
static int64_t __glagol_string_parse_i32_result_err(void) {
return __glagol_string_parse_i32_result_encode(1, 1);
}
int64_t __glagol_string_parse_i32_result(const char *text) {
if (text == NULL || text[0] == '\0') {
return __glagol_string_parse_i32_result_err();
}
const unsigned char *cursor = (const unsigned char *)text;
bool negative = false;
if (*cursor == '-') {
negative = true;
cursor++;
if (*cursor == '\0') {
return __glagol_string_parse_i32_result_err();
}
}
int64_t limit = negative ? 2147483648LL : 2147483647LL;
int64_t value = 0;
while (*cursor != '\0') {
unsigned char byte = *cursor;
if (byte < '0' || byte > '9') {
return __glagol_string_parse_i32_result_err();
}
int64_t digit = (int64_t)(byte - '0');
if (value > (limit - digit) / 10) {
return __glagol_string_parse_i32_result_err();
}
value = value * 10 + digit;
cursor++;
}
int32_t parsed;
if (negative) {
parsed = value == 2147483648LL ? INT32_MIN : (int32_t)-value;
} else {
parsed = (int32_t)value;
}
return __glagol_string_parse_i32_result_encode(0, parsed);
}
static int64_t __glagol_string_parse_u32_result_err(void) {
return __glagol_string_parse_i32_result_encode(1, 1);
}
int64_t __glagol_string_parse_u32_result(const char *text) {
if (text == NULL || text[0] == '\0') {
return __glagol_string_parse_u32_result_err();
}
const unsigned char *cursor = (const unsigned char *)text;
uint64_t value = 0;
while (*cursor != '\0') {
unsigned char byte = *cursor;
if (byte < '0' || byte > '9') {
return __glagol_string_parse_u32_result_err();
}
uint64_t digit = (uint64_t)(byte - '0');
if (value > (((uint64_t)UINT32_MAX) - digit) / 10u) {
return __glagol_string_parse_u32_result_err();
}
value = value * 10u + digit;
cursor++;
}
return __glagol_string_parse_i32_result_encode(0, (int32_t)(uint32_t)value);
}
int32_t __glagol_string_parse_i64_result(const char *text, int64_t *out) {
if (out == NULL || text == NULL || text[0] == '\0') {
return 1;
}
const unsigned char *cursor = (const unsigned char *)text;
bool negative = false;
if (*cursor == '-') {
negative = true;
cursor++;
if (*cursor == '\0') {
return 1;
}
}
uint64_t limit = negative ? ((uint64_t)INT64_MAX + 1u) : (uint64_t)INT64_MAX;
uint64_t value = 0;
while (*cursor != '\0') {
unsigned char byte = *cursor;
if (byte < '0' || byte > '9') {
return 1;
}
uint64_t digit = (uint64_t)(byte - '0');
if (value > (limit - digit) / 10u) {
return 1;
}
value = value * 10u + digit;
cursor++;
}
if (negative) {
*out = value == ((uint64_t)INT64_MAX + 1u) ? INT64_MIN : -(int64_t)value;
} else {
*out = (int64_t)value;
}
return 0;
}
int32_t __glagol_string_parse_u64_result(const char *text, uint64_t *out) {
if (out == NULL || text == NULL || text[0] == '\0') {
return 1;
}
const unsigned char *cursor = (const unsigned char *)text;
uint64_t value = 0;
while (*cursor != '\0') {
unsigned char byte = *cursor;
if (byte < '0' || byte > '9') {
return 1;
}
uint64_t digit = (uint64_t)(byte - '0');
if (value > (UINT64_MAX - digit) / 10u) {
return 1;
}
value = value * 10u + digit;
cursor++;
}
*out = value;
return 0;
}
static size_t __glagol_consume_ascii_digits(const unsigned char *text, size_t index) {
while (text[index] >= '0' && text[index] <= '9') {
index++;
}
return index;
}
static bool __glagol_string_is_ascii_decimal_f64(const char *text) {
if (text == NULL || text[0] == '\0') {
return false;
}
const unsigned char *bytes = (const unsigned char *)text;
size_t index = 0;
if (bytes[index] == '-') {
index++;
if (bytes[index] == '\0') {
return false;
}
}
size_t whole_start = index;
index = __glagol_consume_ascii_digits(bytes, index);
size_t whole_digits = index - whole_start;
if (whole_digits == 0 || bytes[index] != '.') {
return false;
}
index++;
size_t fractional_start = index;
index = __glagol_consume_ascii_digits(bytes, index);
size_t fractional_digits = index - fractional_start;
if (fractional_digits == 0) {
return false;
}
return bytes[index] == '\0';
}
int32_t __glagol_string_parse_f64_result(const char *text, double *out) {
if (out == NULL || !__glagol_string_is_ascii_decimal_f64(text)) {
return 1;
}
errno = 0;
char *end = NULL;
double value = strtod(text, &end);
if (errno == ERANGE || end == text || end == NULL || *end != '\0' || !isfinite(value)) {
return 1;
}
*out = value;
return 0;
}
int32_t __glagol_string_parse_bool_result(const char *text, bool *out) {
if (out == NULL || text == NULL) {
return 1;
}
if (strcmp(text, "true") == 0) {
*out = true;
return 0;
}
if (strcmp(text, "false") == 0) {
*out = false;
return 0;
}
return 1;
}
static void __glagol_vec_i32_allocation_trap(void) {
fputs("slovo runtime error: vector allocation failed\n", stderr);
exit(1);
}
static void __glagol_vec_i32_index_trap(void) {
fputs("slovo runtime error: vector index out of bounds\n", stderr);
exit(1);
}
__glagol_vec_i32 *__glagol_vec_i32_empty(void) {
__glagol_vec_i32 *value = malloc(sizeof(__glagol_vec_i32));
if (value == NULL) {
__glagol_vec_i32_allocation_trap();
}
value->len = 0;
value->data = NULL;
return value;
}
__glagol_vec_i32 *__glagol_vec_i32_append(const __glagol_vec_i32 *source, int32_t element) {
if (source->len < 0 || source->len == INT32_MAX) {
__glagol_vec_i32_allocation_trap();
}
size_t old_len = (size_t)source->len;
size_t new_len = old_len + 1;
if (new_len > SIZE_MAX / sizeof(int32_t)) {
__glagol_vec_i32_allocation_trap();
}
__glagol_vec_i32 *value = malloc(sizeof(__glagol_vec_i32));
if (value == NULL) {
__glagol_vec_i32_allocation_trap();
}
int32_t *data = malloc(new_len * sizeof(int32_t));
if (data == NULL) {
free(value);
__glagol_vec_i32_allocation_trap();
}
if (old_len > 0) {
memcpy(data, source->data, old_len * sizeof(int32_t));
}
data[old_len] = element;
value->len = (int32_t)new_len;
value->data = data;
return value;
}
int32_t __glagol_vec_i32_len(const __glagol_vec_i32 *value) {
return value->len;
}
int32_t __glagol_vec_i32_index(const __glagol_vec_i32 *value, int32_t index) {
if (index < 0 || index >= value->len) {
__glagol_vec_i32_index_trap();
}
return value->data[index];
}
bool __glagol_vec_i32_eq(const __glagol_vec_i32 *left, const __glagol_vec_i32 *right) {
if (left->len != right->len) {
return false;
}
if (left->len == 0) {
return true;
}
return memcmp(left->data, right->data, (size_t)left->len * sizeof(int32_t)) == 0;
}
static void __glagol_vec_i64_allocation_trap(void) {
fputs("slovo runtime error: vector allocation failed\n", stderr);
exit(1);
}
static void __glagol_vec_i64_index_trap(void) {
fputs("slovo runtime error: vector index out of bounds\n", stderr);
exit(1);
}
__glagol_vec_i64 *__glagol_vec_i64_empty(void) {
__glagol_vec_i64 *value = malloc(sizeof(__glagol_vec_i64));
if (value == NULL) {
__glagol_vec_i64_allocation_trap();
}
value->len = 0;
value->data = NULL;
return value;
}
__glagol_vec_i64 *__glagol_vec_i64_append(const __glagol_vec_i64 *source, int64_t element) {
if (source->len < 0 || source->len == INT32_MAX) {
__glagol_vec_i64_allocation_trap();
}
size_t old_len = (size_t)source->len;
size_t new_len = old_len + 1;
if (new_len > SIZE_MAX / sizeof(int64_t)) {
__glagol_vec_i64_allocation_trap();
}
__glagol_vec_i64 *value = malloc(sizeof(__glagol_vec_i64));
if (value == NULL) {
__glagol_vec_i64_allocation_trap();
}
int64_t *data = malloc(new_len * sizeof(int64_t));
if (data == NULL) {
free(value);
__glagol_vec_i64_allocation_trap();
}
if (old_len > 0) {
memcpy(data, source->data, old_len * sizeof(int64_t));
}
data[old_len] = element;
value->len = (int32_t)new_len;
value->data = data;
return value;
}
int32_t __glagol_vec_i64_len(const __glagol_vec_i64 *value) {
return value->len;
}
int64_t __glagol_vec_i64_index(const __glagol_vec_i64 *value, int32_t index) {
if (index < 0 || index >= value->len) {
__glagol_vec_i64_index_trap();
}
return value->data[index];
}
bool __glagol_vec_i64_eq(const __glagol_vec_i64 *left, const __glagol_vec_i64 *right) {
if (left->len != right->len) {
return false;
}
if (left->len == 0) {
return true;
}
return memcmp(left->data, right->data, (size_t)left->len * sizeof(int64_t)) == 0;
}
static void __glagol_vec_f64_allocation_trap(void) {
fputs("slovo runtime error: vector allocation failed\n", stderr);
exit(1);
}
static void __glagol_vec_f64_index_trap(void) {
fputs("slovo runtime error: vector index out of bounds\n", stderr);
exit(1);
}
__glagol_vec_f64 *__glagol_vec_f64_empty(void) {
__glagol_vec_f64 *value = malloc(sizeof(__glagol_vec_f64));
if (value == NULL) {
__glagol_vec_f64_allocation_trap();
}
value->len = 0;
value->data = NULL;
return value;
}
__glagol_vec_f64 *__glagol_vec_f64_append(const __glagol_vec_f64 *source, double element) {
if (source->len < 0 || source->len == INT32_MAX) {
__glagol_vec_f64_allocation_trap();
}
size_t old_len = (size_t)source->len;
size_t new_len = old_len + 1;
if (new_len > SIZE_MAX / sizeof(double)) {
__glagol_vec_f64_allocation_trap();
}
__glagol_vec_f64 *value = malloc(sizeof(__glagol_vec_f64));
if (value == NULL) {
__glagol_vec_f64_allocation_trap();
}
double *data = malloc(new_len * sizeof(double));
if (data == NULL) {
free(value);
__glagol_vec_f64_allocation_trap();
}
if (old_len > 0) {
memcpy(data, source->data, old_len * sizeof(double));
}
data[old_len] = element;
value->len = (int32_t)new_len;
value->data = data;
return value;
}
int32_t __glagol_vec_f64_len(const __glagol_vec_f64 *value) {
return value->len;
}
double __glagol_vec_f64_index(const __glagol_vec_f64 *value, int32_t index) {
if (index < 0 || index >= value->len) {
__glagol_vec_f64_index_trap();
}
return value->data[index];
}
bool __glagol_vec_f64_eq(const __glagol_vec_f64 *left, const __glagol_vec_f64 *right) {
if (left->len != right->len) {
return false;
}
for (int32_t index = 0; index < left->len; index++) {
if (left->data[index] != right->data[index]) {
return false;
}
}
return true;
}
static void __glagol_vec_bool_allocation_trap(void) {
fputs("slovo runtime error: vector allocation failed\n", stderr);
exit(1);
}
static void __glagol_vec_bool_index_trap(void) {
fputs("slovo runtime error: vector index out of bounds\n", stderr);
exit(1);
}
__glagol_vec_bool *__glagol_vec_bool_empty(void) {
__glagol_vec_bool *value = malloc(sizeof(__glagol_vec_bool));
if (value == NULL) {
__glagol_vec_bool_allocation_trap();
}
value->len = 0;
value->data = NULL;
return value;
}
__glagol_vec_bool *__glagol_vec_bool_append(const __glagol_vec_bool *source, bool element) {
if (source->len < 0 || source->len == INT32_MAX) {
__glagol_vec_bool_allocation_trap();
}
size_t old_len = (size_t)source->len;
size_t new_len = old_len + 1;
if (new_len > SIZE_MAX / sizeof(bool)) {
__glagol_vec_bool_allocation_trap();
}
__glagol_vec_bool *value = malloc(sizeof(__glagol_vec_bool));
if (value == NULL) {
__glagol_vec_bool_allocation_trap();
}
bool *data = malloc(new_len * sizeof(bool));
if (data == NULL) {
free(value);
__glagol_vec_bool_allocation_trap();
}
if (old_len > 0) {
memcpy(data, source->data, old_len * sizeof(bool));
}
data[old_len] = element;
value->len = (int32_t)new_len;
value->data = data;
return value;
}
int32_t __glagol_vec_bool_len(const __glagol_vec_bool *value) {
return value->len;
}
bool __glagol_vec_bool_index(const __glagol_vec_bool *value, int32_t index) {
if (index < 0 || index >= value->len) {
__glagol_vec_bool_index_trap();
}
return value->data[index];
}
bool __glagol_vec_bool_eq(const __glagol_vec_bool *left, const __glagol_vec_bool *right) {
if (left->len != right->len) {
return false;
}
if (left->len == 0) {
return true;
}
return memcmp(left->data, right->data, (size_t)left->len * sizeof(bool)) == 0;
}
static void __glagol_vec_string_allocation_trap(void) {
fputs("slovo runtime error: vector allocation failed\n", stderr);
exit(1);
}
static void __glagol_vec_string_index_trap(void) {
fputs("slovo runtime error: vector index out of bounds\n", stderr);
exit(1);
}
__glagol_vec_string *__glagol_vec_string_empty(void) {
__glagol_vec_string *value = malloc(sizeof(__glagol_vec_string));
if (value == NULL) {
__glagol_vec_string_allocation_trap();
}
value->len = 0;
value->data = NULL;
return value;
}
__glagol_vec_string *__glagol_vec_string_append(
const __glagol_vec_string *source,
const char *element
) {
if (source->len < 0 || source->len == INT32_MAX) {
__glagol_vec_string_allocation_trap();
}
size_t old_len = (size_t)source->len;
size_t new_len = old_len + 1;
if (new_len > SIZE_MAX / sizeof(char *)) {
__glagol_vec_string_allocation_trap();
}
__glagol_vec_string *value = malloc(sizeof(__glagol_vec_string));
if (value == NULL) {
__glagol_vec_string_allocation_trap();
}
char **data = malloc(new_len * sizeof(char *));
if (data == NULL) {
free(value);
__glagol_vec_string_allocation_trap();
}
if (old_len > 0) {
memcpy(data, source->data, old_len * sizeof(char *));
}
data[old_len] = (char *)element;
value->len = (int32_t)new_len;
value->data = data;
return value;
}
int32_t __glagol_vec_string_len(const __glagol_vec_string *value) {
return value->len;
}
char *__glagol_vec_string_index(const __glagol_vec_string *value, int32_t index) {
if (index < 0 || index >= value->len) {
__glagol_vec_string_index_trap();
}
return value->data[index];
}
bool __glagol_vec_string_eq(const __glagol_vec_string *left, const __glagol_vec_string *right) {
if (left->len != right->len) {
return false;
}
for (int32_t index = 0; index < left->len; index++) {
if (strcmp(left->data[index], right->data[index]) != 0) {
return false;
}
}
return true;
}
static void __glagol_time_monotonic_unavailable_trap(void) {
fputs("slovo runtime error: monotonic time unavailable\n", stderr);
exit(1);
}
static void __glagol_time_sleep_negative_trap(void) {
fputs("slovo runtime error: sleep_ms negative duration\n", stderr);
exit(1);
}
static void __glagol_time_sleep_failed_trap(void) {
fputs("slovo runtime error: sleep failed\n", stderr);
exit(1);
}
int32_t __glagol_time_monotonic_ms(void) {
struct timespec now;
if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) {
__glagol_time_monotonic_unavailable_trap();
}
if (!__glagol_time_base_initialized) {
__glagol_time_base = now;
__glagol_time_base_initialized = true;
return 0;
}
time_t seconds = now.tv_sec - __glagol_time_base.tv_sec;
long nanoseconds = now.tv_nsec - __glagol_time_base.tv_nsec;
if (nanoseconds < 0) {
seconds -= 1;
nanoseconds += 1000000000L;
}
if (seconds < 0) {
return 0;
}
if (seconds > INT32_MAX / 1000) {
return INT32_MAX;
}
int64_t milliseconds = (int64_t)seconds * 1000 + nanoseconds / 1000000L;
if (milliseconds > INT32_MAX) {
return INT32_MAX;
}
return (int32_t)milliseconds;
}
void __glagol_time_sleep_ms(int32_t ms) {
if (ms < 0) {
__glagol_time_sleep_negative_trap();
}
struct timespec remaining;
remaining.tv_sec = ms / 1000;
remaining.tv_nsec = (long)(ms % 1000) * 1000000L;
while (nanosleep(&remaining, &remaining) != 0) {
if (errno != EINTR) {
__glagol_time_sleep_failed_trap();
}
}
}
static void __glagol_random_i32_unavailable_trap(void) {
fputs("slovo runtime error: random i32 unavailable\n", stderr);
exit(1);
}
int32_t __glagol_random_i32(void) {
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) {
__glagol_random_i32_unavailable_trap();
}
uint32_t value = 0;
unsigned char *cursor = (unsigned char *)&value;
size_t remaining = sizeof(value);
while (remaining > 0) {
ssize_t n = read(fd, cursor, remaining);
if (n < 0) {
if (errno == EINTR) {
continue;
}
close(fd);
__glagol_random_i32_unavailable_trap();
}
if (n == 0) {
close(fd);
__glagol_random_i32_unavailable_trap();
}
cursor += n;
remaining -= (size_t)n;
}
if (close(fd) != 0) {
__glagol_random_i32_unavailable_trap();
}
return (int32_t)(value & INT32_MAX);
}
void __glagol_array_bounds_trap(void) {
fputs("slovo runtime error: array index out of bounds\n", stderr);
exit(1);
}
void __glagol_unwrap_some_trap(void) {
fputs("slovo runtime error: unwrap_some on none\n", stderr);
exit(1);
}
void __glagol_unwrap_ok_trap(void) {
fputs("slovo runtime error: unwrap_ok on err\n", stderr);
exit(1);
}
void __glagol_unwrap_err_trap(void) {
fputs("slovo runtime error: unwrap_err on ok\n", stderr);
exit(1);
}