mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Improved error messages for initializers. Array initializers work.
This commit is contained in:
committed by
Christoffer Lerno
parent
1d73338fb0
commit
ff31bd17c0
11
README.md
11
README.md
@@ -25,8 +25,6 @@ There are some small work being done on the parser here, but most of the structu
|
||||
#### What's missing in the parser
|
||||
|
||||
- `asm` sections.
|
||||
- Macro parameter lists to imports.
|
||||
- auxiliary data for enums.
|
||||
- Docs not linked to statements/functions/declarations.
|
||||
|
||||
#### What's missing in the semantic analyser
|
||||
@@ -46,17 +44,18 @@ There are some small work being done on the parser here, but most of the structu
|
||||
- `type` not handled.
|
||||
- Identifier analysis incomplete.
|
||||
- Macro call not handled completely.
|
||||
- Function calls not handled completely.
|
||||
- Struct initializers not complete.
|
||||
- Varargs.
|
||||
|
||||
#### What's missing overall
|
||||
|
||||
- Integration with C.
|
||||
- Improved integration with C.
|
||||
- Generic macros.
|
||||
|
||||
#### What's working?
|
||||
|
||||
- Lexing and parsing works (except for the exceptions noted above).
|
||||
- Simple "hello world"
|
||||
- Most simpler C code.
|
||||
|
||||
(For more details see missing.txt)
|
||||
|
||||
If you wish to contribute with ideas, please file issues on the c3docs: https://github.com/c3lang/c3docs instead of the compiler.
|
||||
|
||||
@@ -12,13 +12,12 @@ Things missing:
|
||||
- Labels: @unused
|
||||
|
||||
* Designated initializer
|
||||
- Array initializer
|
||||
- Array range initializer { [1..2] = 2 }
|
||||
|
||||
* Initializers
|
||||
- Array initializers
|
||||
- Union initializers
|
||||
- Initializers with anonymous members
|
||||
- Vararray initializers
|
||||
- Incremental array initializers
|
||||
- Slice initializers
|
||||
|
||||
* Asserts
|
||||
- assert, $assert
|
||||
|
||||
@@ -255,6 +255,7 @@ func int barok() throws Error, OtherError
|
||||
return 100;
|
||||
}
|
||||
|
||||
|
||||
struct SimpleStruct
|
||||
{
|
||||
int a;
|
||||
@@ -283,7 +284,7 @@ func void testSimpleStruct(int x)
|
||||
struct AnonStruct
|
||||
{
|
||||
int a;
|
||||
struct sune
|
||||
struct xx
|
||||
{
|
||||
int b;
|
||||
int c;
|
||||
@@ -301,22 +302,50 @@ struct AnonStruct
|
||||
int x;
|
||||
}
|
||||
|
||||
func void testAnonStruct()
|
||||
func void testAnonStruct2()
|
||||
{
|
||||
AnonStruct s = { b2 = 3, b1 = 7, sune.b = 1 };
|
||||
AnonStruct s = { b2 = 3, b1 = 7, xx.b = 1 };
|
||||
AnonStruct foo;
|
||||
|
||||
printf("a = %d, b = %d (1), c = %d, b1 = %d (7), c1 = %d, b2 = %d (3), c2 = %d (3), x = %d\n", s.a, s.sune.b, s.sune.c, s.b1, s.c1, s.b2, s.c2, s.x);
|
||||
printf("a = %d, b = %d (1), c = %d, b1 = %d (7), c1 = %d, b2 = %d (3), c2 = %d (3), x = %d\n", s.a, s.xx.b, s.xx.c, s.b1, s.c1, s.b2, s.c2, s.x);
|
||||
|
||||
s.sune.b = 100;
|
||||
s.sune.c = 99;
|
||||
s.xx.b = 100;
|
||||
s.xx.c = 99;
|
||||
s.b1 = 3;
|
||||
s.b2 = 5;
|
||||
s.c2 = 7;
|
||||
|
||||
printf("a = %d, b = %d (100), c = %d (99), b1 = %d (3), c1 = %d, b2 = %d (7), c2 = %d (7), x = %d\n", s.a, s.sune.b, s.sune.c, s.b1, s.c1, s.b2, s.c2, s.x);
|
||||
printf("a = %d, b = %d (100), c = %d (99), b1 = %d (3), c1 = %d, b2 = %d (7), c2 = %d (7), x = %d\n", s.a, s.xx.b, s.xx.c, s.b1, s.c1, s.b2, s.c2, s.x);
|
||||
|
||||
|
||||
}
|
||||
|
||||
func void testAnonStruct()
|
||||
{
|
||||
AnonStruct s = { b2 = 3, b1 = 7, xx.b = 1 };
|
||||
AnonStruct foo;
|
||||
|
||||
printf("a = %d, b = %d (1), c = %d, b1 = %d (7), c1 = %d, b2 = %d (3), c2 = %d (3), x = %d\n", s.a, s.xx.b, s.xx.c, s.b1, s.c1, s.b2, s.c2, s.x);
|
||||
|
||||
s.xx.b = 100;
|
||||
s.xx.c = 99;
|
||||
s.b1 = 3;
|
||||
s.b2 = 5;
|
||||
s.c2 = 7;
|
||||
|
||||
printf("a = %d, b = %d (100), c = %d (99), b1 = %d (3), c1 = %d, b2 = %d (7), c2 = %d (7), x = %d\n", s.a, s.xx.b, s.xx.c, s.b1, s.c1, s.b2, s.c2, s.x);
|
||||
|
||||
s = { xx = { c = 2 }};
|
||||
|
||||
printf("a = %d, b = %d, c = %d (2), b1 = %d, c1 = %d, b2 = %d, c2 = %d, x = %d\n", s.a, s.xx.b, s.xx.c, s.b1, s.c1, s.b2, s.c2, s.x);
|
||||
|
||||
s.xx.c = 3;
|
||||
s.x = 1212;
|
||||
s.a = 29183;
|
||||
s = AnonStruct { xx = { c = 2 }};
|
||||
|
||||
printf("a = %d, b = %d, c = %d (2), b1 = %d, c1 = %d, b2 = %d, c2 = %d, x = %d\n", s.a, s.xx.b, s.xx.c, s.b1, s.c1, s.b2, s.c2, s.x);
|
||||
|
||||
}
|
||||
func int boba(int y, int j)
|
||||
{
|
||||
@@ -561,7 +590,8 @@ struct WithArray
|
||||
|
||||
func void testArray()
|
||||
{
|
||||
//int[4] zebra = { [0] = 1 };
|
||||
int[4] zebra = { [2] = 1 };
|
||||
int[4] deok = { 1, 2, 3, 4 };
|
||||
WithArray boo;
|
||||
boo.x[0] = 2;
|
||||
printf("boo.x[0] = %d\n", boo.x[0]);
|
||||
|
||||
@@ -136,7 +136,7 @@ typedef struct _Path
|
||||
typedef enum
|
||||
{
|
||||
DESIGNATED_IDENT,
|
||||
DESIGNATED_SUBSCRIPT
|
||||
DESIGNATED_SUBSCRIPT,
|
||||
} DesignatedPathKind;
|
||||
|
||||
typedef struct _DesignatedPath
|
||||
@@ -150,6 +150,7 @@ typedef struct _DesignatedPath
|
||||
Expr *index_expr;
|
||||
};
|
||||
} DesignatedPath;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char bitsize;
|
||||
|
||||
@@ -76,10 +76,13 @@ bool parse_param_list(Context *context, Expr ***result, bool allow_type)
|
||||
Expr *expr = NULL;
|
||||
SourceRange start = context->tok.span;
|
||||
// Special handling of [123]
|
||||
if (try_consume(context, TOKEN_LBRACKET))
|
||||
if (context->tok.type == TOKEN_LBRACKET)
|
||||
{
|
||||
expr = TRY_EXPR_OR(parse_expr(context), false);
|
||||
expr = expr_new(EXPR_SUBSCRIPT, context->tok.span);
|
||||
advance_and_verify(context, TOKEN_LBRACKET);
|
||||
expr->subscript_expr.index = TRY_EXPR_OR(parse_expr(context), false);
|
||||
CONSUME_OR(TOKEN_RBRACKET, false);
|
||||
RANGE_EXTEND_PREV(expr);
|
||||
expr = TRY_EXPR_OR(parse_precedence_with_left_side(context, expr, PREC_ASSIGNMENT), false);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -357,24 +357,11 @@ static inline bool sema_expr_analyse_subscript_after_parent_resolution(Context *
|
||||
Expr *subscripted = expr->subscript_expr.expr;
|
||||
Type *type = parent ? parent->canonical : subscripted->type->canonical;
|
||||
Expr *index = expr->subscript_expr.index;
|
||||
Type *inner_type;
|
||||
switch (type->type_kind)
|
||||
Type *inner_type = type_get_indexed_type(type);
|
||||
if (!inner_type)
|
||||
{
|
||||
case TYPE_POINTER:
|
||||
inner_type = type->pointer;
|
||||
break;
|
||||
case TYPE_VARARRAY:
|
||||
case TYPE_ARRAY:
|
||||
inner_type = type->array.base;
|
||||
break;
|
||||
case TYPE_SUBARRAY:
|
||||
TODO
|
||||
case TYPE_STRING:
|
||||
inner_type = type_char;
|
||||
break;
|
||||
default:
|
||||
SEMA_ERROR((parent ? expr : subscripted), "Cannot index '%s'.", type_to_error_string(type));
|
||||
return false;
|
||||
SEMA_ERROR((parent ? expr : subscripted), "Cannot index '%s'.", type_to_error_string(type));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sema_analyse_expr(context, type_isize, index)) return false;
|
||||
@@ -575,9 +562,9 @@ static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Exp
|
||||
return false;
|
||||
}
|
||||
|
||||
static DesignatedPath *sema_analyse_init_path(Context *context, DesignatedPath *path, Expr *expr);
|
||||
static DesignatedPath *sema_analyse_init_path(Context *context, DesignatedPath *parent, Expr *expr, bool *has_found_match, bool *has_reported_error);
|
||||
|
||||
static DesignatedPath *sema_analyse_init_identifier_string(Context *context, DesignatedPath *parent_path, const char *string)
|
||||
static DesignatedPath *sema_analyse_init_identifier_string(Context *context, DesignatedPath *parent_path, const char *string, bool *has_found_match, bool *has_reported_error)
|
||||
{
|
||||
assert(type_is_structlike(parent_path->type));
|
||||
Decl **members = parent_path->type->decl->strukt.members;
|
||||
@@ -591,19 +578,21 @@ static DesignatedPath *sema_analyse_init_identifier_string(Context *context, Des
|
||||
sub_path->kind = DESIGNATED_IDENT;
|
||||
sub_path->index = i;
|
||||
parent_path->sub_path = sub_path;
|
||||
*has_found_match = true;
|
||||
return sub_path;
|
||||
}
|
||||
if (!member->name)
|
||||
{
|
||||
DesignatedPath temp_path;
|
||||
temp_path.type = member->type;
|
||||
DesignatedPath *found = sema_analyse_init_identifier_string(context, &temp_path, string);
|
||||
DesignatedPath *found = sema_analyse_init_identifier_string(context, &temp_path, string, has_found_match, has_reported_error);
|
||||
if (!found) continue;
|
||||
DesignatedPath *real_path = malloc_arena(sizeof(DesignatedPath));
|
||||
*real_path = temp_path;
|
||||
real_path->index = i;
|
||||
real_path->kind = DESIGNATED_IDENT;
|
||||
parent_path->sub_path = real_path;
|
||||
*has_found_match = true;
|
||||
return found;
|
||||
}
|
||||
}
|
||||
@@ -611,11 +600,17 @@ static DesignatedPath *sema_analyse_init_identifier_string(Context *context, Des
|
||||
}
|
||||
|
||||
|
||||
static DesignatedPath *sema_analyse_init_access(Context *context, DesignatedPath *parent, Expr *access_expr)
|
||||
static DesignatedPath *sema_analyse_init_access(Context *context, DesignatedPath *parent, Expr *access_expr, bool *has_found_match, bool *has_reported_error)
|
||||
{
|
||||
DesignatedPath *last_path = sema_analyse_init_path(context, parent, access_expr->access_expr.parent);
|
||||
DesignatedPath *last_path = sema_analyse_init_path(context, parent, access_expr->access_expr.parent, has_found_match, has_reported_error);
|
||||
if (!last_path) return NULL;
|
||||
return sema_analyse_init_identifier_string(context, last_path, access_expr->access_expr.sub_element.string);
|
||||
DesignatedPath *path = sema_analyse_init_identifier_string(context, last_path, access_expr->access_expr.sub_element.string, has_found_match, has_reported_error);
|
||||
if (!path && has_found_match && !has_reported_error)
|
||||
{
|
||||
SEMA_TOKEN_ERROR(access_expr->access_expr.sub_element, "'%s' is not a valid sub member.", access_expr->access_expr.sub_element.string);
|
||||
*has_reported_error = true;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
static bool expr_cast_to_index(Expr *index)
|
||||
@@ -667,17 +662,22 @@ static bool expr_check_index_in_range(Type *type, Expr *index)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static DesignatedPath *sema_analyse_init_subscript(Context *context, DesignatedPath *parent, Expr *expr)
|
||||
static DesignatedPath *sema_analyse_init_subscript(Context *context, DesignatedPath *parent, Expr *expr, bool *has_found_match, bool *has_reported_error)
|
||||
{
|
||||
assert(expr->expr_kind == EXPR_SUBSCRIPT);
|
||||
DesignatedPath *path = sema_analyse_init_path(context, parent, expr->subscript_expr.expr);
|
||||
DesignatedPath *path = parent;
|
||||
if (expr->subscript_expr.expr)
|
||||
{
|
||||
path = sema_analyse_init_path(context, parent, expr->subscript_expr.expr, has_found_match, has_reported_error);
|
||||
}
|
||||
if (!path) return NULL;
|
||||
|
||||
Type *type = path->type;
|
||||
if (type->canonical->type_kind == TYPE_POINTER)
|
||||
{
|
||||
SEMA_ERROR(expr, "It's not possible to subscript a pointer field in a designated initializer.");
|
||||
return false;
|
||||
*has_reported_error = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Expr *index = expr->subscript_expr.index;
|
||||
@@ -685,79 +685,82 @@ static DesignatedPath *sema_analyse_init_subscript(Context *context, DesignatedP
|
||||
if (!inner_type)
|
||||
{
|
||||
SEMA_ERROR(expr, "Not possible to index a value of type '%s'.", type_to_error_string(type));
|
||||
return false;
|
||||
*has_reported_error = true;
|
||||
return NULL;
|
||||
}
|
||||
if (!sema_analyse_expr(context, type_isize, index))
|
||||
{
|
||||
*has_reported_error = true;
|
||||
return NULL;
|
||||
}
|
||||
if (!sema_analyse_expr(context, type_isize, index)) return false;
|
||||
|
||||
// Unless we already have type_usize, cast to type_isize;
|
||||
if (!expr_cast_to_index(index)) return false;
|
||||
if (!expr_cast_to_index(index))
|
||||
{
|
||||
*has_reported_error = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check range
|
||||
if (!expr_check_index_in_range(type->canonical, index)) return false;
|
||||
if (!expr_check_index_in_range(type->canonical, index))
|
||||
{
|
||||
*has_reported_error = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DesignatedPath *sub_path = CALLOCS(DesignatedPath);
|
||||
path->sub_path = sub_path;
|
||||
sub_path->type = inner_type;
|
||||
sub_path->kind = DESIGNATED_SUBSCRIPT;
|
||||
sub_path->index_expr = index;
|
||||
*has_found_match = true;
|
||||
return sub_path;
|
||||
}
|
||||
|
||||
static DesignatedPath *sema_analyse_init_path(Context *context, DesignatedPath *parent, Expr *expr)
|
||||
static DesignatedPath *sema_analyse_init_path(Context *context, DesignatedPath *parent, Expr *expr, bool *has_found_match, bool *has_reported_error)
|
||||
{
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_ACCESS:
|
||||
return sema_analyse_init_access(context, parent, expr);
|
||||
return sema_analyse_init_access(context, parent, expr, has_found_match, has_reported_error);
|
||||
case EXPR_IDENTIFIER:
|
||||
return sema_analyse_init_identifier_string(context, parent, expr->identifier_expr.identifier);
|
||||
return sema_analyse_init_identifier_string(context, parent, expr->identifier_expr.identifier, has_found_match, has_reported_error);
|
||||
case EXPR_SUBSCRIPT:
|
||||
return sema_analyse_init_subscript(context, parent, expr);
|
||||
return sema_analyse_init_subscript(context, parent, expr, has_found_match, has_reported_error);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively find a node in a declaration.
|
||||
* @return NULL if it wasn't found, otherwise the member.
|
||||
*/
|
||||
DesignatedInitializer *find_initializer(Decl *decl, DesignatedInitializer *initializer, const char* name)
|
||||
{
|
||||
Decl** compare_members = decl->strukt.members;
|
||||
VECEACH(compare_members, i)
|
||||
{
|
||||
Decl *member = compare_members[i];
|
||||
if (!member->name)
|
||||
{
|
||||
DesignatedInitializer *sub_initializer = initializer->initializers[i];
|
||||
DesignatedInitializer *found = find_initializer(member, sub_initializer, name);
|
||||
if (found) return found;
|
||||
}
|
||||
else if (member->name == name) return initializer;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static bool sema_expr_analyse_struct_designated_initializer(Context *context, Type *assigned, Expr *initializer)
|
||||
static bool sema_expr_analyse_designated_initializer(Context *context, Type *assigned, Expr *initializer)
|
||||
{
|
||||
Expr **init_expressions = initializer->expr_initializer.initializer_expr;
|
||||
bool is_structlike = type_is_structlike(assigned->canonical);
|
||||
|
||||
VECEACH(init_expressions, i)
|
||||
{
|
||||
Expr *expr = init_expressions[i];
|
||||
|
||||
// 1. Ensure that're seeing expr = expr on the top level.
|
||||
if (expr->expr_kind != EXPR_BINARY || expr->binary_expr.operator != BINARYOP_ASSIGN)
|
||||
{
|
||||
SEMA_ERROR(expr, "Expected an initializer on the format 'foo = 123' here.");
|
||||
if (is_structlike)
|
||||
{
|
||||
SEMA_ERROR(expr, "Expected an initializer on the format 'foo = 123' here.");
|
||||
}
|
||||
else
|
||||
{
|
||||
SEMA_ERROR(expr, "Expected an initializer on the format '[1] = 123' here.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Expr *init_expr = expr->binary_expr.left;
|
||||
DesignatedPath path = { .type = assigned };
|
||||
DesignatedPath *last_path = sema_analyse_init_path(context, &path, init_expr);
|
||||
if (!last_path)
|
||||
bool has_reported_error = false;
|
||||
bool has_found_match = false;
|
||||
DesignatedPath *last_path = sema_analyse_init_path(context, &path, init_expr, &has_found_match, &has_reported_error);
|
||||
if (!has_reported_error && !last_path)
|
||||
{
|
||||
SEMA_ERROR(expr, "This is not a valid member of '%s'.", type_to_error_string(assigned));
|
||||
return false;
|
||||
@@ -773,6 +776,10 @@ static bool sema_expr_analyse_struct_designated_initializer(Context *context, Ty
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform analysis for a plain initializer, that is one initializing all fields.
|
||||
* @return true if analysis succeeds.
|
||||
*/
|
||||
static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, Decl *assigned, Expr *initializer)
|
||||
{
|
||||
Expr **elements = initializer->expr_initializer.initializer_expr;
|
||||
@@ -781,17 +788,74 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context,
|
||||
unsigned size = vec_size(elements);
|
||||
unsigned expected_members = vec_size(members);
|
||||
|
||||
// For struct number of members must be the same as the size of the struct.
|
||||
|
||||
assert(size > 0);
|
||||
// 1. For struct number of members must be the same as the size of the struct.
|
||||
// Since we already handled the case with an empty initializer before going here
|
||||
// zero entries must be an error.
|
||||
assert(size > 0 && "We should already have handled the size == 0 case.");
|
||||
if (expected_members == 0)
|
||||
{
|
||||
// Generate a nice error message for zero.
|
||||
SEMA_ERROR(elements[0], "Too many elements in initializer, it must be empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. In case of a union, only expect a single entry.
|
||||
if (assigned->decl_kind == DECL_UNION) expected_members = 1;
|
||||
|
||||
|
||||
// 3. Loop through all elements.
|
||||
VECEACH(elements, i)
|
||||
{
|
||||
// 4. Check if we exceeded the list of elements in the struct/union.
|
||||
// This way we can check the other elements which might help the
|
||||
// user pinpoint where they put the double elements.
|
||||
if (i >= expected_members)
|
||||
{
|
||||
SEMA_ERROR(elements[i], "Too many elements in initializer, expected only %d.", expected_members);
|
||||
return false;
|
||||
}
|
||||
// 5. We know the required type, so resolve the expression.
|
||||
if (!sema_analyse_expr_of_required_type(context, members[i]->type, elements[i])) return false;
|
||||
}
|
||||
|
||||
// 6. There's the case of too few values as well. Mark the last element as wrong.
|
||||
if (expected_members > size)
|
||||
{
|
||||
SEMA_ERROR(elements[size - 1], "Too few elements in initializer, there should be elements after this one.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 7. Done!
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform analysis for a plain initializer, that is one initializing all fields.
|
||||
* @return true if analysis succeeds.
|
||||
*/
|
||||
static inline bool sema_expr_analyse_array_plain_initializer(Context *context, Type *assigned, Expr *initializer)
|
||||
{
|
||||
Expr **elements = initializer->expr_initializer.initializer_expr;
|
||||
|
||||
assert(assigned->type_kind == TYPE_ARRAY && "The other types are not done yet.");
|
||||
|
||||
Type *inner_type = type_get_indexed_type(assigned);
|
||||
assert(inner_type);
|
||||
|
||||
|
||||
initializer->expr_initializer.init_type = INITIALIZER_NORMAL;
|
||||
unsigned size = vec_size(elements);
|
||||
unsigned expected_members = assigned->array.len;
|
||||
|
||||
assert(size > 0 && "We should already have handled the size == 0 case.");
|
||||
if (expected_members == 0)
|
||||
{
|
||||
// Generate a nice error message for zero.
|
||||
SEMA_ERROR(elements[0], "Too many elements in initializer, it must be empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_union = assigned->decl_kind == DECL_UNION;
|
||||
expected_members = is_union ? 1 : expected_members;
|
||||
VECEACH(elements, i)
|
||||
{
|
||||
if (i >= expected_members)
|
||||
@@ -799,17 +863,20 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context,
|
||||
SEMA_ERROR(elements[i], "Too many elements in initializer, expected only %d.", expected_members);
|
||||
return false;
|
||||
}
|
||||
if (!sema_analyse_expr_of_required_type(context, members[i]->type, elements[i])) return false;
|
||||
if (!sema_analyse_expr_of_required_type(context, inner_type, elements[i])) return false;
|
||||
}
|
||||
|
||||
if (expected_members > size)
|
||||
{
|
||||
SEMA_ERROR(elements[size - 1], "Few elements in initializer, there should be elements after this one.");
|
||||
SEMA_ERROR(elements[size - 1], "Too few elements in initializer, %d elements are needed.", expected_members);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 7. Done!
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_struct_initializer(Context *context, Type *assigned, Expr *expr)
|
||||
static inline bool sema_expr_analyse_initializer(Context *context, Type *assigned, Expr *expr)
|
||||
{
|
||||
expr->type = assigned;
|
||||
|
||||
@@ -826,11 +893,18 @@ static inline bool sema_expr_analyse_struct_initializer(Context *context, Type *
|
||||
// this means that in this case we're actually not resolving macros here.
|
||||
if (init_expressions[0]->expr_kind == EXPR_BINARY && init_expressions[0]->binary_expr.operator == BINARYOP_ASSIGN)
|
||||
{
|
||||
return sema_expr_analyse_struct_designated_initializer(context, assigned, expr);
|
||||
return sema_expr_analyse_designated_initializer(context, assigned, expr);
|
||||
}
|
||||
|
||||
// 3. Otherwise use the plain initializer.
|
||||
return sema_expr_analyse_struct_plain_initializer(context, assigned->decl, expr);
|
||||
if (assigned->type_kind == TYPE_ARRAY)
|
||||
{
|
||||
return sema_expr_analyse_array_plain_initializer(context, assigned, expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
return sema_expr_analyse_struct_plain_initializer(context, assigned->decl, expr);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to, Expr *expr)
|
||||
@@ -842,9 +916,8 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to
|
||||
{
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
return sema_expr_analyse_struct_initializer(context, assigned, expr);
|
||||
case TYPE_ARRAY:
|
||||
TODO
|
||||
return sema_expr_analyse_initializer(context, assigned, expr);
|
||||
case TYPE_VARARRAY:
|
||||
TODO
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user