/* * a small library of types, functions and macros that * are used throughout the bootstrap compiler. * allocation done purely statically. */ #include #include #include #include #include #define uint8 uint8_t #define uint16 uint16_t #define uint32 uint32_t #define uint64 uint64_t #define int8 int8_t #define int16 int16_t #define int32 int32_t #define int64 int64_t #define float32 float #define float64 double #define real float64 #define uint uint64 #define integer int64 #define flags int32 #define ascii char #define byte char #define bool _Bool #define true 1 #define false 0 #define nil NULL #define unknown void // call on irrecoverable failure. // prints a very sad, apologetic message for // the user and aborts program with failure status. void failure(const ascii* message) { const ascii* format = "\\e[0;31m" ";( sorry, a failure has occurred...\n" "-> %s!\n" "\\e[0m"; fprintf(stderr, format, message); exit(EXIT_FAILURE); } // check a condition, triggering a failure if it's false. void check(bool condition, const ascii* message) { if (!condition) failure(message); } // the common size of region memory blocks. #define REGION_SIZE 65536 // statically allocates a region of memory of a given size // for a single type. #define REGION_OF_SIZE(type, of, size) \ type region_##of[size]; \ uint region_##of##_cursor = 0; // statically allocates a region of memory for a type. #define REGION(type, of) REGION_OF_SIZE(type, of, REGION_SIZE) // the global string region. REGION(ascii, string) // a string. struct String { ascii* data; uint length; }; #define STRING_ITERATE(index, c, str) \ ascii c = string_at(str, 0); \ for (uint index = 0; index < str.length; c = string_at(str, ++index)) // allocates a new string in the global string region. struct String string_new(const ascii* data, uint length) { // for compatibility, we include an additional null byte at the end. uint allocation_length = length + 1; check(region_string_cursor + allocation_length < REGION_SIZE, "out of string memory"); ascii* at = region_string + region_string_cursor; region_string_cursor += allocation_length; for (uint i = 0; i < length; ++i) at[i] = data[i]; at[length] = '\0'; return { .data = at, .length = length, }; } // allocates a new string in the global string region, // taking the data from a null-terminated C string. struct String string_from_c_string(const char* c_string) { uint length = strlen(c_string); return string_new(c_string, length); } // allocates a new string in the global string region, // taking the data from a static null-terminated C string. // // NOTE: The string is not copied, so it MUST have a lifetime // spanning the entire program. struct String string_from_static_c_string(const char* c_string) { uint length = strlen(c_string); return { .data = (ascii*)c_string, .length = length, }; } // returns the character at a given index. // does bounds-checking. ascii string_at(struct String s, uint index) { check(index < s.length, "index out of bounds"); return s.data[index]; } uint string_length(struct String s) { return s.length; }