8e74215378
- Phase 3: High-Level IR (HIR) with lowering from AST - Method call desugaring (obj.method() → Type_method(obj)) - if/else, while, loop, break, continue lowering - struct, enum, function lowering - 8 HIR tests passing - Phase 5A: C backend code generation - Type mapping (Bux types → C11 types) - Expression and statement emission - Struct, enum, function generation - C main() wrapper for Bux Main() - Runtime shim (stdlib/runtime.c) - bux_alloc, bux_free, bux_print, bux_panic - BuxString, BuxSlice types - Bounds checking, division by zero - Build integration - bux build: lex → parse → sema → HIR → C → cc - bux run: build + execute - bux clean: remove build directory - Parser fixes - Newline handling in struct, enum, extend, interface blocks - self keyword as expression and parameter name - Sema improvements - Method resolution (extend blocks) - Interface conformance checking - collectGlobals made public - All 70 tests passing (25 lexer + 16 parser + 21 sema + 8 HIR) - End-to-end: Bux programs compile to native ELF64 binaries
130 lines
2.6 KiB
C
130 lines
2.6 KiB
C
/* Bux Runtime - Minimal C runtime for Bux programs */
|
|
/* This is linked with every Bux program compiled via the C backend */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
/* Memory allocation */
|
|
void* bux_alloc(size_t size) {
|
|
void* ptr = malloc(size);
|
|
if (ptr == NULL) {
|
|
fprintf(stderr, "bux runtime: out of memory (alloc %zu bytes)\n", size);
|
|
abort();
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
void* bux_realloc(void* ptr, size_t size) {
|
|
void* new_ptr = realloc(ptr, size);
|
|
if (new_ptr == NULL && size > 0) {
|
|
fprintf(stderr, "bux runtime: out of memory (realloc %zu bytes)\n", size);
|
|
abort();
|
|
}
|
|
return new_ptr;
|
|
}
|
|
|
|
void bux_free(void* ptr) {
|
|
free(ptr);
|
|
}
|
|
|
|
/* I/O */
|
|
void bux_print(const char* s) {
|
|
if (s != NULL) {
|
|
fputs(s, stdout);
|
|
}
|
|
}
|
|
|
|
void bux_println(const char* s) {
|
|
if (s != NULL) {
|
|
puts(s);
|
|
} else {
|
|
puts("");
|
|
}
|
|
}
|
|
|
|
void bux_print_int(int64_t n) {
|
|
printf("%lld", (long long)n);
|
|
}
|
|
|
|
void bux_print_float(double f) {
|
|
printf("%g", f);
|
|
}
|
|
|
|
void bux_print_bool(bool b) {
|
|
printf("%s", b ? "true" : "false");
|
|
}
|
|
|
|
void bux_print_char(char c) {
|
|
putchar(c);
|
|
}
|
|
|
|
/* Panic */
|
|
void bux_panic(const char* msg) {
|
|
fprintf(stderr, "bux panic: %s\n", msg ? msg : "unknown error");
|
|
abort();
|
|
}
|
|
|
|
/* Division by zero check */
|
|
int64_t bux_div_i64(int64_t a, int64_t b) {
|
|
if (b == 0) {
|
|
bux_panic("division by zero");
|
|
}
|
|
return a / b;
|
|
}
|
|
|
|
int64_t bux_mod_i64(int64_t a, int64_t b) {
|
|
if (b == 0) {
|
|
bux_panic("modulo by zero");
|
|
}
|
|
return a % b;
|
|
}
|
|
|
|
/* String operations */
|
|
typedef struct {
|
|
const char* data;
|
|
size_t len;
|
|
} BuxString;
|
|
|
|
BuxString bux_string_from_cstr(const char* s) {
|
|
BuxString result;
|
|
result.data = s;
|
|
result.len = s ? strlen(s) : 0;
|
|
return result;
|
|
}
|
|
|
|
BuxString bux_string_concat(BuxString a, BuxString b) {
|
|
BuxString result;
|
|
result.len = a.len + b.len;
|
|
char* buf = (char*)bux_alloc(result.len + 1);
|
|
if (a.data && a.len > 0) memcpy(buf, a.data, a.len);
|
|
if (b.data && b.len > 0) memcpy(buf + a.len, b.data, b.len);
|
|
buf[result.len] = '\0';
|
|
result.data = buf;
|
|
return result;
|
|
}
|
|
|
|
/* Slice operations */
|
|
typedef struct {
|
|
void* data;
|
|
size_t len;
|
|
size_t cap;
|
|
} BuxSlice;
|
|
|
|
BuxSlice bux_slice_new(size_t elem_size, size_t len) {
|
|
BuxSlice result;
|
|
result.len = len;
|
|
result.cap = len;
|
|
result.data = bux_alloc(elem_size * len);
|
|
return result;
|
|
}
|
|
|
|
void bux_bounds_check(size_t index, size_t len) {
|
|
if (index >= len) {
|
|
fprintf(stderr, "bux panic: index out of bounds (index %zu, len %zu)\n", index, len);
|
|
abort();
|
|
}
|
|
}
|