feat: Std::String, Std::Map, Result/Option, ? operator, sizeof fix, docs

Add standard library modules:
- Std::String: strlen, strcmp, concat, copy, starts_with wrappers
- Std::Map: linear-probing hash map with String keys, int values

Add error handling:
- Result and Option algebraic enum examples
- ? try operator for automatic error propagation in HIR lowering

Compiler bugfixes:
- Fix sizeof() for user-defined structs (new hSizeOf HIR node)
- Fix HIR type lowering for char8, bool8, int8, uint8, etc.
- Fix let statement lowering for pointer types (*char8 → int* bug)
- Fix PrintInt ABI mismatch (int64_t → int in io.c)
- Fix Makefile test bug (_test_tmp_pkg already exists)

Documentation:
- Rewrite README.md with features, examples, project structure
- Add docs/LanguageRef.md — complete language reference
- Add docs/Stdlib.md — standard library documentation
- Add docs/BuildAndTest.md — build and test guide

New examples: strings, map, result_option, try_operator (13 total)
This commit is contained in:
2026-05-31 10:15:44 +03:00
parent e328af6eee
commit 7ee6a73ea4
22 changed files with 1475 additions and 55 deletions
+79
View File
@@ -0,0 +1,79 @@
module Std::Map {
extern func bux_hash_string(s: String) -> uint;
struct MapEntry {
key: String,
value: int,
occupied: bool,
}
struct Map {
entries: *MapEntry,
cap: uint,
len: uint,
}
func Map_New(cap: uint) -> Map {
let total: uint = cap * sizeof(MapEntry);
let data: *MapEntry = bux_alloc(total) as *MapEntry;
var i: uint = 0;
while i < cap {
data[i].occupied = false;
i = i + 1;
}
return Map { entries: data, cap: cap, len: 0 };
}
func Map_Set(m: *Map, key: String, value: int) {
let hash: uint = bux_hash_string(key);
var idx: uint = hash % m.cap;
while m.entries[idx].occupied {
if String_Eq(m.entries[idx].key, key) {
m.entries[idx].value = value;
return;
}
idx = (idx + 1) % m.cap;
}
m.entries[idx].key = key;
m.entries[idx].value = value;
m.entries[idx].occupied = true;
m.len = m.len + 1;
}
func Map_Get(m: *Map, key: String) -> int {
let hash: uint = bux_hash_string(key);
var idx: uint = hash % m.cap;
while m.entries[idx].occupied {
if String_Eq(m.entries[idx].key, key) {
return m.entries[idx].value;
}
idx = (idx + 1) % m.cap;
}
return 0;
}
func Map_Has(m: *Map, key: String) -> bool {
let hash: uint = bux_hash_string(key);
var idx: uint = hash % m.cap;
while m.entries[idx].occupied {
if String_Eq(m.entries[idx].key, key) {
return true;
}
idx = (idx + 1) % m.cap;
}
return false;
}
func Map_Len(m: *Map) -> uint {
return m.len;
}
func Map_Free(m: *Map) {
bux_free(m.entries as *void);
m.entries = null as *MapEntry;
m.cap = 0;
m.len = 0;
}
}
+45
View File
@@ -0,0 +1,45 @@
module Std::String {
extern func bux_strlen(s: String) -> uint;
extern func bux_strcmp(a: String, b: String) -> int;
extern func bux_strncmp(a: String, b: String, n: uint) -> int;
extern func bux_strcpy(dest: *char8, src: String) -> *char8;
extern func bux_strcat(dest: *char8, src: String) -> *char8;
extern func bux_strncpy(dest: *char8, src: String, n: uint) -> *char8;
func String_Len(s: String) -> uint {
return bux_strlen(s);
}
func String_Eq(a: String, b: String) -> bool {
return bux_strcmp(a, b) == 0;
}
func String_Concat(a: String, b: String) -> String {
let len_a: uint = bux_strlen(a);
let len_b: uint = bux_strlen(b);
let total: uint = len_a + len_b + 1;
let buf: *char8 = bux_alloc(total) as *char8;
bux_strcpy(buf, a);
bux_strcat(buf, b);
return buf;
}
func String_Copy(s: String) -> String {
let len: uint = bux_strlen(s);
let buf: *char8 = bux_alloc(len + 1) as *char8;
bux_strcpy(buf, s);
return buf;
}
func String_StartsWith(s: String, prefix: String) -> bool {
let s_len: uint = bux_strlen(s);
let p_len: uint = bux_strlen(prefix);
if p_len > s_len {
return false;
}
let r: int = bux_strncmp(s, prefix, p_len);
return r == 0;
}
}
+2 -2
View File
@@ -21,8 +21,8 @@ void Print(const char* s) {
}
/* PrintInt - print integer */
void PrintInt(int64_t n) {
printf("%lld", (long long)n);
void PrintInt(int n) {
printf("%d", n);
}
/* PrintFloat - print float */
+35
View File
@@ -127,3 +127,38 @@ void bux_bounds_check(size_t index, size_t len) {
abort();
}
}
/* String wrappers with Bux-compatible signatures */
unsigned int bux_strlen(const char* s) {
return (unsigned int)strlen(s);
}
int bux_strcmp(const char* a, const char* b) {
return strcmp(a, b);
}
int bux_strncmp(const char* a, const char* b, unsigned int n) {
return strncmp(a, b, (size_t)n);
}
char* bux_strcpy(char* dest, const char* src) {
return strcpy(dest, src);
}
char* bux_strcat(char* dest, const char* src) {
return strcat(dest, src);
}
char* bux_strncpy(char* dest, const char* src, unsigned int n) {
return strncpy(dest, src, (size_t)n);
}
/* Hash function (djb2) for string keys */
unsigned int bux_hash_string(const char* s) {
unsigned int hash = 5381;
int c;
while ((c = *s++)) {
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
}
return hash;
}