aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2025-08-05 22:49:40 +0200
committerMel <mel@rnrd.eu>2025-08-05 22:49:40 +0200
commitc2c84f4d15d964fb663f390046b1d17441145c61 (patch)
treea1724e49fefe143fd82404ffb1a0891ad6bc9755
parent1d277d507498d8f3649684e7ff0ad2c3a19792a4 (diff)
downloadcatskill-c2c84f4d15d964fb663f390046b1d17441145c61.tar.zst
catskill-c2c84f4d15d964fb663f390046b1d17441145c61.zip
Add core library for catskill transpiled source, output defined types in transpiler
Signed-off-by: Mel <mel@rnrd.eu>
-rw-r--r--boot/common.c19
-rw-r--r--boot/runtime/core.c742
-rw-r--r--boot/transpile.c19
3 files changed, 773 insertions, 7 deletions
diff --git a/boot/common.c b/boot/common.c
index 6a95bb6..4f9c2ad 100644
--- a/boot/common.c
+++ b/boot/common.c
@@ -8,6 +8,9 @@
* SPDX-License-Identifier: MPL-2.0
*/
+// TODO: merge our common library with `boot/runtime/core.c`
+// to avoid implementing a semi-standard library twice!
+
#pragma once
#include <math.h>
@@ -239,6 +242,22 @@ string_length(struct String s)
return s.length;
}
+bool
+string_equals(const struct String a, const struct String b)
+{
+ if (string_length(a) != string_length(b)) return false;
+ if (string_length(a) == 0) return true;
+ return memcmp(a.data, b.data, a.length) == 0;
+}
+
+bool
+string_equals_c_str(const struct String a, const ascii* b)
+{
+ uint b_length = strlen(b);
+ if (string_length(a) != b_length) return false;
+ if (string_length(a) == 0) return true;
+ return memcmp(a.data, b, a.length) == 0;
+}
void
string_print(struct String s)
{
diff --git a/boot/runtime/core.c b/boot/runtime/core.c
new file mode 100644
index 0000000..a409604
--- /dev/null
+++ b/boot/runtime/core.c
@@ -0,0 +1,742 @@
+/*
+ * the core catskill c-library for
+ * catskill source files transpiled to c.
+ * used during bootstrapping, while the full
+ * catskill standard library is not yet available.
+ *
+ * copyright (c) 2025, mel g. <mel@rnrd.eu>
+ *
+ * spdx-license-identifier: mpl-2.0
+ */
+
+// TODO: as mentioned in `boot/common.c`, the catskill transpiled
+// source code "core" library should be merged with the catboot
+// "common" library.
+
+#pragma once
+
+// common headers for both your average catskill program.
+// other libc headers can be included with the pragma
+// `| c-header "header.h"`.
+#include <fcntl.h>
+#include <features.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+// types predefined for catskill programs.
+// the transpiler outputs these types directly when seen
+// in the source code.
+#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 ascii char
+#define byte char
+
+#define bool _Bool
+#define true 1
+#define false 0
+#define nil NULL
+
+_Noreturn void
+panic(const ascii* message, ...)
+{
+ fprintf(stderr, "panic: ");
+
+ va_list args;
+ va_start(args, message);
+ vfprintf(stderr, message, args);
+ va_end(args);
+
+ fprintf(stderr, "\n");
+ exit(EXIT_FAILURE);
+}
+
+void*
+allocate(size_t size)
+{
+ void* ptr = malloc(size);
+ if (!ptr) panic("failed to allocate %zu bytes. are we out of memory? :(", size);
+ return ptr;
+}
+
+void*
+reallocate(void* ptr, size_t size)
+{
+ void* new_ptr = realloc(ptr, size);
+ if (!new_ptr) panic("failed to reallocate %zu bytes. are we out of memory? :(", size);
+ if (size == 0) return nil;
+ return new_ptr;
+}
+
+struct _Array
+{
+ uint element_size;
+ void* data;
+ uint length;
+ uint capacity;
+};
+
+// a dynamic array type.
+#define Array(type) struct _Array
+
+#define ARRAY_DEFAULT_CAPACITY 16
+
+void array_grow(struct _Array* array);
+void array_grow_until(struct _Array* array, uint min_capacity);
+
+// internal use, try the `array_new` macro.
+struct _Array
+_array_new(uint element_size)
+{
+ struct _Array array = {
+ .element_size = element_size,
+ .data = nil,
+ .length = 0,
+ .capacity = 0,
+ };
+ array_grow(&array);
+ return array;
+}
+
+// creates a new, empty array for the given type.
+#define array_new(type) _array_new(sizeof(type))
+
+// returns the number of elements in the array.
+uint
+array_length(const struct _Array* array)
+{
+ return array->length;
+}
+
+// returns the total number of elements the array can hold before reallocating.
+uint
+array_capacity(const struct _Array* array)
+{
+ return array->capacity;
+}
+
+// true if the array is empty.
+bool
+array_is_empty(const struct _Array* array)
+{
+ return array->length == 0;
+}
+
+// resizes the array backing allocation to the new capacity.
+// if the new capacity is smaller than the current length,
+// the array will be truncated to the new length.
+// if the new capacity is 0, the array's data will be freed.
+void
+array_resize_allocation(struct _Array* array, uint new_capacity)
+{
+ // reallocate can handle data being nil, so we don't need to check for that.
+ array->data = reallocate(array->data, new_capacity * array->element_size);
+ array->capacity = new_capacity;
+ array->length = array->length < new_capacity ? array->length : new_capacity;
+}
+
+// resizes the array to a new length.
+// if the new length is larger than the current capacity,
+// the array will be grown to fit, and the new elements will be zero-initialized.
+// if the new length is smaller than the current length,
+// the array will be truncated, and the discarded elements are zeroed out.
+// this function does not shrink the underlying allocation.
+void
+array_resize(struct _Array* array, uint new_length)
+{
+ if (new_length > array->capacity) {
+ // grow array to fit the new length naturally.
+ array_grow_until(array, new_length);
+ // initialize the new elements to zero.
+ memset((uint8*)array->data + (array->length * array->element_size), 0,
+ (new_length - array->length) * array->element_size);
+ } else if (new_length < array->length) {
+ // truncate the array elements to the new length.
+ memset((uint8*)array->data + (new_length * array->element_size), 0,
+ (array->length - new_length) * array->element_size);
+ }
+ array->length = new_length;
+}
+
+// frees the memory used by the array's data.
+void
+array_free(struct _Array* array)
+{
+ array_resize_allocation(array, 0);
+}
+
+// grows the array's capacity naturally.
+void
+array_grow(struct _Array* array)
+{
+ if (array->capacity == 0)
+ array_resize_allocation(array, ARRAY_DEFAULT_CAPACITY);
+ else
+ array_resize_allocation(array, array->capacity * 2);
+}
+
+// grows the array's capacity naturally to hold at least `min_capacity` elements.
+// if current capacity is already enough, nothing happens.
+void
+array_grow_until(struct _Array* array, uint min_capacity)
+{
+ while (array->capacity < min_capacity) array_grow(array);
+}
+
+// internal use, try the `array_get` macro.
+void
+_array_get(const struct _Array* array, uint index, void* out_element)
+{
+ if (index >= array->length) panic("index out of bounds: %u (length: %u)", index, array->length);
+ memcpy(out_element, (uint8*)array->data + (index * array->element_size), array->element_size);
+}
+
+// gets the element at a given index and copies it to `out_element`.
+// panic if the index is out of bounds.
+#define array_get(array, index, out_element) _array_get(array, index, (void*)(out_element))
+
+// internal use, prefer the `array_set` macro.
+void
+_array_set(struct _Array* array, uint index, const void* element)
+{
+ if (index >= array->length) {
+ panic("index out of bounds: %u (length: %u)", index, array->length);
+ }
+ memcpy((uint8*)array->data + (index * array->element_size), element, array->element_size);
+}
+
+// sets the element at a given index.
+// panic if the index is out of bounds.
+#define array_set(array, index, element) _array_set(array, index, (const void*)(element))
+
+// internal use, prefer the `array_at` macro.
+void*
+_array_at(const struct _Array* array, uint index)
+{
+ if (index >= array->length) {
+ panic("index out of bounds: %u (length: %u)", index, array->length);
+ }
+ return (uint8*)array->data + (index * array->element_size);
+}
+
+// returns a pointer to the element at a given index.
+// panics if the index is out of bounds.
+#define array_at(type, array, index) ((type*)_array_at(array, index))
+
+// internal use, prefer the `array_insert` macro.
+void
+_array_insert(struct _Array* array, uint index, const void* element)
+{
+ if (index > array->length) panic("index out of bounds: %u (length: %u)", index, array->length);
+ array_grow_until(array, array->length + 1);
+
+ // shift elements to the right to make space for the new element
+ // if we are inserting at the end, we don't need to shift anything.
+ // if there aren't any elements, we also don't need to shift anything.
+ if (index < array->length && array->length > 0)
+ memmove(
+ (uint8*)array->data + ((index + 1) * array->element_size),
+ (uint8*)array->data + (index * array->element_size),
+ (array->length - index) * array->element_size);
+ // insert the new element at the specified index
+ memcpy((uint8*)array->data + (index * array->element_size), element, array->element_size);
+
+ ++array->length;
+}
+
+// inserts an element at a given index, shifting subsequent elements.
+// panics if the index is out of bounds (greater than length).
+#define array_insert(array, index, element) _array_insert(array, index, (const void*)(element))
+
+// adds an element to the end of the array.
+// internal use; prefer the `array_push` macro.
+void
+_array_push(struct _Array* array, const void* element)
+{
+ array_insert(array, array->length, element);
+}
+
+// adds an element to the end of the array.
+#define array_push(array, element) _array_push(array, (const void*)(element))
+
+// removes an element at a given index, shifting subsequent elements.
+// if `removed_element` is not null, the removed element is copied to it.
+// panics if the index is out of bounds.
+// internal use; prefer the `array_remove` macro.
+void
+_array_remove(struct _Array* array, uint index, void* removed_element)
+{
+ if (index >= array->length) {
+ panic("index out of bounds: %u (length: %u)", index, array->length);
+ }
+
+ if (removed_element)
+ memcpy(removed_element, (uint8*)array->data + (index * array->element_size),
+ array->element_size);
+
+ // shift elements to the left to fill the gap
+ // if we are removing the last element, we don't need to shift anything.
+ // if there aren't any elements, there is also nothing to shift.
+ if (index < array->length - 1 && array->length > 1)
+ memmove(
+ (uint8*)array->data + (index * array->element_size),
+ (uint8*)array->data + ((index + 1) * array->element_size),
+ (array->length - index - 1) * array->element_size);
+
+ --array->length;
+}
+
+// removes an element at a given index, shifting subsequent elements.
+// if `removed_element` is not null, the removed element is copied to it.
+// panics if the index is out of bounds.
+#define array_remove(array, index, removed_element) \
+ _array_remove(array, index, (void*)(removed_element))
+
+// removes and optionally returns the last element of the array.
+// panics if the array is empty.
+// internal use; prefer the `array_pop` macro.
+void
+_array_pop(struct _Array* array, void* removed_element)
+{
+ if (array->length == 0) panic("cannot pop from an empty array");
+ array_remove(array, array->length - 1, removed_element);
+}
+
+// removes and optionally returns the last element of the array.
+// panics if the array is empty.
+#define array_pop(array, removed_element) _array_pop(array, (void*)(removed_element))
+
+// clears the array, setting its length to 0.
+// this does not free the allocated memory.
+void
+array_clear(struct _Array* array)
+{
+ memset(array->data, 0, array->element_size * array->length);
+ array->length = 0;
+}
+
+// appends all elements from array `b` to the end of array `a`.
+// panics if the element sizes of the arrays are different.
+void
+array_append(struct _Array* a, struct _Array* b)
+{
+ if (a->element_size != b->element_size)
+ panic("cannot append arrays of different type and element size: %u vs %u", a->element_size,
+ b->element_size);
+
+ // grow array `a` to fit the new elements, following the array's growth strategy.
+ array_grow_until(a, a->length + b->length);
+
+ memcpy((uint8*)a->data + (a->length * a->element_size), b->data, b->length * a->element_size);
+
+ a->length += b->length;
+}
+
+// a macro for iterating over each element in an array.
+#define FOR_EACH_ARRAY(type, array, action) \
+ for (uint i = 0; i < array_length(array); ++i) { \
+ type* element = array_at(type, array, i); \
+ action; \
+ }
+
+#define ARRAY_FREE_ELEMENTS(type, array, free_action) \
+ FOR_EACH_ARRAY(type, array, { free_action(element); })
+
+// a macro for iterating over a range of elements in an array.
+#define FOR_EACH_IN_RANGE(type, array, start, end, action) \
+ for (uint i = start; i < end && i < array_length(array); ++i) { \
+ type* element = array_at(type, array, i); \
+ action; \
+ }
+
+// a dynamic string type.
+// the string is always null-terminated to be compatible with c functions.
+// the length of the string does not include the null terminator.
+struct String
+{
+ Array(ascii) data;
+};
+
+void string_ensure_capacity(struct String* str, uint new_len);
+
+// creates a new, empty string.
+struct String
+string_new(void)
+{
+ struct String str;
+ str.data = array_new(ascii);
+ ((ascii*)str.data.data)[0] = '\0';
+ return str;
+}
+
+// creates a new string from a c-style string.
+struct String
+string_from(const ascii* c_str)
+{
+ struct String str = string_new();
+ uint len = strlen(c_str);
+ string_ensure_capacity(&str, len);
+ memcpy(str.data.data, c_str, len);
+ str.data.length = len;
+ ((ascii*)str.data.data)[len] = '\0';
+ return str;
+}
+
+// frees the memory used by the string.
+void
+string_free(struct String* str)
+{
+ array_free(&str->data);
+}
+
+// returns the length of the string.
+uint
+string_length(const struct String* str)
+{
+ return str->data.length;
+}
+
+// returns the current capacity of the string (excluding the null terminator).
+uint
+string_capacity(const struct String* str)
+{
+ return str->data.capacity > 0 ? str->data.capacity - 1 : 0;
+}
+
+Array(ascii) string_backing(const struct String* str)
+{
+ return str->data;
+}
+
+// checks if the string is empty.
+bool
+string_is_empty(const struct String* str)
+{
+ return str->data.length == 0;
+}
+
+// returns a null-terminated c-string representation.
+const ascii*
+string_c_str(const struct String* str)
+{
+ return (const ascii*)str->data.data;
+}
+
+// ensures the array has enough capacity for `new_len` characters plus a null terminator.
+void
+string_ensure_capacity(struct String* str, uint new_len)
+{
+ uint required_capacity = new_len + 1;
+ if (required_capacity > str->data.capacity) {
+ uint new_cap = str->data.capacity;
+ if (new_cap == 0) new_cap = ARRAY_DEFAULT_CAPACITY;
+ while (required_capacity > new_cap) new_cap *= 2;
+ array_resize_allocation(&str->data, new_cap);
+ }
+}
+
+// appends a character to the end of the string.
+void
+string_push(struct String* str, ascii c)
+{
+ uint new_len = str->data.length + 1;
+ string_ensure_capacity(str, new_len);
+ ((ascii*)str->data.data)[str->data.length] = c;
+ str->data.length = new_len;
+ ((ascii*)str->data.data)[new_len] = '\0';
+}
+
+// removes and returns the last character of the string.
+// panics if the string is empty.
+ascii
+string_pop(struct String* str)
+{
+ if (str->data.length == 0) { panic("cannot pop from an empty string"); }
+ str->data.length--;
+ ascii c = ((ascii*)str->data.data)[str->data.length];
+ ((ascii*)str->data.data)[str->data.length] = '\0';
+ return c;
+}
+
+// appends a string to the end of another string.
+void
+string_append(struct String* dest, const struct String* src)
+{
+ uint old_len = dest->data.length;
+ uint new_len = old_len + src->data.length;
+ string_ensure_capacity(dest, new_len);
+ memcpy((ascii*)dest->data.data + old_len, src->data.data, src->data.length);
+ dest->data.length = new_len;
+ ((ascii*)dest->data.data)[new_len] = '\0';
+}
+
+// appends a c-style string to the end of a string.
+void
+string_append_c_str(struct String* dest, const ascii* c_str)
+{
+ uint c_str_len = strlen(c_str);
+ uint old_len = dest->data.length;
+ uint new_len = old_len + c_str_len;
+ string_ensure_capacity(dest, new_len);
+ memcpy((ascii*)dest->data.data + old_len, c_str, c_str_len);
+ dest->data.length = new_len;
+ ((ascii*)dest->data.data)[new_len] = '\0';
+}
+
+// clears the string, making it empty.
+void
+string_clear(struct String* str)
+{
+ str->data.length = 0;
+ ((ascii*)str->data.data)[0] = '\0';
+}
+
+// creates a copy of a string.
+struct String
+string_clone(const struct String* str)
+{
+ struct String new_str = string_new();
+ string_ensure_capacity(&new_str, str->data.length);
+ memcpy(new_str.data.data, str->data.data, str->data.length + 1); // copy with null terminator
+ new_str.data.length = str->data.length;
+ return new_str;
+}
+
+// compares two strings for equality.
+bool
+string_equals(const struct String* a, const struct String* b)
+{
+ if (a->data.length != b->data.length) return false;
+ if (a->data.length == 0) return true;
+ return memcmp(a->data.data, b->data.data, a->data.length) == 0;
+}
+
+// compares a string with a c-style string for equality.
+bool
+string_equals_c_str(const struct String* a, const ascii* b)
+{
+ uint b_len = strlen(b);
+ if (a->data.length != b_len) return false;
+ if (a->data.length == 0) return true;
+ return memcmp(a->data.data, b, a->data.length) == 0;
+}
+
+// returns a new string that is a slice of the original.
+// the slice is from `start` (inclusive) to `end` (exclusive).
+// panics if the range is invalid.
+struct String
+string_slice(const struct String* str, uint start, uint end)
+{
+ if (start > end || end > str->data.length) {
+ panic("invalid slice range [%u, %u) for string of length %u", start, end, str->data.length);
+ }
+ uint slice_len = end - start;
+ struct String new_str = string_new();
+ string_ensure_capacity(&new_str, slice_len);
+ memcpy(new_str.data.data, (const ascii*)str->data.data + start, slice_len);
+ new_str.data.length = slice_len;
+ ((ascii*)new_str.data.data)[slice_len] = '\0';
+ return new_str;
+}
+
+// returns the character at the given index.
+// panics if the index is out of bounds.
+ascii
+string_get(const struct String* str, uint index)
+{
+ if (index >= str->data.length) {
+ panic("index out of bounds: %u (length: %u)", index, str->data.length);
+ }
+ return ((ascii*)str->data.data)[index];
+}
+
+// sets the character at the given index.
+// panics if the index is out of bounds.
+void
+string_set(struct String* str, uint index, ascii c)
+{
+ if (index >= str->data.length) {
+ panic("index out of bounds: %u (length: %u)", index, str->data.length);
+ }
+ ((ascii*)str->data.data)[index] = c;
+}
+
+#define FOR_EACH_IN_STRING(character_variable, str, action) \
+ for (uint i = 0; i < string_length(str); ++i) { \
+ ascii character_variable = ((ascii*)((str)->data.data))[i]; \
+ action; \
+ }
+
+// a slice is a view into a block of memory.
+// it does not own the data it points to.
+struct _Slice
+{
+ uint element_size;
+ void* data;
+ uint length;
+};
+
+#define Slice(type) struct _Slice
+
+// internal use, try the `slice_new` macro.
+struct _Slice
+slice_new(void* data, uint length, uint element_size)
+{
+ struct _Slice slice = { .data = data, .length = length, .element_size = element_size };
+ return slice;
+}
+
+#define slice_new(data, length) slice_new((void*)(data), (length), sizeof(*(data)))
+
+// a string_view is a slice of characters.
+// it is not null-terminated.
+struct String_View
+{
+ Slice(ascii) data;
+};
+
+uint
+string_view_length(const struct String_View view)
+{
+ return view.data.length;
+}
+
+Slice(ascii) string_view_backing(const struct String_View view)
+{
+ return view.data;
+}
+
+// creates a new string_view from a string.
+struct String_View
+string_view_from_string(const struct String* str)
+{
+ return (struct String_View){ .data = slice_new(str->data.data, str->data.length) };
+}
+
+// creates a new string_view from a c-style string.
+struct String_View
+string_view_from_c_str(const ascii* c_str)
+{
+ return (struct String_View){ .data = slice_new((void*)c_str, strlen(c_str)) };
+}
+
+struct String_View
+string_view_from_slice(Slice(ascii) slice)
+{
+ return (struct String_View){ .data = slice };
+}
+
+// compares two string_views for equality.
+bool
+string_view_equals(struct String_View a, struct String_View b)
+{
+ Slice(ascii) a_backing = string_view_backing(a), b_backing = string_view_backing(b);
+ if (string_view_length(a) != string_view_length(b)) return false;
+ if (a.data.length == 0) return true;
+ return memcmp(a_backing.data, b_backing.data, a_backing.length) == 0;
+}
+
+// a file handle.
+struct File
+{
+ FILE* handle;
+ struct String* path;
+};
+
+// opens a file and returns a handle to it.
+// returns nil if the file cannot be opened.
+struct File*
+file_open(struct String* path, const ascii* mode)
+{
+ FILE* handle = fopen(string_c_str(path), mode);
+ if (!handle) return nil;
+
+ struct File* file = allocate(sizeof(struct File));
+ file->handle = handle;
+ file->path = path;
+ return file;
+}
+
+// closes a file.
+void
+file_close(struct File* file)
+{
+ if (!file) return;
+ fclose(file->handle);
+ free(file);
+}
+
+// reads the entire content of a file into a string.
+struct String
+file_read_all(struct File* file)
+{
+ fseek(file->handle, 0, SEEK_END);
+ long file_size = ftell(file->handle);
+ fseek(file->handle, 0, SEEK_SET);
+
+ struct String content = string_new();
+ string_ensure_capacity(&content, file_size);
+
+ fread(content.data.data, 1, file_size, file->handle);
+ content.data.length = file_size;
+ ((ascii*)content.data.data)[file_size] = '\0';
+
+ return content;
+}
+
+// writes the content of a string to a file.
+void
+file_write(struct File* file, struct String* content)
+{
+ fwrite(string_c_str(content), 1, string_length(content), file->handle);
+}
+
+// checks if a file exists at the given path.
+bool
+file_exists(struct String* path)
+{
+ return access(string_c_str(path), F_OK) != -1;
+}
+
+// memory-maps a file and returns a string_view of its content.
+// panic if the file cannot be mapped.
+struct String_View
+file_map_to_string_view(struct File* file)
+{
+ struct stat st;
+ if (fstat(fileno(file->handle), &st) == -1) { panic("could not get file status for mmap"); }
+
+ void* mapped = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fileno(file->handle), 0);
+ if (mapped == MAP_FAILED) { panic("could not map file to memory"); }
+
+ return string_view_from_slice(slice_new(mapped, st.st_size));
+}
+
+// unmaps a memory-mapped view.
+void
+file_unmap(struct File* file, struct String_View view)
+{
+ (void)file;
+ munmap(string_view_backing(view).data, string_view_length(view));
+}
diff --git a/boot/transpile.c b/boot/transpile.c
index bebcbbc..25a3d79 100644
--- a/boot/transpile.c
+++ b/boot/transpile.c
@@ -65,13 +65,19 @@ transpiler_visit_type_node(struct Visit* visit, struct Type_Node* node)
case TYPE_NODE_NAME: {
struct String name = node->value.name.name;
if (strcmp(name.data, "int") == 0) {
- fprintf(transpiler->output, "int64_t");
+ fprintf(transpiler->output, "integer");
} else if (strcmp(name.data, "string") == 0) {
- fprintf(transpiler->output, "const char*");
+ fprintf(transpiler->output, "struct String");
} else if (strcmp(name.data, "bool") == 0) {
fprintf(transpiler->output, "bool");
} else if (strcmp(name.data, "float") == 0) {
- fprintf(transpiler->output, "double");
+ fprintf(transpiler->output, "real");
+ } else if (strcmp(name.data, "uint") == 0) {
+ fprintf(transpiler->output, "uint");
+ } else if (strcmp(name.data, "byte") == 0) {
+ fprintf(transpiler->output, "byte");
+ } else if (strcmp(name.data, "ascii") == 0) {
+ fprintf(transpiler->output, "ascii");
} else {
fprintf(transpiler->output, "%.*s", (int)name.length, name.data);
}
@@ -369,10 +375,9 @@ transpiler_visit_tree(struct Visit* visit, struct Tree* tree)
{
TRANSPILER_PREAMBLE
- // include some standard c headers
- // catskill should have it's own standard library,
- // but until bootstrapping is complete, we will just use a
- // normal libc (preferably musl).
+ // include the catskill runtime core library
+ // which provides all the necessary types and functions
+ // for transpiled catskill programs.
// other headers can be included by the user
// with the pragma `| c-header "header.h"`.
fprintf(transpiler->output, "#include <stdio.h>\n");