mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Allow indexing of constant strings. Fixed reverse indexing of constant initializers.
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define COMPILER_VERSION "0.4.624"
|
#define COMPILER_VERSION "0.4.625"
|
||||||
15
test/unit/regression/subscripting.c3
Normal file
15
test/unit/regression/subscripting.c3
Normal 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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user