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:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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, "", "", "", "", "");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user