Add rand_in_range random function. Fix methodsof to apply to more types. Prevent methodsof in the wrong stage.

This commit is contained in:
Christoffer Lerno
2024-09-25 00:18:11 +02:00
parent a258f2084f
commit 6f7ffbeb3c
8 changed files with 77 additions and 40 deletions

View File

@@ -29,15 +29,35 @@ macro void seed_entropy(random)
}
/**
* Get the next value between 0 and max (not including max).
* Get the next value between 0 and range (not including range).
*
* @require is_random(random)
* @require max > 0
* @require range > 0
**/
macro int next(random, int max)
macro int next(random, uint range)
{
if (max == 1) return 0;
return (int)(random.next_long() % (uint)max);
if (range == 1) return 0;
uint mask = ~0U;
range--;
mask >>= range.clz();
uint x @noinit;
do
{
x = random.next_int() & mask;
}
while (x > range);
return x;
}
/**
* Get a random in the range [min, max], both included.
*
* @require is_random(random)
* @require max >= min
**/
macro int next_in_range(random, int min, int max)
{
return next(random, max - min + 1) + min;
}
def DefaultRandom = Sfc64Random;
@@ -55,14 +75,23 @@ fn void srand(ulong seed) @builtin
}
/**
* Get a default random value between 0 and max (not including max)
* Get a default random value between 0 and range (not including range)
**/
fn int rand(int max) @builtin
fn int rand(int range) @builtin
{
init_default_random();
return next(&default_random, max);
return next(&default_random, range);
}
/**
* Get a random in the range, both included.
* @require max >= min
**/
fn int rand_in_range(int min, int max) @builtin
{
init_default_random();
return next_in_range(&default_random, min, max);
}
fn double rnd() @builtin
{

View File

@@ -65,7 +65,7 @@
- Add support for the QOI format.
- Add `io::read_new_fully` for reading to the end of a stream.
- Add `io::wrap_bytes` for reading bytes with `io` functions.
- Add `rnd` default random function.
- Add `rnd` and `rand_in_range` default random functions.
## 0.6.2 Change list

View File

@@ -853,7 +853,7 @@ typedef struct
{
Decl *type;
TypeProperty property;
} ExprTagOf;
} ExprTypeCall;
typedef struct
{
@@ -1162,7 +1162,7 @@ struct Expr_
ExprSwizzle swizzle_expr;
ExprTernary ternary_expr; // 16
BuiltinDefine benchmark_hook_expr;
ExprTagOf tag_of_expr;
ExprTypeCall type_call_expr;
BuiltinDefine test_hook_expr;
Expr** try_unwrap_chain_expr; // 8
ExprTryUnwrap try_unwrap_expr; // 24
@@ -3350,7 +3350,7 @@ static inline void expr_set_span(Expr *expr, SourceSpan loc)
case EXPR_VASPLAT:
case EXPR_MACRO_BODY:
case EXPR_DEFAULT_ARG:
case EXPR_TAGOF:
case EXPR_TYPECALL:
case EXPR_MEMBER_GET:
break;
}

View File

