v0.3.0: restructure directories

- src/        ← compiler/selfhost/  (canonical Bux compiler)
- bootstrap/  ← compiler/bootstrap/ (Nim bootstrap)
- lib/        ← library/std/        (standard library)
- rt/         ← library/runtime/    (C runtime)
- tests/      ← compiler/tests/     (unit tests)
- Remove _selfhost/ (built into build/selfhost/ now)
- Update all path references (Makefile, cli.nim, cli.bux, docs)
- Bump version to 0.3.0
This commit is contained in:
2026-06-06 04:53:39 +03:00
parent 0dade151d2
commit ac969b37c1
65 changed files with 68 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
module Std::Array {
extern func bux_alloc(size: uint) -> *void;
extern func bux_realloc(ptr: *void, size: uint) -> *void;
extern func bux_free(ptr: *void);
extern func bux_bounds_check(index: uint, len: uint);
struct Array<T> {
data: *T,
len: uint,
cap: uint,
}
func Array_New<T>(cap: uint) -> Array<T> {
let data = bux_alloc(cap * sizeof(T)) as *T;
return Array<T> { data: data, len: 0, cap: cap };
}
func Array_Push<T>(self: *Array<T>, value: T) {
if self.len >= self.cap {
self.cap = self.cap * 2;
self.data = bux_realloc(self.data as *void, self.cap * sizeof(T)) as *T;
}
self.data[self.len] = value;
self.len = self.len + 1;
}
func Array_Get<T>(self: *Array<T>, index: uint) -> T {
bux_bounds_check(index, self.len);
return self.data[index];
}
func Array_Len<T>(self: *Array<T>) -> uint {
return self.len;
}
func Array_Free<T>(self: *Array<T>) {
bux_free(self.data as *void);
self.data = null as *T;
self.len = 0;
self.cap = 0;
}
}
+56
View File
@@ -0,0 +1,56 @@
module Std::Channel {
extern func bux_channel_new(capacity: int64, elem_size: int64) -> *void;
extern func bux_channel_send(handle: *void, elem: *void);
extern func bux_channel_recv(handle: *void, out: *void) -> int;
extern func bux_channel_close(handle: *void);
extern func bux_channel_free(handle: *void);
struct Channel<T> {
handle: *void;
}
func Channel_New<T>(capacity: int64) -> Channel<T> {
return Channel<T> { handle: bux_channel_new(capacity, sizeof(T)) };
}
func Channel_Send<T>(ch: *Channel<T>, value: T) {
bux_channel_send(ch.handle, (&value) as *void);
}
func Channel_Recv<T>(ch: *Channel<T>) -> T {
var result: T;
bux_channel_recv(ch.handle, (&result) as *void);
return result;
}
func Channel_Close<T>(ch: *Channel<T>) {
bux_channel_close(ch.handle);
}
func Channel_Free<T>(ch: *Channel<T>) {
bux_channel_free(ch.handle);
}
/* Convenience wrappers for common types */
func Channel_SendInt(ch: *Channel<int>, value: int) {
bux_channel_send(ch.handle, (&value) as *void);
}
func Channel_RecvInt(ch: *Channel<int>) -> int {
var result: int = 0;
bux_channel_recv(ch.handle, (&result) as *void);
return result;
}
func Channel_SendFloat64(ch: *Channel<float64>, value: float64) {
bux_channel_send(ch.handle, (&value) as *void);
}
func Channel_RecvFloat64(ch: *Channel<float64>) -> float64 {
var result: float64 = 0.0;
bux_channel_recv(ch.handle, (&result) as *void);
return result;
}
}
+66
View File
@@ -0,0 +1,66 @@
module Std::Crypto {
import Std::Mem::{Alloc, Free};
import Std::String::{String_Len};
extern func bux_sha256(data: String, len: int, out: *void);
extern func bux_hmac_sha256(key: String, keylen: int, msg: String, msglen: int, out: *void);
extern func bux_random_bytes(buf: *void, len: int) -> int;
extern func bux_base64_encode(data: String, len: int) -> String;
extern func bux_base64_decode(data: String, len: int, outlen: *int) -> String;
extern func bux_bytes_to_hex(data: *void, len: int) -> String;
/* SHA-256: returns lowercase hex string of the hash */
func Crypto_Sha256(data: String) -> String {
let len: int = String_Len(data) as int;
let hashBuf: *void = Alloc(32);
bux_sha256(data, len, hashBuf);
let result: String = bux_bytes_to_hex(hashBuf as *void, 32);
Free(hashBuf);
return result;
}
/* HMAC-SHA256: returns lowercase hex string */
func Crypto_HmacSha256(key: String, message: String) -> String {
let keylen: int = String_Len(key) as int;
let msglen: int = String_Len(message) as int;
let hmacBuf: *void = Alloc(32);
bux_hmac_sha256(key, keylen, message, msglen, hmacBuf);
let result: String = bux_bytes_to_hex(hmacBuf as *void, 32);
Free(hmacBuf);
return result;
}
/* Random bytes: returns a string of n random bytes */
func Crypto_RandomBytes(n: int) -> String {
if n <= 0 { return ""; }
let buf: *void = Alloc(n as uint);
if bux_random_bytes(buf, n) != 1 {
Free(buf);
return "";
}
let result: String = bux_base64_encode(buf as String, n);
Free(buf);
return result;
}
/* Base64 encode */
func Crypto_Base64Encode(s: String) -> String {
return bux_base64_encode(s, String_Len(s) as int);
}
/* HMAC-SHA256 raw: returns base64 of raw binary hmac */
func Crypto_HmacSha256Raw(key: String, message: String) -> String {
let keylen: int = String_Len(key) as int;
let msglen: int = String_Len(message) as int;
let hmacBuf: *void = Alloc(32);
bux_hmac_sha256(key, keylen, message, msglen, hmacBuf);
let result: String = bux_base64_encode(hmacBuf as String, 32);
Free(hmacBuf);
return result;
}
/* Base64 decode */
func Crypto_Base64Decode(s: String) -> String {
let outlen: int = 0;
return bux_base64_decode(s, String_Len(s) as int, &outlen);
}
}
+42
View File
@@ -0,0 +1,42 @@
module Std::Fmt {
/* String formatting with positional placeholders {0}, {1}, {2}...
*
* Usage:
* Fmt_Fmt1("Hello, {0}!", "World")
* Fmt_FmtInt("Count: {0}", 42)
* Fmt_FmtFloat("Pi: {0}", 3.14159)
* Fmt_FmtBool("Active: {0}", true)
* Fmt_Fmt2("Name: {0}, Age: {1}", name, String_FromInt(age))
*/
func Fmt_Fmt1(pattern: String, a: String) -> String {
return String_Format1(pattern, a);
}
func Fmt_Fmt2(pattern: String, a: String, b: String) -> String {
return String_Format2(pattern, a, b);
}
func Fmt_Fmt3(pattern: String, a: String, b: String, c: String) -> String {
return String_Format3(pattern, a, b, c);
}
func Fmt_FmtInt(pattern: String, n: int64) -> String {
return String_Format1(pattern, String_FromInt(n));
}
func Fmt_FmtInt2(pattern: String, n1: int64, n2: int64) -> String {
return String_Format2(pattern, String_FromInt(n1), String_FromInt(n2));
}
func Fmt_FmtFloat(pattern: String, f: float64) -> String {
return String_Format1(pattern, String_FromFloat(f));
}
func Fmt_FmtBool(pattern: String, b: bool) -> String {
if b {
return String_Format1(pattern, "true");
}
return String_Format1(pattern, "false");
}
}
+19
View File
@@ -0,0 +1,19 @@
module Std::Fs {
extern func bux_dir_exists(path: String) -> int;
extern func bux_mkdir_if_needed(path: String) -> int;
extern func bux_list_dir(dir: String, ext: String, out_count: *int) -> *String;
func DirExists(path: String) -> bool {
return bux_dir_exists(path) != 0;
}
func Mkdir(path: String) -> bool {
return bux_mkdir_if_needed(path) != 0;
}
func ListDir(dir: String, ext: String, count: *int) -> *String {
return bux_list_dir(dir, ext, count);
}
}
+28
View File
@@ -0,0 +1,28 @@
module Std::Io {
extern func PrintLine(s: String);
extern func Print(s: String);
extern func PrintInt(n: int);
extern func PrintInt64(n: int64);
extern func PrintFloat(f: float64);
extern func PrintBool(b: bool);
extern func ReadLine() -> String;
extern func bux_read_file(path: String) -> String;
extern func bux_write_file(path: String, content: String) -> int;
extern func bux_file_exists(path: String) -> int;
func ReadFile(path: String) -> String {
return bux_read_file(path);
}
func WriteFile(path: String, content: String) -> bool {
let r: int = bux_write_file(path, content);
return r != 0;
}
func FileExists(path: String) -> bool {
let r: int = bux_file_exists(path);
return r != 0;
}
}
+70
View File
@@ -0,0 +1,70 @@
module Std::Iter {
import Std::Array::*;
struct Iter<T> {
data: *T,
len: uint,
pos: uint,
}
/* Create an iterator from an Array */
func Array_Iter<T>(arr: *Array<T>) -> Iter<T> {
return Iter<T> { data: arr.data, len: arr.len, pos: 0 };
}
/* Check if there are more elements */
func Iter_HasNext<T>(it: *Iter<T>) -> bool {
return it.pos < it.len;
}
/* Get the next element and advance (undefined if HasNext is false) */
func Iter_Next<T>(it: *Iter<T>) -> T {
let val: T = it.data[it.pos];
it.pos = it.pos + 1;
return val;
}
/* Peek current element without advancing (undefined if HasNext is false) */
func Iter_Peek<T>(it: *Iter<T>) -> T {
return it.data[it.pos];
}
/* Reset iterator to the beginning */
func Iter_Reset<T>(it: *Iter<T>) {
it.pos = 0;
}
/* Current position */
func Iter_Pos<T>(it: *Iter<T>) -> uint {
return it.pos;
}
/* Remaining length */
func Iter_Len<T>(it: *Iter<T>) -> uint {
return it.len;
}
/* Count remaining elements */
func Iter_Count<T>(it: *Iter<T>) -> uint {
return it.len - it.pos;
}
/* Skip N elements */
func Iter_Skip<T>(it: *Iter<T>, n: uint) {
it.pos = it.pos + n;
if it.pos > it.len {
it.pos = it.len;
}
}
/* Take first N elements (by limiting len) */
func Iter_Take<T>(it: *Iter<T>, n: uint) -> Iter<T> {
var endPos: uint = it.pos + n;
if endPos > it.len {
endPos = it.len;
}
return Iter<T> { data: it.data, len: endPos, pos: it.pos };
}
}
+495
View File
@@ -0,0 +1,495 @@
module Std::Json {
import Std::Mem::{Alloc, Realloc, Free};
import Std::String;
/* === Tags === */
const JsonTagNull: int = 0;
const JsonTagBool: int = 1;
const JsonTagNumber: int = 2;
const JsonTagString: int = 3;
const JsonTagArray: int = 4;
const JsonTagObject: int = 5;
/* === Core type === */
struct JsonValue {
tag: int,
boolVal: bool,
numVal: float64,
strVal: String,
arrData: *JsonValue,
arrLen: uint,
arrCap: uint,
objKeys: *String,
objValues: *JsonValue,
objLen: uint,
objCap: uint
}
/* === Constructors === */
func Json_Null() -> JsonValue {
return JsonValue {
tag: JsonTagNull, boolVal: false, numVal: 0.0, strVal: "",
arrData: null, arrLen: 0, arrCap: 0,
objKeys: null, objValues: null, objLen: 0, objCap: 0
};
}
func Json_Bool(b: bool) -> JsonValue {
return JsonValue {
tag: JsonTagBool, boolVal: b, numVal: 0.0, strVal: "",
arrData: null, arrLen: 0, arrCap: 0,
objKeys: null, objValues: null, objLen: 0, objCap: 0
};
}
func Json_Number(n: float64) -> JsonValue {
return JsonValue {
tag: JsonTagNumber, boolVal: false, numVal: n, strVal: "",
arrData: null, arrLen: 0, arrCap: 0,
objKeys: null, objValues: null, objLen: 0, objCap: 0
};
}
func Json_String(s: String) -> JsonValue {
return JsonValue {
tag: JsonTagString, boolVal: false, numVal: 0.0, strVal: s,
arrData: null, arrLen: 0, arrCap: 0,
objKeys: null, objValues: null, objLen: 0, objCap: 0
};
}
func Json_Array() -> JsonValue {
return JsonValue {
tag: JsonTagArray, boolVal: false, numVal: 0.0, strVal: "",
arrData: null, arrLen: 0, arrCap: 0,
objKeys: null, objValues: null, objLen: 0, objCap: 0
};
}
func Json_Object() -> JsonValue {
return JsonValue {
tag: JsonTagObject, boolVal: false, numVal: 0.0, strVal: "",
arrData: null, arrLen: 0, arrCap: 0,
objKeys: null, objValues: null, objLen: 0, objCap: 0
};
}
/* === Array helpers === */
func Json_ArrayLen(v: JsonValue) -> uint {
if v.tag != JsonTagArray { return 0; }
return v.arrLen;
}
func Json_ArrayGet(v: JsonValue, index: uint) -> JsonValue {
if v.tag != JsonTagArray { return Json_Null(); }
if index >= v.arrLen { return Json_Null(); }
return v.arrData[index];
}
func Json_ArrayPush(self: *JsonValue, val: JsonValue) {
if self.tag != JsonTagArray { return; }
if self.arrLen >= self.arrCap {
var newCap: uint = self.arrCap;
if newCap == 0 { newCap = 4; }
else { newCap = newCap * 2; }
let newSize: uint = newCap * sizeof(JsonValue);
if self.arrCap == 0 {
self.arrData = Alloc(newSize) as *JsonValue;
} else {
self.arrData = Realloc(self.arrData as *void, newSize) as *JsonValue;
}
self.arrCap = newCap;
}
self.arrData[self.arrLen] = val;
self.arrLen = self.arrLen + 1;
}
/* === Object helpers === */
func Json_ObjectLen(v: JsonValue) -> uint {
if v.tag != JsonTagObject { return 0; }
return v.objLen;
}
func Json_ObjectGet(v: JsonValue, key: String) -> JsonValue {
if v.tag != JsonTagObject { return Json_Null(); }
var i: uint = 0;
while i < v.objLen {
if String_Eq(v.objKeys[i], key) {
return v.objValues[i];
}
i = i + 1;
}
return Json_Null();
}
func Json_ObjectHas(v: JsonValue, key: String) -> bool {
if v.tag != JsonTagObject { return false; }
var i: uint = 0;
while i < v.objLen {
if String_Eq(v.objKeys[i], key) {
return true;
}
i = i + 1;
}
return false;
}
func Json_ObjectSet(self: *JsonValue, key: String, val: JsonValue) {
if self.tag != JsonTagObject { return; }
var i: uint = 0;
while i < self.objLen {
if String_Eq(self.objKeys[i], key) {
self.objValues[i] = val;
return;
}
i = i + 1;
}
if self.objLen >= self.objCap {
var newCap: uint = self.objCap;
if newCap == 0 { newCap = 4; }
else { newCap = newCap * 2; }
let keySize: uint = newCap * sizeof(String);
let valSize: uint = newCap * sizeof(JsonValue);
if self.objCap == 0 {
self.objKeys = Alloc(keySize) as *String;
self.objValues = Alloc(valSize) as *JsonValue;
} else {
self.objKeys = Realloc(self.objKeys as *void, keySize) as *String;
self.objValues = Realloc(self.objValues as *void, valSize) as *JsonValue;
}
self.objCap = newCap;
}
self.objKeys[self.objLen] = key;
self.objValues[self.objLen] = val;
self.objLen = self.objLen + 1;
}
/* === Accessors === */
func Json_IsNull(v: JsonValue) -> bool {
return v.tag == JsonTagNull;
}
func Json_AsBool(v: JsonValue) -> bool {
if v.tag == JsonTagBool { return v.boolVal; }
return false;
}
func Json_AsNumber(v: JsonValue) -> float64 {
if v.tag == JsonTagNumber { return v.numVal; }
return 0.0;
}
func Json_AsString(v: JsonValue) -> String {
if v.tag == JsonTagString { return v.strVal; }
return "";
}
/* === Parser === */
struct JsonParser {
src: String,
pos: uint,
len: uint,
error: String
}
func JsonParser_Peek(p: *JsonParser) -> int {
if p.pos >= p.len { return 0; }
return p.src[p.pos] as int;
}
func JsonParser_Advance(p: *JsonParser) {
if p.pos < p.len {
p.pos = p.pos + 1;
}
}
func JsonParser_SkipWhitespace(p: *JsonParser) {
while true {
let c: int = JsonParser_Peek(p);
if c == 32 || c == 9 || c == 10 || c == 13 {
JsonParser_Advance(p);
} else {
return;
}
}
}
func JsonParser_Match(p: *JsonParser, expected: String) -> bool {
let elen: uint = String_Len(expected);
if p.pos + elen > p.len { return false; }
var i: uint = 0;
while i < elen {
if p.src[p.pos + i] != expected[i] {
return false;
}
i = i + 1;
}
p.pos = p.pos + elen;
return true;
}
func JsonParser_ParseValue(p: *JsonParser) -> JsonValue;
func JsonParser_ParseString(p: *JsonParser) -> String {
if JsonParser_Peek(p) != 34 {
p.error = "Expected string";
return "";
}
JsonParser_Advance(p);
let sb: StringBuilder = StringBuilder_New();
while true {
let c: int = JsonParser_Peek(p);
if c == 0 || c == 34 {
break;
}
if c == 92 {
JsonParser_Advance(p);
let esc: int = JsonParser_Peek(p);
if esc == 0 {
p.error = "Unterminated string escape";
StringBuilder_Free(&sb);
return "";
}
if esc == 110 { StringBuilder_AppendChar(&sb, 10 as char8); } // \n
else if esc == 116 { StringBuilder_AppendChar(&sb, 9 as char8); } // \t
else if esc == 114 { StringBuilder_AppendChar(&sb, 13 as char8); } // \r
else if esc == 98 { StringBuilder_AppendChar(&sb, 8 as char8); } // \b
else if esc == 102 { StringBuilder_AppendChar(&sb, 12 as char8); } // \f
else if esc == 34 { StringBuilder_AppendChar(&sb, 34 as char8); } // \"
else if esc == 92 { StringBuilder_AppendChar(&sb, 92 as char8); } // \\
else {
// Unknown escape — keep literal
StringBuilder_AppendChar(&sb, 92 as char8);
StringBuilder_AppendChar(&sb, esc as char8);
}
JsonParser_Advance(p);
} else {
StringBuilder_AppendChar(&sb, c as char8);
JsonParser_Advance(p);
}
}
if JsonParser_Peek(p) != 34 {
p.error = "Unterminated string";
StringBuilder_Free(&sb);
return "";
}
JsonParser_Advance(p);
let result: String = StringBuilder_Build(&sb);
StringBuilder_Free(&sb);
return result;
}
func JsonParser_ParseNumber(p: *JsonParser) -> JsonValue {
let start: uint = p.pos;
let c0: int = JsonParser_Peek(p);
if c0 == 45 {
JsonParser_Advance(p);
}
while true {
let c: int = JsonParser_Peek(p);
if c >= 48 && c <= 57 {
JsonParser_Advance(p);
} else {
break;
}
}
if JsonParser_Peek(p) == 46 {
JsonParser_Advance(p);
while true {
let c: int = JsonParser_Peek(p);
if c >= 48 && c <= 57 {
JsonParser_Advance(p);
} else {
break;
}
}
}
let numStr: String = String_Slice(p.src, start, p.pos - start);
let n: float64 = String_ToFloat(numStr);
return Json_Number(n);
}
func JsonParser_ParseArray(p: *JsonParser) -> JsonValue {
JsonParser_Advance(p);
var arr: JsonValue = Json_Array();
JsonParser_SkipWhitespace(p);
if JsonParser_Peek(p) == 93 {
JsonParser_Advance(p);
return arr;
}
while true {
JsonParser_SkipWhitespace(p);
let val: JsonValue = JsonParser_ParseValue(p);
if p.error != "" { return Json_Null(); }
Json_ArrayPush(&arr, val);
JsonParser_SkipWhitespace(p);
let c: int = JsonParser_Peek(p);
if c == 93 {
JsonParser_Advance(p);
return arr;
}
if c == 44 {
JsonParser_Advance(p);
} else {
p.error = "Expected ',' or ']' in array";
return Json_Null();
}
}
}
func JsonParser_ParseObject(p: *JsonParser) -> JsonValue {
JsonParser_Advance(p);
var obj: JsonValue = Json_Object();
JsonParser_SkipWhitespace(p);
if JsonParser_Peek(p) == 125 {
JsonParser_Advance(p);
return obj;
}
while true {
JsonParser_SkipWhitespace(p);
let key: String = JsonParser_ParseString(p);
if p.error != "" { return Json_Null(); }
JsonParser_SkipWhitespace(p);
if JsonParser_Peek(p) != 58 {
p.error = "Expected ':' after object key";
return Json_Null();
}
JsonParser_Advance(p);
JsonParser_SkipWhitespace(p);
let val: JsonValue = JsonParser_ParseValue(p);
if p.error != "" { return Json_Null(); }
Json_ObjectSet(&obj, key, val);
JsonParser_SkipWhitespace(p);
let c: int = JsonParser_Peek(p);
if c == 125 {
JsonParser_Advance(p);
return obj;
}
if c == 44 {
JsonParser_Advance(p);
} else {
p.error = "Expected ',' or '}' in object";
return Json_Null();
}
}
}
func JsonParser_ParseValue(p: *JsonParser) -> JsonValue {
JsonParser_SkipWhitespace(p);
let c: int = JsonParser_Peek(p);
if c == 0 {
p.error = "Unexpected end of input";
return Json_Null();
}
if c == 34 {
return Json_String(JsonParser_ParseString(p));
}
if c == 123 {
return JsonParser_ParseObject(p);
}
if c == 91 {
return JsonParser_ParseArray(p);
}
if c == 116 {
if JsonParser_Match(p, "true") {
return Json_Bool(true);
}
p.error = "Expected 'true'";
return Json_Null();
}
if c == 102 {
if JsonParser_Match(p, "false") {
return Json_Bool(false);
}
p.error = "Expected 'false'";
return Json_Null();
}
if c == 110 {
if JsonParser_Match(p, "null") {
return Json_Null();
}
p.error = "Expected 'null'";
return Json_Null();
}
if (c >= 48 && c <= 57) || c == 45 {
return JsonParser_ParseNumber(p);
}
p.error = "Unexpected character";
return Json_Null();
}
/* === Public parser === */
func Json_Parse(s: String) -> JsonValue {
var p: JsonParser = JsonParser { src: s, pos: 0, len: String_Len(s), error: "" };
let result: JsonValue = JsonParser_ParseValue(&p);
JsonParser_SkipWhitespace(&p);
if p.error == "" && p.pos != p.len {
p.error = "Trailing data after JSON value";
return Json_Null();
}
return result;
}
/* === Serializer === */
func Json_StringifyImpl(sb: *StringBuilder, v: JsonValue) {
if v.tag == JsonTagNull {
StringBuilder_Append(sb, "null");
return;
}
if v.tag == JsonTagBool {
if v.boolVal {
StringBuilder_Append(sb, "true");
} else {
StringBuilder_Append(sb, "false");
}
return;
}
if v.tag == JsonTagNumber {
StringBuilder_AppendFloat(sb, v.numVal);
return;
}
if v.tag == JsonTagString {
StringBuilder_AppendChar(sb, 34 as char8);
StringBuilder_Append(sb, v.strVal);
StringBuilder_AppendChar(sb, 34 as char8);
return;
}
if v.tag == JsonTagArray {
StringBuilder_AppendChar(sb, 91 as char8);
var i: uint = 0;
while i < v.arrLen {
if i > 0 {
StringBuilder_AppendChar(sb, 44 as char8);
}
Json_StringifyImpl(sb, v.arrData[i]);
i = i + 1;
}
StringBuilder_AppendChar(sb, 93 as char8);
return;
}
if v.tag == JsonTagObject {
StringBuilder_AppendChar(sb, 123 as char8);
var i: uint = 0;
while i < v.objLen {
if i > 0 {
StringBuilder_AppendChar(sb, 44 as char8);
}
StringBuilder_AppendChar(sb, 34 as char8);
StringBuilder_Append(sb, v.objKeys[i]);
StringBuilder_AppendChar(sb, 34 as char8);
StringBuilder_AppendChar(sb, 58 as char8);
Json_StringifyImpl(sb, v.objValues[i]);
i = i + 1;
}
StringBuilder_AppendChar(sb, 125 as char8);
return;
}
}
func Json_Stringify(v: JsonValue) -> String {
let sb: StringBuilder = StringBuilder_New();
Json_StringifyImpl(&sb, v);
return StringBuilder_Build(&sb);
}
}
+169
View File
@@ -0,0 +1,169 @@
module Std::Map {
extern func bux_hash_bytes(ptr: *void, size: uint) -> uint;
extern func bux_hash_string(s: String) -> uint;
// ---------------------------------------------------------------------------
// Generic Map<K, V> — works with value-type keys (int, float, etc.)
// For String keys, use StringMap below.
// ---------------------------------------------------------------------------
struct MapEntry<K, V> {
key: K,
value: V,
occupied: bool,
}
struct Map<K, V> {
entries: *MapEntry<K, V>,
cap: uint,
len: uint,
}
func Map_New<K, V>(cap: uint) -> Map<K, V> {
let total: uint = cap * sizeof(MapEntry<K, V>);
let data: *MapEntry<K, V> = bux_alloc(total) as *MapEntry<K, V>;
var i: uint = 0;
while i < cap {
data[i].occupied = false;
i = i + 1;
}
return Map<K, V> { entries: data, cap: cap, len: 0 };
}
func Map_Set<K, V>(m: *Map<K, V>, key: K, value: V) {
var keyPtr: *K = &key;
let hash: uint = bux_hash_bytes(keyPtr as *void, sizeof(K));
var idx: uint = hash % m.cap;
while m.entries[idx].occupied {
if 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<K, V>(m: *Map<K, V>, key: K) -> V {
var keyPtr: *K = &key;
let hash: uint = bux_hash_bytes(keyPtr as *void, sizeof(K));
var idx: uint = hash % m.cap;
while m.entries[idx].occupied {
if m.entries[idx].key == key {
return m.entries[idx].value;
}
idx = (idx + 1) % m.cap;
}
// Return zero value for missing key
var zero: V = 0 as V;
return zero;
}
func Map_Has<K, V>(m: *Map<K, V>, key: K) -> bool {
var keyPtr: *K = &key;
let hash: uint = bux_hash_bytes(keyPtr as *void, sizeof(K));
var idx: uint = hash % m.cap;
while m.entries[idx].occupied {
if m.entries[idx].key == key {
return true;
}
idx = (idx + 1) % m.cap;
}
return false;
}
func Map_Len<K, V>(m: *Map<K, V>) -> uint {
return m.len;
}
func Map_Free<K, V>(m: *Map<K, V>) {
bux_free(m.entries as *void);
m.entries = null as *MapEntry<K, V>;
m.cap = 0;
m.len = 0;
}
// ---------------------------------------------------------------------------
// StringMap<V> — specialized Map for String keys, using strcmp
// ---------------------------------------------------------------------------
struct StringMapEntry<V> {
key: String,
value: V,
occupied: bool,
}
struct StringMap<V> {
entries: *StringMapEntry<V>,
cap: uint,
len: uint,
}
func StringMap_New<V>(cap: uint) -> StringMap<V> {
let total: uint = cap * sizeof(StringMapEntry<V>);
let data: *StringMapEntry<V> = bux_alloc(total) as *StringMapEntry<V>;
var i: uint = 0;
while i < cap {
data[i].occupied = false;
i = i + 1;
}
return StringMap<V> { entries: data, cap: cap, len: 0 };
}
func StringMap_Set<V>(m: *StringMap<V>, key: String, value: V) {
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 StringMap_Get<V>(m: *StringMap<V>, key: String) -> V {
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;
}
var zero: V = 0 as V;
return zero;
}
func StringMap_Has<V>(m: *StringMap<V>, 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 StringMap_Len<V>(m: *StringMap<V>) -> uint {
return m.len;
}
func StringMap_Free<V>(m: *StringMap<V>) {
bux_free(m.entries as *void);
m.entries = null as *StringMapEntry<V>;
m.cap = 0;
m.len = 0;
}
}
+44
View File
@@ -0,0 +1,44 @@
module Std::Math {
extern func bux_sqrt(x: float64) -> float64;
extern func bux_pow(x: float64, y: float64) -> float64;
extern func bux_abs_i64(x: int64) -> int64;
extern func bux_abs_f64(x: float64) -> float64;
extern func bux_min_i64(a: int64, b: int64) -> int64;
extern func bux_max_i64(a: int64, b: int64) -> int64;
extern func bux_min_f64(a: float64, b: float64) -> float64;
extern func bux_max_f64(a: float64, b: float64) -> float64;
func Sqrt(x: float64) -> float64 {
return bux_sqrt(x);
}
func Pow(x: float64, y: float64) -> float64 {
return bux_pow(x, y);
}
func Abs(n: int64) -> int64 {
return bux_abs_i64(n);
}
func AbsF(f: float64) -> float64 {
return bux_abs_f64(f);
}
func Min(a: int64, b: int64) -> int64 {
return bux_min_i64(a, b);
}
func Max(a: int64, b: int64) -> int64 {
return bux_max_i64(a, b);
}
func MinF(a: float64, b: float64) -> float64 {
return bux_min_f64(a, b);
}
func MaxF(a: float64, b: float64) -> float64 {
return bux_max_f64(a, b);
}
}
+29
View File
@@ -0,0 +1,29 @@
module Std::Mem {
extern func bux_alloc(size: uint) -> *void;
extern func bux_realloc(ptr: *void, size: uint) -> *void;
extern func bux_free(ptr: *void);
extern func bux_mem_eq(a: *void, b: *void, size: uint) -> int;
func Alloc(size: uint) -> *void {
return bux_alloc(size);
}
func Realloc(ptr: *void, size: uint) -> *void {
return bux_realloc(ptr, size);
}
func Free(ptr: *void) {
bux_free(ptr);
}
func MemEq(a: *void, b: *void, size: uint) -> bool {
return bux_mem_eq(a, b, size) != 0;
}
func New<T>() -> *T {
let sz: uint = sizeof(T);
return bux_alloc(sz) as *T;
}
}
+62
View File
@@ -0,0 +1,62 @@
module Std::Net {
extern func bux_socket_create() -> int;
extern func bux_socket_reuse(fd: int) -> int;
extern func bux_socket_bind(fd: int, addr: String, port: int) -> int;
extern func bux_socket_listen(fd: int, backlog: int) -> int;
extern func bux_socket_accept(fd: int) -> int;
extern func bux_socket_connect(fd: int, addr: String, port: int) -> int;
extern func bux_socket_send(fd: int, data: String, len: int) -> int;
extern func bux_socket_recv(fd: int, maxLen: int) -> String;
extern func bux_socket_close(fd: int) -> int;
extern func bux_socket_error() -> String;
/* Create a TCP socket. Returns -1 on error. */
func Net_Create() -> int {
return bux_socket_create();
}
/* Enable SO_REUSEADDR on a socket. */
func Net_SetReuse(fd: int) -> bool {
return bux_socket_reuse(fd) == 0;
}
/* Bind a socket to an address and port. */
func Net_Bind(fd: int, addr: String, port: int) -> bool {
return bux_socket_bind(fd, addr, port) == 0;
}
/* Start listening for connections. */
func Net_Listen(fd: int, backlog: int) -> bool {
return bux_socket_listen(fd, backlog) == 0;
}
/* Accept a connection. Returns new fd or -1 on error. */
func Net_Accept(fd: int) -> int {
return bux_socket_accept(fd);
}
/* Connect to a remote address and port. */
func Net_Connect(fd: int, addr: String, port: int) -> bool {
return bux_socket_connect(fd, addr, port) == 0;
}
/* Send data. Returns bytes sent or -1 on error. */
func Net_Send(fd: int, data: String) -> int {
return bux_socket_send(fd, data, String_Len(data) as int);
}
/* Receive up to maxLen bytes. Returns empty string on error/EOF. */
func Net_Recv(fd: int, maxLen: int) -> String {
return bux_socket_recv(fd, maxLen);
}
/* Close a socket. */
func Net_Close(fd: int) -> bool {
return bux_socket_close(fd) == 0;
}
/* Get last socket error as a string. */
func Net_LastError() -> String {
return bux_socket_error();
}
}
+42
View File
@@ -0,0 +1,42 @@
module Std::Option {
import Std::Io::{PrintLine};
enum Option {
Some(int),
None,
}
func Option_NewSome(value: int) -> Option {
let o: Option = Option { tag: Option_Some };
o.data.Some_0 = value;
return o;
}
func Option_NewNone() -> Option {
return Option { tag: Option_None };
}
func Option_IsSome(o: Option) -> bool {
return o.tag == Option_Some;
}
func Option_IsNone(o: Option) -> bool {
return o.tag == Option_None;
}
func Option_Unwrap(o: Option) -> int {
if o.tag != Option_Some {
PrintLine("panic: unwrap on None");
return 0;
}
return o.data.Some_0;
}
func Option_UnwrapOr(o: Option, fallback: int) -> int {
if o.tag == Option_Some {
return o.data.Some_0;
}
return fallback;
}
}
+34
View File
@@ -0,0 +1,34 @@
module Std::Os {
extern func bux_argc() -> int;
extern func bux_argv(index: int) -> String;
extern func bux_getenv(name: String) -> String;
extern func bux_setenv(name: String, value: String) -> int;
extern func bux_getcwd() -> String;
extern func bux_chdir(path: String) -> int;
func Os_ArgsCount() -> int {
return bux_argc();
}
func Os_Args(index: int) -> String {
return bux_argv(index);
}
func Os_GetEnv(name: String) -> String {
return bux_getenv(name);
}
func Os_SetEnv(name: String, value: String) -> bool {
return bux_setenv(name, value) == 0;
}
func Os_GetCwd() -> String {
return bux_getcwd();
}
func Os_Chdir(path: String) -> bool {
return bux_chdir(path) == 0;
}
}
+19
View File
@@ -0,0 +1,19 @@
module Std::Path {
extern func bux_path_join(a: String, b: String) -> String;
extern func bux_path_parent(path: String) -> String;
extern func bux_path_ext(path: String) -> String;
func Path_Join(a: String, b: String) -> String {
return bux_path_join(a, b);
}
func Path_Parent(path: String) -> String {
return bux_path_parent(path);
}
func Path_Ext(path: String) -> String {
return bux_path_ext(path);
}
}
+14
View File
@@ -0,0 +1,14 @@
module Std::Process {
extern func bux_process_run(cmd: String) -> int;
extern func bux_process_output(cmd: String) -> String;
func Process_Run(cmd: String) -> int {
return bux_process_run(cmd);
}
func Process_Output(cmd: String) -> String {
return bux_process_output(cmd);
}
}
+44
View File
@@ -0,0 +1,44 @@
module Std::Result {
import Std::Io::{PrintLine};
enum Result {
Ok(int),
Err(String),
}
func Result_NewOk(value: int) -> Result {
let r: Result = Result { tag: Result_Ok };
r.data.Ok_0 = value;
return r;
}
func Result_NewErr(msg: String) -> Result {
let r: Result = Result { tag: Result_Err };
r.data.Err_0 = msg;
return r;
}
func Result_IsOk(r: Result) -> bool {
return r.tag == Result_Ok;
}
func Result_IsErr(r: Result) -> bool {
return r.tag == Result_Err;
}
func Result_Unwrap(r: Result) -> int {
if r.tag != Result_Ok {
PrintLine("panic: unwrap on Err");
return 0;
}
return r.data.Ok_0;
}
func Result_UnwrapOr(r: Result, fallback: int) -> int {
if r.tag == Result_Ok {
return r.data.Ok_0;
}
return fallback;
}
}
+71
View File
@@ -0,0 +1,71 @@
module Std::Set {
extern func bux_hash_bytes(ptr: *void, size: uint) -> uint;
extern func bux_mem_eq(a: *void, b: *void, size: uint) -> int;
extern func bux_alloc(size: uint) -> *void;
extern func bux_free(ptr: *void);
struct SetEntry<T> {
value: T,
occupied: bool,
}
struct Set<T> {
entries: *SetEntry<T>,
cap: uint,
len: uint,
}
func Set_New<T>(cap: uint) -> Set<T> {
let total: uint = cap * sizeof(SetEntry<T>);
let data: *SetEntry<T> = bux_alloc(total) as *SetEntry<T>;
var i: uint = 0;
while i < cap {
data[i].occupied = false;
i = i + 1;
}
return Set<T> { entries: data, cap: cap, len: 0 };
}
func Set_Add<T>(s: *Set<T>, value: T) {
var valuePtr: *T = &value;
let hash: uint = bux_hash_bytes(valuePtr as *void, sizeof(T));
var idx: uint = hash % s.cap;
while s.entries[idx].occupied {
var entryPtr: *T = &s.entries[idx].value;
if bux_mem_eq(entryPtr as *void, valuePtr as *void, sizeof(T)) != 0 {
return;
}
idx = (idx + 1) % s.cap;
}
s.entries[idx].value = value;
s.entries[idx].occupied = true;
s.len = s.len + 1;
}
func Set_Has<T>(s: *Set<T>, value: T) -> bool {
var valuePtr: *T = &value;
let hash: uint = bux_hash_bytes(valuePtr as *void, sizeof(T));
var idx: uint = hash % s.cap;
while s.entries[idx].occupied {
var entryPtr: *T = &s.entries[idx].value;
if bux_mem_eq(entryPtr as *void, valuePtr as *void, sizeof(T)) != 0 {
return true;
}
idx = (idx + 1) % s.cap;
}
return false;
}
func Set_Len<T>(s: *Set<T>) -> uint {
return s.len;
}
func Set_Free<T>(s: *Set<T>) {
bux_free(s.entries as *void);
s.entries = null as *SetEntry<T>;
s.cap = 0;
s.len = 0;
}
}
+204
View File
@@ -0,0 +1,204 @@
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;
extern func bux_strstr(haystack: String, needle: String) -> String;
extern func bux_str_contains(haystack: String, needle: String) -> int;
extern func bux_str_slice(s: String, start: uint, len: uint) -> String;
extern func bux_str_trim_left(s: String) -> String;
extern func bux_str_trim_right(s: String) -> String;
extern func bux_str_trim(s: String) -> String;
extern func bux_int_to_str(n: int64) -> String;
extern func bux_str_to_int(s: String) -> int64;
extern func bux_sb_new(initial_cap: uint) -> *void;
extern func bux_sb_append(sb: *void, s: String);
extern func bux_sb_append_int(sb: *void, n: int64);
extern func bux_sb_append_float(sb: *void, f: float64);
extern func bux_sb_append_char(sb: *void, c: char8);
extern func bux_sb_build(sb: *void) -> String;
extern func bux_sb_free(sb: *void);
extern func bux_str_split_count(s: String, delim: String) -> uint;
extern func bux_str_split_part(s: String, delim: String, index: uint) -> String;
extern func bux_str_join2(a: String, b: String, sep: String) -> String;
extern func bux_float_to_string(f: float64) -> String;
extern func bux_str_format(pattern: String, a0: String, a1: String, a2: String, a3: String, a4: String, a5: String, a6: String, a7: String) -> String;
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;
}
func String_EndsWith(s: String, suffix: String) -> bool {
let s_len: uint = bux_strlen(s);
let suf_len: uint = bux_strlen(suffix);
if suf_len > s_len {
return false;
}
let start: uint = s_len - suf_len;
let tail: String = bux_str_slice(s, start, suf_len);
let eq: bool = bux_strcmp(tail, suffix) == 0;
return eq;
}
func String_Contains(s: String, substr: String) -> bool {
let r: int = bux_str_contains(s, substr);
return r != 0;
}
func String_Slice(s: String, start: uint, len: uint) -> String {
return bux_str_slice(s, start, len);
}
func String_Trim(s: String) -> String {
return bux_str_trim(s);
}
func String_TrimLeft(s: String) -> String {
return bux_str_trim_left(s);
}
func String_TrimRight(s: String) -> String {
return bux_str_trim_right(s);
}
func String_FromInt(n: int64) -> String {
return bux_int_to_str(n);
}
func String_ToInt(s: String) -> int64 {
return bux_str_to_int(s);
}
// String Builder — efficient string construction
struct StringBuilder {
handle: *void,
}
func StringBuilder_New() -> StringBuilder {
return StringBuilder { handle: bux_sb_new(64) };
}
func StringBuilder_NewCap(cap: uint) -> StringBuilder {
return StringBuilder { handle: bux_sb_new(cap) };
}
func StringBuilder_Append(sb: *StringBuilder, s: String) {
bux_sb_append(sb.handle, s);
}
func StringBuilder_AppendInt(sb: *StringBuilder, n: int64) {
bux_sb_append_int(sb.handle, n);
}
func StringBuilder_AppendFloat(sb: *StringBuilder, f: float64) {
bux_sb_append_float(sb.handle, f);
}
func StringBuilder_AppendChar(sb: *StringBuilder, c: char8) {
bux_sb_append_char(sb.handle, c);
}
func StringBuilder_Build(sb: *StringBuilder) -> String {
return bux_sb_build(sb.handle);
}
func StringBuilder_Free(sb: *StringBuilder) {
bux_sb_free(sb.handle);
}
// ---------------------------------------------------------------------------
// String split/join
// ---------------------------------------------------------------------------
func String_SplitCount(s: String, delim: String) -> uint {
return bux_str_split_count(s, delim);
}
func String_SplitPart(s: String, delim: String, index: uint) -> String {
return bux_str_split_part(s, delim, index);
}
func String_Join2(a: String, b: String, sep: String) -> String {
return bux_str_join2(a, b, sep);
}
// ---------------------------------------------------------------------------
// String find/replace/format
// ---------------------------------------------------------------------------
func String_Find(haystack: String, needle: String) -> String {
return bux_strstr(haystack, needle);
}
func String_Replace(s: String, old: String, new: String) -> String {
let pos: String = bux_strstr(s, old);
if pos as uint == 0 {
return s;
}
let oldLen: uint = bux_strlen(old);
let prefixLen: uint = pos as uint - s as uint;
let prefix: String = bux_str_slice(s, 0, prefixLen);
let suffix: String = bux_str_slice(s, prefixLen + oldLen, bux_strlen(s) - prefixLen - oldLen);
let temp: String = String_Concat(prefix, new);
let result: String = String_Concat(temp, suffix);
return result;
}
extern func bux_str_to_float(s: String) -> float64;
func String_ToFloat(s: String) -> float64 {
return bux_str_to_float(s);
}
func String_FromFloat(f: float64) -> String {
return bux_float_to_string(f);
}
func String_Format1(pattern: String, a0: String) -> String {
return bux_str_format(pattern, a0, "", "", "", "", "", "", "");
}
func String_Format2(pattern: String, a0: String, a1: String) -> String {
return bux_str_format(pattern, a0, a1, "", "", "", "", "", "");
}
func String_Format3(pattern: String, a0: String, a1: String, a2: String) -> String {
return bux_str_format(pattern, a0, a1, a2, "", "", "", "", "");
}
}
+58
View File
@@ -0,0 +1,58 @@
module Std::Sync {
extern func bux_mutex_new() -> *void;
extern func bux_mutex_lock(handle: *void);
extern func bux_mutex_unlock(handle: *void);
extern func bux_mutex_free(handle: *void);
extern func bux_rwlock_new() -> *void;
extern func bux_rwlock_rdlock(handle: *void);
extern func bux_rwlock_wrlock(handle: *void);
extern func bux_rwlock_unlock(handle: *void);
extern func bux_rwlock_free(handle: *void);
struct Mutex {
handle: *void;
}
struct RwLock {
handle: *void;
}
func Mutex_New() -> Mutex {
return Mutex { handle: bux_mutex_new() };
}
func Mutex_Lock(m: *Mutex) {
bux_mutex_lock(m.handle);
}
func Mutex_Unlock(m: *Mutex) {
bux_mutex_unlock(m.handle);
}
func Mutex_Free(m: *Mutex) {
bux_mutex_free(m.handle);
}
func RwLock_New() -> RwLock {
return RwLock { handle: bux_rwlock_new() };
}
func RwLock_ReadLock(rw: *RwLock) {
bux_rwlock_rdlock(rw.handle);
}
func RwLock_WriteLock(rw: *RwLock) {
bux_rwlock_wrlock(rw.handle);
}
func RwLock_Unlock(rw: *RwLock) {
bux_rwlock_unlock(rw.handle);
}
func RwLock_Free(rw: *RwLock) {
bux_rwlock_free(rw.handle);
}
}
+23
View File
@@ -0,0 +1,23 @@
module Std::Task {
extern func bux_task_spawn(fn: *void, arg: *void) -> *void;
extern func bux_task_join(handle: *void);
extern func bux_task_sleep(ms: int64);
struct TaskHandle {
handle: *void;
}
func Task_Spawn(fn: *void, arg: *void) -> TaskHandle {
return TaskHandle { handle: bux_task_spawn(fn, arg) };
}
func Task_Join(t: TaskHandle) {
bux_task_join(t.handle);
}
func Task_Sleep(ms: int64) {
bux_task_sleep(ms);
}
}
+45
View File
@@ -0,0 +1,45 @@
module Std::Test {
import Std::Io::{PrintLine, PrintInt};
extern func bux_exit(code: int);
extern func bux_assert(cond: int, file: String, line: int, expr: String);
func Test_Exit(code: int) {
bux_exit(code);
}
func Test_Assert(cond: bool) {
bux_assert(cond as int, "", 0, "");
}
func Test_AssertEqInt(a: int, b: int) {
if a != b {
PrintLine("ASSERT_EQ FAILED:");
PrintInt(a);
PrintLine(" != ");
PrintInt(b);
bux_exit(1);
}
}
func Test_AssertTrue(cond: bool) {
if !cond {
PrintLine("ASSERT_TRUE FAILED");
bux_exit(1);
}
}
func Test_AssertFalse(cond: bool) {
if cond {
PrintLine("ASSERT_FALSE FAILED");
bux_exit(1);
}
}
func Test_Fail(msg: String) {
PrintLine("FAIL:");
PrintLine(msg);
bux_exit(1);
}
}
+19
View File
@@ -0,0 +1,19 @@
module Std::Time {
extern func bux_time_ms() -> int64;
extern func bux_time_us() -> int64;
extern func bux_sleep_ms(ms: int64);
func Time_NowMs() -> int64 {
return bux_time_ms();
}
func Time_NowUs() -> int64 {
return bux_time_us();
}
func Time_SleepMs(ms: int64) {
bux_sleep_ms(ms);
}
}