start fmt, type. impl more of mem. add some tests.

This commit is contained in:
koniifer 2025-03-08 21:53:25 +00:00
parent bbd1565fc9
commit 53ae50f3b9
7 changed files with 165 additions and 9 deletions

13
hbc-tests/lang/anytype.hb Normal file
View file

@ -0,0 +1,13 @@
expectations := .{
return_value: 0,
}
// ! (compiler) bug: parser has no clue what to do with this
// ! additionally, if $a: @Any(), then 'type can not be constructed as integer literal' referring to 'a'
func := fn(a: @Any(), b: @TypeOf(a)): uint {
return 0
}
main := fn(): uint {
return func()
}

View file

@ -0,0 +1,10 @@
expectations := .{
return_value: 0,
}
main := fn(): uint {
ptr0: ^u8 = @bit_cast(0)
// ! (compiler) bug: cannot offset ptr by int
ptr1 := ptr0 + 100
if ptr0 != @bit_cast(100) return 1
}

15
main.hb
View file

@ -1,8 +1,15 @@
lily.{target, log, mem} := @use("lily")
lily.{target, log, mem, fmt} := @use("lily")
b: []u8 = idk
main := fn(): void {
a := "Hello, World!"
b := mem.bytes(a).take(5).for_each(fn(x: u8): void {
if x % 2 == 0 log.info("even") else log.info("odd")
a := target.alloc(1000)
if a == null die
b = @as(^u8, @bit_cast(a.?))[0..1000]
mem.bytes(mem.reverse("Hello, World!")[1..]).take(5).for_each(fn(x: u8): void {
// len := fmt.fmt_int(b, x, 16)
b[0] = x
log.info(b[0..1])
// mem.set(b.ptr, 0, len)
})
}

62
src/fmt.hb Normal file
View file

@ -0,0 +1,62 @@
.{target, Type, TypeOf, mem} := @use("lib.hb")
// ! uint only for now, due to broken @Any(). just upcast.
fmt_int := fn(buf: []u8, v: uint, radix: uint): uint {
if radix == 0 {
mem.copy(buf.ptr, @bit_cast(&v), @size_of(@TypeOf(v)))
return @size_of(@TypeOf(v))
}
prefix_len := 0
// ! see above comment ^^
// if TypeOf(v).is_signed_int() & v < 0 {
// v = -v
// // 0x2D == '-'
// buf[0] = 0x2D
// prefix_len += 1
// }
if radix == 16 {
// ! @bit_cast() for now, due to broken ptr offsets
mem.copy(buf.ptr + @bit_cast(prefix_len), "0x".ptr, 2)
prefix_len += 2
} else if radix == 8 {
mem.copy(buf.ptr + @bit_cast(prefix_len), "0o".ptr, 2)
prefix_len += 2
} else if radix == 2 {
mem.copy(buf.ptr + @bit_cast(prefix_len), "0b".ptr, 2)
prefix_len += 2
}
if v == 0 {
// 0x30 == '0'
buf[prefix_len] = 0x30
return prefix_len + 1
}
i := prefix_len
loop if v <= 0 break else {
remainder := v % radix
// todo: complain about /= not existing
v = v / radix
if remainder > 9 {
// 0x41 == 'A'
buf[i] = @int_cast(remainder - 10 + 0x41)
} else {
// 0x30 == '0'
buf[i] = @int_cast(remainder + 0x30)
}
i += 1
}
_ = mem.reverse(buf[prefix_len..i])
return i
}
fmt_bool := fn(buf: []u8, v: bool): uint {
if v {
mem.copy(buf.ptr, "true".ptr, 4)
return 4
} else {
mem.copy(buf.ptr, "false".ptr, 5)
return 5
}
}

View file

@ -1,3 +1,10 @@
.{Type, TypeOf} := @use("type.hb")
target := @use("target/lib.hb")
iter := @use("iter.hb")
mem := @use("mem.hb")
log := @use("log.hb")
fmt := @use("fmt.hb")
Version := struct {
.major: uint;
.minor: uint;
@ -5,8 +12,3 @@ Version := struct {
}
$VERSION := Version.(0, 1, 0)
target := @use("target/lib.hb")
iter := @use("iter.hb")
mem := @use("mem.hb")
log := @use("log.hb")

View file

@ -23,6 +23,20 @@ equals := fn(lhs: []u8, rhs: []u8): bool {
return true
}
reverse := fn(slice: []u8): []u8 {
if slice.len == 0 return slice
j := slice.len - 1
i := 0
temp: u8 = 0
loop if i < j {
temp = slice[i]
slice[i] = slice[j]
slice[j] = temp
i += 1
j -= 1
} else return slice
}
$bytes := fn(slice: []u8): Iterator(struct {
.slice: []u8

48
src/type.hb Normal file
View file

@ -0,0 +1,48 @@
// ! broken, due to broken @Any(). just upcast.
TypeOf := fn(T: @Any()): type return Type(@TypeOf(T))
Type := fn($T: type): type return struct {
USize := fn(): type {
if @size_of(T) == 0 @error(T, "(size=", @size_of(T), ")", "is too small to fit into an integer.")
if @size_of(T) == 1 return u8 else if @size_of(T) == 2 return u16 else if @size_of(T) <= 4 return u32 else if @size_of(T) <= 8 return uint else @error(T, "(size=", @size_of(T), ")", "is too big to fit into an integer.")
}
Child := fn(): type {
return Type(@ChildOf(T))
}
This := fn(): type {
return T
}
$name := fn(): []u8 {
return @name_of(T)
}
$is_bool := fn(): bool {
return T == bool
}
$is_unsigned_int := fn(): bool {
return T == uint | T == u8 | T == u16 | T == u32
}
$is_signed_int := fn(): bool {
return T == int | T == i8 | T == i16 | T == i32
}
$is_int := fn(): bool {
return @CurrentScope().is_unsigned_int() | @CurrentScope().is_signed_int()
}
$is_float := fn(): bool {
return T == f32 | T == f64
}
$len := fn(): uint {
return @len_of(T)
}
$align := fn(): uint {
return @align_of(T)
}
$size := fn(): uint {
return @size_of(T)
}
$bits := fn(): @CurrentScope().USize() {
return @size_of(T) << 3
}
$bitmask := fn(): @CurrentScope().USize() {
return ~0
}
}