mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
- Compile time array assignment #1806.
- Allow `+++` to work on all types of arrays.
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
- Error on switch case fallthough if there is more than one newline #1849.
|
||||
- Added flags to `c3c project view` to filter displayed properties
|
||||
- VERY experimental `<[ ]>` syntax for generics.
|
||||
- Compile time array assignment #1806.
|
||||
- Allow `+++` to work on all types of arrays.
|
||||
|
||||
### Fixes
|
||||
- Fix issue requiring prefix on a generic interface declaration.
|
||||
|
||||
@@ -772,6 +772,12 @@ typedef struct
|
||||
SubscriptIndex index;
|
||||
} ExprSubscript;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Decl *var;
|
||||
ArrayIndex index;
|
||||
} ExprCtSubscript;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ExprId expr;
|
||||
@@ -1177,6 +1183,7 @@ struct Expr_
|
||||
ExprSliceAssign slice_assign_expr; // 8
|
||||
ExprSubscriptAssign subscript_assign_expr;
|
||||
ExprSubscript subscript_expr; // 12
|
||||
ExprCtSubscript ct_subscript_expr;
|
||||
ExprSlice slice_expr;
|
||||
ExprSwizzle swizzle_expr;
|
||||
ExprTernary ternary_expr; // 16
|
||||
@@ -3281,6 +3288,7 @@ ConstInitializer *const_init_new_zero_array_value(Type *type, ArrayIndex index);
|
||||
ConstInitializer *const_init_new_array_value(Expr *expr, ArrayIndex index);
|
||||
bool const_init_is_zero(ConstInitializer *init);
|
||||
void const_init_rewrite_to_value(ConstInitializer *const_init, Expr *value);
|
||||
void const_init_rewrite_array_at(ConstInitializer *const_init, Expr *value, ArrayIndex index);
|
||||
void const_init_rewrite_to_zero(ConstInitializer *init, Type *type);
|
||||
|
||||
static inline void const_init_set_span(ConstInitializer *init, SourceSpan loc)
|
||||
@@ -3459,6 +3467,7 @@ static inline void expr_set_span(Expr *expr, SourceSpan loc)
|
||||
case EXPR_TYPECALL:
|
||||
case EXPR_MEMBER_GET:
|
||||
case EXPR_RVALUE:
|
||||
case EXPR_CT_SUBSCRIPT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,6 +296,7 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
{
|
||||
case EXPR_TYPECALL:
|
||||
case EXPR_ANYSWITCH:
|
||||
case EXPR_CT_SUBSCRIPT:
|
||||
UNREACHABLE
|
||||
case EXPR_OTHER_CONTEXT:
|
||||
MACRO_COPY_EXPR(expr->expr_other_context.inner);
|
||||
|
||||
@@ -743,6 +743,7 @@ typedef enum
|
||||
EXPR_CT_EVAL,
|
||||
EXPR_CT_IDENT,
|
||||
EXPR_CT_IS_CONST,
|
||||
EXPR_CT_SUBSCRIPT,
|
||||
EXPR_DECL,
|
||||
EXPR_DEFAULT_ARG,
|
||||
EXPR_DESIGNATED_INITIALIZER_LIST,
|
||||
@@ -1662,6 +1663,6 @@ case TYPE_U8: case TYPE_U16: case TYPE_U32: case TYPE_U64: case TYPE_U128
|
||||
#define UNRESOLVED_EXPRS EXPR_TRY_UNRESOLVED: case EXPR_ACCESS_UNRESOLVED: \
|
||||
case EXPR_CATCH_UNRESOLVED: case EXPR_UNRESOLVED_IDENTIFIER: case EXPR_CAST: \
|
||||
case EXPR_TYPEID: case EXPR_EMBED: case EXPR_VASPLAT: case EXPR_OTHER_CONTEXT: \
|
||||
case EXPR_GENERIC_IDENT: case EXPR_COMPOUND_LITERAL: case EXPR_MACRO_BODY
|
||||
case EXPR_GENERIC_IDENT: case EXPR_COMPOUND_LITERAL: case EXPR_MACRO_BODY: case EXPR_CT_SUBSCRIPT
|
||||
|
||||
|
||||
|
||||
@@ -363,6 +363,7 @@ bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *concat_expr, Expr *
|
||||
len = vec_size(left->const_expr.untyped_list);
|
||||
break;
|
||||
}
|
||||
ArraySize len_lhs = len;
|
||||
switch (right->const_expr.const_kind)
|
||||
{
|
||||
case CONST_FLOAT:
|
||||
@@ -400,7 +401,8 @@ bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *concat_expr, Expr *
|
||||
{
|
||||
indexed_type = NULL;
|
||||
}
|
||||
len += sema_len_from_const(right);
|
||||
ArraySize len_rhs = sema_len_from_const(right);
|
||||
len += len_rhs;
|
||||
if (!indexed_type)
|
||||
{
|
||||
Expr **untyped_exprs = VECNEW(Expr*, len + 1);
|
||||
@@ -419,15 +421,69 @@ bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *concat_expr, Expr *
|
||||
ConstInitializer *init = expr_const_initializer_from_expr(single_expr);
|
||||
// Skip zero arrays from slices.
|
||||
if (!init) continue;
|
||||
if (init && init->kind != CONST_INIT_ARRAY_FULL)
|
||||
switch (init->kind)
|
||||
{
|
||||
ASSERT(!init || init->type != type_untypedlist);
|
||||
RETURN_SEMA_ERROR(single_expr, "Expected a full array here.");
|
||||
}
|
||||
FOREACH(ConstInitializer *, val, init->init_array_full)
|
||||
{
|
||||
vec_add(untyped_exprs, val->init_value);
|
||||
case CONST_INIT_UNION:
|
||||
case CONST_INIT_STRUCT:
|
||||
case CONST_INIT_ARRAY_VALUE:
|
||||
case CONST_INIT_VALUE:
|
||||
UNREACHABLE
|
||||
case CONST_INIT_ARRAY_FULL:
|
||||
{
|
||||
FOREACH(ConstInitializer *, val, init->init_array_full)
|
||||
{
|
||||
vec_add(untyped_exprs, val->init_value);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case CONST_INIT_ZERO:
|
||||
{
|
||||
Type *index_type = type_get_indexed_type(type_flatten(init->type));
|
||||
ArraySize len_zero = i == 0 ? len_lhs : len_rhs;
|
||||
for (ArraySize j = 0; j < len_zero; j++)
|
||||
{
|
||||
Expr *zero = expr_new_expr(EXPR_CONST, single_expr);
|
||||
expr_rewrite_to_const_zero(zero, index_type);
|
||||
vec_add(untyped_exprs, zero);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case CONST_INIT_ARRAY:
|
||||
{
|
||||
Type *index_type = type_get_indexed_type(type_flatten(init->type));
|
||||
ArraySize len_zero = i == 0 ? len_lhs : len_rhs;
|
||||
ArraySize offset = vec_size(untyped_exprs);
|
||||
for (ArraySize j = 0; j < len_zero; j++)
|
||||
{
|
||||
Expr *zero = expr_new_expr(EXPR_CONST, single_expr);
|
||||
expr_rewrite_to_const_zero(zero, index_type);
|
||||
vec_add(untyped_exprs, zero);
|
||||
}
|
||||
FOREACH(ConstInitializer *, element, init->init_array.elements)
|
||||
{
|
||||
ASSERT_SPAN(right, element->kind == CONST_INIT_ARRAY_VALUE);
|
||||
ConstInitializer *inner_element = element->init_array_value.element;
|
||||
Expr *inner_expr = untyped_exprs[offset + element->init_array_value.index];
|
||||
switch (inner_element->kind)
|
||||
{
|
||||
case CONST_INIT_ZERO:
|
||||
continue;
|
||||
case CONST_INIT_STRUCT:
|
||||
case CONST_INIT_UNION:
|
||||
case CONST_INIT_ARRAY:
|
||||
case CONST_INIT_ARRAY_FULL:
|
||||
case CONST_INIT_ARRAY_VALUE:
|
||||
expr_rewrite_const_initializer(inner_expr, index_type, inner_element);
|
||||
continue;
|
||||
case CONST_INIT_VALUE:
|
||||
*inner_expr = *inner_element->init_value;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
concat_expr->expr_kind = EXPR_CONST;
|
||||
concat_expr->type = type_untypedlist;
|
||||
@@ -438,34 +494,193 @@ bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *concat_expr, Expr *
|
||||
};
|
||||
return true;
|
||||
}
|
||||
ConstInitializer **inits = VECNEW(ConstInitializer*, len);
|
||||
Expr *exprs[2] = { left, right };
|
||||
for (int i = 0; i < 2; i++)
|
||||
// Zero slice + zero slice => slice
|
||||
if (len == 0)
|
||||
{
|
||||
Expr *element = exprs[i];
|
||||
ConstInitializer *inititializer = expr_const_initializer_from_expr(element);
|
||||
// Zero sized slice:
|
||||
if (!inititializer)
|
||||
{
|
||||
ASSERT_SPAN(element, element->const_expr.const_kind == CONST_SLICE);
|
||||
continue;
|
||||
}
|
||||
switch (inititializer->kind)
|
||||
{
|
||||
case CONST_INIT_ARRAY_FULL:
|
||||
break;
|
||||
case CONST_INIT_ZERO:
|
||||
if (type_flatten(element->type)->type_kind == TYPE_SLICE) continue;
|
||||
default:
|
||||
RETURN_SEMA_ERROR(element, "Only fully initialized arrays may be concatenated.");
|
||||
}
|
||||
FOREACH(ConstInitializer *, init, inititializer->init_array_full)
|
||||
{
|
||||
vec_add(inits, init);
|
||||
}
|
||||
expr_rewrite_to_const_zero(concat_expr, type_get_slice(indexed_type));
|
||||
}
|
||||
Type *type = use_array ? type_get_array(indexed_type, len) : type_get_vector(indexed_type, len);
|
||||
expr_rewrite_const_initializer(concat_expr, type, const_init_new_array_full(type, inits));
|
||||
ConstInitializer *lhs_init = expr_const_initializer_from_expr(left);
|
||||
ConstInitializer *rhs_init = expr_const_initializer_from_expr(right);
|
||||
if (!rhs_init)
|
||||
{
|
||||
rhs_init = lhs_init;
|
||||
lhs_init = NULL;
|
||||
}
|
||||
if (!lhs_init)
|
||||
{
|
||||
ASSERT(rhs_init);
|
||||
expr_rewrite_const_initializer(concat_expr, type, rhs_init);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
switch (lhs_init->kind)
|
||||
{
|
||||
case CONST_INIT_UNION:
|
||||
case CONST_INIT_STRUCT:
|
||||
case CONST_INIT_ARRAY_VALUE:
|
||||
case CONST_INIT_VALUE:
|
||||
UNREACHABLE
|
||||
case CONST_INIT_ZERO:
|
||||
switch (rhs_init->kind)
|
||||
{
|
||||
case CONST_INIT_ZERO:
|
||||
// { 0, 0, 0 } + { 0, 0, 0 }
|
||||
expr_rewrite_const_initializer(concat_expr, type, const_init_new_zero(type));
|
||||
return true;
|
||||
case CONST_INIT_ARRAY_FULL:
|
||||
{
|
||||
// { 0, 0, 0 } + { 1, 2, 3 }
|
||||
ConstInitializer **inits = VECNEW(ConstInitializer*, len);
|
||||
for (ArraySize i = 0; i < len_lhs; i++)
|
||||
{
|
||||
vec_add(inits, const_init_new_zero(indexed_type));
|
||||
}
|
||||
FOREACH(ConstInitializer *, init, rhs_init->init_array_full)
|
||||
{
|
||||
vec_add(inits, init);
|
||||
}
|
||||
expr_rewrite_const_initializer(concat_expr, type, const_init_new_array_full(type, inits));
|
||||
return true;
|
||||
}
|
||||
case CONST_INIT_ARRAY:
|
||||
{
|
||||
// { 0, 0, 0 } + { 1 => 3 }
|
||||
FOREACH(ConstInitializer *, element, rhs_init->init_array.elements)
|
||||
{
|
||||
ASSERT_SPAN(right, element->kind == CONST_INIT_ARRAY_VALUE);
|
||||
element->init_array_value.index += len_lhs;
|
||||
}
|
||||
rhs_init->type = type;
|
||||
expr_rewrite_const_initializer(concat_expr, type, rhs_init);
|
||||
return true;
|
||||
}
|
||||
case CONST_INIT_STRUCT:
|
||||
case CONST_INIT_UNION:
|
||||
case CONST_INIT_VALUE:
|
||||
case CONST_INIT_ARRAY_VALUE:
|
||||
UNREACHABLE
|
||||
}
|
||||
UNREACHABLE
|
||||
case CONST_INIT_ARRAY_FULL:
|
||||
{
|
||||
switch (rhs_init->kind)
|
||||
{
|
||||
case CONST_INIT_UNION:
|
||||
case CONST_INIT_STRUCT:
|
||||
case CONST_INIT_ARRAY_VALUE:
|
||||
case CONST_INIT_VALUE:
|
||||
UNREACHABLE
|
||||
case CONST_INIT_ZERO:
|
||||
{
|
||||
// { 1, 2, 3 } + { 0, 0, 0 }
|
||||
ConstInitializer **inits = VECNEW(ConstInitializer*, len);
|
||||
FOREACH(ConstInitializer *, init, lhs_init->init_array_full)
|
||||
{
|
||||
vec_add(inits, init);
|
||||
}
|
||||
for (ArraySize i = 0; i < len_rhs; i++)
|
||||
{
|
||||
vec_add(inits, const_init_new_zero(indexed_type));
|
||||
}
|
||||
expr_rewrite_const_initializer(concat_expr, type, const_init_new_array_full(type, inits));
|
||||
return true;
|
||||
}
|
||||
case CONST_INIT_ARRAY_FULL:
|
||||
{
|
||||
// { 1, 2, 3 } + { 1, 2, 3 }
|
||||
ConstInitializer **inits = VECNEW(ConstInitializer*, len);
|
||||
FOREACH(ConstInitializer *, init, lhs_init->init_array_full)
|
||||
{
|
||||
vec_add(inits, init);
|
||||
}
|
||||
FOREACH(ConstInitializer *, init, rhs_init->init_array_full)
|
||||
{
|
||||
vec_add(inits, init);
|
||||
}
|
||||
expr_rewrite_const_initializer(concat_expr, type, const_init_new_array_full(type, inits));
|
||||
return true;
|
||||
}
|
||||
case CONST_INIT_ARRAY:
|
||||
{
|
||||
// { 1, 2, 3 } + { 1 => 3 }
|
||||
ConstInitializer **inits = VECNEW(ConstInitializer*, len);
|
||||
FOREACH(ConstInitializer *, init, lhs_init->init_array_full)
|
||||
{
|
||||
vec_add(inits, init);
|
||||
}
|
||||
for (ArraySize i = 0; i < len_rhs; i++)
|
||||
{
|
||||
vec_add(inits, const_init_new_zero(indexed_type));
|
||||
}
|
||||
FOREACH(ConstInitializer *, element, rhs_init->init_array.elements)
|
||||
{
|
||||
ASSERT_SPAN(right, element->kind == CONST_INIT_ARRAY_VALUE);
|
||||
inits[element->init_array_value.index + len_lhs] = element->init_array_value.element;
|
||||
}
|
||||
expr_rewrite_const_initializer(concat_expr, type, const_init_new_array_full(type, inits));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
case CONST_INIT_ARRAY:
|
||||
{
|
||||
switch (rhs_init->kind)
|
||||
{
|
||||
case CONST_INIT_UNION:
|
||||
case CONST_INIT_STRUCT:
|
||||
case CONST_INIT_ARRAY_VALUE:
|
||||
case CONST_INIT_VALUE:
|
||||
UNREACHABLE
|
||||
case CONST_INIT_ZERO:
|
||||
{
|
||||
// { 1 => 3 } + { 0, 0, 0 }
|
||||
lhs_init->type = type;
|
||||
expr_rewrite_const_initializer(concat_expr, type, lhs_init);
|
||||
return true;
|
||||
}
|
||||
case CONST_INIT_ARRAY_FULL:
|
||||
{
|
||||
// { 1 => 3 } + { 1, 2, 3 }
|
||||
ConstInitializer **inits = VECNEW(ConstInitializer*, len);
|
||||
for (ArraySize i = 0; i < len_lhs; i++)
|
||||
{
|
||||
vec_add(inits, const_init_new_zero(indexed_type));
|
||||
}
|
||||
FOREACH(ConstInitializer *, element, lhs_init->init_array.elements)
|
||||
{
|
||||
ASSERT_SPAN(left, element->kind == CONST_INIT_ARRAY_VALUE);
|
||||
inits[element->init_array_value.index] = element->init_array_value.element;
|
||||
}
|
||||
FOREACH(ConstInitializer *, init, rhs_init->init_array_full)
|
||||
{
|
||||
vec_add(inits, init);
|
||||
}
|
||||
expr_rewrite_const_initializer(concat_expr, type, const_init_new_array_full(type, inits));
|
||||
return true;
|
||||
}
|
||||
case CONST_INIT_ARRAY:
|
||||
{
|
||||
// { 1 => 3 } + { 1 => 3 }
|
||||
ArraySize elements = vec_size(lhs_init->init_array.elements) + vec_size(rhs_init->init_array.elements);
|
||||
ConstInitializer **inits = VECNEW(ConstInitializer*, elements);
|
||||
FOREACH(ConstInitializer *, element, lhs_init->init_array.elements)
|
||||
{
|
||||
vec_add(inits, element);
|
||||
}
|
||||
FOREACH(ConstInitializer *, element, rhs_init->init_array.elements)
|
||||
{
|
||||
ASSERT_SPAN(right, element->kind == CONST_INIT_ARRAY_VALUE);
|
||||
element->init_array_value.index += len_lhs;
|
||||
vec_add(inits, element);
|
||||
}
|
||||
expr_rewrite_const_initializer(concat_expr, type, const_init_new_array(type, inits));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
@@ -3065,7 +3065,8 @@ static inline bool sema_expr_resolve_subscript_index(SemaContext *context, Expr
|
||||
}
|
||||
ArrayIndex size;
|
||||
bool check_len = !context->call_env.in_no_eval || current_type == type_untypedlist;
|
||||
if (check_len && expr_is_const_int(index) && (size = sema_len_from_expr(current_expr)) >= 0)
|
||||
Expr *len_expr = current_expr->expr_kind == EXPR_CT_IDENT ? current_expr->ct_ident_expr.decl->var.init_expr : current_expr;
|
||||
if (check_len && expr_is_const_int(index) && (size = sema_len_from_expr(len_expr)) >= 0)
|
||||
{
|
||||
// 4c. And that it's in range.
|
||||
if (int_is_neg(index->const_expr.ixx))
|
||||
@@ -3115,7 +3116,14 @@ static inline bool sema_expr_analyse_subscript_lvalue(SemaContext *context, Expr
|
||||
{
|
||||
// Evaluate the expression to index.
|
||||
Expr *subscripted = exprptr(expr->subscript_expr.expr);
|
||||
if (!sema_analyse_expr(context, subscripted)) return false;
|
||||
if (subscripted->expr_kind == EXPR_CT_IDENT)
|
||||
{
|
||||
if (!sema_analyse_expr_lvalue(context, subscripted, NULL)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sema_analyse_expr(context, subscripted)) return false;
|
||||
}
|
||||
|
||||
if (!sema_expr_check_assign(context, expr, NULL)) return false;
|
||||
|
||||
@@ -3142,9 +3150,17 @@ static inline bool sema_expr_analyse_subscript_lvalue(SemaContext *context, Expr
|
||||
}
|
||||
|
||||
// 4. If we are indexing into a complist
|
||||
if (current_type == type_untypedlist)
|
||||
if (current_expr->expr_kind == EXPR_CT_IDENT)
|
||||
{
|
||||
TODO;
|
||||
if (index_value == -1)
|
||||
{
|
||||
if (check_valid) goto VALID_FAIL_POISON;
|
||||
RETURN_SEMA_ERROR(index, "Assigning to a compile time constant requires a constant index.");
|
||||
}
|
||||
expr->expr_kind = EXPR_CT_SUBSCRIPT;
|
||||
expr->ct_subscript_expr = (ExprCtSubscript) { .var = current_expr->ct_ident_expr.decl, .index = index_value };
|
||||
expr->type = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!sema_cast_rvalue(context, subscripted, true)) return false;
|
||||
@@ -4955,8 +4971,7 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr,
|
||||
|
||||
|
||||
static inline bool sema_expr_analyse_swizzle(SemaContext *context, Expr *expr, Expr *parent, Type *flat_type,
|
||||
const char *kw,
|
||||
unsigned len, CheckType check, bool is_lvalue)
|
||||
const char *kw, unsigned len, CheckType check, bool is_lvalue)
|
||||
{
|
||||
unsigned vec_len = flat_type->array.len;
|
||||
Type *indexed_type = type_get_indexed_type(parent->type);
|
||||
@@ -5825,6 +5840,70 @@ static bool sema_expr_analyse_ct_identifier_assign(SemaContext *context, Expr *e
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sema_expr_analyse_ct_subscript_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right)
|
||||
{
|
||||
Decl *ct_var = left->ct_subscript_expr.var;
|
||||
ArrayIndex index = left->ct_subscript_expr.index;
|
||||
|
||||
if (ct_var->type == type_untypedlist)
|
||||
{
|
||||
if (!sema_analyse_expr(context, right)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sema_analyse_inferred_expr(context, type_get_indexed_type(ct_var->type), right)) return false;
|
||||
}
|
||||
if (!sema_cast_const(right))
|
||||
{
|
||||
RETURN_SEMA_ERROR(right, "The argument must be a constant value.");
|
||||
}
|
||||
if (context->call_env.in_other)
|
||||
{
|
||||
RETURN_SEMA_ERROR(left, "Compile time variables may only be modified in the scope they are defined in.");
|
||||
}
|
||||
|
||||
Expr *original_value = ct_var->var.init_expr;
|
||||
ASSERT_SPAN(original_value, original_value->expr_kind == EXPR_CONST);
|
||||
|
||||
ExprConst *expr_const = &original_value->const_expr;
|
||||
|
||||
switch (expr_const->const_kind)
|
||||
{
|
||||
case CONST_FLOAT:
|
||||
case CONST_INTEGER:
|
||||
case CONST_BOOL:
|
||||
case CONST_ENUM:
|
||||
case CONST_ERR:
|
||||
case CONST_POINTER:
|
||||
case CONST_TYPEID:
|
||||
case CONST_REF:
|
||||
case CONST_MEMBER:
|
||||
UNREACHABLE
|
||||
case CONST_BYTES:
|
||||
case CONST_STRING:
|
||||
{
|
||||
unsigned char *copy = MALLOC(expr_const->bytes.len + 1);
|
||||
memcpy(copy, expr_const->bytes.ptr, expr_const->bytes.len + 1);
|
||||
assert(right->const_expr.const_kind == CONST_INTEGER);
|
||||
copy[index] = (unsigned char)right->const_expr.ixx.i.low;
|
||||
expr_const->bytes.ptr = (char *)copy;
|
||||
break;
|
||||
}
|
||||
case CONST_SLICE:
|
||||
const_init_rewrite_array_at(expr_const->slice_init, right, index);
|
||||
break;
|
||||
case CONST_INITIALIZER:
|
||||
const_init_rewrite_array_at(expr_const->initializer, right, index);
|
||||
break;
|
||||
case CONST_UNTYPED_LIST:
|
||||
expr_const->untyped_list[index] = right;
|
||||
break;
|
||||
}
|
||||
Expr *original = expr_copy(original_value);
|
||||
expr_replace(expr, original);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sema_expr_analyse_ct_type_identifier_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right)
|
||||
{
|
||||
TypeInfo *info = left->type_expr;
|
||||
@@ -5884,10 +5963,15 @@ static bool sema_expr_analyse_assign(SemaContext *context, Expr *expr, Expr *lef
|
||||
return sema_expr_analyse_ct_type_identifier_assign(context, expr, left, right);
|
||||
}
|
||||
if (!sema_analyse_expr_lvalue(context, left, failed_ref)) return false;
|
||||
if (left->expr_kind == EXPR_CT_IDENT)
|
||||
switch (left->expr_kind)
|
||||
{
|
||||
// $foo = ...
|
||||
return sema_expr_analyse_ct_identifier_assign(context, expr, left, right);
|
||||
case EXPR_CT_IDENT:
|
||||
// $foo = ...
|
||||
return sema_expr_analyse_ct_identifier_assign(context, expr, left, right);
|
||||
case EXPR_CT_SUBSCRIPT:
|
||||
return sema_expr_analyse_ct_subscript_assign(context, expr, left, right);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 2. Check assignability
|
||||
@@ -9184,6 +9268,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
|
||||
case EXPR_IDENTIFIER:
|
||||
case EXPR_NAMED_ARGUMENT:
|
||||
case EXPR_ACCESS_RESOLVED:
|
||||
case EXPR_CT_SUBSCRIPT:
|
||||
UNREACHABLE
|
||||
case EXPR_BINARY:
|
||||
main_expr->resolve_status = RESOLVE_RUNNING;
|
||||
@@ -9661,6 +9746,7 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr,
|
||||
case EXPR_SLICE_TO_VEC_ARRAY:
|
||||
case EXPR_SCALAR_TO_VECTOR:
|
||||
case EXPR_MAKE_SLICE:
|
||||
case EXPR_CT_SUBSCRIPT:
|
||||
UNREACHABLE
|
||||
case EXPR_MAKE_ANY:
|
||||
if (!sema_analyse_expr(context, expr->make_any_expr.typeid)) return false;
|
||||
@@ -10223,6 +10309,7 @@ IDENT_CHECK:;
|
||||
case EXPR_BITACCESS:
|
||||
case EXPR_SUBSCRIPT_ASSIGN:
|
||||
case EXPR_ACCESS_RESOLVED:
|
||||
case EXPR_CT_SUBSCRIPT:
|
||||
UNREACHABLE
|
||||
}
|
||||
if (failed_ref) goto FAILED_REF;
|
||||
|
||||
@@ -1049,6 +1049,81 @@ static inline void sema_update_const_initializer_with_designator_union(ConstInit
|
||||
const_init_rewrite_to_value(sub_element, value);
|
||||
}
|
||||
|
||||
static inline ConstInitializer *sema_update_const_initializer_at_index(ConstInitializer *const_init, Type *element_type,
|
||||
ArraySize array_count, ArrayIndex index,
|
||||
ArrayIndex *insert_index_ref, Expr *value)
|
||||
{
|
||||
ConstInitializer **array_elements = const_init->init_array.elements;
|
||||
ArrayIndex insert_index = *insert_index_ref;
|
||||
ASSERT(insert_index >= array_count || array_elements);
|
||||
// Walk to the insert point or until we reached the end of the array.
|
||||
while (insert_index < array_count && array_elements[insert_index]->init_array_value.index < index)
|
||||
{
|
||||
insert_index++;
|
||||
}
|
||||
// Pick up the initializer at the insert point.
|
||||
ConstInitializer *initializer = insert_index < array_count ? array_elements[insert_index] : NULL;
|
||||
ConstInitializer *inner_value;
|
||||
|
||||
// If we don't have an initializer, the location needs to be at the end.
|
||||
// Create and append:
|
||||
if (!initializer)
|
||||
{
|
||||
initializer = const_init_new_zero_array_value(element_type, index);
|
||||
vec_add(array_elements, initializer);
|
||||
array_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we already have an initializer "found"
|
||||
// it might be after the index. In this case, we
|
||||
// need to do an insert.
|
||||
if (initializer->init_array_value.index != insert_index)
|
||||
{
|
||||
ASSERT(initializer->init_array_value.index > insert_index);
|
||||
|
||||
// First we add a null at the end.
|
||||
vec_add(array_elements, NULL);
|
||||
// Shift all values one step up:
|
||||
for (unsigned i = array_count; i > insert_index; i--)
|
||||
{
|
||||
array_elements[i] = array_elements[i - 1];
|
||||
}
|
||||
// Then we create our new entry.
|
||||
initializer = const_init_new_zero_array_value(element_type, index);
|
||||
// And assign it to the location.
|
||||
array_elements[insert_index] = initializer;
|
||||
}
|
||||
}
|
||||
|
||||
const_init->init_array.elements = array_elements;
|
||||
*insert_index_ref = insert_index;
|
||||
return initializer->init_array_value.element;
|
||||
}
|
||||
|
||||
void const_init_rewrite_array_at(ConstInitializer *const_init, Expr *value, ArrayIndex index)
|
||||
{
|
||||
// Expand zero into array.
|
||||
if (const_init->kind == CONST_INIT_ZERO)
|
||||
{
|
||||
const_init->kind = CONST_INIT_ARRAY;
|
||||
const_init->init_array.elements = NULL;
|
||||
}
|
||||
|
||||
Type *element_type = type_flatten(const_init->type->array.base);
|
||||
|
||||
// Get all the elements in the array
|
||||
ConstInitializer **array_elements = const_init->init_array.elements;
|
||||
|
||||
unsigned array_count = vec_size(array_elements);
|
||||
ArrayIndex insert_index = 0;
|
||||
|
||||
ConstInitializer *inner_value = sema_update_const_initializer_at_index(const_init, element_type,
|
||||
array_count, index, &insert_index, value);
|
||||
|
||||
const_init_rewrite_to_value(inner_value, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an array { [2] = 1 }
|
||||
*/
|
||||
@@ -1074,56 +1149,15 @@ static inline void sema_update_const_initializer_with_designator_array(ConstInit
|
||||
bool is_last_path_element = next_element == end;
|
||||
|
||||
// Get all the elements in the array
|
||||
ConstInitializer **array_elements = const_init->init_array.elements;
|
||||
|
||||
unsigned array_count = vec_size(array_elements);
|
||||
unsigned array_count = vec_size(const_init->init_array.elements);
|
||||
ArrayIndex insert_index = 0;
|
||||
|
||||
for (ArrayIndex index = low_index; index <= high_index; index++)
|
||||
{
|
||||
ASSERT(insert_index >= array_count || array_elements);
|
||||
// Walk to the insert point or until we reached the end of the array.
|
||||
while (insert_index < array_count && array_elements[insert_index]->init_array_value.index < index)
|
||||
{
|
||||
insert_index++;
|
||||
}
|
||||
// Pick up the initializer at the insert point.
|
||||
ConstInitializer *initializer = insert_index < array_count ? array_elements[insert_index] : NULL;
|
||||
ConstInitializer *inner_value;
|
||||
|
||||
// If we don't have an initializer, the location needs to be at the end.
|
||||
// Create and append:
|
||||
if (!initializer)
|
||||
{
|
||||
initializer = const_init_new_zero_array_value(element_type, index);
|
||||
vec_add(array_elements, initializer);
|
||||
array_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we already have an initializer "found"
|
||||
// it might be after the index. In this case, we
|
||||
// need to do an insert.
|
||||
if (initializer->init_array_value.index != insert_index)
|
||||
{
|
||||
ASSERT(initializer->init_array_value.index > insert_index);
|
||||
|
||||
// First we add a null at the end.
|
||||
vec_add(array_elements, NULL);
|
||||
// Shift all values one step up:
|
||||
for (unsigned i = array_count; i > insert_index; i--)
|
||||
{
|
||||
array_elements[i] = array_elements[i - 1];
|
||||
}
|
||||
// Then we create our new entry.
|
||||
initializer = const_init_new_zero_array_value(element_type, index);
|
||||
// And assign it to the location.
|
||||
array_elements[insert_index] = initializer;
|
||||
}
|
||||
}
|
||||
|
||||
const_init->init_array.elements = array_elements;
|
||||
inner_value = initializer->init_array_value.element;
|
||||
ConstInitializer *inner_value = sema_update_const_initializer_at_index(const_init, element_type,
|
||||
array_count, index, &insert_index,
|
||||
value);
|
||||
|
||||
// Update
|
||||
if (!is_last_path_element)
|
||||
|
||||
1895
test/test_suite/compile_time/concat_append_extended_and_edit.c3t
Normal file
1895
test/test_suite/compile_time/concat_append_extended_and_edit.c3t
Normal file
File diff suppressed because it is too large
Load Diff
@@ -9,8 +9,8 @@ fn int main()
|
||||
$foreach ( $c : $chars)
|
||||
int $offset = ($c - $from) / BITS;
|
||||
int $rem = ($c - $from) % BITS;
|
||||
uint128 $value = $bitmap[$offset];
|
||||
uint128 $value = $bitmap[$offset]; // #error: is out of range
|
||||
$value |= 1u128 << $rem;
|
||||
$bitmap = $bitmap[:$offset] +++ $value +++ $bitmap[$offset+1..]; // #error: Only fully initialized arrays
|
||||
$bitmap = $bitmap[:$offset] +++ $value +++ $bitmap[$offset+1..]; // #error: End index out of bounds
|
||||
$endforeach
|
||||
}
|
||||
Reference in New Issue
Block a user