diff --git a/build b/build index 53c3695..23f8280 100755 --- a/build +++ b/build @@ -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" diff --git a/docs/spec.md b/docs/spec.md index 1a49d4e..85fc12b 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -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) diff --git a/docs/spec/tests.md b/docs/spec/tests.md new file mode 100644 index 0000000..e024d69 --- /dev/null +++ b/docs/spec/tests.md @@ -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) diff --git a/hbc-tests/lang/inline-declaration-order.hb b/hbc-tests/lang/inline-declaration-order.hb new file mode 100644 index 0000000..89c6e72 --- /dev/null +++ b/hbc-tests/lang/inline-declaration-order.hb @@ -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() +} \ No newline at end of file diff --git a/hbc-tests/lily/type-kindof.hb b/hbc-tests/lily/type-kindof.hb new file mode 100644 index 0000000..5152717 --- /dev/null +++ b/hbc-tests/lily/type-kindof.hb @@ -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 +} \ No newline at end of file diff --git a/hbc-tests/lily/type-of.hb b/hbc-tests/lily/type-of.hb new file mode 100644 index 0000000..70ecc2b --- /dev/null +++ b/hbc-tests/lily/type-of.hb @@ -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 +} \ No newline at end of file diff --git a/src/ipc.hb b/src/ipc.hb new file mode 100644 index 0000000..57a81e0 --- /dev/null +++ b/src/ipc.hb @@ -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) + } +} diff --git a/src/lib.hb b/src/lib.hb index 9d2249a..042c828 100644 --- a/src/lib.hb +++ b/src/lib.hb @@ -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") diff --git a/src/mem.hb b/src/mem.hb index 54834a5..c4d20ca 100644 --- a/src/mem.hb +++ b/src/mem.hb @@ -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 } diff --git a/src/process.hb b/src/process.hb new file mode 100644 index 0000000..012e9d4 --- /dev/null +++ b/src/process.hb @@ -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) +} diff --git a/src/target/ableos.hb b/src/target/ableos.hb index 5f51412..a95923c 100644 --- a/src/target/ableos.hb +++ b/src/target/ableos.hb @@ -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) +} diff --git a/src/target/lib.hb b/src/target/lib.hb index e707f21..823d6a7 100644 --- a/src/target/lib.hb +++ b/src/target/lib.hb @@ -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 {