return hs;
}
-auto_heap_free :: (hs: ^AutoHeapState) {
+auto_heap_clear :: (hs: ^AutoHeapState) {
for^ hs.set.entries {
raw_free(hs.backing_allocator, it.value);
}
+ hs.set->clear();
+}
+
+auto_heap_free :: (hs: ^AutoHeapState) {
+ auto_heap_clear(hs);
hs.set->free();
}
// ---------------------------------
// Dynamic Arrays
// ---------------------------------
-make :: #match #locked {
- ($T: type_expr, capacity := 4, allocator := context.allocator) -> [..] T {
- arr : [..] T;
- init(^arr, capacity, allocator);
- return arr;
- },
-
- (base: [] $T, allocator := context.allocator) -> [..] T {
- arr: [..] T;
- init(^arr, base.count, allocator);
- for^ base do arr << *it;
- return arr;
- }
+make :: #match #local {}
+
+#overload
+make :: ($T: type_expr, capacity := 4, allocator := context.allocator) -> [..] T {
+ arr : [..] T;
+ init(^arr, capacity, allocator);
+ return arr;
+}
+
+#overload
+make :: (base: [] $T, allocator := context.allocator) -> [..] T {
+ arr: [..] T;
+ init(^arr, base.count, allocator);
+ for^ base do arr << *it;
+ return arr;
}
-#match __make_overload macro (_: ^[..] $T, allocator := context.allocator) -> [..] T {
+#overload
+__make_overload :: macro (_: ^[..] $T, allocator := context.allocator) -> [..] T {
return (package core.array).make(T, allocator=allocator);
}
-#match __make_overload macro (_: ^[..] $T, capacity: u32, allocator := context.allocator) -> [..] T {
+#overload
+__make_overload :: macro (_: ^[..] $T, capacity: u32, allocator := context.allocator) -> [..] T {
return (package core.array).make(T, capacity, allocator);
}
arr.data = null;
}
-#match (package builtin).delete macro (x: ^[..] $T) {
- (package core.array).free(x);
+#overload
+builtin.delete :: macro (x: ^[..] $T) {
+ core.array.free(x);
}
copy :: #match #locked {
// Simple insertion sort
// cmp should return >0 if left > right
//
-sort :: #match #locked {
- (arr: [] $T, cmp: (T, T) -> i32) {
- for i: 1 .. arr.count {
- x := arr.data[i];
- j := i - 1;
-
- @ShortCircuitLogicalOps // This is written this way because '&&' does not short circuit right now.
- while j >= 0 {
- if cmp(arr.data[j], x) > 0 {
- arr.data[j + 1] = arr.data[j];
- j -= 1;
- } else {
- break;
- }
- }
+sort :: #match #local {}
- arr.data[j + 1] = x;
+#overload
+sort :: (arr: [] $T, cmp: (T, T) -> i32) {
+ for i: 1 .. arr.count {
+ x := arr.data[i];
+ j := i - 1;
+
+ @ShortCircuitLogicalOps // This is written this way because '&&' does not short circuit right now.
+ while j >= 0 {
+ if cmp(arr.data[j], x) > 0 {
+ arr.data[j + 1] = arr.data[j];
+ j -= 1;
+ } else {
+ break;
+ }
}
- },
- (arr: [] $T, cmp: (^T, ^T) -> i32) {
- for i: 1 .. arr.count {
- j := i;
-
- while j > 0 {
- if cmp(^arr.data[j - 1], ^arr.data[j]) > 0 {
- arr.data[j], arr.data[j - 1] = arr.data[j - 1], arr.data[j];
- j -= 1;
- } else {
- break;
- }
+ arr.data[j + 1] = x;
+ }
+}
+
+#overload
+sort :: (arr: [] $T, cmp: (^T, ^T) -> i32) {
+ for i: 1 .. arr.count {
+ j := i;
+
+ while j > 0 {
+ if cmp(^arr.data[j - 1], ^arr.data[j]) > 0 {
+ arr.data[j], arr.data[j - 1] = arr.data[j - 1], arr.data[j];
+ j -= 1;
+ } else {
+ break;
}
}
}
quicksort_impl(arr, cmp, pivot + 1, hi);
}
- quicksort_partition :: #match #locked {
- (arr: [] $T, cmp: (T, T) -> i32, lo, hi: i32) -> i32 {
- pivot := arr[hi];
- i := lo - 1;
+ quicksort_partition :: #match #local {}
+
+ #overload
+ quicksort_partition :: (arr: [] $T, cmp: (T, T) -> i32, lo, hi: i32) -> i32 {
+ pivot := arr[hi];
+ i := lo - 1;
- for j: lo .. hi+1 {
- if cmp(arr[j], pivot) <= 0 {
- i += 1;
- arr[i], arr[j] = arr[j], arr[i];
- }
+ for j: lo .. hi+1 {
+ if cmp(arr[j], pivot) <= 0 {
+ i += 1;
+ arr[i], arr[j] = arr[j], arr[i];
}
+ }
- return i;
- },
+ return i;
+ }
- (arr: [] $T, cmp: (^T, ^T) -> i32, lo, hi: i32) -> i32 {
- pivot := ^arr[hi];
- i := lo - 1;
+ #overload
+ quicksort_partition :: (arr: [] $T, cmp: (^T, ^T) -> i32, lo, hi: i32) -> i32 {
+ pivot := ^arr[hi];
+ i := lo - 1;
- for j: lo .. hi+1 {
- if cmp(^arr[j], pivot) <= 0 {
- i += 1;
- arr[i], arr[j] = arr[j], arr[i];
- }
+ for j: lo .. hi+1 {
+ if cmp(^arr[j], pivot) <= 0 {
+ i += 1;
+ arr[i], arr[j] = arr[j], arr[i];
}
-
- return i;
}
+
+ return i;
}
}
it.close(it.data);
}
-filter :: #match {}
-#match filter (it: Iterator($T), predicate: (T) -> bool, allocator := iter_allocator) -> Iterator(T) {
+filter :: #match #local {}
+#overload
+filter :: (it: Iterator($T), predicate: (T) -> bool, allocator := iter_allocator) -> Iterator(T) {
FilterIterator :: struct (T: type_expr) {
iterator: Iterator(T);
predicate: (T) -> bool;
};
}
-#match filter (it: Iterator($T), ctx: $Ctx, predicate: (T, Ctx) -> bool, allocator := iter_allocator) -> Iterator(T) {
+#overload
+filter :: (it: Iterator($T), ctx: $Ctx, predicate: (T, Ctx) -> bool, allocator := iter_allocator) -> Iterator(T) {
FilterIterator :: struct (T: type_expr, Ctx: type_expr) {
iterator: Iterator(T);
predicate: (T, Ctx) -> bool;
};
}
-map :: #match {}
-#match map (it: Iterator($T), transform: (T) -> $R, allocator := iter_allocator) -> Iterator(R) {
+map :: #match #local {}
+
+#overload
+map :: (it: Iterator($T), transform: (T) -> $R, allocator := iter_allocator) -> Iterator(R) {
MapIterator :: struct (T: type_expr, R: type_expr) {
iterator: Iterator(T);
transform: (T) -> R;
};
}
-#match map (it: Iterator($T), ctx: $Ctx, transform: (T, Ctx) -> $R, allocator := iter_allocator) -> Iterator(R) {
+#overload
+map :: (it: Iterator($T), ctx: $Ctx, transform: (T, Ctx) -> $R, allocator := iter_allocator) -> Iterator(R) {
MapIterator :: struct (T: type_expr, R: type_expr, Ctx: type_expr) {
iterator: Iterator(T);
transform: (T, Ctx) -> R;
value: T;
}
-enumerate :: #match {}
-#match enumerate macro (it: $T, start_index: i32 = 0) -> #auto where Iterable(T) {
+enumerate :: #match #local {}
+
+#overload
+enumerate :: macro (it: $T, start_index: i32 = 0) -> #auto where Iterable(T) {
as_iterator :: as_iterator
enumerate :: enumerate
return enumerate(as_iterator(it), start_index);
}
-#match enumerate (it: Iterator($T), start_index: i32 = 0) -> Iterator(Enumeration_Value(T)) {
+#overload
+enumerate :: (it: Iterator($T), start_index: i32 = 0) -> Iterator(Enumeration_Value(T)) {
Enumeration_Context :: struct (T: type_expr) {
iterator: Iterator(T);
current_index: i32;
};
}
-#match as_iterator from_array
+#overload
+as_iterator :: from_array
from_array :: (arr: [] $T) -> Iterator(^T) {
Context :: struct (T: type_expr) {
data: ^T;
};
}
-#match as_iterator (x: ^[..] $T) -> Iterator(T) {
+#overload
+as_iterator :: (x: ^[..] $T) -> Iterator(T) {
Context :: struct (T: type_expr) {
arr: ^[..] T;
current: u32;
};
}
-#match as_iterator (x: ^[..] $T, by_pointer: bool) -> Iterator(^T) {
+#overload
+as_iterator :: (x: ^[..] $T, by_pointer: bool) -> Iterator(^T) {
Context :: struct (T: type_expr) {
arr: ^[..] T;
current: u32;
};
}
-#match as_iterator (r: range) -> Iterator(i32) {
+#overload
+as_iterator :: (r: range) -> Iterator(i32) {
Context :: struct {
r: range;
v: i32;
};
}
-fold :: #match {}
+fold :: #match #local {}
+
@Cleanup // some way to shorten this would be nice
-#match fold macro (it: $T, init: $R, combine: $S) -> #auto where Iterable(T) {
+#overload
+fold :: macro (it: $T, init: $R, combine: $S) -> #auto where Iterable(T) {
fold :: fold
return fold(as_iterator(it), init, combine);
}
-#match fold (it: Iterator($T), initial_value: $R, combine: (T, R) -> R) -> R {
+#overload
+fold :: (it: Iterator($T), initial_value: $R, combine: (T, R) -> R) -> R {
for value: it {
initial_value = combine(value, initial_value);
}
return initial_value;
}
-count :: #match {}
-#match count macro (it: $T, cond: $F) -> #auto where Iterable(T) {
+count :: #match #local {}
+
+#overload
+count :: macro (it: $T, cond: $F) -> #auto where Iterable(T) {
count :: count
return count(as_iterator(it), cond);
}
-#match count (it: Iterator($T), cond: (T) -> bool) -> i32 {
+#overload
+count :: (it: Iterator($T), cond: (T) -> bool) -> i32 {
c := 0;
for value: it do if cond(value) do c += 1;
return c;
}
-some :: #match {}
-#match some macro (it: $T, cond: $F) -> #auto where Iterable(T) {
+some :: #match #local {}
+
+#overload
+some :: macro (it: $T, cond: $F) -> #auto where Iterable(T) {
some :: some
as_iterator :: as_iterator
return some(as_iterator(it), cond);
}
-#match some (it: Iterator($T), cond: (T) -> bool) -> bool {
+#overload
+some :: (it: Iterator($T), cond: (T) -> bool) -> bool {
for value: it do if cond(value) do return true;
return false;
}
-every :: #match {}
-#match every macro (it: $T, cond: $F) -> #auto where Iterable(T) {
+every :: #match #local {}
+
+#overload
+every :: macro (it: $T, cond: $F) -> #auto where Iterable(T) {
every :: every
as_iterator :: as_iterator
return every(as_iterator(it), cond);
}
-#match every (it: Iterator($T), cond: (T) -> bool) -> bool {
+#overload
+every :: (it: Iterator($T), cond: (T) -> bool) -> bool {
for value: it do if !cond(value) do return false;
return true;
}
}
-#local runtime :: package runtime
#if runtime.Multi_Threading_Enabled {
- #local sync :: package core.sync
- distributor :: #match {}
- #match distributor macro (it: $T) -> #auto where Iterable(T) {
+ #local sync :: core.sync
+
+ distributor :: #match #local {}
+
+ #overload
+ distributor :: macro (it: $T) -> #auto where Iterable(T) {
distributor :: distributor;
as_iterator :: as_iterator;
return distributor(as_iterator(it));
}
- #match distributor (it: Iterator) -> Iterator(it.Iter_Type) {
+ #overload
+ distributor :: (it: Iterator) -> Iterator(it.Iter_Type) {
Context :: struct (T: type_expr) {
mutex: sync.Mutex;
iterator: Iterator(T);
return .{c, #solidify next {T=it.Iter_Type}, #solidify close {T=it.Iter_Type}};
}
- parallel_for :: #match {}
- #match parallel_for macro (iterable: $I, thread_count: u32, thread_data: ^$Ctx, body: Code) where Iterable(I) {
+ parallel_for :: #match #local {}
+
+ #overload
+ parallel_for :: macro (iterable: $I, thread_count: u32, thread_data: ^$Ctx, body: Code) where Iterable(I) {
parallel_for :: parallel_for;
as_iterator :: as_iterator;
parallel_for(as_iterator(iterable), thread_count, thread_data, body);
}
- #match parallel_for macro (iter: Iterator($T), thread_count: u32, thread_data: ^$Ctx, body: Code) {
+ #overload
+ parallel_for :: macro (iter: Iterator($T), thread_count: u32, thread_data: ^$Ctx, body: Code) {
thread :: package core.thread;
alloc :: package core.alloc;
distributor :: distributor;
// they would be however, the fact that these overloads are intrinsic means they cannot
// be reference from the element section and therefore cannot be passed around or used
// as values.
-max :: #match { wasm.max_f32, wasm.max_f64, max_poly }
+max :: #match #local { wasm.max_f32, wasm.max_f64, max_poly }
max_poly :: (a: $T, b: T) -> T {
return a if a >= b else b;
}
-min :: #match { wasm.min_f32, wasm.min_f64, min_poly }
+min :: #match #local { wasm.min_f32, wasm.min_f64, min_poly }
min_poly :: (a: $T, b: T) -> T {
return a if a <= b else b;
}
return v;
}
-sqrt :: #match { wasm.sqrt_f32, wasm.sqrt_f64, sqrt_poly }
+sqrt :: #match #local { wasm.sqrt_f32, wasm.sqrt_f64, sqrt_poly }
sqrt_poly :: (x: $T) -> T {
return ~~ wasm.sqrt_f64(~~ x);
}
-abs :: #match { wasm.abs_f32, wasm.abs_f64, abs_poly }
+abs :: #match #local { wasm.abs_f32, wasm.abs_f64, abs_poly }
abs_poly :: (x: $T) -> T {
return x if x >= 0 else -x;
}
return 0;
}
-copysign :: #match { wasm.copysign_f32, wasm.copysign_f64, copysign_poly }
+copysign :: #match #local { wasm.copysign_f32, wasm.copysign_f64, copysign_poly }
copysign_poly :: (x: $T, y: T) -> T {
return abs(x) * sign(y);
}
// Floating point rounding
//
-ceil :: #match { wasm.ceil_f32, wasm.ceil_f64 }
-floor :: #match { wasm.floor_f32, wasm.floor_f64 }
-trunc :: #match { wasm.trunc_f32, wasm.trunc_f64 }
-nearest :: #match { wasm.nearest_f32, wasm.nearest_f64 }
+ceil :: #match #local { wasm.ceil_f32, wasm.ceil_f64 }
+floor :: #match #local { wasm.floor_f32, wasm.floor_f64 }
+trunc :: #match #local { wasm.trunc_f32, wasm.trunc_f64 }
+nearest :: #match #local { wasm.nearest_f32, wasm.nearest_f64 }
// Integer operations
//
-clz :: #match { wasm.clz_i32, wasm.clz_i64 }
-ctz :: #match { wasm.ctz_i32, wasm.ctz_i64 }
-popcnt :: #match { wasm.popcnt_i32, wasm.popcnt_i64 }
-rotate_left :: #match { wasm.rotl_i32, wasm.rotl_i64 }
-rotate_right :: #match { wasm.rotr_i32, wasm.rotr_i64 }
+clz :: #match #local { wasm.clz_i32, wasm.clz_i64 }
+ctz :: #match #local { wasm.ctz_i32, wasm.ctz_i64 }
+popcnt :: #match #local { wasm.popcnt_i32, wasm.popcnt_i64 }
+rotate_left :: #match #local { wasm.rotl_i32, wasm.rotl_i64 }
+rotate_right :: #match #local { wasm.rotr_i32, wasm.rotr_i64 }
package core.memory
-use package core.intrinsics.wasm { memory_copy, memory_fill }
-
-copy :: (dest: rawptr, src: rawptr, count: i32) do memory_copy(dest, src, count);
-set :: (dest: rawptr, byte: u8, count: i32) do memory_fill(dest, byte, count);
+align :: #match {
+ (size: ^u64, align: u64) {
+ if *size % align != 0 {
+ *size += align - (*size % align);
+ }
+ },
-// Old and slow copy and set
-copy_ :: (dst_: rawptr, src_: rawptr, len: u32) {
- dst := cast(^u8) dst_;
- src := cast(^u8) src_;
- for i: 0 .. len do dst[i] = src[i];
+ (size: u64, align: u64) -> u64 {
+ if size % align != 0 {
+ size += align - (size % align);
+ }
+ return size;
+ }
}
-set_ :: (start: rawptr, value: u8, length: u32) {
- s := cast(^u8) start;
- for i: 0 .. length do s[i] = value;
-}
+copy :: core.intrinsics.wasm.memory_copy
+set :: core.intrinsics.wasm.memory_fill
alloc_slice :: (sl: ^[] $T, count: i32, allocator := context.allocator) {
sl.data = raw_alloc(allocator, sizeof T * count);
};
}
-#match __make_overload macro (_: ^[] $T, count: u32, allocator := context.allocator) -> [] T {
- return (package core.memory).make_slice(T, count, allocator);
-}
-
free_slice :: (sl: ^[] $T, allocator := context.allocator) {
if sl.data == null do return;
sl.count = 0;
}
-#match (package builtin).delete macro (x: ^[] $T) {
- (package core.memory).free_slice(x);
-}
-
copy_slice :: (sl: [] $T, allocator := context.allocator) -> [] T {
data := raw_alloc(allocator, sl.count * sizeof T);
copy(data, sl.data, sl.count * sizeof T);
return new_slice;
}
-align :: #match {
- (size: ^u64, align: u64) {
- if *size % align != 0 {
- *size += align - (*size % align);
- }
- },
- (size: u64, align: u64) -> u64 {
- if size % align != 0 {
- size += align - (size % align);
- }
- return size;
- }
+#overload
+builtin.__make_overload :: macro (_: ^[] $T, count: u32, allocator := context.allocator) -> [] T {
+ return (package core.memory).make_slice(T, count, allocator);
+}
+
+#overload
+builtin.delete :: macro (x: ^[] $T) {
+ core.memory.free_slice(x);
}
#if runtime.runtime == .Onyx {
#load "./runtime/onyx_run"
+
#load "./os/process"
+ #load "./time/time"
#load "./net/net"
#load "./net/tcp"
// in anyway.
-#local runtime :: package runtime
#if runtime.runtime == .Custom {
#error "'stdio' can only be included in the 'wasi' or 'js' runtime."
}
+stdin: io.Stream;
+
auto_flush_stdio := true
print :: #match #locked {
}
// Print to standard error, if available.
-#if #defined((package runtime).__output_error) {
+#if #defined(runtime.__output_error) {
eprintf :: (format: str, va: ..any) -> str {
flush :: (_, to_output) => {
- (package runtime).__output_error(to_output);
+ runtime.__output_error(to_output);
return true;
}
buffer: [1024] u8;
- (package runtime).__output_error(conv.format_va(buffer, format, va, .{null, flush}));
+ runtime.__output_error(conv.format_va(buffer, format, va, .{null, flush}));
}
}
return .None, buf[0];
}
}
-
-stdin: io.Stream;
use package core
+as_str :: #match {}
+
+free :: (s: str, allocator := context.allocator) do raw_free(allocator, s.data);
alloc_copy :: (original: str, allocator := context.allocator) -> str {
new_str : str;
memory.copy(dest.data, orig.data, len);
}
+#match as_str from_cstr
from_cstr :: (s: cstr) -> str {
return .{ data = s, count = length(s) };
}
-free :: (s: str, allocator := context.allocator) do raw_free(allocator, s.data);
-
-length :: #match {
- (s: str) -> u32 {
- return s.count;
- },
-
- (s: cstr) -> u32 {
- len := 0;
- c := s;
- while *c != #char "\0" {
- len += 1;
- c += 1;
- }
-
- return len;
- },
-}
-
-concat :: #match {
- (s1: str, s2: str, allocator := context.allocator) -> str {
- len1 := length(s1);
- len2 := length(s2);
- data := cast(^u8) raw_alloc(allocator, len1 + len2);
- memory.copy(data, s1.data, len1);
- memory.copy(data + len1, s2.data, len2);
+length :: #match #local {}
- return str.{ data, len1 + len2 };
- },
+#overload
+length :: (s: str) => s.count;
- @Cleanup // Don't love that the allocator is necessary here,
- // but it is impossible to specify a default value for the
- // allocator while having a variadic number of strings. This
- // is only due to the languages constraints however. This
- // could easily be changed since there is no ambiguity.
- (allocator: Allocator, strings: ..str) -> str {
- total_length := 0;
- for s: strings do total_length += s.count;
+#overload
+length :: (s: cstr) -> u32 {
+ len := 0;
+ c := s;
+ while *c != #char "\0" {
+ len += 1;
+ c += 1;
+ }
- data := cast(^u8) raw_alloc(allocator, total_length);
- offset := 0;
- for s: strings {
- memory.copy(data + offset, s.data, s.count);
- offset += s.count;
- }
+ return len;
+}
- return str.{ data, total_length };
- },
- (buffer: [] u8, strings: ..str) -> str {
- total_copied := 0;
- for s: strings {
- // Should never greater than, but better safe than sorry.
- if total_copied >= buffer.count do break;
+concat :: #match #local {}
- bytes_to_copy := math.min(s.count, buffer.count - total_copied);
- memory.copy(buffer.data + total_copied, s.data, bytes_to_copy);
- total_copied += bytes_to_copy;
- }
+#overload
+concat :: (s1: str, s2: str, allocator := context.allocator) -> str {
+ len1 := length(s1);
+ len2 := length(s2);
- return buffer[0 .. total_copied];
- },
+ data := cast(^u8) raw_alloc(allocator, len1 + len2);
+ memory.copy(data, s1.data, len1);
+ memory.copy(data + len1, s2.data, len2);
- (into: ^[..] u8, strings: ..str) -> str {
- for s: strings {
- array.ensure_capacity(into, into.count + s.count);
- memory.copy(into.data + into.count, s.data, s.count);
- into.count += s.count;
- }
- return .{ into.data, into.count };
- }
+ return str.{ data, len1 + len2 };
}
+@Cleanup // Don't love that the allocator is necessary here,
+// but it is impossible to specify a default value for the
+// allocator while having a variadic number of strings. This
+// is only due to the languages constraints however. This
+// could easily be changed since there is no ambiguity.
+#overload
+concat :: (allocator: Allocator, strings: ..str) -> str {
+ total_length := 0;
+ for s: strings do total_length += s.count;
+
+ data := cast(^u8) raw_alloc(allocator, total_length);
+ offset := 0;
+ for s: strings {
+ memory.copy(data + offset, s.data, s.count);
+ offset += s.count;
+ }
-split :: (s: str, delim: u8, allocator := context.allocator) -> []str {
- delim_count := 0;
- for i: 0 .. s.count do if s[i] == delim do delim_count += 1;
-
- strarr := cast(^str) raw_alloc(allocator, sizeof str * (delim_count + 1));
+ return str.{ data, total_length };
+}
- curr_str := 0;
- begin := 0;
+#overload
+concat :: (buffer: [] u8, strings: ..str) -> str {
+ total_copied := 0;
+ for s: strings {
+ // Should never greater than, but better safe than sorry.
+ if total_copied >= buffer.count do break;
- for i: 0 .. s.count {
- if s[i] == delim {
- strarr[curr_str] = s.data[begin .. i];
- begin = i + 1;
- curr_str += 1;
- }
+ bytes_to_copy := math.min(s.count, buffer.count - total_copied);
+ memory.copy(buffer.data + total_copied, s.data, bytes_to_copy);
+ total_copied += bytes_to_copy;
}
- strarr[curr_str] = s.data[begin .. s.count];
+ return buffer[0 .. total_copied];
+}
- return strarr[0 .. delim_count + 1];
+#overload
+concat :: (into: ^[..] u8, strings: ..str) -> str {
+ for s: strings {
+ array.ensure_capacity(into, into.count + s.count);
+ memory.copy(into.data + into.count, s.data, s.count);
+ into.count += s.count;
+ }
+ return .{ into.data, into.count };
}
-contains :: #match {
- (s: str, c: u8) -> bool {
- for ch: s do if ch == c do return true;
- return false;
- },
- (s: str, substr: str) -> bool {
- while i := 0; i < s.count {
- while j := 0; j < substr.count {
- if s[i + j] != substr[j] {
- i += j + 1;
- continue continue;
- }
+contains :: #match #local {}
+
+#overload
+contains :: (s: str, c: u8) -> bool {
+ for ch: s do if ch == c do return true;
+ return false;
+}
- j += 1;
+#overload
+contains :: (s: str, substr: str) -> bool {
+ while i := 0; i < s.count {
+ while j := 0; j < substr.count {
+ if s[i + j] != substr[j] {
+ i += j + 1;
+ continue continue;
}
- return true;
+ j += 1;
}
- return false;
- },
+ return true;
+ }
+
+ return false;
}
+
@TODO
// Check this for edge cases and other bugs. I'm not confident
// it will work perfectly yet. - brendanfh 2020/12/21
return -1;
}
-strip_whitespace :: #match {
- (s: ^str) { strip_leading_whitespace(s); strip_trailing_whitespace(s); },
- (s: str) => s |> strip_leading_whitespace() |> strip_trailing_whitespace()
+
+strip_whitespace :: #match #local {}
+
+#overload
+strip_whitespace :: (s: ^str) {
+ strip_leading_whitespace(s);
+ strip_trailing_whitespace(s);
}
-strip_leading_whitespace :: #match {
- (s: ^str) {
- while s.count > 0 do switch s.data[0] {
- case #char " ", #char "\t", #char "\n", #char "\r" {
- s.data += 1;
- s.count -= 1;
- }
+#overload
+strip_whitespace :: (s: str) =>
+ s |> strip_leading_whitespace()
+ |> strip_trailing_whitespace()
+
+
+strip_leading_whitespace :: #match #local {}
- case #default do return;
+#overload
+strip_leading_whitespace :: (s: ^str) {
+ while s.count > 0 do switch s.data[0] {
+ case #char " ", #char "\t", #char "\n", #char "\r" {
+ s.data += 1;
+ s.count -= 1;
}
- },
-
- (s: str) -> str {
- out := s;
- strip_leading_whitespace(^out);
- return out;
- },
-}
-
-strip_trailing_whitespace :: #match {
- (s: ^str) {
- while s.count >= 1 do switch s.data[s.count - 1] {
- case #char " ", #char "\t", #char "\n", #char "\r" {
- s.count -= 1;
- }
- case #default do return;
+ case #default do return;
+ }
+}
+
+#overload
+strip_leading_whitespace :: (s: str) -> str {
+ out := s;
+ strip_leading_whitespace(^out);
+ return out;
+}
+
+
+strip_trailing_whitespace :: #match #local {}
+
+#overload
+strip_trailing_whitespace :: (s: ^str) {
+ while s.count >= 1 do switch s.data[s.count - 1] {
+ case #char " ", #char "\t", #char "\n", #char "\r" {
+ s.count -= 1;
}
- },
- (s: str) -> str {
- out := s;
- strip_trailing_whitespace(^out);
- return out;
- },
+ case #default do return;
+ }
+}
+
+#overload
+strip_trailing_whitespace :: (s: str) -> str {
+ out := s;
+ strip_trailing_whitespace(^out);
+ return out;
}
to_uppercase :: (s: str) -> str {
return s;
}
-trim_start :: #match {
- (s: ^str, char: u8) {
- while s.data[0] == char {
- s.data += 1;
- s.count -= 1;
- }
- },
- (s: str, char: u8) -> str {
- out := s;
- trim_start(^out, char);
- return out;
+trim_start :: #match #local {}
+
+#overload
+trim_start :: (s: ^str, char: u8) {
+ while s.data[0] == char {
+ s.data += 1;
+ s.count -= 1;
}
}
-trim_end :: #match {
- (s: ^str, char: u8) {
- while s.data[s.count - 1] == char {
- s.count -= 1;
- }
- },
+#overload
+trim_start :: (s: str, char: u8) -> str {
+ out := s;
+ trim_start(^out, char);
+ return out;
+}
+
- (s: str, char: u8) -> str {
- out := s;
- trim_end(^out, char);
- return out;
+trim_end :: #match #local {}
+
+#overload
+trim_end :: (s: ^str, char: u8) {
+ while s.data[s.count - 1] == char {
+ s.count -= 1;
}
}
-advance :: #match {
- (s: ^str, chars := 1) {
- chars = math.min(chars, s.count);
+#overload
+trim_end :: (s: str, char: u8) -> str {
+ out := s;
+ trim_end(^out, char);
+ return out;
+}
+
- s.data += chars;
- s.count -= chars;
- },
+advance :: #match #local {}
- (s: str, chars := 1) -> str {
- chars = math.min(chars, s.count);
- out := s;
+#overload
+advance :: (s: ^str, chars := 1) {
+ chars = math.min(chars, s.count);
- out.data += chars;
- out.count -= chars;
+ s.data += chars;
+ s.count -= chars;
+}
- return out;
- }
+#overload
+advance :: (s: str, chars := 1) -> str {
+ chars = math.min(chars, s.count);
+ out := s;
+
+ out.data += chars;
+ out.count -= chars;
+
+ return out;
}
replace :: (s: str, to_replace: u8, replace_with: u8) {
}
}
-read_until :: #match #locked {
- (s: ^str, upto: u8, skip := 0) -> str {
- if s.count == 0 do return "";
+read_until :: #match #local {}
- out : str;
- out.data = s.data;
- out.count = 0;
+#overload
+read_until :: (s: ^str, upto: u8, skip := 0) -> str {
+ if s.count == 0 do return "";
- rem := skip;
- for ch: *s {
- if ch == upto {
- if rem <= 0 do break;
- else do rem -= 1;
- }
+ out : str;
+ out.data = s.data;
+ out.count = 0;
- out.count += 1;
+ rem := skip;
+ for ch: *s {
+ if ch == upto {
+ if rem <= 0 do break;
+ else do rem -= 1;
}
- s.data += out.count;
- s.count -= out.count;
+ out.count += 1;
+ }
- return out;
- },
+ s.data += out.count;
+ s.count -= out.count;
- (s: ^str, upto: str, skip := 0) -> str {
- if s.count == 0 do return "";
+ return out;
+}
- out := str.{ data = s.data };
+#overload
+read_until :: (s: ^str, upto: str, skip := 0) -> str {
+ if s.count == 0 do return "";
- rem := skip;
- i := 0;
- while i <= s.count - upto.count {
- match := true;
- j := i;
- for upto {
- if s.data[j] != it {
- match = false;
- break;
- }
+ out := str.{ data = s.data };
- j += 1;
+ rem := skip;
+ i := 0;
+ while i <= s.count - upto.count {
+ match := true;
+ j := i;
+ for upto {
+ if s.data[j] != it {
+ match = false;
+ break;
}
- if match {
- if rem <= 0 do break;
- else do rem -= 1;
- }
+ j += 1;
+ }
- i += 1;
+ if match {
+ if rem <= 0 do break;
+ else do rem -= 1;
}
- if i > s.count - upto.count {
- out = *s;
- s.data += out.count;
- s.count = 0;
+ i += 1;
+ }
- } else {
- out.count = i - 1;
- s.data += out.count + (upto.count - 1);
- s.count -= out.count + (upto.count - 1);
- }
+ if i > s.count - upto.count {
+ out = *s;
+ s.data += out.count;
+ s.count = 0;
- return out;
+ } else {
+ out.count = i - 1;
+ s.data += out.count + (upto.count - 1);
+ s.count -= out.count + (upto.count - 1);
}
+
+ return out;
}
read_until_any :: (s: ^str, skip: u32, uptos: ..u8) -> str {
s.count -= adv + 1;
}
-as_str :: #match {
- from_cstr
+split :: (s: str, delim: u8, allocator := context.allocator) -> []str {
+ delim_count := 0;
+ for i: 0 .. s.count do if s[i] == delim do delim_count += 1;
+
+ strarr := cast(^str) raw_alloc(allocator, sizeof str * (delim_count + 1));
+
+ curr_str := 0;
+ begin := 0;
+
+ for i: 0 .. s.count {
+ if s[i] == delim {
+ strarr[curr_str] = s.data[begin .. i];
+ begin = i + 1;
+ curr_str += 1;
+ }
+ }
+
+ strarr[curr_str] = s.data[begin .. s.count];
+
+ return strarr[0 .. delim_count + 1];
}
--- /dev/null
+package core.time
+
+//
+// This module provides a thin wrapper for the builtin POSIX
+// time functionality of:
+// - localtime, gmtime
+// - strptime, strftime
+//
+
+#if runtime.runtime != .Onyx {
+ #error "'core.time' should only be used with the Onyx runtime.";
+}
+
+//
+// This structure has to match the 'struct tm'
+// defined in time.h of POSIX.
+Timestamp :: struct #size (sizeof u32 * 12) {
+ sec: u32;
+ min: u32;
+ hour: u32;
+ mday: u32;
+ mon: u32;
+ year: u32;
+ wday: u32;
+ yday: u32;
+ isdst: u32;
+}
+
+localtime :: __time_localtime
+gmtime :: __time_gmtime
+
+strftime :: (buf: [] u8, format: [] u8, tm: ^Timestamp) -> str {
+ f := cast(cstr) core.alloc.from_stack(format.length + 1);
+ core.memory.copy(f, format.data, format.length);
+ f[format.length] = 0;
+
+ len := __time_strftime(buf, f, tm);
+ return buf[0..len];
+}
+
+strptime :: (buf: [] u8, format: [] u8, tm: ^Timestamp) -> bool {
+ f := cast(cstr) core.alloc.from_stack(format.length + 1);
+ core.memory.copy(f, format.data, format.length);
+ f[format.length] = 0;
+
+ return __time_strptime(buf, f, tm);
+}
+
+#local {
+ #foreign "onyx_runtime" {
+ __time_localtime :: (time: u64, tm: ^Timestamp) -> void ---
+ __time_gmtime :: (time: u64, tm: ^Timestamp) -> void ---
+ __time_strftime :: (buf: [] u8, format: cstr, tm: ^Timestamp) -> u32 ---
+ __time_strptime :: (buf: [] u8, format: cstr, tm: ^Timestamp) -> bool ---
+ }
+}
+
bh_imap all_overloads;
b32 locked : 1;
+ b32 only_local_functions : 1;
};
// @CLEANUP: Is this really necessary?
b32 token_equals(OnyxToken* tkn1, OnyxToken* tkn2);
b32 token_text_equals(OnyxToken* tkn, char* text);
+b32 token_same_file(OnyxToken *tkn1, OnyxToken *tkn2);
#endif
else if (node->kind == Ast_Kind_Zero_Value) {
if (node_type == NULL) {
node->type = type;
- return TYPE_MATCH_SUCCESS;
+ return TYPE_MATCH_SUCCESS; // Shouldn't this be on the next line? And have node_type == node->type checked?
}
}
return 1;
}
+
+b32 token_same_file(OnyxToken *tkn1, OnyxToken *tkn2) {
+ if (!tkn1 || !tkn2) return 0;
+
+ if (tkn1->pos.filename == tkn2->pos.filename) return 1;
+
+ // :Security?
+ return strcmp(tkn1->pos.filename, tkn2->pos.filename) == 0;
+}
+
+//
+// Dates and Times
+//
+ONYX_DEF(__time_localtime, (WASM_I64, WASM_I32), ()) {
+ u64 t = params->data[0].of.i64;
+ localtime_r(&t, ONYX_PTR(params->data[1].of.i32));
+ return NULL;
+}
+
+ONYX_DEF(__time_gmtime, (WASM_I64, WASM_I32), ()) {
+ u64 t = params->data[0].of.i64;
+ gmtime_r(&t, ONYX_PTR(params->data[1].of.i32));
+ return NULL;
+}
+
+ONYX_DEF(__time_strftime, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+ u32 len = strftime(ONYX_PTR(params->data[0].of.i32), params->data[1].of.i32, ONYX_PTR(params->data[2].of.i32), ONYX_PTR(params->data[3].of.i32));
+ results->data[0] = WASM_I32_VAL(len);
+ return NULL;
+}
+
+ONYX_DEF(__time_strptime, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+ char *rem = strptime(ONYX_PTR(params->data[0].of.i32), params->data[1].of.i32, ONYX_PTR(params->data[2].of.i32), ONYX_PTR(params->data[3].of.i32));
+ results->data[0] = WASM_I32_VAL(rem != NULL);
+ return NULL;
+}
+
+
+
//
// Networking
//
ONYX_FUNC(__sleep)
ONYX_FUNC(__time)
+ ONYX_FUNC(__time_localtime)
+ ONYX_FUNC(__time_gmtime)
+ ONYX_FUNC(__time_strftime)
+ ONYX_FUNC(__time_strptime)
+
ONYX_FUNC(__net_create_socket)
ONYX_FUNC(__net_close_socket)
ONYX_FUNC(__net_setting)
locked = 1;
}
+ b32 local = 0;
+ if (parse_possible_directive(parser, "local")) {
+ local = 1;
+ }
+
+ // This could be checked elsewhere?
+ if (locked && local) {
+ onyx_report_error(token->pos, Error_Critical, "Only one of '#locked' and '#local' can because use at a time.");
+ }
+
expect_token(parser, '{');
AstOverloadedFunction* ofunc = make_node(AstOverloadedFunction, Ast_Kind_Overloaded_Function);
ofunc->token = token;
ofunc->flags |= Ast_Flag_Comptime;
ofunc->locked = locked;
+ ofunc->only_local_functions = local;
bh_arr_new(global_heap_allocator, ofunc->overloads, 4);
ENTITY_SUBMIT(operator);
return;
}
- else if (parse_possible_directive(parser, "match")) {
+ else if (parse_possible_directive(parser, "match") || parse_possible_directive(parser, "overload")) {
AstDirectiveAddOverload *add_overload = make_node(AstDirectiveAddOverload, Ast_Kind_Directive_Add_Overload);
add_overload->token = dir_token;
- parser->parse_calls = 0;
- add_overload->overloaded_function = (AstNode *) parse_expression(parser, 0);
- parser->parse_calls = 1;
-
if (parse_possible_directive(parser, "precedence")) {
AstNumLit* pre = parse_int_literal(parser);
if (parser->hit_unexpected_token) return;
add_overload->precedence = 0;
}
+ parser->parse_calls = 0;
+ add_overload->overloaded_function = (AstNode *) parse_expression(parser, 0);
+ parser->parse_calls = 1;
+
+ // Allow for
+ // #match
+ // something :: (....) {
+ // }
+ //
+ // This will make converting something to a overloaded
+ // function easier and require less copying by the programmer.
+ if (next_tokens_are(parser, 2, ':', ':')) {
+ consume_tokens(parser, 2);
+ }
+
add_overload->overload = parse_expression(parser, 0);
ENTITY_SUBMIT(add_overload);
return Symres_Error;
}
+ if (ofunc->only_local_functions) {
+ if (!token_same_file(add_overload->token, ofunc->token)) {
+ onyx_report_error(add_overload->token->pos, Error_Critical, "Cannot add match option here as this option is not within the same file as the original #match declared with #local.");
+ onyx_report_error(ofunc->token->pos, Error_Critical, "Here is the original #match.");
+ }
+ }
+
SYMRES(expression, (AstTyped **) &add_overload->overload);
add_overload_option(&ofunc->overloads, add_overload->precedence, add_overload->overload);
break;
}
}
-time :: macro (name: str) {
+time_block :: macro (name: str) {
start := 10;
defer {
end := 1010;
main :: (args) => {
test_macro();
- time("main");
+ time_block("main");
}
overloaded(z=10);
}
-#match overloaded #precedence 3 (q: i32) { println("Option Q"); }
-#match overloaded #precedence 2 (r: i32) { println("Option R"); }
-#match overloaded #precedence 1 (m: i32) { println("Option M"); }
+#match #precedence 3 overloaded (q: i32) { println("Option Q"); }
+#match #precedence 2 overloaded (r: i32) { println("Option R"); }
+#match #precedence 1 overloaded (m: i32) { println("Option M"); }