reintroduce spec

This commit is contained in:
koniifer 2025-03-09 15:12:15 +00:00
parent 138060e27a
commit c7bb6be547
8 changed files with 84 additions and 13 deletions

View file

@ -1,10 +1,10 @@
# Lily
# lily
an attempt at a cross-platform standard library for hblang.
> [!CAUTION]
> [!caution]
> 0.1.x currently only supports ableos target, as the new hblang compiler does not support native compilation yet.
> [!IMPORTANT]
> [!important]
> all features, targets, modules, etc, are provisional and may be subject to change or deletion
# working Features

4
TODO.md Normal file
View file

@ -0,0 +1,4 @@
see [here](<README.md#todo-features>) for feature todos.<br>
this is strictly for dev todos.
- replace `idk` in places with Type(T).uninit()

9
docs/spec.md Normal file
View file

@ -0,0 +1,9 @@
# lily specification
> [!important]
> before lily version 1.0.0, the spec is provisional and may be subject to change.
a collection of guidelines for programmers to use to create lily-compatible implementations.
the following files define the spec:
- [allocators](./spec/alloc.md)
- [iterators](./spec/iter.md)

26
docs/spec/alloc.md Normal file
View file

@ -0,0 +1,26 @@
# allocators
1. all spec compliant allocators should implement:
> unless otherwise stated, functions can be optionally inline.<br>
> names of arguments are up to programmer discretion.<br>
> names and signature of functions must be identical to shown below.
```rust
Allocator := struct {
new := fn(): Self
/// prepare to be deallocated.
deinit := fn(self: ^Self): void
/// should return null on failure.
/// should dealloc any intermediate allocations on failure.
alloc := fn(self: ^Self, $T: type, count: uint): ?[]T
/// same behaviour as alloc, except:
/// must be zeroed.
alloc_zeroed := fn(self: ^Self, $T: type, count: uint): ?[]T
/// same behaviour as alloc, except:
/// must move data to new allocation,
/// must ensure the old allocation is freed at some point.
realloc := fn(self: ^Self, $T: type, ptr: ^T, new_count: uint): ?[]T
/// must dealloc or schedule the freeing of the given allocation
dealloc := fn(self: ^Self, $T: type, ptr: ^T): void
}
```

11
docs/spec/iter.md Normal file
View file

@ -0,0 +1,11 @@
# iterators
> [!note]
> spec tbd
```rust
iter.{Iterator, Next} := @use("lily").iter
Iterable := struct {
next := fn(self: ^Self): Next(T)
}

View file

@ -13,7 +13,7 @@ main := fn(): void {
// i += 1
// }
b = alloc.Arena.alloc(&arena, u8, 1000).?
b = alloc.Arena.alloc_zeroed(&arena, u8, 1000).?
mem.bytes(mem.reverse("Hello, World!")[1..]).take(5).for_each(fn(x: u8): void {
len := fmt.fmt_int(b, x, 16)

View file

@ -3,15 +3,17 @@ lily.{target, mem} := @use("../lib.hb")
AllocationHeader := struct {
.cap: uint;
.len: uint;
.next: ?^AllocationHeader
.next: ?^Self
new := fn(size: uint): ?^AllocationHeader {
total_size := size + @size_of(AllocationHeader)
ptr: ?^AllocationHeader = @bit_cast(target.alloc(total_size))
Self := @CurrentScope()
$new := fn(size: uint): ?^Self {
total_size := size + @size_of(Self)
ptr: ?^Self = @bit_cast(target.alloc(total_size))
if ptr == null return null
header: ^AllocationHeader = @bit_cast(ptr)
header: ^Self = @bit_cast(ptr)
header.* = .(
target.pages(total_size) * target.page_len() - @size_of(AllocationHeader),
target.pages(total_size) * target.page_len() - @size_of(Self),
0,
null,
)
@ -22,11 +24,13 @@ AllocationHeader := struct {
Arena := struct {
.allocation: ?^AllocationHeader
Self := @CurrentScope()
$new := fn(): @CurrentScope() {
return .(null)
}
// todo: handle alignment
alloc := fn(self: ^Arena, $T: type, count: uint): ?[]T {
alloc := fn(self: ^Self, $T: type, count: uint): ?[]T {
size := mem.size(T, count)
header: ^AllocationHeader = idk
if self.allocation == null {
@ -51,7 +55,19 @@ Arena := struct {
}
return @as(^T, @bit_cast(@as(^u8, @bit_cast(header + 1)) + header.len - size))[0..count]
}
deinit := fn(self: ^Arena): void {
$alloc_zeroed := fn(self: ^Self, $T: type, count: uint): ?[]T {
// todo: change back after struct method fix
slice := Self.alloc(self, T, count)
if slice == null return null
mem.set(slice.?.ptr, 0, slice.?.len)
return slice
}
$realloc := fn(self: ^Self, $T: type, ptr_old: ^T, count_new: uint): ?[]T {
@error("todo: ", Self.realloc)
return null
}
$dealloc := fn(self: ^Self, $T: type, ptr: ^T): void {}
deinit := fn(self: ^Self): void {
if self.allocation == null {
lily.log.error("fixme: double free arena. can't fix due to compiler.")
die

View file

@ -4,7 +4,12 @@ Vec := fn(T: type, A: type): type return struct {
.cap: uint;
.allocator: ^A
new := fn(allocator: ^A): @CurrentScope() {
Self := @CurrentScope()
$new := fn(allocator: ^A): Self {
return .(idk, 0, allocator)
}
deinit := fn(self: ^Self): void {
}
}