- Added $kindof compile time function.

- Deprecated `@typekind` macro in favour of `$kindof`.
- Deprecated `@typeis` macro in favour of `$typeof(#foo) == int`.
This commit is contained in:
Christoffer Lerno
2025-08-27 20:38:12 +02:00
parent 7312c10b9e
commit 239d249f01
24 changed files with 169 additions and 150 deletions

View File

@@ -17,9 +17,9 @@ macro void trim_bench($trim_str, String $target = WHITESPACE_TARGET) => @pool()
runtime::@start_benchmark();
$switch:
$case @typeis($trim_str, String):
$case $typeof($trim_str) == String:
s1 = s2.trim($trim_str);
$case @typeis($trim_str, AsciiCharset):
$case $typeof($$trim_str) == AsciiCharset:
s1 = s2.trim_charset($trim_str);
$default: $error "Unable to determine the right String `trim` operation to use.";
$endswitch

View File

@@ -185,7 +185,7 @@ fn void Object.set_object(&self, String key, Object* new_object) @private
<*
@require self.allocator != null : "This object is not properly initialized, was it really created using 'new'"
@require !@typeis(value, void*) ||| value == null : "void pointers cannot be stored in an object"
@require $typeof(value) != void* ||| value == null : "void pointers cannot be stored in an object"
*>
macro Object* Object.object_from_value(&self, value) @private
{

View File

@@ -6,7 +6,7 @@ import std::collections::pair, std::io;
@param [in] array
@param [in] element
@require @typekind(array) == SLICE || @typekind(array) == ARRAY
@require $kindof(array) == SLICE || $kindof(array) == ARRAY
@require @typematch(array[0], element) : "array and element must have the same type"
*>
macro bool contains(array, element)
@@ -24,7 +24,7 @@ macro bool contains(array, element)
@param [in] array
@param [in] element
@require @typekind(array) == SLICE || @typekind(array) == ARRAY
@require $kindof(array) == SLICE || $kindof(array) == ARRAY
@require @typematch(array[0], element) : "array and element must have the same type"
@return "the first index of the element"
@return? NOT_FOUND
@@ -48,9 +48,9 @@ macro index_of(array, element)
@param xlen : "The length of the slice in x, defaults to the length of the array"
@param ylen : "The length of the slice in y, defaults to the length of the array"
@return "A Slice2d from the array"
@require @typekind(array_ptr) == POINTER
@require @typekind(*array_ptr) == VECTOR || @typekind(*array_ptr) == ARRAY
@require @typekind((*array_ptr)[0]) == VECTOR || @typekind((*array_ptr)[0]) == ARRAY
@require $kindof(array_ptr) == POINTER
@require $kindof(*array_ptr) == VECTOR || $kindof(*array_ptr) == ARRAY
@require $kindof((*array_ptr)[0]) == VECTOR || $kindof((*array_ptr)[0]) == ARRAY
*>
macro slice2d(array_ptr, x = 0, xlen = 0, y = 0, ylen = 0)
{
@@ -85,8 +85,8 @@ macro rindex_of(array, element)
@param [in] arr1
@param [in] arr2
@param [&inout] allocator : "The allocator to use, default is the heap allocator"
@require @typekind(arr1) == SLICE || @typekind(arr1) == ARRAY
@require @typekind(arr2) == SLICE || @typekind(arr2) == ARRAY
@require $kindof(arr1) == SLICE || $kindof(arr1) == ARRAY
@require $kindof(arr2) == SLICE || $kindof(arr2) == ARRAY
@require @typematch(arr1[0], arr2[0]) : "Arrays must have the same type"
@ensure result.len == arr1.len + arr2.len
*>
@@ -111,8 +111,8 @@ macro concat(Allocator allocator, arr1, arr2) @nodiscard
@param [in] arr1
@param [in] arr2
@require @typekind(arr1) == SLICE || @typekind(arr1) == ARRAY
@require @typekind(arr2) == SLICE || @typekind(arr2) == ARRAY
@require $kindof(arr1) == SLICE || $kindof(arr1) == ARRAY
@require $kindof(arr2) == SLICE || $kindof(arr2) == ARRAY
@require @typematch(arr1[0], arr2[0]) : "Arrays must have the same type"
@ensure return.len == arr1.len + arr2.len
*>
@@ -531,7 +531,7 @@ macro bool @is_valid_operation(#operation, #left, #right) @const
$switch:
$case @is_empty_macro_slot(#operation):
return true;
$case @typekind(#operation) != FUNC:
$case $kindof(#operation) != FUNC:
return false;
$default:
return $defined(#operation(#left[0], #right[0]));

View File

@@ -94,7 +94,7 @@ bitstruct UInt128LE : uint128 @littleendian
macro read(bytes, $Type)
{
char[] s;
$switch @typekind(bytes):
$switch $kindof(bytes):
$case POINTER:
s = (*bytes)[:$Type.sizeof];
$default:
@@ -110,7 +110,7 @@ macro read(bytes, $Type)
macro write(x, bytes, $Type)
{
char[] s;
$switch @typekind(bytes):
$switch $kindof(bytes):
$case POINTER:
s = (*bytes)[:$Type.sizeof];
$default:

View File

@@ -27,8 +27,8 @@ macro foo(a, #b = EMPTY_MACRO_SLOT)
const EmptySlot EMPTY_MACRO_SLOT @builtin = null;
typedef EmptySlot = void*;
macro @is_empty_macro_slot(#arg) @const @builtin => @typeis(#arg, EmptySlot);
macro @is_valid_macro_slot(#arg) @const @builtin => !@typeis(#arg, EmptySlot);
macro @is_empty_macro_slot(#arg) @const @builtin => $typeof(#arg) == EmptySlot;
macro @is_valid_macro_slot(#arg) @const @builtin => $typeof(#arg) != EmptySlot;
<*
Returns a random value at compile time.
@@ -99,7 +99,7 @@ macro usz @bitsizeof(#expr) @builtin @const => $sizeof(#expr) * 8u;
@param v : `the any to convert to the given type.`
@param $Type : `the type to convert to`
@return `The any.ptr converted to its type.`
@ensure @typeis(return, $Type*)
@ensure $typeof(return) == $Type*
@return? TYPE_MISMATCH
*>
macro anycast(any v, $Type) @builtin
@@ -124,12 +124,12 @@ macro typeid @typeid(#value) @const @builtin
return $typeof(#value).typeid;
}
macro TypeKind @typekind(#value) @const @builtin
macro TypeKind @typekind(#value) @const @builtin @deprecated("Use `$kindof(#value)`.")
{
return $typeof(#value).kindof;
return $kindof(#value);
}
macro bool @typeis(#value, $Type) @const @builtin
macro bool @typeis(#value, $Type) @const @builtin @deprecated("Use `$typeof(#value) == $Type` instead.")
{
return $typeof(#value).typeid == $Type.typeid;
}
@@ -285,7 +285,7 @@ macro any.as_inner(&self)
@param $Type : "the type to cast to"
@require $sizeof(expr) == $Type.sizeof : "Cannot bitcast between types of different size."
@ensure @typeis(return, $Type)
@ensure $typeof(return) == $Type*
*>
macro bitcast(expr, $Type) @builtin
{
@@ -302,7 +302,7 @@ macro bitcast(expr, $Type) @builtin
@param $Type : `The type of the enum`
@param [in] enum_name : `The name of the enum to search for`
@require $Type.kindof == ENUM : `Only enums may be used`
@ensure @typeis(return, $Type)
@ensure $typeof(return) == $Type*
@return? NOT_FOUND
*>
macro enum_by_name($Type, String enum_name) @builtin
@@ -320,7 +320,7 @@ macro enum_by_name($Type, String enum_name) @builtin
@require $Type.kindof == ENUM : `Only enums may be used`
@require $defined($Type.#value) : `Expected '#value' to match an enum associated value`
@require $defined($typeof(($Type){}.#value) v = value) : `Expected the value to match the type of the associated value`
@ensure @typeis(return, $Type)
@ensure $typeof(return) == $Type*
@return? NOT_FOUND
*>
macro @enum_from_value($Type, #value, value) @builtin @deprecated("Use Enum.lookup_field and Enum.lookup")
@@ -454,7 +454,7 @@ macro @clz($value) @builtin @const
Return the excuse in the Optional if it is Empty, otherwise
return a null fault.
@require @typekind(#expr) == OPTIONAL : `@catch expects an Optional value`
@require $kindof(#expr) == OPTIONAL : `@catch expects an Optional value`
*>
macro fault @catch(#expr) @builtin
{
@@ -466,7 +466,7 @@ macro fault @catch(#expr) @builtin
Check if an Optional expression holds a value or is empty, returning true
if it has a value.
@require @typekind(#expr) == OPTIONAL : `@ok expects an Optional value`
@require $kindof(#expr) == OPTIONAL : `@ok expects an Optional value`
*>
macro bool @ok(#expr) @builtin
{
@@ -609,7 +609,7 @@ macro uint char[].hash(char[] c) => (uint)a5hash::hash(c);
macro uint void*.hash(void* ptr) => @generic_hash(((ulong)(uptr)ptr));
<*
@require @typekind(array_ptr) == POINTER &&& @typekind(*array_ptr) == ARRAY
@require $kindof(array_ptr) == POINTER &&& $kindof(*array_ptr) == ARRAY
*>
macro uint hash_array(array_ptr) @local
{
@@ -623,7 +623,7 @@ macro uint hash_array(array_ptr) @local
}
<*
@require @typekind(vec) == VECTOR
@require $kindof(vec) == VECTOR
*>
macro uint hash_vec(vec) @local
{

View File

@@ -45,7 +45,7 @@ fn usz os_pagesize()
@param mask : "The mask for the load"
@param passthru : "The value to use for non masked values"
@require $defined(*ptr = passthru) : "Pointer and passthru must match"
@require @typekind(passthru) == VECTOR : "Expected passthru to be a vector"
@require $kindof(passthru) == VECTOR : "Expected passthru to be a vector"
@require passthru.len == mask.len : "Mask and passthru must have the same length"
@return "A vector with the loaded values where the mask is true, passthru where the mask is false"
@@ -64,7 +64,7 @@ macro masked_load(ptr, bool[<*>] mask, passthru)
@param $alignment : "The alignment to assume for the pointer"
@require $defined(*ptr = passthru) : "Pointer and passthru must match"
@require @typekind(passthru) == VECTOR : "Expected passthru to be a vector"
@require $kindof(passthru) == VECTOR : "Expected passthru to be a vector"
@require passthru.len == mask.len : "Mask and passthru must have the same length"
@require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
@@ -82,8 +82,8 @@ macro @masked_load_aligned(ptr, bool[<*>] mask, passthru, usz $alignment)
@param mask : "The mask for the load"
@param passthru : "The value to use for non masked values"
@require @typekind(ptrvec) == VECTOR : "Expected ptrvec to be a vector"
@require @typekind(passthru) == VECTOR : "Expected passthru to be a vector"
@require $kindof(ptrvec) == VECTOR : "Expected ptrvec to be a vector"
@require $kindof(passthru) == VECTOR : "Expected passthru to be a vector"
@require $defined(*ptrvec[0] = passthru[0]) : "Pointer and passthru must match"
@require passthru.len == mask.len : "Mask and passthru must have the same length"
@require mask.len == ptrvec.len : "Mask and ptrvec must have the same length"
@@ -104,8 +104,8 @@ macro gather(ptrvec, bool[<*>] mask, passthru)
@param passthru : "The value to use for non masked values"
@param $alignment : "The alignment to assume for the pointers"
@require @typekind(ptrvec) == VECTOR : "Expected ptrvec to be a vector"
@require @typekind(passthru) == VECTOR : "Expected passthru to be a vector"
@require $kindof(ptrvec) == VECTOR : "Expected ptrvec to be a vector"
@require $kindof(passthru) == VECTOR : "Expected passthru to be a vector"
@require $defined(*ptrvec[0] = passthru[0]) : "Pointer and passthru must match"
@require passthru.len == mask.len : "Mask and passthru must have the same length"
@require mask.len == ptrvec.len : "Mask and ptrvec must have the same length"
@@ -127,7 +127,7 @@ macro @gather_aligned(ptrvec, bool[<*>] mask, passthru, usz $alignment)
@param mask : "The mask for the store"
@require $defined(*ptr = value) : "Pointer and value must match"
@require @typekind(value) == VECTOR : "Expected value to be a vector"
@require $kindof(value) == VECTOR : "Expected value to be a vector"
@require value.len == mask.len : "Mask and value must have the same length"
*>
macro masked_store(ptr, value, bool[<*>] mask)
@@ -142,7 +142,7 @@ macro masked_store(ptr, value, bool[<*>] mask)
@param $alignment : "The alignment of the pointer"
@require $defined(*ptr = value) : "Pointer and value must match"
@require @typekind(value) == VECTOR : "Expected value to be a vector"
@require $kindof(value) == VECTOR : "Expected value to be a vector"
@require value.len == mask.len : "Mask and value must have the same length"
@require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
@@ -156,8 +156,8 @@ macro @masked_store_aligned(ptr, value, bool[<*>] mask, usz $alignment)
@param ptrvec : "The vector pointer containing the addresses to store to."
@param value : "The value to store masked"
@param mask : "The mask for the store"
@require @typekind(ptrvec) == VECTOR : "Expected ptrvec to be a vector"
@require @typekind(value) == VECTOR : "Expected value to be a vector"
@require $kindof(ptrvec) == VECTOR : "Expected ptrvec to be a vector"
@require $kindof(value) == VECTOR : "Expected value to be a vector"
@require $defined(*ptrvec[0] = value[0]) : "Pointer and value must match"
@require value.len == mask.len : "Mask and value must have the same length"
@require mask.len == ptrvec.len : "Mask and ptrvec must have the same length"
@@ -174,8 +174,8 @@ macro scatter(ptrvec, value, bool[<*>] mask)
@param mask : "The mask for the store"
@param $alignment : "The alignment of the load"
@require @typekind(ptrvec) == VECTOR : "Expected ptrvec to be a vector"
@require @typekind(value) == VECTOR : "Expected value to be a vector"
@require $kindof(ptrvec) == VECTOR : "Expected ptrvec to be a vector"
@require $kindof(value) == VECTOR : "Expected value to be a vector"
@require $defined(*ptrvec[0] = value[0]) : "Pointer and value must match"
@require value.len == mask.len : "Mask and value must have the same length"
@require mask.len == ptrvec.len : "Mask and ptrvec must have the same length"

View File

@@ -322,7 +322,7 @@ macro clone(Allocator allocator, value) @nodiscard
@param slice : "The slice to clone"
@return "A pointer to the cloned slice"
@require @typekind(slice) == SLICE || @typekind(slice) == ARRAY
@require $kindof(slice) == SLICE || $kindof(slice) == ARRAY
*>
macro clone_slice(Allocator allocator, slice) @nodiscard
{
@@ -365,7 +365,7 @@ macro void*? @aligned_alloc(#alloc_fn, usz bytes, usz alignment)
if (alignment < void*.alignof) alignment = void*.alignof;
usz header = AlignedBlock.sizeof + alignment;
usz alignsize = bytes + header;
$if @typekind(#alloc_fn(bytes)) == OPTIONAL:
$if $kindof(#alloc_fn(bytes)) == OPTIONAL:
void* data = #alloc_fn(alignsize)!;
$else
void* data = #alloc_fn(alignsize);
@@ -386,7 +386,7 @@ struct AlignedBlock
macro void? @aligned_free(#free_fn, void* old_pointer)
{
AlignedBlock* desc = (AlignedBlock*)old_pointer - 1;
$if @typekind(#free_fn(desc.start)) == OPTIONAL:
$if $kindof(#free_fn(desc.start)) == OPTIONAL:
#free_fn(desc.start)!;
$else
#free_fn(desc.start);
@@ -403,7 +403,7 @@ macro void*? @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes
void* data_start = desc.start;
void* new_data = @aligned_alloc(#calloc_fn, bytes, alignment)!;
mem::copy(new_data, old_pointer, desc.len < bytes ? desc.len : bytes, 1, 1);
$if @typekind(#free_fn(data_start)) == OPTIONAL:
$if $kindof(#free_fn(data_start)) == OPTIONAL:
#free_fn(data_start)!;
$else
#free_fn(data_start);

View File

@@ -6,7 +6,7 @@
then free the pointer and the atomic variable assuming that they are allocated using the Allocator in the Ref.
@require !$defined(Type.dealloc) ||| $defined(Type.dealloc(&&(Type){})) : "'dealloc' must only take a pointer to the underlying type"
@require !$defined(Type.dealloc) ||| @typeis((Type){}.dealloc(), void) : "'dealloc' must return 'void'"
@require !$defined(Type.dealloc) ||| $typeof((Type){}.dealloc()) == void : "'dealloc' must return 'void'"
*>
module std::core::mem::ref { Type };
import std::thread, std::atomic;
@@ -113,7 +113,7 @@ macro retain(refcounted)
<*
@require $defined(RefCounted* c = refcounted) : "Expected a ref counted value"
@require !$defined(refcounted.dealloc()) ||| @typeis(refcounted.dealloc(), void)
@require !$defined(refcounted.dealloc()) ||| $typeof(refcounted.dealloc()) == void
: "Expected refcounted type to have a valid dealloc"
*>
macro void release(refcounted)

View File

@@ -27,7 +27,7 @@ macro bool is_struct_with_default_print($Type)
<*
Introspect a struct and print it to a formatter
@require @typekind(value) == STRUCT || @typekind(value) == BITSTRUCT : `This macro is only valid on macros`
@require $kindof(value) == STRUCT || $kindof(value) == BITSTRUCT : `This macro is only valid on macros`
*>
macro usz? struct_to_format(value, Formatter* f, bool $force_dump)
{

View File

@@ -98,14 +98,14 @@ macro String? treadline(stream = io::stdin())
*>
macro usz? readline_to_stream(out_stream, in_stream = io::stdin())
{
bool $is_stream = @typeis(in_stream, InStream);
bool $is_stream = $typeof(in_stream) == InStream;
$if $is_stream:
var func = &in_stream.read_byte;
char val = func((void*)in_stream)!;
$else
char val = in_stream.read_byte()!;
$endif
bool $is_out_stream = @typeis(out_stream, OutStream);
bool $is_out_stream = $typeof(out_stream) == OutStream;
$if $is_out_stream:
var out_func = &out_stream.write_byte;
$endif
@@ -215,7 +215,7 @@ macro usz? fprintn(out, x = "")
usz len = fprint(out, x)!;
out.write_byte('\n')!;
$switch:
$case @typeid(out) == OutStream.typeid:
$case $typeof(out) == OutStream:
if (&out.flush) out.flush()!;
$case $defined(out.flush):
out.flush()!;

View File

@@ -45,7 +45,7 @@ fn Path? tcwd() => cwd(tmem) @inline;
*>
macro void? chdir(path)
{
$if @typeis(path, String):
$if $typeof(path) == String:
@pool()
{
return os::native_chdir(temp(path));
@@ -59,7 +59,7 @@ fn Path? temp_directory(Allocator allocator) => os::native_temp_directory(alloca
fn void? delete(Path path) => os::native_remove(path.str_view()) @inline;
macro bool @is_pathlike(#path) => @typeis(#path, String) || @typeis(#path, Path);
macro bool @is_pathlike(#path) @const => $typeof(#path) == String ||| $typeof(#path) == Path;
macro bool is_separator(char c, PathEnv path_env = DEFAULT_ENV)
{
@@ -95,7 +95,7 @@ enum MkdirPermissions
*>
macro bool? mkdir(path, bool recursive = false, MkdirPermissions permissions = NORMAL)
{
$if @typeis(path, String):
$if $typeof(path) == String:
@pool() { return _mkdir(temp(path), recursive, permissions); };
$else
return _mkdir(path, recursive, permissions);
@@ -113,7 +113,7 @@ macro bool? mkdir(path, bool recursive = false, MkdirPermissions permissions = N
*>
macro bool? rmdir(path)
{
$if @typeis(path, String):
$if $typeof(path) == String:
@pool() { return _rmdir(temp(path)); };
$else
return _mkdir(path);

View File

@@ -197,7 +197,7 @@ const char[*] MAX_VARS @private = { [2] = 3, [4] = 5, [8] = 10 };
<*
@require @is_instream(stream)
@require @typekind(x_ptr) == POINTER && $typeof(x_ptr).inner.kindof.is_int()
@require $kindof(x_ptr) == POINTER && $typeof(x_ptr).inner.kindof.is_int()
*>
macro usz? read_varint(stream, x_ptr)
{
@@ -232,7 +232,7 @@ macro usz? read_varint(stream, x_ptr)
}
<*
@require @is_outstream(stream)
@require @typekind(x).is_int()
@require $kindof(x).is_int()
*>
macro usz? write_varint(stream, x)
{

View File

@@ -101,7 +101,7 @@ macro is_approx_rel(x, y, eps)
}
<*
@require values::@is_int(x) : `The input must be an integer`
@require $kindof(x).is_int() : `The input must be an integer`
*>
macro sign(x)
{
@@ -119,7 +119,7 @@ macro sign(x)
*>
macro atan2(x, y)
{
$if @typeis(x, float) && @typeis(y, float):
$if $typeof(x) == float &&& $typeof(y) == float:
return _atan2f(x, y);
$else
return _atan2(x, y);
@@ -128,16 +128,16 @@ macro atan2(x, y)
<*
@require values::@is_int(x) || values::@is_float(x) : "Expected an integer or floating point value"
@require @typekind(sinp) == POINTER : "Expected sinp to be a pointer"
@require $kindof(sinp) == POINTER : "Expected sinp to be a pointer"
@require @typematch(sinp, cosp) : "Expected sinp and cosp to have the same type"
@require $defined(*sinp = x) : "Expected x and sinp/cosp to have the same type"
@require $defined(*sinp = x) : "Expected x and *sinp/*cosp to have the same type"
*>
macro sincos_ref(x, sinp, cosp)
{
$if @typeis(sinp, float*.typeid):
return _sincosf(x, sinp, cosp);
$if $typeof(sinp) == float*:
_sincosf(x, sinp, cosp);
$else
return _sincos(x, sinp, cosp);
_sincos(x, sinp, cosp);
$endif
}
@@ -149,7 +149,7 @@ macro sincos_ref(x, sinp, cosp)
*>
macro sincos(x)
{
$if @typeis(x, float):
$if $typeof(x) == float:
float[<2>] v @noinit;
_sincosf(x, &v[0], &v[1]);
$else
@@ -164,7 +164,7 @@ macro sincos(x)
*>
macro atan(x)
{
$if @typeis(x, float):
$if $typeof(x) == float:
return _atanf(x);
$else
return _atan(x);
@@ -176,7 +176,7 @@ macro atan(x)
*>
macro atanh(x)
{
$if @typeis(x, float):
$if $typeof(x) == float:
return _atanhf(x);
$else
return _atanh(x);
@@ -188,7 +188,7 @@ macro atanh(x)
*>
macro acos(x)
{
$if @typeis(x, float):
$if $typeof(x) == float:
return _acosf(x);
$else
return _acos(x);
@@ -200,7 +200,7 @@ macro acos(x)
*>
macro acosh(x)
{
$if @typeis(x, float):
$if $typeof(x) == float:
return _acoshf(x);
$else
return _acosh(x);
@@ -212,7 +212,7 @@ macro acosh(x)
*>
macro asin(x)
{
$if @typeis(x, float):
$if $typeof(x) == float:
return _asinf(x);
$else
return _asin(x);
@@ -224,7 +224,7 @@ macro asin(x)
*>
macro asinh(x)
{
$if @typeis(x, float):
$if $typeof(x) == float:
return _asinhf(x);
$else
return _asinh(x);
@@ -239,7 +239,7 @@ macro ceil(x) => $$ceil(x);
<*
Ceil for compile time evaluation.
@require @typeis($input, double) || @typeis($input, float) : "Only float and double may be used"
@require $kindof($input) == FLOAT : "Only float and double may be used"
*>
macro @ceil($input) @const => $$ceil($input);

View File

@@ -8,7 +8,7 @@ Sort list using the quick sort algorithm.
*>
macro insertionsort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin @safemacro
{
$if @typekind(list) == POINTER &&& (@typekind(*list) == ARRAY || @typekind(*list) == VECTOR):
$if $kindof(list) == POINTER &&& ($kindof(*list) == ARRAY || $kindof(*list) == VECTOR):
$typeof((*list)[0])[] list2 = list;
is::isort{$typeof(list2), $typeof(cmp), $typeof(context)}(list2, 0, list.len, cmp, context);
$else

View File

@@ -9,7 +9,7 @@ Sort list using the quick sort algorithm.
*>
macro quicksort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
{
$if @typekind(list) == POINTER &&& (@typekind(*list) == ARRAY || @typekind(*list) == VECTOR):
$if $kindof(list) == POINTER &&& ($kindof(*list) == ARRAY || $kindof(*list) == VECTOR):
$typeof((*list)[0])[] list2 = list;
qs::qsort{$typeof(list2), $typeof(cmp), $typeof(context)}(list2, 0, (isz)list.len - 1, cmp, context);
$else

View File

@@ -16,7 +16,7 @@ macro bool @is_sortable(#list)
return false;
$case !$defined(#list.len):
return false;
$case @typekind(#list) == VECTOR || @typekind(#list) == ARRAY:
$case $kindof(#list) == VECTOR || $kindof(#list) == ARRAY:
return false;
$case $defined(&#list[0]) &&& !types::is_same($typeof(&#list[0]), $typeof(#list[0])*):
return false;
@@ -49,7 +49,7 @@ macro bool @is_cmp_key_fn(#key_fn, #list)
{
$switch:
$case @is_empty_macro_slot(#key_fn): return true;
$case $typeof(#key_fn).kindof != FUNC: return false;
$case $kindof(#key_fn) != FUNC: return false;
$case $typeof(#key_fn).returns.kindof != UNSIGNED_INT: return false;
$case $defined(#key_fn(#list[0])): return true;
$case $defined(#key_fn(&&(#list[0]))): return true;

View File

@@ -30,6 +30,9 @@
- Update error message for missing body after if/for/etc #2289.
- `@is_const` is deprecated in favour of directly using `$defined`.
- `@is_lvalue(#value)` is deprecated in favour of directly using `$defined`.
- Added `$kindof` compile time function.
- Deprecated `@typekind` macro in favour of `$kindof`.
- Deprecated `@typeis` macro in favour of `$typeof(#foo) == int`.
### Fixes
- List.remove_at would incorrectly trigger ASAN.

View File

@@ -1267,6 +1267,7 @@ typedef enum
TOKEN_CT_IF, // $if
TOKEN_CT_INCLUDE, // $include
TOKEN_CT_IS_CONST, // $is_const
TOKEN_CT_KINDOF, // $kindof
TOKEN_CT_NAMEOF, // $nameof
TOKEN_CT_OFFSETOF, // $offsetof
TOKEN_CT_QNAMEOF, // $qnameof

View File

@@ -1268,6 +1268,27 @@ static Expr *parse_ct_assignable(ParseContext *c, Expr *left, SourceSpan lhs_sta
return expr;
}
static Expr *parse_ct_kindof(ParseContext *c, Expr *left, SourceSpan lhs_start UNUSED)
{
ASSERT(!left && "Unexpected left hand side");
Expr *access = expr_new(EXPR_ACCESS_UNRESOLVED, c->span);
advance(c);
CONSUME_OR_RET(TOKEN_LPAREN, poisoned_expr);
ASSIGN_EXPR_OR_RET(Expr *inner, parse_expr(c), poisoned_expr);
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_expr);
Expr *typeof_expr = expr_new(EXPR_TYPEINFO, inner->span);
TypeInfo *type_info = type_info_new(TYPE_INFO_TYPEOF, inner->span);
type_info->optional = try_consume(c, TOKEN_BANG);
type_info->unresolved_type_expr = inner;
typeof_expr->type_expr = type_info;
access->access_unresolved_expr.parent = typeof_expr;
Expr *ident = expr_new(EXPR_UNRESOLVED_IDENTIFIER, c->span);
ident->unresolved_ident_expr.ident = type_property_list[TYPE_PROPERTY_KINDOF];
access->access_unresolved_expr.child = ident;
RANGE_EXTEND_PREV(access);
return access;
}
/**
* ct_arg ::= VACOUNT | (VAARG | VAREF | VAEXPR | VACONST) '(' expr ')'
*/
@@ -2170,6 +2191,7 @@ ParseRule rules[TOKEN_EOF + 1] = {
[TOKEN_CT_EXTNAMEOF] = { parse_ct_call, NULL, PREC_NONE },
[TOKEN_CT_FEATURE] = { parse_ct_call, NULL, PREC_NONE },
[TOKEN_CT_IS_CONST] = {parse_ct_is_const, NULL, PREC_NONE },
[TOKEN_CT_KINDOF] = { parse_ct_kindof, NULL, PREC_NONE },
[TOKEN_CT_NAMEOF] = { parse_ct_call, NULL, PREC_NONE },
[TOKEN_CT_OFFSETOF] = { parse_ct_call, NULL, PREC_NONE },
[TOKEN_CT_QNAMEOF] = { parse_ct_call, NULL, PREC_NONE },

View File

@@ -1383,13 +1383,14 @@ Ast *parse_stmt(ParseContext *c)
case TOKEN_CT_ASSIGNABLE:
case TOKEN_CT_CONCAT:
case TOKEN_CT_CONST_IDENT:
case TOKEN_CT_IS_CONST:
case TOKEN_CT_DEFINED:
case TOKEN_CT_EMBED:
case TOKEN_CT_EVAL:
case TOKEN_CT_EXTNAMEOF:
case TOKEN_CT_FEATURE:
case TOKEN_CT_IDENT:
case TOKEN_CT_IS_CONST:
case TOKEN_CT_KINDOF:
case TOKEN_CT_NAMEOF:
case TOKEN_CT_OFFSETOF:
case TOKEN_CT_OR:

View File

@@ -363,6 +363,8 @@ const char *token_type_to_string(TokenType type)
return "$is_const";
case TOKEN_CT_INCLUDE:
return "$include";
case TOKEN_CT_KINDOF:
return "$kindof";
case TOKEN_CT_VACOUNT:
return "$vacount";
case TOKEN_CT_VATYPE:

View File

@@ -15,8 +15,7 @@ fn void abs() @test
CInt x = 21;
assert(libc::abs(x) == 21);
assert(libc::abs(-x) == 21);
$assert @typeis(libc::abs(x), CInt);
$assert @typeis(libc::abs(-x), CInt);
$assert $typeof(libc::abs(x)) == CInt;
}
fn void asctime() @test
@@ -72,37 +71,28 @@ fn void atexit() @test
fn void atof() @test
{
assert(libc::atof("123.45") == 123.45);
$assert @typeis(libc::atof("123.45"), double);
$assert $typeof(libc::atof("123.45")) == double;
assert(libc::atof("-3.14") == -3.14);
$assert @typeis(libc::atof("-3.14"), double);
assert(libc::atof("x") == 0.0);
$assert @typeis(libc::atof("x"), double);
assert(libc::atof("") == 0.0);
$assert @typeis(libc::atof(""), double);
}
fn void atoi() @test
{
assert(libc::atoi("123") == 123);
$assert @typeis(libc::atoi("123"), int);
$assert $typeof(libc::atoi("123")) == CInt;
assert(libc::atoi("-3.14") == -3);
$assert @typeis(libc::atoi("-3.14"), int);
assert(libc::atoi("x") == 0);
$assert @typeis(libc::atoi("x"), int);
assert(libc::atoi("") == 0);
$assert @typeis(libc::atoi(""), int);
}
fn void atoll() @test
{
assert(libc::atoi("123") == 123);
$assert @typeis(libc::atoi("123"), int);
assert(libc::atoi("-3.14") == -3);
$assert @typeis(libc::atoi("-3.14"), int);
assert(libc::atoi("x") == 0);
$assert @typeis(libc::atoi("x"), int);
assert(libc::atoi("") == 0);
$assert @typeis(libc::atoi(""), int);
assert(libc::atoll("123") == 123);
assert(libc::atoll("-3.14") == -3);
$assert $typeof(libc::atoll("-3.14")) == CLongLong;
assert(libc::atoll("x") == 0);
assert(libc::atoll("") == 0);
}
// Compare function, struct and function for libc::bsearch test

View File

@@ -59,7 +59,7 @@ fn void test_abs() @test
assert(math::abs(y) == 123.0);
float z = -21.0f;
assert(math::abs(z) == 21.0f);
$assert @typeis(math::abs(z), float);
$assert $typeof(math::abs(z)) == float;
int[<3>] xx = { -1, -1000, 1000 };
assert(math::abs(xx) == (int[<3>]) { 1, 1000, 1000 });
double[<3>] yy = { -1, -0.5, 1000 };
@@ -72,9 +72,9 @@ fn void test_acos() @test
double [<3>] out = { 0.0, math::PI_2, math::PI };
double [<6>] in2 = { 0.9, 0.6, 0.1, -0.1, -0.6, -0.9 };
double [<6>] out2 = { 0.45102681179626236, 0.9272952180016123, 1.4706289056333368, 1.6709637479564565, 2.214297435588181, 2.6905658417935308 };
assert(@typeis(math::acos(in[0]), double));
assert(@typeis(math::acos((float)in[0]), float));
assert(@typeis(math::acos((double)in[0]), double));
assert($typeof(math::acos(in[0])) == double);
assert($typeof(math::acos((float)in[0])) == float);
assert($typeof(math::acos((double)in[0])) == double);
for (int i = 0; i < 2; i++)
{
double x = math::acos(in[i]);
@@ -108,9 +108,9 @@ fn void test_acosh() @test
{
int [<5>] in = { 0, -1, 1, 2, 231 };
double [<3>] out = { 0.0, 1.3169578969248166, 6.135560205979194 };
assert(@typeis(math::acosh(in[0]), double));
assert(@typeis(math::acosh((float)in[0]), float));
assert(@typeis(math::acosh((double)in[0]), double));
assert($typeof(math::acosh(in[0])) == double);
assert($typeof(math::acosh((float)in[0])) == float);
assert($typeof(math::acosh((double)in[0])) == double);
for (int i = 0; i < 2; i++)
{
assert(math::is_nan(math::acosh(in[i])), "acosh(%d)=%f is not nan", in[i]);
@@ -135,9 +135,9 @@ fn void test_asin() @test
double [<3>] out = { math::PI_2, 0.0, -math::PI_2 };
double [<6>] in2 = { 0.98, 0.6, 0.1, -0.1, -0.6, -0.98 };
double [<6>] out2 = { 1.3704614844717768, 0.6435011087932844, 0.1001674211615598, -0.1001674211615598, -0.6435011087932844, -1.3704614844717768 };
assert(@typeis(math::asin(in[0]), double));
assert(@typeis(math::asin((float)in[0]), float));
assert(@typeis(math::asin((double)in[0]), double));
assert($typeof(math::asin(in[0])) == double);
assert($typeof(math::asin((float)in[0])) == float);
assert($typeof(math::asin((double)in[0])) == double);
for (int i = 0; i < 2; i++)
{
assert(math::is_nan(math::asin(in[i])), "asin(%d)=%f is not nan", in[i]);
@@ -167,9 +167,9 @@ fn void test_asinh() @test
{
int [<5>] in = { 231, 1, 0, -1, -231 };
double [<5>] out = { 6.135569576118435, 0.881373587019543, 0.0, -0.881373587019543, -6.135569576118435 };
assert(@typeis(math::asinh(in[0]), double));
assert(@typeis(math::asinh((float)in[0]), float));
assert(@typeis(math::asinh((double)in[0]), double));
assert($typeof(math::asinh(in[0])) == double);
assert($typeof(math::asinh((float)in[0])) == float);
assert($typeof(math::asinh((double)in[0])) == double);
for (int i = 0; i < 5; i++)
{
double x = math::asinh(in[i]);
@@ -187,9 +187,9 @@ fn void test_atan() @test
double [<9>] out = { 1.5664673495078372, 1.2490457723982544, 1.1071487177940904, math::PI_4, 0.0, -math::PI_4, -1.1071487177940904, -1.2490457723982544, -1.5664673495078372 };
double [<6>] in2 = { 0.6, 0.4, 0.1, -0.1, -0.4, -0.6 };
double [<6>] out2 = { 0.5404195002705842, 0.3805063771123649, 0.09966865249116204, -0.09966865249116204, -0.3805063771123649, -0.5404195002705842 };
assert(@typeis(math::atan(in[0]), double));
assert(@typeis(math::atan((float)in[0]), float));
assert(@typeis(math::atan((double)in[0]), double));
assert($typeof(math::atan(in[0])) == double);
assert($typeof(math::atan((float)in[0])) == float);
assert($typeof(math::atan((double)in[0])) == double);
for (int i = 0; i < 9; i++)
{
double x = math::atan(in[i]);
@@ -213,9 +213,9 @@ fn void test_atanh() @test
int [<4>] in = { 231, -231, 1, -1 };
double [<6>] in2 = {0.8, 0.5, 0.3, -0.3, -0.5, -0.8 };
double [<6>] out = { 1.0986122886681098, 0.5493061443340548, 0.30951960420311175, -0.30951960420311175, -0.5493061443340548, -1.0986122886681098 };
assert(@typeis(math::atanh(in[0]), double));
assert(@typeis(math::atanh((float)in[0]), float));
assert(@typeis(math::atanh((double)in[0]), double));
assert($typeof(math::atanh(in[0])) == double);
assert($typeof(math::atanh((float)in[0])) == float);
assert($typeof(math::atanh((double)in[0])) == double);
for (int i = 0; i < 2; i++)
{
assert(math::is_nan(math::atanh(in[i])), "atanh(%d) is not nan", in[i]);
@@ -308,7 +308,7 @@ fn void test_ceil() @test
assert(math::ceil(d) == 1);
d = -0.9;
assert(math::ceil(d) == 0);
$assert @typeis(math::ceil(d), double);
$assert $typeof(math::ceil(d)) == double;
float f = -123.1f;
assert(math::ceil(f) == -123.0f);
f = 123.1f;
@@ -317,7 +317,7 @@ fn void test_ceil() @test
assert(math::ceil(f) == 1.0f);
f = -0.9f;
assert(math::ceil(f) == 0.0f);
$assert @typeis(math::ceil(f), float);
$assert $typeof(math::ceil(f)) == float;
double[<5>] vec = { -123.1, 123.1, 0.1, -0.9, 0 };
assert(math::ceil(vec) == (double[<5>]) { -123, 124, 1, 0, 0 });
}
@@ -342,9 +342,9 @@ fn void test_cos() @test
float [<2>] out2 = { -1.0f, 1.0f };
double [<2>] in3 = { math::PI, 0.0 };
double [<2>] out3 = { -1.0, 1.0 };
assert(@typeis(math::cos(in[0]), double));
assert(@typeis(math::cos((float)in[0]), float));
assert(@typeis(math::cos((double)in[0]), double));
assert($typeof(math::cos(in[0])) == double);
assert($typeof(math::cos((float)in[0])) == float);
assert($typeof(math::cos((double)in[0])) == double);
for (int i = 0; i < 5; i++)
{
double x = math::cos(in[i]);
@@ -371,9 +371,9 @@ fn void test_exp() @test
float[<6>] out2 = {6.049647464412946f, 1.8221188003905089f, 1.4918246976412703f, 0.6703200460356393f, 0.44932896411722156f, 0.16529888822158656f };
double[<6>] in3 = { 1.8, 0.6, 0.4, -0.4, -0.8, -1.8 };
double[<6>] out3 = {6.049647464412946, 1.8221188003905089, 1.4918246976412703, 0.6703200460356393, 0.44932896411722156, 0.16529888822158656 };
assert(@typeis(math::exp(in[0]), double));
assert(@typeis(math::exp((float)in[0]), float));
assert(@typeis(math::exp((double)in[0]), double));
assert($typeof(math::exp(in[0])) == double);
assert($typeof(math::exp((float)in[0])) == float);
assert($typeof(math::exp((double)in[0])) == double);
for (int i = 0; i < 5; i++)
{
double x = math::exp(in[i]);
@@ -402,7 +402,7 @@ fn void test_floor() @test
assert(math::floor(d) == 0);
d = -0.1;
assert(math::floor(d) == -1);
$assert @typeis(math::floor(d), double);
$assert $typeof(math::floor(d)) == double;
float f = -123.1f;
assert(math::floor(f) == -124.0f);
f = 123.1f;
@@ -411,7 +411,7 @@ fn void test_floor() @test
assert(math::floor(f) == 0.0f);
f = -0.1f;
assert(math::floor(f) == -1.0f);
$assert @typeis(math::floor(f), float);
$assert $typeof(math::floor(f)) == float;
double[<5>] vec = { -123.1, 123.1, 0.9, -0.1, 0 };
assert(math::floor(vec) == (double[<5>]) { -124, 123, 0, -1, 0 });
}
@@ -426,15 +426,15 @@ fn void test_log() @test
double[<4>] bx = { 1.0 / math::E, 1.0 / (math::E * math::E), 1.0 / (math::E * math::E), 1.0 / math::E };
double[<4>] in3 = { math::E * math::E, math::E, 1.0 / math::E, 1.0 / (math::E * math::E) };
double[<4>] out3 = { -2.0, -0.5, 0.5, 2.0 };
assert(@typeis(math::log(in[0], in[0]), double));
assert(@typeis(math::log(in[0], (float)in[0]), float));
assert(@typeis(math::log((float)in[0], in[0]), float));
assert(@typeis(math::log(in[0], (double)in[0]), double));
assert(@typeis(math::log((double)in[0], in[0]), double));
assert(@typeis(math::log((float)in[0], (float)in[0]), float));
assert(@typeis(math::log((float)in[0], (double)in[0]), double));
assert(@typeis(math::log((double)in[0], (float)in[0]), double));
assert(@typeis(math::log((double)in[0], (double)in[0]), double));
assert($typeof(math::log(in[0], in[0])) == double);
assert($typeof(math::log(in[0], (float)in[0])) == float);
assert($typeof(math::log((float)in[0], in[0])) == float);
assert($typeof(math::log(in[0], (double)in[0])) == double);
assert($typeof(math::log((double)in[0], in[0])) == double);
assert($typeof(math::log((float)in[0], (float)in[0])) == float);
assert($typeof(math::log((float)in[0], (double)in[0])) == double);
assert($typeof(math::log((double)in[0], (float)in[0])) == double);
assert($typeof(math::log((double)in[0], (double)in[0])) == double);
for (int i = 0; i < 8; i++)
{
int base = (i < 4) ? 10 : 8;
@@ -483,9 +483,9 @@ fn void test_pow() @test
float[<5>] out2 = { 1.0f / (math::E * math::E), 1.0f / math::E, 1.0f, math::E, math::E * math::E };
double[<2>] base3 = { -1.0 / math::E, 1.0 / math::E };
double[<5>] out3 = { 1.0 / (math::E * math::E), 1.0 / math::E, 1.0, math::E, math::E * math::E };
assert(@typeis(math::pow(e[1], e[1]), double));
assert(@typeis(math::pow((float)e[1], e[1]), float));
assert(@typeis(math::pow((double)e[1], e[1]), double));
assert($typeof(math::pow(e[1], e[1])) == double);
assert($typeof(math::pow((float)e[1], e[1])) == float);
assert($typeof(math::pow((double)e[1], e[1])) == double);
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 2; j++)
@@ -533,7 +533,7 @@ fn void test_sign() @test
assert(math::sign(y) == 0);
y = (uint)-21;
assert(math::sign(y) == 1);
assert(@typeis(math::sign(y), uint));
assert($typeof(math::sign(y)) == uint);
}
@@ -545,9 +545,9 @@ fn void test_sin() @test
float [<2>] out2 = { 1.0f, -1.0f };
double [<2>] in3 = { math::PI_2, -math::PI_2 };
double [<2>] out3 = { 1.0, -1.0 };
assert(@typeis(math::sin(in[0]), double));
assert(@typeis(math::sin((float)in[0]), float));
assert(@typeis(math::sin((double)in[0]), double));
assert($typeof(math::sin(in[0])) == double);
assert($typeof(math::sin((float)in[0])) == float);
assert($typeof(math::sin((double)in[0])) == double);
for (int i = 0; i < 5; i++)
{
double x = math::sin(in[i]);
@@ -574,9 +574,9 @@ fn void test_tan() @test
float [<2>] out2 = { 1.0f, -1.0f };
double [<2>] in3 = { math::PI_4, -math::PI_4 };
double [<2>] out3 = { 1.0, -1.0 };
assert(@typeis(math::tan(in[0]), double));
assert(@typeis(math::tan((float)in[0]), float));
assert(@typeis(math::tan((double)in[0]), double));
assert($typeof(math::tan(in[0])) == double);
assert($typeof(math::tan((float)in[0])) == float);
assert($typeof(math::tan((double)in[0])) == double);
for (int i = 0; i < 5; i++)
{
double x = math::tan(in[i]);
@@ -605,7 +605,7 @@ fn void test_trunc() @test
assert(math::trunc(d) == 0);
d = -0.9;
assert(math::trunc(d) == 0);
$assert @typeis(math::trunc(d), double);
$assert $typeof(math::trunc(d)) == double;
float f = -123.9f;
assert(math::trunc(f) == -123.0f);
f = 123.9f;
@@ -614,7 +614,7 @@ fn void test_trunc() @test
assert(math::trunc(f) == 0.0f);
f = -0.9f;
assert(math::trunc(f) == -0.0f);
$assert @typeis(math::trunc(f), float);
$assert $typeof(math::trunc(f)) == float;
double[<5>] vec = { -123.9, 123.9, 0.9, -0.9, 0 };
assert(math::trunc(vec) == (double[<5>]) { -123, 123, 0, 0, 0 });
}

View File

@@ -8,8 +8,8 @@ fn void test_vec2_init() @test
{
float[<2>] v1 = { 1.0f, 2.0f };
double[<2>] v2 = { 1.0, 2.0 };
$assert @typeis(v1[0], float);
$assert @typeis(v2[0], double);
$assert $typeof(v1[0]) == float;
$assert $typeof(v2[0]) == double;
assert(v1[0] == 1.0f && v1[1] == 2.0f);
assert(v2[0] == 1.0 && v2[1] == 2.0);
}
@@ -116,10 +116,10 @@ fn void test_type_consistency() @test
{
float[<2>] vf = { 1.0f, 2.0f };
double[<2>] vd = { 1.0, 2.0 };
$assert @typeis(vf.sq_magnitude(), float);
$assert @typeis(vd.sq_magnitude(), double);
$assert $typeof(vf.sq_magnitude()) == float;
$assert $typeof(vd.sq_magnitude()) == double;
float[<3>] v3f = { 1.0f, 2.0f, 3.0f };
double[<3>] v3d = { 1.0, 2.0, 3.0 };
$assert @typeis(v3f.cross(v3f)[0], float);
$assert @typeis(v3d.cross(v3d)[0], double);
$assert $typeof(v3f.cross(v3f)[0]) == float;
$assert $typeof(v3d.cross(v3d)[0]) == double;
}