feat: restructure repo, borrow checker, expanded stdlib
- Reorganize repository to Rust-style layout: compiler/bootstrap/ compiler/selfhost/ compiler/tests/ library/std/ library/runtime/ tests/ tools/ - Add buxs/ Windows-compatible project root - Add borrow checker tests and implement: - Alias analysis (double mutable borrow detection) - Use-after-move detection for own T - Expand standard library: - Std::Os: Args, Env, Cwd, Chdir - Std::Time: NowMs, NowUs, SleepMs - Std::Process: Run, Output - Std::Io: PrintInt64 (fixes 32-bit truncation bug) - Add examples: os_time.bux, process.bux - Fix PrintInt to use int64_t in C runtime
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
/* Bux Standard Library - I/O functions */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/* PrintLine - print string with newline */
|
||||
void PrintLine(const char* s) {
|
||||
if (s != NULL) {
|
||||
puts(s);
|
||||
} else {
|
||||
puts("");
|
||||
}
|
||||
}
|
||||
|
||||
/* Print - print string without newline */
|
||||
void Print(const char* s) {
|
||||
if (s != NULL) {
|
||||
printf("%s", s);
|
||||
}
|
||||
}
|
||||
|
||||
/* PrintInt - print integer */
|
||||
void PrintInt(int n) {
|
||||
printf("%d", n);
|
||||
}
|
||||
|
||||
/* PrintInt64 - print 64-bit integer */
|
||||
void PrintInt64(int64_t n) {
|
||||
printf("%lld", (long long)n);
|
||||
}
|
||||
|
||||
/* PrintFloat - print float */
|
||||
void PrintFloat(double f) {
|
||||
printf("%g", f);
|
||||
}
|
||||
|
||||
/* PrintBool - print boolean */
|
||||
void PrintBool(int b) {
|
||||
printf("%s", b ? "true" : "false");
|
||||
}
|
||||
|
||||
/* ReadLine - read line from stdin (simplified) */
|
||||
const char* ReadLine(void) {
|
||||
static char buffer[1024];
|
||||
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
|
||||
size_t len = strlen(buffer);
|
||||
if (len > 0 && buffer[len-1] == '\n') {
|
||||
buffer[len-1] = '\0';
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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,35 @@
|
||||
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);
|
||||
}
|
||||
|
||||
func Channel_Recv<T>(ch: *Channel<T>) -> T {
|
||||
var result: T;
|
||||
bux_channel_recv(ch.handle, &result);
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
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_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;
|
||||
}
|
||||
|
||||
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,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,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