begin work on iterators & memory functions

This commit is contained in:
koniifer 2025-03-08 19:11:06 +00:00
parent 01ea41bc34
commit c1d8688539
7 changed files with 156 additions and 43 deletions

62
build
View file

@ -8,56 +8,62 @@ readonly LILY_TEST_DIR="${LILY_TEST_DIR:-$LILY_SCRIPT_DIR/test}"
readonly LILY_BUILD_DIR="${LILY_BUILD_DIR:-$LILY_SCRIPT_DIR/out}"
readonly HBLANG_GIT="https://git.ablecorp.us/mlokis/hblang"
readonly HBLANG_COMMIT="fcbcaac67dd47887fef81bc62d4b66a6cf071f8c"
readonly HBLANG_BRANCH="main"
readonly HBLANG_COMMIT="025a4865beb9b372f6f1025fdcca13f55aa55517"
readonly HBLANG_CFLAGS="--path-projection lily $LILY_SRC_DIR/lib.hb ${HBLANG_CFLAGS:-}"
die() { error "$2" && exit "$1"; }
error() { printf "\033[31mERROR\033[0m: %s\n" "$1" 1>&2; }
log() { printf "\033[32mINFO\033[0m: %s\n" "$1"; }
warn() { printf "\033[33mWARN\033[0m: %s\n" "$1"; }
log() { printf "\033[32mINFO\033[0m: %s\n" "$1" 1>&2; }
warn() { printf "\033[33mWARN\033[0m: %s\n" "$1" 1>&2; }
fetch_step() {
command -v zig >/dev/null 2>&1 || die 101 "'zig' binary not found in PATH"
command -v git >/dev/null 2>&1 || die 101 "'git' binary not found in PATH"
if [ -d "$LILY_BUILD_DIR/hblang" ]; then
cd "$LILY_BUILD_DIR/hblang" || die 1 "cd to $LILY_BUILD_DIR/hblang failed"
hblang_dir="$LILY_BUILD_DIR/hblang"
mkdir -p "$hblang_dir" || die 1 "failed to create hblang directory"
CURR_BRANCH=$(git rev-parse --abbrev-ref HEAD >/dev/null 2>&1)
[ "$CURR_BRANCH" = "$HBLANG_BRANCH" ] || git checkout "$HBLANG_BRANCH" >/dev/null 2>&1
CURR_COMMIT=$(git rev-parse HEAD >/dev/null 2>&1)
[ "$CURR_COMMIT" = "$HBLANG_COMMIT" ] || git checkout "$HBLANG_COMMIT" >/dev/null 2>&1
if [ -d "$hblang_dir/.git" ]; then
cd "$hblang_dir" || die 1 "failed to enter hblang directory"
current_commit=$(git rev-parse HEAD 2>/dev/null)
if [ "$current_commit" != "$HBLANG_COMMIT" ]; then
if ! git cat-file -e "$HBLANG_COMMIT^{commit}" 2>/dev/null; then
log "fetching hblang repository updates"
git fetch --all >/dev/null 2>&1 || die 1 "failed to fetch repository"
fi
git checkout -f "$HBLANG_COMMIT" >/dev/null 2>&1 || die 1 "failed to checkout commit"
fi
else
mkdir -p "$LILY_BUILD_DIR/hblang"
git clone "$HBLANG_GIT" "$LILY_BUILD_DIR/hblang" --branch "$HBLANG_BRANCH"
cd "$LILY_BUILD_DIR/hblang" || die 1 "cd to $LILY_BUILD_DIR/hblang failed"
git checkout "$HBLANG_COMMIT" >/dev/null 2>&1
log "cloning hblang repository"
git clone "$HBLANG_GIT" "$hblang_dir" >/dev/null 2>&1 || die 1 "failed to clone repository"
cd "$hblang_dir" || die 1 "failed to enter cloned directory"
if ! git cat-file -e "$HBLANG_COMMIT^{commit}" 2>/dev/null; then
git fetch origin "$HBLANG_COMMIT" >/dev/null 2>&1 || die 1 "failed to fetch commit"
fi
git checkout -f "$HBLANG_COMMIT" >/dev/null 2>&1 || die 1 "failed to checkout commit"
fi
zig build install
PATH="$LILY_BUILD_DIR/hblang/zig-out/bin:$PATH"
cd "$LILY_SCRIPT_DIR" || die 1 "cd to $LILY_SCRIPT_DIR failed"
zig build install >/dev/null 2>&1 || die 1 "failed to build hblang"
PATH="$hblang_dir/zig-out/bin:$PATH"
cd "$LILY_SCRIPT_DIR" || die 1 "failed to return to script directory"
}
main() {
mkdir -p "$LILY_BUILD_DIR" || die 1 "can't create build dir"
mkdir -p "$LILY_BUILD_DIR" || die 1 "failed to create build directory"
fetch_step
inp="${1:-main.hb}"
[ -z "$inp" ] || [ ! -e "$inp" ] && die 1 "source file '$inp' does not exist"
[ ! -e "$inp" ] && die 1 "source file '$inp' does not exist"
# shellcheck disable=SC2086
{
hblang $HBLANG_CFLAGS $inp
# todo: dont do this second compile if first fails
hblang $HBLANG_CFLAGS $inp --fmt >/dev/null 2>&1
}
if hblang $HBLANG_CFLAGS "$inp"; then
hblang $HBLANG_CFLAGS "$inp" --fmt >/dev/null 2>&1
else
exit $?
fi
}
main "$@"

