replace _ with hide and _token_kind_str with rich debug.print rich formatting

This commit is contained in:
2026-07-15 21:17:25 +02:00
parent 6d024e6a0c
commit 73da0d95c4
10 changed files with 593 additions and 197 deletions
+12 -30
View File
@@ -1,5 +1,5 @@
import "@ffi/c"
import "@std"
import "@std/debug"
import "@std/mem"
import "@std/arraylist"
@@ -28,36 +28,18 @@ Token :: struct {
start int
}
_token_kind_str func(kind TokenKind) *c_char {
return match kind {
.ident: "ident"
.int: "int"
.float: "float"
.string: "string"
.equal: "equal"
.double_colon: "double_colon"
.left_paren: "left_paren"
.right_paren: "right_paren"
.left_curly: "left_curly"
.right_curly: "right_curly"
.newline: "newline"
.invalid: "invalid"
.eof: "eof"
}
}
_is_whitespace func(char u8) bool {
hide is_whitespace func(char u8) bool {
return char == ' ' or char == '\t' or char == '\n' or char == '\r'
}
_is_alpha func(char u8) bool {
hide is_alpha func(char u8) bool {
return match char {
'a'..'z', 'A'..'Z': true
else: false
}
}
_is_digit func(char u8) bool {
hide is_digit func(char u8) bool {
return match char {
'0'..'9': true
else: false
@@ -74,7 +56,7 @@ scan func(tokens @mut std.ArrayList(Token), input []u8) void ! mem.AllocError {
try arraylist.append(tokens, Token{ kind = .newline, start = cursor })
cursor += 1
continue
} else if _is_whitespace(char) {
} else if is_whitespace(char) {
cursor += 1
continue
}
@@ -87,10 +69,10 @@ scan func(tokens @mut std.ArrayList(Token), input []u8) void ! mem.AllocError {
}
# identifiers and keywords
if _is_alpha(char) or char == '_' {
if is_alpha(char) or char == '_' {
start :: cursor
cursor += 1
while cursor < input.len and (_is_alpha(input[cursor]) or _is_digit(input[cursor]) or input[cursor] == '_') {
while cursor < input.len and (is_alpha(input[cursor]) or is_digit(input[cursor]) or input[cursor] == '_') {
cursor += 1
}
try arraylist.append(tokens, Token{ kind = .ident, start = start })
@@ -98,10 +80,10 @@ scan func(tokens @mut std.ArrayList(Token), input []u8) void ! mem.AllocError {
}
# integers literals
if _is_digit(char) {
if is_digit(char) {
start :: cursor
cursor += 1
while cursor < input.len and _is_digit(input[cursor]) {
while cursor < input.len and is_digit(input[cursor]) {
cursor += 1
}
try arraylist.append(tokens, Token{ kind = .int, start = start })
@@ -159,11 +141,11 @@ main func() void {
defer arraylist.deinit(&tokens)
scan(&tokens, program) catch |_| {
_ = c.printf("failed to scan: out of memory\n")
return _
debug.print("failed to scan: out of memory\n", {})
return
}
for tokens.items |token| {
_ = c.printf("%s\n", _token_kind_str(token.kind))
debug.print("{}\n", { token.kind })
}
}
@@ -25,13 +25,13 @@ deinit func($T type, list @mut ArrayList(T)) void {
reserve func($T type, list @mut ArrayList(T), minimum_capacity usize) void ! mem.AllocError {
if minimum_capacity <= list.capacity {
return _
return
}
new_capacity usize = 8
if list.capacity >= 8 {
half usize :: div_trunc(list.capacity, 2)
if list.capacity > max_value(usize) - half {
half usize :: divtrunc!(list.capacity, 2)
if list.capacity > maxval!(usize) - half {
new_capacity = minimum_capacity
} else {
new_capacity = list.capacity + half
@@ -48,18 +48,18 @@ reserve func($T type, list @mut ArrayList(T), minimum_capacity usize) void ! mem
}
list.items = grown.ptr[..length]
list.capacity = new_capacity
return _
return
}
append func($T type, list @mut ArrayList(T), value T) void ! mem.AllocError {
length usize :: list.items.len
if length == max_value(usize) {
if length == maxval!(usize) {
return .out_of_memory
}
try reserve(list, length + 1)
list.items = list.items.ptr[..length + 1]
list.items[length] = value
return _
return
}
clear func($T type, list @mut ArrayList(T)) void {
+36
View File
@@ -0,0 +1,36 @@
c :: import "@ffi/c"
io :: import "@std/io"
hide write func(_ ?*mut anyopaque, _ io.WriteStream, bytes []u8) usize ! io.WriteError {
request usize = bytes.len
maximum usize :: usize(maxval!(c_long))
if request > maximum {
request = maximum
}
while true {
count c_long :: c.write(2, bytes.ptr, c_ulong(request))
if count >= 0 {
return usize(count)
}
if c.__error()^ != 4 {
return .write_failed
}
}
}
hide read func(_ ?*mut anyopaque, _ io.ReadStream, _ []mut u8) usize ! io.ReadError {
return .read_failed
}
hide vtable io.IoVTable :: io.IoVTable {
read = read,
write = write,
}
print func($format []u8, $Args type, args Args) void {
writer io.Writer :: io.Writer {
impl = io.Io {context = none, vtable = &vtable},
stream = .stderr,
}
io.print(writer, format, Args, args) catch |_| {}
}
+452
View File
@@ -0,0 +1,452 @@
c :: import "@ffi/c"
meta :: import "@std/meta"
ReadError :: enum {
read_failed
}
WriteError :: enum {
write_failed
no_progress
}
Io :: struct {
context ?*mut anyopaque
vtable @IoVTable
}
IoVTable :: struct {
read @func(context ?*mut anyopaque, stream ReadStream, buffer []mut u8) usize ! ReadError
write @func(context ?*mut anyopaque, stream WriteStream, bytes []u8) usize ! WriteError
}
ReadStream :: enum(c_int) {
stdin = 0
}
WriteStream :: enum(c_int) {
stdout = 1
stderr = 2
}
Reader :: struct {
impl Io
stream ReadStream
}
Writer :: struct {
impl Io
stream WriteStream
}
read func(reader Reader, buffer []mut u8) usize ! ReadError {
if buffer.len == 0 {
return 0
}
count usize :: try reader.impl.vtable.read(reader.impl.context, reader.stream, buffer)
if count > buffer.len {
return .read_failed
}
return count
}
write func(writer Writer, bytes []u8) usize ! WriteError {
if bytes.len == 0 {
return 0
}
count usize :: try writer.impl.vtable.write(writer.impl.context, writer.stream, bytes)
if count > bytes.len {
return .write_failed
}
return count
}
write_all func(writer Writer, bytes []u8) void ! WriteError {
offset usize = 0
while offset < bytes.len {
count usize :: write(writer, bytes[offset..]) catch |err| {
return err
}
if count == 0 {
return .no_progress
}
offset += count
}
return
}
hide write_integer_signed func(writer Writer, value i64, base u64, uppercase bool) void ! WriteError {
buffer [65]mut u8 = undefined
end usize = buffer.len
current i64 = value
while true {
digit_value i64 :: rem!(current, i64(base))
digit u8 = 0
if digit_value < 0 {
digit = u8(-digit_value)
} else {
digit = u8(digit_value)
}
end -= 1
if digit < 10 {
buffer[end] = '0' + digit
} else if uppercase {
buffer[end] = 'A' + digit - 10
} else {
buffer[end] = 'a' + digit - 10
}
current = divtrunc!(current, i64(base))
if current == 0 {
break
}
}
if value < 0 {
end -= 1
buffer[end] = '-'
}
try write_all(writer, buffer[end..])
return
}
hide write_integer_unsigned func(writer Writer, value u64, base u64, uppercase bool) void ! WriteError {
buffer [65]mut u8 = undefined
end usize = buffer.len
current u64 = value
while true {
digit u8 :: u8(rem!(current, base))
end -= 1
if digit < 10 {
buffer[end] = '0' + digit
} else if uppercase {
buffer[end] = 'A' + digit - 10
} else {
buffer[end] = 'a' + digit - 10
}
current = divtrunc!(current, base)
if current == 0 {
break
}
}
try write_all(writer, buffer[end..])
return
}
hide FormatTokenKind :: enum {
unused
literal
default
string
decimal
binary
octal
hex_lower
hex_upper
character
scientific
}
hide FormatToken :: struct {
kind FormatTokenKind
start usize
end usize
field []u8
}
hide parse_format func($N usize, $format []u8, $Args type) [N]mut FormatToken {
tokens [N]mut FormatToken = undefined
for (usize(0))..format.len |index| {
tokens[index] = FormatToken {kind = .unused, start = 0, end = 0, field = ""}
}
field_count usize = 0
match typeinfo!(Args) {
.record |record|: {
if !record.is_tuple {
compile_error!("io.print arguments must be a tuple")
}
field_count = record.fields.len
}
else: compile_error!("io.print arguments must be a tuple")
}
token_count usize = 0
argument_count usize = 0
literal_start usize = 0
cursor usize = 0
while cursor < format.len {
byte :: format[cursor]
if byte == '{' {
if cursor + 1 >= format.len {
compile_error!("io.print format has an unmatched '{'")
}
if cursor > literal_start {
tokens[token_count] = FormatToken {kind = .literal, start = literal_start, end = cursor, field = ""}
token_count += 1
}
next :: format[cursor + 1]
if next == '{' {
tokens[token_count] = FormatToken {kind = .literal, start = cursor, end = cursor + 1, field = ""}
token_count += 1
cursor += 2
literal_start = cursor
continue
}
kind FormatTokenKind = .default
width usize = 2
if next != '}' {
if cursor + 2 >= format.len or format[cursor + 2] != '}' {
compile_error!("io.print format expects a one-character specifier")
}
width = 3
if next == 's' {
kind = .string
} else if next == 'd' {
kind = .decimal
} else if next == 'b' {
kind = .binary
} else if next == 'o' {
kind = .octal
} else if next == 'x' {
kind = .hex_lower
} else if next == 'X' {
kind = .hex_upper
} else if next == 'c' {
kind = .character
} else if next == 'e' {
kind = .scientific
} else {
compile_error!("io.print format has an unknown specifier")
}
}
if argument_count >= field_count {
compile_error!("io.print format argument count does not match the tuple")
}
tokens[token_count] = FormatToken {
kind = kind,
start = 0,
end = 0,
field = format_field_name(Args, argument_count),
}
token_count += 1
argument_count += 1
cursor += width
literal_start = cursor
continue
}
if byte == '}' {
if cursor + 1 >= format.len or format[cursor + 1] != '}' {
compile_error!("io.print format has an unmatched '}'")
}
if cursor > literal_start {
tokens[token_count] = FormatToken {kind = .literal, start = literal_start, end = cursor, field = ""}
token_count += 1
}
tokens[token_count] = FormatToken {kind = .literal, start = cursor, end = cursor + 1, field = ""}
token_count += 1
cursor += 2
literal_start = cursor
continue
}
cursor += 1
}
if literal_start < format.len {
tokens[token_count] = FormatToken {kind = .literal, start = literal_start, end = format.len, field = ""}
}
if argument_count != field_count {
compile_error!("io.print format argument count does not match the tuple")
}
return tokens
}
hide format_field_name func($T type, index usize) []u8 {
match typeinfo!(T) {
.record |record|: return record.fields[index].name
else: compile_error!("io.print arguments must be a tuple")
}
}
hide write_integer func(writer Writer, $T type, value T, base u64, uppercase bool) void ! WriteError {
match typeinfo!(T) {
.integer: if minval!(T) < 0 {
try write_integer_signed(writer, i64(value), base, uppercase)
} else {
try write_integer_unsigned(writer, u64(value), base, uppercase)
}
else: compile_error!("io.print integer format requires an integer argument")
}
return
}
# ponytail: libc keeps float formatting small; replace it with a native shortest-roundtrip writer if locale independence matters.
hide write_float func(writer Writer, $T type, value T, scientific bool) void ! WriteError {
match typeinfo!(T) {
.float: {
buffer [64]mut u8 = undefined
count c_int = 0
if sizeof!(T) == 4 {
if scientific {
count = c.snprintf(ptrcast!(c_char, (&buffer).ptr), c_ulong(buffer.len), "%.8e", value)
} else {
count = c.snprintf(ptrcast!(c_char, (&buffer).ptr), c_ulong(buffer.len), "%.9g", value)
}
} else if scientific {
count = c.snprintf(ptrcast!(c_char, (&buffer).ptr), c_ulong(buffer.len), "%.16e", value)
} else {
count = c.snprintf(ptrcast!(c_char, (&buffer).ptr), c_ulong(buffer.len), "%.17g", value)
}
if count < 0 or usize(count) >= buffer.len {
return .write_failed
}
try write_all(writer, buffer[0..usize(count)])
}
else: compile_error!("io.print float format requires a float argument")
}
return
}
hide write_decimal func(writer Writer, $T type, value T) void ! WriteError {
match typeinfo!(T) {
.integer: try write_integer(writer, value, 10, false)
.float: try write_float(writer, value, false)
else: compile_error!("io.print '{d}' requires an integer or float argument")
}
return
}
hide write_character func(writer Writer, $T type, value T) void ! WriteError {
match typeinfo!(T) {
.integer: {
if minval!(T) < 0 or maxval!(T) > 255 {
compile_error!("io.print '{c}' requires an unsigned integer that fits in u8")
}
buffer [1]u8 = [u8(value)]
try write_all(writer, buffer[..])
}
else: compile_error!("io.print '{c}' requires an unsigned integer that fits in u8")
}
return
}
hide write_default func(writer Writer, $T type, value T) void ! WriteError {
match typeinfo!(T) {
.bool: if value {
try write_all(writer, "true")
} else {
try write_all(writer, "false")
}
.integer: try write_integer(writer, value, 10, false)
.float: try write_float(writer, value, false)
.array: try write_all(writer, value)
.pointer: try write_all(writer, value)
.slice: try write_all(writer, value)
.enum |enum_info|: {
inline for enum_info.fields |field| {
if value == field!(T, field.name) {
try write_all(writer, ".")
try write_all(writer, field.name)
return
}
}
return .write_failed
}
else: compile_error!("io.print '{}' does not support this argument type")
}
return
}
print func(
writer Writer,
$format []u8,
$Args type,
args Args,
) void ! WriteError {
inline for parse_format(format.len, format, Args) |token| {
if (token.kind == .unused) {
break
}
if (token.kind == .literal) {
try write_all(writer, format[token.start..token.end])
continue
}
if (token.kind == .string) {
try write_all(writer, field!(args, token.field))
continue
}
if (token.kind == .default) {
try write_default(writer, field!(args, token.field))
continue
}
if (token.kind == .decimal) {
try write_decimal(writer, field!(args, token.field))
continue
}
if (token.kind == .binary) {
try write_integer(writer, field!(args, token.field), 2, false)
continue
}
if (token.kind == .octal) {
try write_integer(writer, field!(args, token.field), 8, false)
continue
}
if (token.kind == .hex_lower) {
try write_integer(writer, field!(args, token.field), 16, false)
continue
}
if (token.kind == .hex_upper) {
try write_integer(writer, field!(args, token.field), 16, true)
continue
}
if (token.kind == .character) {
try write_character(writer, field!(args, token.field))
continue
}
try write_float(writer, field!(args, token.field), true)
}
return
}
hide system_read func(_ ?*mut anyopaque, stream ReadStream, buffer []mut u8) usize ! ReadError {
request usize = buffer.len
maximum usize :: usize(maxval!(c_long))
if request > maximum {
request = maximum
}
while true {
count c_long :: c.read(c_int(stream), buffer.ptr, c_ulong(request))
if count >= 0 {
return usize(count)
}
if c.__error()^ != 4 {
return .read_failed
}
}
}
hide system_write func(_ ?*mut anyopaque, stream WriteStream, bytes []u8) usize ! WriteError {
fd c_int :: c_int(stream)
request usize = bytes.len
maximum usize :: usize(maxval!(c_long))
if request > maximum {
request = maximum
}
while true {
count c_long :: c.write(fd, bytes.ptr, c_ulong(request))
if count >= 0 {
return usize(count)
}
if c.__error()^ != 4 {
return .write_failed
}
}
}
hide system_vtable IoVTable :: IoVTable {
read = system_read,
write = system_write,
}
hide system func() Io {
return Io {
context = none,
vtable = &system_vtable,
}
}
-122
View File
@@ -1,122 +0,0 @@
c :: import "@ffi/c"
ReadError :: enum {
read_failed
}
WriteError :: enum {
write_failed
no_progress
}
Io :: struct {
context ?*mut anyopaque
vtable @IoVTable
}
IoVTable :: struct {
read @func(context ?*mut anyopaque, stream ReadStream, buffer []mut u8) usize ! ReadError
write @func(context ?*mut anyopaque, stream WriteStream, bytes []u8) usize ! WriteError
}
ReadStream :: enum(c_int) {
stdin = 0
}
WriteStream :: enum(c_int) {
stdout = 1
stderr = 2
}
Reader :: struct {
impl Io
stream ReadStream
}
Writer :: struct {
impl Io
stream WriteStream
}
read func(reader Reader, buffer []mut u8) usize ! ReadError {
if buffer.len == 0 {
return 0
}
count usize :: try reader.impl.vtable.read(reader.impl.context, reader.stream, buffer)
if count > buffer.len {
return .read_failed
}
return count
}
write func(writer Writer, bytes []u8) usize ! WriteError {
if bytes.len == 0 {
return 0
}
count usize :: try writer.impl.vtable.write(writer.impl.context, writer.stream, bytes)
if count > bytes.len {
return .write_failed
}
return count
}
write_all func(writer Writer, bytes []u8) void ! WriteError {
offset usize = 0
while offset < bytes.len {
count usize :: write(writer, bytes[offset..]) catch |err| {
return err
}
if count == 0 {
return .no_progress
}
offset += count
}
return _
}
_system_read func(_ ?*mut anyopaque, stream ReadStream, buffer []mut u8) usize ! ReadError {
request usize = buffer.len
maximum usize :: usize(max_value(c_long))
if request > maximum {
request = maximum
}
while true {
count c_long :: c.read(c_int(stream), buffer.ptr, c_ulong(request))
if count >= 0 {
return usize(count)
}
if c.__error()^ != 4 {
return .read_failed
}
}
}
_system_write func(_ ?*mut anyopaque, stream WriteStream, bytes []u8) usize ! WriteError {
fd c_int :: c_int(stream)
request usize = bytes.len
maximum usize :: usize(max_value(c_long))
if request > maximum {
request = maximum
}
while true {
count c_long :: c.write(fd, bytes.ptr, c_ulong(request))
if count >= 0 {
return usize(count)
}
if c.__error()^ != 4 {
return .write_failed
}
}
}
_system_vtable IoVTable :: IoVTable {
read = _system_read,
write = _system_write,
}
_system func() Io {
return Io {
context = none,
vtable = &_system_vtable,
}
}
+39 -39
View File
@@ -41,33 +41,33 @@ eql func($T type, left, right []T) bool {
return true
}
_empty_storage [1]mut u64 = [0]
hide empty_storage [1]mut u64 = [0]
_empty_slice func($T type, count usize) []mut T {
pointer *mut T :: ptr_cast(T, (&_empty_storage).ptr)
hide empty_slice func($T type, count usize) []mut T {
pointer *mut T :: ptrcast!(T, (&empty_storage).ptr)
return pointer[..count]
}
empty func($T type) []mut T {
return _empty_slice(T, 0)
return empty_slice(T, 0)
}
alloc func($T type, allocator Allocator, count usize) []mut T ! AllocError {
if count == 0 {
return _empty_slice(T, 0)
return empty_slice(T, 0)
}
element_size usize :: size_of(T)
element_size usize :: sizeof!(T)
if element_size == 0 {
return _empty_slice(T, count)
return empty_slice(T, count)
}
if count > div_trunc(max_value(usize), element_size) {
if count > divtrunc!(maxval!(usize), element_size) {
return .out_of_memory
}
memory ?*mut u8 = raw_alloc(allocator, count * element_size, align_of(T))
memory ?*mut u8 = raw_alloc(allocator, count * element_size, alignof!(T))
if memory |bytes| {
pointer *mut T :: ptr_cast(T, bytes)
pointer *mut T :: ptrcast!(T, bytes)
return pointer[..count]
}
return .out_of_memory
@@ -79,21 +79,21 @@ realloc func($T type, allocator Allocator, memory []mut T, new_count usize) []mu
}
if new_count == 0 {
free(allocator, memory)
return _empty_slice(T, 0)
return empty_slice(T, 0)
}
element_size usize :: size_of(T)
element_size usize :: sizeof!(T)
if element_size == 0 {
return _empty_slice(T, new_count)
return empty_slice(T, new_count)
}
if new_count > div_trunc(max_value(usize), element_size) {
if new_count > divtrunc!(maxval!(usize), element_size) {
return .out_of_memory
}
old_memory ?*mut u8 = none
old_size usize = 0
if memory.len != 0 {
old_memory = ptr_cast(u8, memory.ptr)
old_memory = ptrcast!(u8, memory.ptr)
old_size = memory.len * element_size
}
resized ?*mut u8 = raw_realloc(
@@ -101,31 +101,31 @@ realloc func($T type, allocator Allocator, memory []mut T, new_count usize) []mu
old_memory,
old_size,
new_count * element_size,
align_of(T),
alignof!(T),
)
if resized |bytes| {
pointer *mut T :: ptr_cast(T, bytes)
pointer *mut T :: ptrcast!(T, bytes)
return pointer[..new_count]
}
return .out_of_memory
}
free func($T type, allocator Allocator, memory []mut T) void {
if memory.len != 0 and size_of(T) != 0 {
raw_free(allocator, ptr_cast(u8, memory.ptr), memory.len * size_of(T), align_of(T))
if memory.len != 0 and sizeof!(T) != 0 {
raw_free(allocator, ptrcast!(u8, memory.ptr), memory.len * sizeof!(T), alignof!(T))
}
}
_malloc_alignment usize :: 16 # ponytail: aarch64-macos libc malloc alignment assumption.
hide malloc_alignment usize :: 16 # ponytail: aarch64-macos libc malloc alignment assumption.
_power_of_two func(value usize) bool {
hide power_of_two func(value usize) bool {
if value == 0 {
return false
}
current usize = value
while current > 1 {
half usize = div_trunc(current, 2)
half usize = divtrunc!(current, 2)
if half * 2 != current {
return false
}
@@ -135,13 +135,13 @@ _power_of_two func(value usize) bool {
return true
}
_c_alloc func(_ ?*mut anyopaque, size usize, alignment usize) ?*mut u8 {
if _power_of_two(alignment) == false {
hide c_alloc func(_ ?*mut anyopaque, size usize, alignment usize) ?*mut u8 {
if power_of_two(alignment) == false {
return none
}
if alignment <= _malloc_alignment {
return ptr_cast(u8, c.malloc(c_ulong(size)))
if alignment <= malloc_alignment {
return ptrcast!(u8, c.malloc(c_ulong(size)))
}
memory [1]mut ?*mut anyopaque = [none]
@@ -150,11 +150,11 @@ _c_alloc func(_ ?*mut anyopaque, size usize, alignment usize) ?*mut u8 {
return none
}
return ptr_cast(u8, memory[0])
return ptrcast!(u8, memory[0])
}
_c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
if _power_of_two(alignment) == false {
hide c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
if power_of_two(alignment) == false {
return none
}
@@ -164,11 +164,11 @@ _c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usi
}
if memory |old_memory| {
if alignment <= _malloc_alignment {
return ptr_cast(u8, c.realloc(old_memory, c_ulong(new_size)))
if alignment <= malloc_alignment {
return ptrcast!(u8, c.realloc(old_memory, c_ulong(new_size)))
}
new_memory ?*mut u8 = _c_alloc(none, new_size, alignment)
new_memory ?*mut u8 = c_alloc(none, new_size, alignment)
if new_memory |new_bytes| {
copy_size usize = old_size
if new_size < copy_size {
@@ -183,20 +183,20 @@ _c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usi
return new_memory
}
return _c_alloc(none, new_size, alignment)
return c_alloc(none, new_size, alignment)
}
_c_free func(_ ?*mut anyopaque, memory ?*mut u8, _ usize, _ usize) void {
hide c_free func(_ ?*mut anyopaque, memory ?*mut u8, _ usize, _ usize) void {
c.free(memory)
}
_c_vtable AllocatorVTable :: AllocatorVTable {
alloc = _c_alloc,
realloc = _c_realloc,
free = _c_free,
hide c_vtable AllocatorVTable :: AllocatorVTable {
alloc = c_alloc,
realloc = c_realloc,
free = c_free,
}
c_allocator Allocator :: Allocator {
context = none,
vtable = &_c_vtable,
vtable = &c_vtable,
}
+41
View File
@@ -0,0 +1,41 @@
Layout :: enum {
auto
c
}
FieldInfo :: struct {
name []u8
type type
index usize
}
RecordInfo :: struct {
name ?[]u8
fields []FieldInfo
is_tuple bool
layout Layout
}
EnumInfo :: struct {
fields []FieldInfo
}
TypeInfo :: union(enum) {
invalid void
void void
anyopaque void
bool void
integer void
float void
array void
pointer void
slice void
range void
optional void
function void
enum EnumInfo
record RecordInfo
union void
fallible void
distinct void
}
+5
View File
@@ -0,0 +1,5 @@
io :: import "@std/io"
Init :: struct {
io io.Io
}
+2
View File
@@ -1,3 +1,5 @@
import "io"
import "arraylist"
Io :: alias io.Io
ArrayList :: alias arraylist.ArrayList