more target stuff. ableos buffer ipc & device tree. update hblang, new tests. minor additions.

This commit is contained in:
koniifer 2025-03-19 17:06:50 +00:00
parent 28afaac383
commit 5717bd9157
12 changed files with 234 additions and 7 deletions

6
build
View file

@ -8,7 +8,7 @@ readonly LILY_TEST_DIR="${LILY_TEST_DIR:-$LILY_SCRIPT_DIR/hbc-tests}"
readonly LILY_BUILD_DIR="${LILY_BUILD_DIR:-$LILY_SCRIPT_DIR/out}"
readonly HBLANG_GIT="https://git.ablecorp.us/mlokis/hblang"
readonly HBLANG_COMMIT="4bd1d3a4e1040b36f9185cf3ebedb99b1ad17ac6"
readonly HBLANG_COMMIT="dd46d8a2d505ea8611f6c5b44c08131bb3abf220"
readonly HBC_FLAGS="--path-projection lily $LILY_SRC_DIR/lib.hb ${HBC_FLAGS:-}"
readonly HBC_BINARY="hbc"
readonly HBC_TESTS="${HBC_TESTS:-0}"
@ -83,8 +83,8 @@ main() {
result_file=$(mktemp)
find "$LILY_TEST_DIR" -type f >"$tmpfile"
while IFS= read -r file; do
# test_name=$(basename "$file" .hb)
test_name=$(echo "$(basename -- "$(dirname -- "$file")")/$(basename -- "$file" .hb)" | tr '/' '.')
test_name=$(realpath -s --relative-to="$LILY_TEST_DIR" "$file" | tr '/' '.')
test_name="${test_name%.*}"
do_test 2>/dev/null &
done <"$tmpfile"
rm -f "$tmpfile"

View file

@ -7,3 +7,4 @@ a collection of guidelines for programmers to use to create lily-compatible impl
the following files define the spec:
- [allocators](./spec/alloc.md)
- [iterators](./spec/iter.md)
- [tests](./spec/tests.md)

22
docs/spec/tests.md Normal file
View file

@ -0,0 +1,22 @@
# tests
1. tests should attempt to be meaningful in some way, patching targeting bugs, or behaviours.
2. tests should be written as hblang vendored tests. all tests can be run with `HBC_TESTS=1 ./build`. status of failed tests should be emitted to `out/subdir.test-name.test`
3. tests should be written as one of:
- part of an exhaustive folder covering all aspects of a datastructure / module. e.g:
```
lily/
some-module/
func1.hb
struct/
method1.hb
method2.hb
other-module/
...
...
lang/
...
```
- one-and-done tests for locating bugs (which should be kept after the bug is patched, unless it is made obsolete by an exhaustive test)

View file

@ -0,0 +1,17 @@
expectations := .{
return_value: 0,
}
secondary := fn(): uint {
return inlined()
}
// ! if $ is removed this works.
// ! if this function is moved above `secondary`, this works.
$inlined := fn(): uint {
return 0
}
main := fn(): uint {
return secondary()
}

View file

@ -0,0 +1,14 @@
expectations := .{
return_value: 0,
}
lily.{Type} := @use("../../src/lib.hb")
main := fn(): uint {
// ! (compiler) bug: "the functions types most likely depend on it being evaluated"
$match Type(uint).kind() {
.Builtin => {},
_ => return 1,
}
return 0
}

14
hbc-tests/lily/type-of.hb Normal file
View file

@ -0,0 +1,14 @@
expectations := .{
return_value: 0,
}
lily.{TypeOf} := @use("../../src/lib.hb")
main := fn(): uint {
// ! (compiler) bug: "the functions types most likely depend on it being evaluated"
$match TypeOf(@as(uint, 1)).kind() {
.Builtin => {},
_ => return 1,
}
return 0
}

86
src/ipc.hb Normal file
View file

@ -0,0 +1,86 @@
lily.{target, mem, Type} := @use("lib.hb")
Buffer := struct {
.id: uint
Self := @CurrentScope()
new := fn(name: ?[]u8): ?Self {
id: uint = 0
if name == null {
id = target.buf_create()
} else {
id = target.buf_create_named(name.?)
}
if id == 0 return null
return Self.from_raw(id)
}
search := fn(name: []u8): ?Self {
id := target.buf_search(name)
if id == 0 return null
return Self.from_raw(id)
}
deinit := fn(self: ^Self): void {
target.buf_destroy(self.id)
self.* = idk
}
$from_raw := fn(id: uint): Self {
return .(id)
}
$await := fn(self: ^Self): void {
target.buf_await(self.id)
}
$write := fn(self: ^Self, val: @Any()): void {
$match Type(@TypeOf(val)).kind() {
.Pointer => target.buf_write(self.id, mem.as_bytes(val)),
.Slice => target.buf_write(self.id, mem.as_bytes(val)),
_ => target.buf_write(self.id, mem.as_bytes(&val)),
}
}
$read_into := fn(self: ^Self, slice: []u8): void {
target.buf_read(self.id, slice)
}
$read := fn(self: ^Self, $T: type): T {
buf: T = idk
target.buf_read(self.id, mem.as_bytes(&buf))
return buf
}
}
Channel := struct {
.local: Buffer;
.remote: Buffer
Self := @CurrentScope()
new := fn(local_name: ?[]u8, remote_name: ?[]u8): ?Self {
local := Buffer.new(local_name)
if local == null return null
remote := Buffer.new(remote_name)
if remote == null return null
return .(local.?, remote.?)
}
$deinit := fn(self: ^Self): void {
self.local.deinit()
self.remote.deinit()
self.* = idk
}
$to_remote := fn(self: Self): Self {
return .(self.remote, self.local)
}
$from_raw := fn(local_id: uint, remote_id: uint): Self {
return .(Buffer.from_raw(local_id), Buffer.from_raw(remote_id))
}
$await := fn(self: ^Self): void {
self.local.await()
}
$write := fn(self: ^Self, val: @Any()): void {
self.remote.write(val)
}
$read_into := fn(self: ^Self, slice: []u8): void {
self.local.read_into(slice)
}
$read := fn(self: ^Self, $T: type): T {
return self.local.read(T)
}
}

View file

@ -1,7 +1,9 @@
.{Type, TypeOf} := @use("type.hb")
process := @use("process.hb")
target := @use("target/lib.hb")
alloc := @use("alloc/lib.hb")
iter := @use("iter.hb")
ipc := @use("ipc.hb")
mem := @use("mem.hb")
log := @use("log.hb")
fmt := @use("fmt.hb")

View file

@ -34,6 +34,17 @@ $as_bytes := fn(v: @Any()): []u8 {
}
}
$to_owned := fn($T: type, slice: []u8): T {
$match Type(T).kind() {
.Array => {
ret: T = idk
copy(ret[..], slice)
return ret
},
_ => @error("todo: write this error"),
}
}
$overlaps := fn(lhs: []u8, rhs: []u8): bool {
return lhs.ptr < rhs.ptr + rhs.len & rhs.ptr < lhs.ptr + lhs.len
}