30
main.hb
View file

@ -1,5 +1,31 @@
lily := @use("lily")
lily.{target, log, mem} := @use("lily")
FunkyTown := struct {
.is_null: bool;
.ptr: ^u8;
}
main := fn(): void {
a := lily.target.func()
a := "Hello, World!"
b := mem.bytes(a).map(fn(x: u8): u8 return x + 2)
c := b.next().val
if c != 0x48 + 2 die
// a := target.alloc(1000)[0..1000]
// // todo: remove @as()
// if @as(uint, @bit_cast(a.ptr)) == 0 {
// log.error("alloced is null")
// die
// }
// mem.copy(a.ptr, "Hello, World!".ptr, 13)
// if !mem.equals(a[0..13], "Hello, World!") {
// log.error("badness")
// die
// }
// log.info(a[0..13])
// target.dealloc(a.ptr, 1000)
}

30
src/iter.hb Normal file
View file

@ -0,0 +1,30 @@
Next := fn(T: type): type return struct {
.finished: bool;
.val: T
$yield := fn(val: T): @CurrentScope() return .(false, val)
$done := fn(): @CurrentScope() return .(true, idk)
}
Iterator := fn(T: type): type return struct {
.inner: T
IterNext := @TypeOf(T.next(idk))
IterVal := @TypeOf(T.next(idk).val)
$next := fn(self: ^@CurrentScope()): IterNext {
return self.inner.next()
}
$map := fn(self: ^@CurrentScope(), func: type): Iterator(Map(T, func)) {
return .(.(self))
}
}
Map := fn(T: type, func: type): type return struct {
.iter: Iterator(T)
IterNext := @TypeOf(func(@as(@TypeOf(T.next(idk).val), idk)))
next := fn(self: ^@CurrentScope()): Next(IterNext) {
x := self.iter.inner.next()
return .(x.finished, func(x.val))
}
}

View file

@ -1,2 +1,4 @@
target := @use("target/lib.hb")
iter := @use("iter.hb")
mem := @use("mem.hb")
log := @use("log.hb")

36
src/mem.hb Normal file
View file

