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
- Temporary objects may now invoke methods using ref parameters.
- Delete object files after successful linking.
- Compile time subscript of constant strings and bytes.
- `@if` introduced, other top level conditional compilation removed.
- `@dynamic` and `@interface` for dynamic dispatch.
- `$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_string(Expr *expr_to_rewrite, const char *string);
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_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_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 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)
{
@@ -517,7 +517,7 @@ bool expr_is_compile_time(Expr *expr)
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)
{
@@ -527,9 +527,23 @@ static inline ConstInitializer *initializer_for_index(ConstInitializer *initiali
case CONST_INIT_VALUE:
return initializer;
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];
}
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;
VECEACH(sub_values, i)
{
@@ -605,15 +619,19 @@ void expr_rewrite_to_const_zero(Expr *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;
switch (kind)
{
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;
}
case CONST_INIT_STRUCT:
case CONST_INIT_UNION:
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);
// -- 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);
// -- 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_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 void sema_expr_flatten_const(SemaContext *context, Expr *expr);
// -- 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);
return expr_rewrite_to_const_initializer_index(const_list->type, const_list->const_expr.initializer, result, idx);
return expr_rewrite_to_const_initializer_index(const_list->type, const_list->const_expr.initializer, result, index, from_back);
}
/**
@@ -2642,7 +2638,6 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
if (remove_from_back)
{
start_from_end = expr->subscript_expr.range.start_from_end = false;
(void)start_from_end;
}
if (eval_type == SUBSCRIPT_EVAL_REF)
@@ -2651,9 +2646,37 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
}
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);

View File

@@ -2562,7 +2562,7 @@ static inline bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *state
else
{
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.");
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
}