24
src/process.hb Normal file
View file

@ -0,0 +1,24 @@
lily.{target} := @use("lib.hb")
ProcessID := fn(): type {
$match target.current() {
.AbleOS => return struct {
.host_id: uint;
.id: uint;
},
}
}
$HOST_ID_PLACEHOLDER := 0
$spawn := fn(executable: []u8): ProcessID() {
raw := target.proc_spawn(executable)
// todo: this
return .(HOST_ID_PLACEHOLDER, raw)
}
$fork := fn(): ProcessID() {
raw := target.proc_fork()
// todo: this
return .(HOST_ID_PLACEHOLDER, raw)
}

View file

@ -45,9 +45,37 @@ $memfill := fn(dest: ^u8, src: ^u8, count: uint, len: uint): void {
$exit := fn(code: u8): void {
}
$fill_rand := fn(dest: ^u8, len: uint): void return @ecall(3, 4, dest, len)
$fork := fn(): uint return @ecall(3, 7)
$rand_fill := fn(dest: ^u8, len: uint): void return @ecall(3, 4, dest, len)
$proc_fork := fn(): uint return @ecall(3, 7)
$proc_spawn := fn(executable: []u8): uint {
return @ecall(3, 6, executable.ptr, executable.len)
}
$dt_get := fn($T: type, query: []u8): T {
return @ecall(3, 5, query.ptr, query.len)
}
BufferEcall := struct align(1){.operation: u8; .str_ptr: ^u8; .str_len: uint}
$buf_create_named := fn(name: []u8): uint {
return @ecall(3, 0, BufferEcall.(0, name.ptr, name.len), @size_of(BufferEcall))
}
$buf_create := fn(): uint {
return @ecall(1, 0)
}
$buf_destroy := fn(id: uint): void {
return @ecall(2, id)
}
$buf_search := fn(name: []u8): uint {
return @ecall(3, 0, BufferEcall.(3, name.ptr, name.len), @size_of(BufferEcall))
}
$buf_await := fn(id: uint): void {
return @ecall(7, id)
}
$buf_read := fn(id: uint, mmap: []u8): void {
return @ecall(4, id, mmap.ptr, mmap.len)
}
$buf_write := fn(id: uint, mmap: []u8): void {
return @ecall(3, id, mmap.ptr, mmap.len)
}

View file

@ -11,8 +11,16 @@ lib.{
memset,
memfill,
exit,
fill_rand,
fork,
rand_fill,
proc_fork,
proc_spawn,
buf_create_named,
buf_create,
buf_destroy,
buf_search,
buf_await,
buf_read,
buf_write,
} := Lib(current())
Target := enum {