@ -0,0 +1,36 @@
.{target, iter: .{Iterator, Next}} := @use("lib.hb")
$copy := fn(dest: ^u8, src: ^u8, len: uint): void {
target.memcopy(dest, src, len)
}
$move := fn(dest: ^u8, src: ^u8, len: uint): void {
target.memmove(dest, src, len)
}
$set := fn(dest: ^u8, src: u8, len: uint): void {
target.memset(dest, src, len)
}
equals := fn(lhs: []u8, rhs: []u8): bool {
if lhs.len != rhs.len return false
if lhs.ptr == rhs.ptr return true
i := 0
loop if i == lhs.len break else {
if lhs[i] != rhs[i] return false
i += 1
}
return true
}
$bytes := fn(slice: []u8): Iterator(struct {
.slice: []u8
$next := fn(self: ^@CurrentScope()): Next(u8) {
tmp := Next(u8).(self.slice.len == 0, self.slice.ptr.*)
self.slice = self.slice[1..]
return tmp
}
}) {
return .(.(slice))
}

View file

@ -1,9 +1,5 @@
.{LogLevel} := @use("../lib.hb").log
func := fn(): uint {
return 0
}
LogEcall := struct align(1){.level: LogLevel; .str_ptr: ^u8; .str_len: uint}
$page_len := fn(): uint {
@ -15,16 +11,19 @@ $pages := fn(len: uint): uint {
}
AllocEcall := struct align(1){.pad: u8; .pages_new: uint; .zeroed: bool}
$alloc := fn(len: uint): ?^u8 {
// todo: return ?^u8
$alloc := fn(len: uint): ^u8 {
return @ecall(3, 2, AllocEcall.(0, pages(len), false), @size_of(AllocEcall))
}
$alloc_zeroed := fn(len: uint): ?^u8 {
// todo: return ?^u8
$alloc_zeroed := fn(len: uint): ^u8 {
return @ecall(3, 2, AllocEcall.(0, pages(len), true), @size_of(AllocEcall))
}
ReallocEcall := struct align(1){.pad: u8; .pages_old: uint; .pages_new: uint; .ptr_old: ^u8}
$realloc := fn(ptr_old: ^u8, len_old: uint, len_new: uint): ?^u8 {
// todo: return ?^u8.
$realloc := fn(ptr_old: ^u8, len_old: uint, len_new: uint): ^u8 {
return @ecall(3, 2, ReallocEcall.(7, pages(len_old), pages(len_new), ptr_old), @size_of(ReallocEcall))
}
@ -42,11 +41,11 @@ $memmove := fn(dest: ^u8, src: ^u8, len: uint): void {
}
SetEcall := struct align(1){.pad: u8; .count: uint; .len: uint; .src: ^u8; .dest: ^u8}
$memcopy := fn(dest: ^u8, src: u8, len: uint): void {
@ecall(3, 2, SetEcall.(4, len, 1, &src, dest), @size_of(SetEcall))
$memset := fn(dest: ^u8, src: u8, len: uint): void {
@ecall(3, 2, SetEcall.(5, len, 1, &src, dest), @size_of(SetEcall))
}
$exit := fn(code: u8): void {
}
$fill_rand := fn(dest: ^u8, len: uint): void @ecall(3, 4, dest, len)
$fill_rand := fn(dest: ^u8, len: uint): void return @ecall(3, 4, dest, len)
$fork := fn(): uint return @ecall(3, 7)

View file

@ -1,10 +1,24 @@
.{func} := Lib(current())
.{
LogEcall,
pages,
page_len,
alloc,
alloc_zeroed,
realloc,
dealloc,
memcopy,
memmove,
memset,
exit,
fill_rand,
fork,
} := Lib(current())
Target := enum {
.AbleOS;
}
$current := fn(): Target {
current := fn(): Target {
$if @target("ableos") {
return .AbleOS
} else {
@ -12,7 +26,7 @@ $current := fn(): Target {
}
}
$Lib := fn(target: Target): type {
Lib := fn(target: Target): type {
$match target {
.AbleOS => return @use("ableos.hb"),
}