@@ -290,7 +290,7 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
Expr *expr = expr_copy(source_expr);
switch (source_expr->expr_kind)
{
case EXPR_TAGOF:
case EXPR_TYPECALL:
case EXPR_ANYSWITCH:
UNREACHABLE
case EXPR_OTHER_CONTEXT:

View File

@@ -759,7 +759,7 @@ typedef enum
EXPR_COMPOUND_LITERAL,
EXPR_COND,
EXPR_CONST,
EXPR_TAGOF,
EXPR_TYPECALL,
EXPR_CT_AND_OR,
EXPR_CT_ARG,
EXPR_CT_APPEND,
@@ -1601,7 +1601,7 @@ typedef enum
case EXPR_CT_CASTABLE: case EXPR_CT_IS_CONST: \
case EXPR_CT_ARG: case EXPR_TYPEINFO: case EXPR_CT_IDENT: case EXPR_HASH_IDENT: \
case EXPR_COMPILER_CONST: case EXPR_CT_CALL: \
case EXPR_SPLAT: case EXPR_ANYSWITCH: case EXPR_STRINGIFY: case EXPR_TAGOF: \
case EXPR_SPLAT: case EXPR_ANYSWITCH: case EXPR_STRINGIFY: case EXPR_TYPECALL: \
case EXPR_CT_EVAL: case EXPR_CT_CONCAT: case EXPR_CT_APPEND
static_assert(EXPR_LAST < 128, "Too many expression types");

View File

@@ -156,7 +156,7 @@ bool expr_is_runtime_const(Expr *expr)
case EXPR_TEST_HOOK:
case EXPR_ANYSWITCH:
case EXPR_BITASSIGN:
case EXPR_TAGOF:
case EXPR_TYPECALL:
case EXPR_BINARY:
case EXPR_OPERATOR_CHARS:
case EXPR_STRINGIFY:
@@ -614,7 +614,7 @@ bool expr_is_pure(Expr *expr)
return exprid_is_pure(expr->pointer_offset_expr.ptr) && exprid_is_pure(expr->pointer_offset_expr.offset);
case EXPR_COMPILER_CONST:
case EXPR_CONST:
case EXPR_TAGOF:
case EXPR_TYPECALL:
case EXPR_CT_AND_OR:
case EXPR_CT_CONCAT:
case EXPR_CT_APPEND:

View File

@@ -548,7 +548,7 @@ static bool sema_binary_is_expr_lvalue(SemaContext *context, Expr *top_expr, Exp
case EXPR_SLICE_COPY:
case EXPR_SPLAT:
case EXPR_STRINGIFY:
case EXPR_TAGOF:
case EXPR_TYPECALL:
case EXPR_TERNARY:
case EXPR_TRY_UNWRAP:
case EXPR_TRY_UNWRAP_CHAIN:
@@ -588,7 +588,7 @@ static bool expr_may_ref(Expr *expr)
case EXPR_CT_IDENT:
case EXPR_EMBED:
case EXPR_DEFAULT_ARG:
case EXPR_TAGOF:
case EXPR_TYPECALL:
case EXPR_MEMBER_GET:
return false;
case EXPR_OTHER_CONTEXT:
@@ -2492,14 +2492,14 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl
}
}
static inline bool sema_expr_analyse_tagof(SemaContext *context, Expr *expr)
static inline bool sema_expr_analyse_typecall(SemaContext *context, Expr *expr)
{
expr->call_expr.arguments = sema_expand_vasplat_exprs(context, expr->call_expr.arguments);
Expr **args = expr->call_expr.arguments;
unsigned arg_count = vec_size(args);
Expr *tag = exprptr(expr->call_expr.function);
Decl *decl = tag->tag_of_expr.type;
bool is_has = tag->tag_of_expr.property == TYPE_PROPERTY_HAS_TAGOF;
Decl *decl = tag->type_call_expr.type;
bool is_has = tag->type_call_expr.property == TYPE_PROPERTY_HAS_TAGOF;
const char *name = is_has ? "has_tagof" : "tagof";
if (arg_count != 1) RETURN_SEMA_ERROR(expr, "Expected a single string argument to '%s'.", name);
Expr *key = args[0];
@@ -2603,8 +2603,8 @@ static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr, bool
Expr *struct_var = NULL;
switch (func_expr->expr_kind)
{
case EXPR_TAGOF:
return sema_expr_analyse_tagof(context, expr);
case EXPR_TYPECALL:
return sema_expr_analyse_typecall(context, expr);
case EXPR_BUILTIN:
return sema_expr_analyse_builtin_call(context, expr);
case EXPR_IDENTIFIER:
@@ -3623,8 +3623,8 @@ static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *e
{
case TYPE_PROPERTY_TAGOF:
case TYPE_PROPERTY_HAS_TAGOF:
expr->expr_kind = EXPR_TAGOF;
expr->tag_of_expr = (ExprTagOf) { .type = decl, .property = type_property };
expr->expr_kind = EXPR_TYPECALL;
expr->type_call_expr = (ExprTypeCall) { .type = decl, .property = type_property };
return true;
case TYPE_PROPERTY_GET:
expr->expr_kind = EXPR_MEMBER_GET;
@@ -3647,7 +3647,6 @@ static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *e
sema_create_const_membersof(context, expr, decl->type->canonical, parent->const_expr.member.align, parent->const_expr.member.offset);
return true;
case TYPE_PROPERTY_METHODSOF:
sema_create_const_methodsof(context, expr, decl->type->canonical);
case TYPE_PROPERTY_KINDOF:
case TYPE_PROPERTY_SIZEOF:
return sema_expr_rewrite_to_type_property(context, expr, decl->type->canonical, type_property, decl->type->canonical);
@@ -4414,12 +4413,19 @@ static bool sema_type_property_is_valid_for_type(Type *original_type, TypeProper
case TYPE_PROPERTY_METHODSOF:
switch (type->type_kind)
{
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_BITSTRUCT:
return true;
default:
case TYPE_POISONED:
case TYPE_VOID:
case TYPE_FUNC_RAW:
case TYPE_TYPEDEF:
case TYPE_UNTYPED_LIST:
case TYPE_FLEXIBLE_ARRAY:
case TYPE_OPTIONAL:
case TYPE_WILDCARD:
case TYPE_TYPEINFO:
case TYPE_MEMBER:
return false;
default:
return true;
}
case TYPE_PROPERTY_PARAMSOF:
case TYPE_PROPERTY_PARAMS:
@@ -4501,10 +4507,12 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr,
return true;
}
case TYPE_PROPERTY_METHODSOF:
{
if (context->compilation_unit->module->stage <= ANALYSIS_DECLS)
{
RETURN_SEMA_ERROR(expr, "'methodsof' is not available until after declaration analysis is complete.");
}
sema_create_const_methodsof(context, expr, flat);
return true;
}
case TYPE_PROPERTY_PARAMSOF:
return sema_create_const_paramsof(context, expr, flat);
case TYPE_PROPERTY_PARAMS:
@@ -4538,8 +4546,8 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr,
return true;
case TYPE_PROPERTY_TAGOF:
case TYPE_PROPERTY_HAS_TAGOF:
expr->expr_kind = EXPR_TAGOF;
expr->tag_of_expr = (ExprTagOf) {
expr->expr_kind = EXPR_TYPECALL;
expr->type_call_expr = (ExprTypeCall) {
.type = type->type_kind == TYPE_FUNC_PTR
? type->pointer->function.decl
: type->decl,
@@ -8624,7 +8632,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
case EXPR_POST_UNARY:
case EXPR_TYPEID:
case EXPR_TYPEID_INFO:
case EXPR_TAGOF:
case EXPR_TYPECALL:
case EXPR_MEMBER_GET:
if (!sema_analyse_expr(active_context, main_expr)) return false;
break;
@@ -9007,7 +9015,7 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr,
case EXPR_TRY_UNWRAP_CHAIN:
case EXPR_TYPEID_INFO:
UNREACHABLE
case EXPR_TAGOF:
case EXPR_TYPECALL:
RETURN_SEMA_ERROR(expr, "Expected '()' after this.");
case EXPR_OTHER_CONTEXT:
context = expr->expr_other_context.context;
@@ -9248,7 +9256,7 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr)
return false;
}
break;
case EXPR_TAGOF:
case EXPR_TYPECALL:
RETURN_SEMA_ERROR(expr, "A tag name must be given.");
case EXPR_BUILTIN:
RETURN_SEMA_ERROR(expr, "A builtin must be followed by ().");

View File

@@ -664,7 +664,7 @@ static inline bool sema_expr_valid_try_expression(Expr *expr)
case EXPR_POST_UNARY:
case EXPR_TERNARY:
case EXPR_LAST_FAULT:
case EXPR_TAGOF:
case EXPR_TYPECALL:
case EXPR_MEMBER_GET:
return false;
case EXPR_BITACCESS: