Allow indexing of constant strings. Fixed reverse indexing of constant initializers.

This commit is contained in:
Christoffer Lerno
2023-08-30 16:36:29 +02:00
parent dd0dc1a936
commit 82ba02a904
7 changed files with 76 additions and 19 deletions

View File

@@ -22,6 +22,7 @@
- Fix to void expression blocks - Fix to void expression blocks
- Temporary objects may now invoke methods using ref parameters. - Temporary objects may now invoke methods using ref parameters.
- Delete object files after successful linking. - Delete object files after successful linking.
- Compile time subscript of constant strings and bytes.
- `@if` introduced, other top level conditional compilation removed. - `@if` introduced, other top level conditional compilation removed.
- `@dynamic` and `@interface` for dynamic dispatch. - `@dynamic` and `@interface` for dynamic dispatch.
- `$if` now uses `$if <expr>:` syntax. - `$if` now uses `$if <expr>:` syntax.

View File

@@ -2214,7 +2214,7 @@ INLINE void expr_rewrite_const_untyped_list(Expr *expr, Expr **elements);
void expr_rewrite_to_builtin_access(Expr *expr, Expr *parent, BuiltinAccessKind kind, Type *type); void expr_rewrite_to_builtin_access(Expr *expr, Expr *parent, BuiltinAccessKind kind, Type *type);
void expr_rewrite_to_string(Expr *expr_to_rewrite, const char *string); void expr_rewrite_to_string(Expr *expr_to_rewrite, const char *string);
void expr_rewrite_to_const_zero(Expr *expr, Type *type); void expr_rewrite_to_const_zero(Expr *expr, Type *type);
bool expr_rewrite_to_const_initializer_index(Type *list_type, ConstInitializer *list, Expr *result, unsigned index); bool expr_rewrite_to_const_initializer_index(Type *list_type, ConstInitializer *list, Expr *result, unsigned index, bool from_back);
void expr_rewrite_to_variable(Expr *expr, Decl *decl); void expr_rewrite_to_variable(Expr *expr, Decl *decl);
void expr_rewrite_to_binary(Expr *expr_to_rewrite, Expr *left, Expr *right, BinaryOp op); void expr_rewrite_to_binary(Expr *expr_to_rewrite, Expr *left, Expr *right, BinaryOp op);

View File

@@ -8,7 +8,7 @@ static inline bool expr_binary_is_constant_eval(Expr *expr, ConstantEvalKind eva
static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind); static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind);
static inline bool expr_list_is_constant_eval(Expr **exprs, ConstantEvalKind eval_kind); static inline bool expr_list_is_constant_eval(Expr **exprs, ConstantEvalKind eval_kind);
static inline bool expr_unary_addr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind); static inline bool expr_unary_addr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind);
static inline ConstInitializer *initializer_for_index(ConstInitializer *initializer, uint32_t index); static inline ConstInitializer *initializer_for_index(ConstInitializer *initializer, ArraySize index, bool from_back);
Expr *expr_negate_expr(Expr *expr) Expr *expr_negate_expr(Expr *expr)
{ {
@@ -517,7 +517,7 @@ bool expr_is_compile_time(Expr *expr)
UNREACHABLE UNREACHABLE
} }
static inline ConstInitializer *initializer_for_index(ConstInitializer *initializer, uint32_t index) static inline ConstInitializer *initializer_for_index(ConstInitializer *initializer, ArraySize index, bool from_back)
{ {
switch (initializer->kind) switch (initializer->kind)
{ {
@@ -527,9 +527,23 @@ static inline ConstInitializer *initializer_for_index(ConstInitializer *initiali
case CONST_INIT_VALUE: case CONST_INIT_VALUE:
return initializer; return initializer;
case CONST_INIT_ARRAY_FULL: case CONST_INIT_ARRAY_FULL:
{
unsigned len = vec_size(initializer->init_array_full);
if (from_back)
{
if (index > len || !index) return NULL;
index = len - index;
}
return initializer->init_array_full[index]; return initializer->init_array_full[index];
}
case CONST_INIT_ARRAY: case CONST_INIT_ARRAY:
{ {
if (from_back)
{
ArraySize len = initializer->type->array.len;
if (index > len || !index) return NULL;
index = len - index;
}
ConstInitializer **sub_values = initializer->init_array.elements; ConstInitializer **sub_values = initializer->init_array.elements;
VECEACH(sub_values, i) VECEACH(sub_values, i)
{ {
@@ -605,15 +619,19 @@ void expr_rewrite_to_const_zero(Expr *expr, Type *type)
expr->type = type; expr->type = type;
} }
bool expr_rewrite_to_const_initializer_index(Type *list_type, ConstInitializer *list, Expr *result, unsigned index) bool expr_rewrite_to_const_initializer_index(Type *list_type, ConstInitializer *list, Expr *result, unsigned index, bool from_back)
{ {
ConstInitializer *initializer = initializer_for_index(list, index); ConstInitializer *initializer = initializer_for_index(list, index, from_back);
ConstInitType kind = initializer ? initializer->kind : CONST_INIT_ZERO; ConstInitType kind = initializer ? initializer->kind : CONST_INIT_ZERO;
switch (kind) switch (kind)
{ {
case CONST_INIT_ZERO: case CONST_INIT_ZERO:
expr_rewrite_to_const_zero(result, type_get_indexed_type(list_type)); {
Type *indexed_type = type_get_indexed_type(list_type);
if (!indexed_type) return false;
expr_rewrite_to_const_zero(result, indexed_type);
return true; return true;
}
case CONST_INIT_STRUCT: case CONST_INIT_STRUCT:
case CONST_INIT_UNION: case CONST_INIT_UNION:
case CONST_INIT_ARRAY: case CONST_INIT_ARRAY:

View File

@@ -108,7 +108,7 @@ static inline const char *sema_addr_may_take_of_var(Expr *expr, Decl *decl);
static inline const char *sema_addr_may_take_of_ident(Expr *inner); static inline const char *sema_addr_may_take_of_ident(Expr *inner);
// -- subscript helpers // -- subscript helpers
static bool sema_subscript_rewrite_index_const_list(Expr *const_list, Expr *index, Expr *result); static bool sema_subscript_rewrite_index_const_list(Expr *const_list, ArraySize index, bool from_back, Expr *result);
static Type *sema_subscript_find_indexable_type_recursively(Type **type, Expr **parent); static Type *sema_subscript_find_indexable_type_recursively(Type **type, Expr **parent);
// -- binary helper functions // -- binary helper functions
@@ -188,6 +188,7 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr);
static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *expr, Type *parent_type, bool was_group, Expr *identifier); static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *expr, Type *parent_type, bool was_group, Expr *identifier);
static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *expr, Expr *parent, bool was_group, Expr *identifier); static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *expr, Expr *parent, bool was_group, Expr *identifier);
static inline bool sema_expr_fold_to_member(Expr *expr, Expr *parent, Decl *member); static inline bool sema_expr_fold_to_member(Expr *expr, Expr *parent, Decl *member);
static inline void sema_expr_flatten_const(SemaContext *context, Expr *expr);
// -- implementations // -- implementations
@@ -2416,15 +2417,10 @@ static Type *sema_subscript_find_indexable_type_recursively(Type **type, Expr **
} }
} }
static bool sema_subscript_rewrite_index_const_list(Expr *const_list, Expr *index, Expr *result) static bool sema_subscript_rewrite_index_const_list(Expr *const_list, ArraySize index, bool from_back, Expr *result)
{ {
assert(expr_is_const_int(index));
if (!int_fits(index->const_expr.ixx, TYPE_U32)) return false;
uint32_t idx = index->const_expr.ixx.i.low;
assert(const_list->const_expr.const_kind == CONST_INITIALIZER); assert(const_list->const_expr.const_kind == CONST_INITIALIZER);
return expr_rewrite_to_const_initializer_index(const_list->type, const_list->const_expr.initializer, result, index, from_back);
return expr_rewrite_to_const_initializer_index(const_list->type, const_list->const_expr.initializer, result, idx);
} }
/** /**
@@ -2642,7 +2638,6 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
if (remove_from_back) if (remove_from_back)
{ {
start_from_end = expr->subscript_expr.range.start_from_end = false; start_from_end = expr->subscript_expr.range.start_from_end = false;
(void)start_from_end;
} }
if (eval_type == SUBSCRIPT_EVAL_REF) if (eval_type == SUBSCRIPT_EVAL_REF)
@@ -2651,9 +2646,37 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
} }
else else
{ {
if (sema_flattened_expr_is_const(context, index) && sema_flattened_expr_is_const_initializer(context, current_expr)) if (sema_flattened_expr_is_const(context, index))
{ {
if (sema_subscript_rewrite_index_const_list(current_expr, index, expr)) return true; assert(expr_is_const_int(index));
sema_expr_flatten_const(context, current_expr);
bool is_const_initializer = expr_is_const_initializer(current_expr);
if (is_const_initializer || expr_is_const_string(current_expr) || expr_is_const_bytes(current_expr))
{
if (!int_fits(index->const_expr.ixx, TYPE_U32))
{
RETURN_SEMA_ERROR(index, "Index is out of range.");
}
ArraySize idx = index->const_expr.ixx.i.low;
if (!is_const_initializer)
{
// Handle bytes / String
ArraySize len = current_expr->const_expr.bytes.len;
if (idx > len || (idx == len && !start_from_end) || (idx == 0 && start_from_end))
{
RETURN_SEMA_ERROR(index, "The index (%s%llu) is out of range, the length is just %llu.",
start_from_end ? "^" : "",
(unsigned long long)idx,
(unsigned long long)current_expr->const_expr.bytes.len);
}
if (start_from_end) idx = len - idx;
unsigned char c = current_expr->const_expr.bytes.ptr[idx];
expr_rewrite_const_int(expr, type_char, c);
expr->type = type_char;
return true;
}
if (sema_subscript_rewrite_index_const_list(current_expr, idx, start_from_end, expr)) return true;
}
} }
} }
expr->subscript_expr.expr = exprid(current_expr); expr->subscript_expr.expr = exprid(current_expr);

View File

@@ -2562,7 +2562,7 @@ static inline bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *state
else else
{ {
Expr *expr = expr_new(EXPR_CONST, collection->span); Expr *expr = expr_new(EXPR_CONST, collection->span);
if (!expr_rewrite_to_const_initializer_index(const_list_type, initializer, expr, i)) if (!expr_rewrite_to_const_initializer_index(const_list_type, initializer, expr, i, false))
{ {
SEMA_ERROR(collection, "Complex expressions are not allowed."); SEMA_ERROR(collection, "Complex expressions are not allowed.");
goto FAILED; goto FAILED;

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.624" #define COMPILER_VERSION "0.4.625"

View File

@@ -0,0 +1,15 @@
module subscripting_tests @test;
fn void subscript_ct()
{
$if int.nameof[0] == 'i':
assert(true);
$else
assert(false);
$endif
$if int.nameof[^1] == 't':
assert(true);
$else
assert(false);
$endif
}