static u32 debug_get_file_id(OnyxWasmModule *mod, const char *name) {
assert(mod && mod->debug_context);
+ // This is not correct at all, but it will not cause an error.
+ if (!name) return 0;
+
i32 index = shgeti(mod->debug_context->file_info, name);
if (index == -1) {
u32 id = mod->debug_context->next_file_id++;
// This is incorrect, but because there is not an "old size",
// this is the best possible.
- memory :: package core.memory
- memory.copy(newptr, oldptr, size);
+ core.memory.copy(newptr, oldptr, size);
return newptr;
}
};
}
-#match (package core.alloc).as_allocator make_allocator
+#match core.alloc.as_allocator make_allocator
make_allocator :: (rs: ^ArenaState) -> Allocator {
return Allocator.{
func = arena_alloc_proc,
auto :: #match {
macro (size := 32 * 1024, $dest: Code = #(context.allocator)) {
- alloc :: package core.alloc
+ use core.alloc {arena, heap_allocator}
- arena := alloc.arena.make(alloc.heap_allocator, size);
+ arena := arena.make(heap_allocator, size);
old_allocator := #unquote dest;
- (#unquote dest) = alloc.arena.make_allocator(^arena);
+ (#unquote dest) = arena.make_allocator(^arena);
defer {
- alloc.arena.free(^arena);
+ arena.free(^arena);
(#unquote dest) = old_allocator;
}
},
hs.set->free();
}
-#match (package core.alloc).as_allocator auto_heap_make_allocator
+#match core.alloc.as_allocator auto_heap_make_allocator
auto_heap_make_allocator :: (hs: ^AutoHeapState) -> Allocator {
return Allocator.{
func = auto_heap_alloc_proc,
auto :: #match {
macro () {
- alloc :: package core.alloc
+ use core.alloc {heap}
- auto_heap := alloc.heap.auto_heap_make();
+ auto_heap := heap.auto_heap_make();
old_allocator := context.allocator;
- context.allocator = alloc.heap.auto_heap_make_allocator(^auto_heap);
+ context.allocator = heap.auto_heap_make_allocator(^auto_heap);
defer {
- alloc.heap.auto_heap_free(^auto_heap);
+ heap.auto_heap_free(^auto_heap);
context.allocator = old_allocator;
}
},
};
}
-#match (package core.alloc).as_allocator make_allocator
+#match core.alloc.as_allocator make_allocator
make_allocator :: (fa_data: ^FixedAllocatorData) -> Allocator {
return Allocator.{
func = fixed_allocator_proc,
// Enable this to enable checking for invalid blocks and other corruptions
// that may happen on the heap, with the added overhead of checking that
// on every alloc/resize/free.
-Enable_Debug :: #defined( (package runtime.vars).Enable_Heap_Debug )
+Enable_Debug :: #defined( runtime.vars.Enable_Heap_Debug )
// This is the implementation for the general purpose heap allocator.
// It is a simple bump allocator, with a free list. It is not very good
#load "core/intrinsics/wasm"
#if runtime.Multi_Threading_Enabled {
- sync :: package core.sync
+ use core {sync}
heap_mutex: sync.Mutex
}
heap_state.next_alloc = cast(rawptr) (cast(uintptr) __heap_start + 8);
heap_state.remaining_space = (memory_size() << 16) - cast(u32) __heap_start;
- use package core.alloc { heap_allocator }
+ use core.alloc { heap_allocator }
heap_allocator.data = ^heap_state;
heap_allocator.func = heap_alloc_proc;
}
#local {
- use package core.intrinsics.wasm {
+ use core.intrinsics.wasm {
memory_size, memory_grow,
memory_copy, memory_fill,
}
- memory :: package core.memory
- math :: package core.math
- runtime :: package runtime
+ use core {memory, math}
uintptr :: #type u32
allocator := cast(^Allocator) data;
res := allocator.func(allocator.data, aa, size, align, oldptr);
- use package core { printf }
+ use core { printf }
printf("{} with size {}, align {}, oldptr {} returns {}\n",
Allocation_Action_Strings[cast(u32) aa], size, align, oldptr, res);
};
}
-#match (package core.alloc).as_allocator make_allocator
+#match core.alloc.as_allocator make_allocator
make_allocator :: (pool: ^PoolAllocator($Elem)) -> Allocator {
return Allocator.{
func = #solidify pool_allocator_proc { Elem = Elem },
};
}
-#match (package core.alloc).as_allocator make_allocator
+#match core.alloc.as_allocator make_allocator
make_allocator :: (rs: ^RingState) -> Allocator {
return .{
func = ring_alloc_proc,
package core.arg_parse
-use package core
+use core
arg_parse :: (c_args: [] cstr, output: any) -> bool {
arg_iter := iter.as_iterator(c_args)
|> iter.map((x) => string.from_cstr(*x));
defer arg_iter.close(arg_iter.data);
- use package runtime.info;
+ use runtime.info;
ptr_type := cast(^Type_Info_Pointer) get_type_info(output.type);
if ptr_type.kind != .Pointer do return false;
#overload
__make_overload :: macro (_: ^[..] $T, allocator := context.allocator) -> [..] T {
- return (package core.array).make(T, allocator=allocator);
+ return core.array.make(T, allocator=allocator);
}
#overload
__make_overload :: macro (_: ^[..] $T, capacity: u32, allocator := context.allocator) -> [..] T {
- return (package core.array).make(T, capacity, allocator);
+ return core.array.make(T, capacity, allocator);
}
init :: (arr: ^[..] $T, capacity := 4, allocator := context.allocator) {
}
// Semi-useful shortcut for adding something to an array.
-#operator << macro (arr: [..] $T, v: T) do (package core.array).push(^arr, v);
+#operator << macro (arr: [..] $T, v: T) do core.array.push(^arr, v);
insert :: (arr: ^[..] $T, idx: u32, x: T) -> bool {
if !ensure_capacity(arr, arr.count + 1) do return false;
package core.avl_tree
-#local math :: package core.math
+use core {math}
AVL_Tree :: struct (T: type_expr) {
data: T;
package core.bucket_array
-#local array :: package core.array
-#local iter :: package core.iter
+use core {array, iter}
Bucket_Array :: struct (T: type_expr) {
allocator : Allocator;
}
}
-#operator << macro (b: Bucket_Array($T), elem: T) do (package core.bucket_array).push(^b, elem);
+#operator << macro (b: Bucket_Array($T), elem: T) do core.bucket_array.push(^b, elem);
pop :: (use b: ^Bucket_Array($T)) {
last_bucket := ^buckets[buckets.count - 1];
c.elem_idx = 0;
next :: (use c: ^Context($T)) -> (T, bool) {
- use package core.intrinsics.onyx
+ use core.intrinsics.onyx
bucket := ^ba.buckets[bucket_idx];
while elem_idx == bucket.count {
package core.heap
-#local {
- array :: package core.array
-}
+use core {array}
Heap :: struct (T: type_expr) {
data: [..] T;
shift_up(heap, data.count - 1);
}
-#operator << macro (heap: Heap($T), v: T) do (package core.heap).insert(^heap, v);
+#operator << macro (heap: Heap($T), v: T) do core.heap.insert(^heap, v);
remove_top :: (use heap: ^Heap) -> heap.T {
x := data[0];
package core.iter
-#local memory :: package core.memory
-#local alloc :: package core.alloc
-
-#local {
- //
- // After struggling to think of a good way for iterators to manage their context
- // data in a way that is completely degradative to the heap memory, I decided that
- // the easiest and most programmer friendly way to do it was to completely remove
- // their dependence on the heap. ALL iterators allocated in this file use the
- // buffer below to store their data. This data is never "freed", but because it
- // is a ring buffer, the data will be reused eventually. I think that 1024 bytes
- // should be plently for the normal number of active iterators. However, it is
- // possible that this *could* overrun, and unexpected behavior could ensue. For
- // this reason, most allocator also support allocating their data from the context's
- // allocator simply by passing that allocator as an arugment.
-
- //
- // BUG: This is not a thread-safe allocator!!
- // Why not use context.temp_allocator?
- //
-
- /*
- iter_ring_buffer: [1024] u8;
- iter_ring: alloc.ring.RingState;
- iter_allocator: Allocator;
-
- #init () {
- iter_ring = alloc.ring.make(iter_ring_buffer);
- iter_allocator = alloc.as_allocator(^iter_ring);
- }
- */
-}
+use core {memory, alloc, array}
as_iterator :: #match {}
//
// This is current - 1 because current will have already
// been incremented by the time this element calls #remove.
- array :: package core.array
array.delete(arr, current - 1);
current -= 1;
}
//
// This is current - 1 because current will have already
// been incremented by the time this element calls #remove.
- array :: package core.array
array.delete(arr, current - 1);
current -= 1;
}
}
to_array :: (it: Iterator($T), allocator := context.allocator) -> [..] T {
- array :: package core.array
-
arr := array.make(T, allocator=allocator);
for v: it do array.push(^arr, v);
#overload
parallel_for :: macro (iter: Iterator($T), thread_count: u32, thread_data: ^$Ctx, body: Code) {
- thread :: package core.thread;
- alloc :: package core.alloc;
+ use core {thread, alloc}
distributor :: distributor;
as_iterator :: as_iterator;
return val;
}
-map :: #match {}
+map :: #match #local {}
#match map (list: ^List($T), f: (^T) -> void) {
elem := list.first;
while elem != null {
package core.map
-#local {
- array :: package core.array
- hash :: package core.hash
- memory :: package core.memory
- math :: package core.math
- conv :: package core.conv
+use core {array, hash, memory, math, conv}
+use core.intrinsics.onyx { __initialize }
- use package core.intrinsics.onyx { __initialize }
-}
+#local ValidKey :: interface (t: $T) {
+ // In order to use a certain type as a key in a Map, you must
+ // provide an implementation of core.hash.to_u32() for that type,
+ // and you must provide an operator overload for ==.
-#local {
- ValidKey :: interface (t: $T) {
- // In order to use a certain type as a key in a Map, you must
- // provide an implementation of core.hash.to_u32() for that type,
- // and you must provide an operator overload for ==.
-
- { hash.to_u32(t) } -> u32;
- { t == t } -> bool;
- }
+ { hash.to_u32(t) } -> u32;
+ { t == t } -> bool;
}
#tag conv.Custom_Format.{
if entries.data != null do array.free(^entries);
}
-#match (package builtin).delete (package core.map).free
+#match builtin.delete core.map.free
put :: (use map: ^Map, key: map.Key_Type, value: map.Value_Type) {
lr := lookup(map, key);
return default_value;
}
-#operator [] macro (map: Map($K, $V), key: K) -> V do return (package core.map).get(^map, key);
-#operator []= macro (map: Map($K, $V), key: K, value: V) do (package core.map).put(^map, key, value);
-#operator ^[] macro (map: Map($K, $V), key: K) -> ^V do return (package core.map).get_ptr(^map, key);
+#operator [] macro (map: Map($K, $V), key: K) -> V do return core.map.get(^map, key);
+#operator []= macro (map: Map($K, $V), key: K, value: V) do core.map.put(^map, key, value);
+#operator ^[] macro (map: Map($K, $V), key: K) -> ^V do return core.map.get_ptr(^map, key);
get_ptr :: (use map: ^Map, key: map.Key_Type) -> ^map.Value_Type {
lr := lookup(map, key);
package core.set
-#local {
- array :: package core.array
- hash :: package core.hash
- memory :: package core.memory
- math :: package core.math
-}
+use core {array, hash, memory, math}
#local SetValue :: interface (t: $T) {
{ hash.to_u32(t) } -> u32;
return set;
}
-#match (package builtin).__make_overload macro (x: ^Set, allocator: Allocator) => (package core.set).make(x.Elem_Type, allocator = allocator);
+#overload
+builtin.__make_overload :: macro (x: ^Set, allocator: Allocator) => core.set.make(x.Elem_Type, allocator = allocator);
init :: (set: ^Set($T), default := T.{}, allocator := context.allocator) {
set.allocator = allocator;
array.free(^entries);
}
-#match (package builtin).delete (package core.set).free
+#overload
+builtin.delete :: core.set.free
insert :: (use set: ^Set, value: set.Elem_Type) {
if hashes.data == null do init(set);
if full(set) do grow(set);
}
-#operator << macro (set: Set($T), value: T) do (package core.set).insert(^set, value);
+#operator << macro (set: Set($T), value: T) do core.set.insert(^set, value);
has :: (use set: ^Set, value: set.Elem_Type) -> bool {
lr := lookup(set, value);
return entries.count == 0;
}
-#match (package core.iter).as_iterator iterator
+#match core.iter.as_iterator iterator
iterator :: (set: ^Set($T)) -> Iterator(T) {
Context :: struct (T: type_expr) {
set: ^Set(T);
Enable_Custom_Formatters :: true
#local {
- map :: package core.map
- string :: package core.string
- array :: package core.array
+ use core {map, string, array, math}
custom_formatters: Map(type_expr, #type (^Format_Output, ^Format, rawptr) -> void);
custom_parsers : Map(type_expr, #type (rawptr, str, Allocator) -> bool);
// This is better than what used to be, but still relies on converting the integer
// part of the float to an integer, which could overflow.
f64_to_str :: (f: f64, buf: [] u8, digits_after_decimal := 4) -> str {
- math :: package core.math;
-
if math.is_nan(f) {
return format(buf, "NaN");
}
package core.io
-use package core
+use core
BinaryWriter :: struct {
stream: ^Stream;
package core.io
-memory :: package core.memory
-math :: package core.math
-array :: package core.array
+use core {memory, math, array}
Reader :: struct {
stream : ^Stream;
package core.io
-use package core
+use core
Stream :: struct {
use vtable : ^Stream_Vtable;
}
}
+#match builtin.delete buffer_stream_free
buffer_stream_free :: (use bs: ^BufferStream) {
if write_enabled && !fixed {
delete(^data);
}
}
-#match builtin.delete buffer_stream_free
-
#match core.string.as_str buffer_stream_to_str
buffer_stream_to_str :: (use bs: ^BufferStream) -> str {
if !write_enabled do return null_str;
package core.io
-#local conv :: package core.conv
+use core {conv, string}
Writer :: struct {
stream : ^Stream;
}
write_cstr :: (use writer: ^Writer, cs: cstr) {
- use package core
-
s := string.from_cstr(cs);
write_str(writer, s);
}
write_i32 :: (use writer: ^Writer, n: i32, base: u32 = 10) {
- use package core
-
buf : [256] u8;
s := conv.i64_to_str(cast(i64) n, cast(u64) base, ~~buf);
write_str(writer, s);
}
write_i64 :: (use writer: ^Writer, n: i64, base: u64 = 10) {
- use package core
-
buf : [256] u8;
s := conv.i64_to_str(n, base, ~~buf);
write_str(writer, s);
}
write_f32 :: (use writer: ^Writer, f: f32) {
- use package core
-
buf : [256] u8;
s := conv.f64_to_str(cast(f64) f, ~~buf);
write_str(writer, s);
}
write_f64 :: (use writer: ^Writer, f: f64) {
- use package core
-
buf : [256] u8;
s := conv.f64_to_str(f, ~~buf);
write_str(writer, s);
package core.math
-#local wasm :: package core.intrinsics.wasm
+use core.intrinsics {wasm}
// Things that are useful in any math library:
// - Trigonometry
package core.net
-#local {
- runtime :: package runtime
- sync :: package core.sync
- thread :: package core.thread
- array :: package core.array
- memory :: package core.memory
- alloc :: package core.alloc
- os :: package core.os
-}
+use core {sync, thread, array, memory, alloc, os}
#if !runtime.Multi_Threading_Enabled {
#error "Expected multi-threading to be enabled for TCP server.";
package core.os
-#local fs :: package runtime.fs
+use runtime {fs}
Directory :: fs.DirectoryData;
package core.os
-use package core
-#local fs :: package runtime.fs
+use core
+use runtime {fs}
FileError :: enum {
None :: 0x00;
#error "The os library is currently only available on the WASI runtime, and should only be included if that is the chosen runtime."
}
-#local {
- runtime :: package runtime
- string :: package core.string
-}
+use core {string}
list_directory :: (path: str) -> Iterator(DirectoryEntry) {
Context :: struct {
#error "This file can only be included in the 'onyx' runtime, because Wasi has not defined how to spawn and manage processes.";
}
-#local {
- runtime :: package runtime
- io :: package core.io
-}
+use core {io}
Process :: struct {
Handle :: #distinct i64;
package runtime
-use package core
-use package core.intrinsics.onyx { __initialize }
+use core
+use core.intrinsics.onyx { __initialize }
// The default assert handler. This assumes that __output_string
// and __exit are defined in the 'runtime' package.
// Use this procedure to initialize everything needed in the
// standard library when you are dropped directly into a function.
__thread_initialize :: macro () {
- use package core.intrinsics.onyx { __initialize }
+ use core.intrinsics.onyx { __initialize }
// This should only be true for the main thread.
if __tls_base == null {
}
_thread_exit :: (id: i32) {
- thread :: package core.thread
-
raw_free(alloc.heap_allocator, __tls_base);
- thread.__exited(id);
+ core.thread.__exited(id);
}
}
package runtime.info
-#local io :: package core.io
+use core {io}
write_type_name :: (writer: ^io.Writer, t: type_expr) {
info := get_type_info(t);
}
for_all_types :: macro (body: Code) {
- for (package runtime.info).type_table.count {
+ for runtime.info.type_table.count {
type_info := (package runtime.info).type_table[it];
type_idx : type_expr = ~~ it;
package runtime.info
+use core {array}
+
tagged_procedures: [] ^Tagged_Procedure
Tagged_Procedure :: struct {
}
get_procedures_with_tag :: ($tag_type: type_expr) -> [] GPWT_Result(tag_type) {
- array :: package core.array
results := make([..] GPWT_Result(tag_type));
for proc: tagged_procedures {
#load "core/runtime/common"
-use package core
+use core
__output_string :: (s: str) -> u32 #foreign "host" "print_str" ---
__exit :: (status: i32) -> void #foreign "host" "exit" ---
#load "core/runtime/common"
-use package core
+use core
#local {
__stdout: os.File;
#load "core/wasi/wasi"
#load "core/runtime/common"
-use package wasi
-use package core
+use wasi
+use core
__output_string :: (s: str) -> u32 {
STDOUT_FILENO :: 1
package core.string
-use package core
+use core
as_str :: #match {}
package core.string
-#local math :: package core.math
+use core {math}
String_Buffer :: struct {
data : ^u8;
package core.sync
-use package core.intrinsics.atomics
-use package core.thread { Thread_ID }
-
-#local runtime :: package runtime
+use core.intrinsics.atomics
+use core.thread { Thread_ID }
// `lock` has two states: 0, and 1.
// 0 means unlocked
package core.sync
-use package core.intrinsics.atomics
-#local runtime :: package runtime
+use core.intrinsics.atomics
Semaphore :: struct {
mutex : Mutex;
package core.thread
-use package core
-use package core.intrinsics.atomics
+use core
+use core.intrinsics.atomics
#package {
- runtime :: package runtime
-
thread_mutex : sync.Mutex;
next_thread_id := 1;
thread_map : Map(Thread_ID, ^Thread);