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
|
#### What's missing in the parser
|
||||||
|
|
||||||
- `asm` sections.
|
- `asm` sections.
|
||||||
- Macro parameter lists to imports.
|
|
||||||
- auxiliary data for enums.
|
|
||||||
- Docs not linked to statements/functions/declarations.
|
- Docs not linked to statements/functions/declarations.
|
||||||
|
|
||||||
#### What's missing in the semantic analyser
|
#### 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.
|
- `type` not handled.
|
||||||
- Identifier analysis incomplete.
|
- Identifier analysis incomplete.
|
||||||
- Macro call not handled completely.
|
- Macro call not handled completely.
|
||||||
- Function calls not handled completely.
|
|
||||||
- Struct initializers not complete.
|
|
||||||
- Varargs.
|
|
||||||
|
|
||||||
#### What's missing overall
|
#### What's missing overall
|
||||||
|
|
||||||
- Integration with C.
|
- Improved integration with C.
|
||||||
|
- Generic macros.
|
||||||
|
|
||||||
#### What's working?
|
#### What's working?
|
||||||
|
|
||||||
- Lexing and parsing works (except for the exceptions noted above).
|
- Lexing and parsing works (except for the exceptions noted above).
|
||||||
- Simple "hello world"
|
- 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.
|
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
|
- Labels: @unused
|
||||||
|
|
||||||
* Designated initializer
|
* Designated initializer
|
||||||
- Array initializer
|
|
||||||
- Array range initializer { [1..2] = 2 }
|
- Array range initializer { [1..2] = 2 }
|
||||||
|
|
||||||
* Initializers
|
* Initializers
|
||||||
- Array initializers
|
- Vararray initializers
|
||||||
- Union initializers
|
- Incremental array initializers
|
||||||
- Initializers with anonymous members
|
- Slice initializers
|
||||||
|
|
||||||
* Asserts
|
* Asserts
|
||||||
- assert, $assert
|
- assert, $assert
|
||||||
|
|||||||
@@ -255,6 +255,7 @@ func int barok() throws Error, OtherError
|
|||||||
return 100;
|
return 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct SimpleStruct
|
struct SimpleStruct
|
||||||
{
|
{
|
||||||
int a;
|
int a;
|
||||||
@@ -283,7 +284,7 @@ func void testSimpleStruct(int x)
|
|||||||
struct AnonStruct
|
struct AnonStruct
|
||||||
{
|
{
|
||||||
int a;
|
int a;
|
||||||
struct sune
|
struct xx
|
||||||
{
|
{
|
||||||
int b;
|
int b;
|
||||||
int c;
|
int c;
|
||||||
@@ -301,22 +302,50 @@ struct AnonStruct
|
|||||||
int x;
|
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;
|
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.xx.b = 100;
|
||||||
s.sune.c = 99;
|
s.xx.c = 99;
|
||||||
s.b1 = 3;
|
s.b1 = 3;
|
||||||
s.b2 = 5;
|
s.b2 = 5;
|
||||||
s.c2 = 7;
|
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)
|
func int boba(int y, int j)
|
||||||
{
|
{
|
||||||
@@ -561,7 +590,8 @@ struct WithArray
|
|||||||
|
|
||||||
func void testArray()
|
func void testArray()
|
||||||
{
|
{
|
||||||
//int[4] zebra = { [0] = 1 };
|
int[4] zebra = { [2] = 1 };
|
||||||
|
int[4] deok = { 1, 2, 3, 4 };
|
||||||
WithArray boo;
|
WithArray boo;
|
||||||
boo.x[0] = 2;
|
boo.x[0] = 2;
|
||||||
printf("boo.x[0] = %d\n", boo.x[0]);
|
printf("boo.x[0] = %d\n", boo.x[0]);
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ typedef struct _Path
|
|||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
DESIGNATED_IDENT,
|
DESIGNATED_IDENT,
|
||||||
DESIGNATED_SUBSCRIPT
|
DESIGNATED_SUBSCRIPT,
|
||||||
} DesignatedPathKind;
|
} DesignatedPathKind;
|
||||||
|
|
||||||
typedef struct _DesignatedPath
|
typedef struct _DesignatedPath
|
||||||
@@ -150,6 +150,7 @@ typedef struct _DesignatedPath
|
|||||||
Expr *index_expr;
|
Expr *index_expr;
|
||||||
};
|
};
|
||||||
} DesignatedPath;
|
} DesignatedPath;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned char bitsize;
|
unsigned char bitsize;
|
||||||
|
|||||||
@@ -76,10 +76,13 @@ bool parse_param_list(Context *context, Expr ***result, bool allow_type)
|
|||||||
Expr *expr = NULL;
|
Expr *expr = NULL;
|
||||||
SourceRange start = context->tok.span;
|
SourceRange start = context->tok.span;
|
||||||
// Special handling of [123]
|
// 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);
|
CONSUME_OR(TOKEN_RBRACKET, false);
|
||||||
|
RANGE_EXTEND_PREV(expr);
|
||||||
expr = TRY_EXPR_OR(parse_precedence_with_left_side(context, expr, PREC_ASSIGNMENT), false);
|
expr = TRY_EXPR_OR(parse_precedence_with_left_side(context, expr, PREC_ASSIGNMENT), false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -357,24 +357,11 @@ static inline bool sema_expr_analyse_subscript_after_parent_resolution(Context *
|
|||||||
Expr *subscripted = expr->subscript_expr.expr;
|
Expr *subscripted = expr->subscript_expr.expr;
|
||||||
Type *type = parent ? parent->canonical : subscripted->type->canonical;
|
Type *type = parent ? parent->canonical : subscripted->type->canonical;
|
||||||
Expr *index = expr->subscript_expr.index;
|
Expr *index = expr->subscript_expr.index;
|
||||||
Type *inner_type;
|
Type *inner_type = type_get_indexed_type(type);
|
||||||
switch (type->type_kind)
|
if (!inner_type)
|
||||||
{
|
{
|
||||||
case TYPE_POINTER:
|
SEMA_ERROR((parent ? expr : subscripted), "Cannot index '%s'.", type_to_error_string(type));
|
||||||
inner_type = type->pointer;
|
return false;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sema_analyse_expr(context, type_isize, index)) 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;
|
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));
|
assert(type_is_structlike(parent_path->type));
|
||||||
Decl **members = parent_path->type->decl->strukt.members;
|
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->kind = DESIGNATED_IDENT;
|
||||||
sub_path->index = i;
|
sub_path->index = i;
|
||||||
parent_path->sub_path = sub_path;
|
parent_path->sub_path = sub_path;
|
||||||
|
*has_found_match = true;
|
||||||
return sub_path;
|
return sub_path;
|
||||||
}
|
}
|
||||||
if (!member->name)
|
if (!member->name)
|
||||||
{
|
{
|
||||||
DesignatedPath temp_path;
|
DesignatedPath temp_path;
|
||||||
temp_path.type = member->type;
|
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;
|
if (!found) continue;
|
||||||
DesignatedPath *real_path = malloc_arena(sizeof(DesignatedPath));
|
DesignatedPath *real_path = malloc_arena(sizeof(DesignatedPath));
|
||||||
*real_path = temp_path;
|
*real_path = temp_path;
|
||||||
real_path->index = i;
|
real_path->index = i;
|
||||||
real_path->kind = DESIGNATED_IDENT;
|
real_path->kind = DESIGNATED_IDENT;
|
||||||
parent_path->sub_path = real_path;
|
parent_path->sub_path = real_path;
|
||||||
|
*has_found_match = true;
|
||||||
return found;
|
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;
|
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)
|
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;
|
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);
|
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;
|
if (!path) return NULL;
|
||||||
|
|
||||||
Type *type = path->type;
|
Type *type = path->type;
|
||||||
if (type->canonical->type_kind == TYPE_POINTER)
|
if (type->canonical->type_kind == TYPE_POINTER)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(expr, "It's not possible to subscript a pointer field in a designated initializer.");
|
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;
|
Expr *index = expr->subscript_expr.index;
|
||||||
@@ -685,79 +685,82 @@ static DesignatedPath *sema_analyse_init_subscript(Context *context, DesignatedP
|
|||||||
if (!inner_type)
|
if (!inner_type)
|
||||||
{
|
{
|
||||||
SEMA_ERROR(expr, "Not possible to index a value of type '%s'.", type_to_error_string(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;
|
// 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
|
// 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);
|
DesignatedPath *sub_path = CALLOCS(DesignatedPath);
|
||||||
path->sub_path = sub_path;
|
path->sub_path = sub_path;
|
||||||
sub_path->type = inner_type;
|
sub_path->type = inner_type;
|
||||||
sub_path->kind = DESIGNATED_SUBSCRIPT;
|
sub_path->kind = DESIGNATED_SUBSCRIPT;
|
||||||
sub_path->index_expr = index;
|
sub_path->index_expr = index;
|
||||||
|
*has_found_match = true;
|
||||||
return sub_path;
|
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)
|
switch (expr->expr_kind)
|
||||||
{
|
{
|
||||||
case EXPR_ACCESS:
|
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:
|
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:
|
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:
|
default:
|
||||||
return NULL;
|
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;
|
Expr **init_expressions = initializer->expr_initializer.initializer_expr;
|
||||||
|
bool is_structlike = type_is_structlike(assigned->canonical);
|
||||||
|
|
||||||
VECEACH(init_expressions, i)
|
VECEACH(init_expressions, i)
|
||||||
{
|
{
|
||||||
Expr *expr = init_expressions[i];
|
Expr *expr = init_expressions[i];
|
||||||
|
|
||||||
// 1. Ensure that're seeing expr = expr on the top level.
|
// 1. Ensure that're seeing expr = expr on the top level.
|
||||||
if (expr->expr_kind != EXPR_BINARY || expr->binary_expr.operator != BINARYOP_ASSIGN)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
Expr *init_expr = expr->binary_expr.left;
|
Expr *init_expr = expr->binary_expr.left;
|
||||||
DesignatedPath path = { .type = assigned };
|
DesignatedPath path = { .type = assigned };
|
||||||
DesignatedPath *last_path = sema_analyse_init_path(context, &path, init_expr);
|
bool has_reported_error = false;
|
||||||
if (!last_path)
|
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));
|
SEMA_ERROR(expr, "This is not a valid member of '%s'.", type_to_error_string(assigned));
|
||||||
return false;
|
return false;
|
||||||
@@ -773,6 +776,10 @@ static bool sema_expr_analyse_struct_designated_initializer(Context *context, Ty
|
|||||||
return true;
|
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)
|
static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, Decl *assigned, Expr *initializer)
|
||||||
{
|
{
|
||||||
Expr **elements = initializer->expr_initializer.initializer_expr;
|
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 size = vec_size(elements);
|
||||||
unsigned expected_members = vec_size(members);
|
unsigned expected_members = vec_size(members);
|
||||||
|
|
||||||
// For struct number of members must be the same as the size of the struct.
|
// 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
|
||||||
assert(size > 0);
|
// zero entries must be an error.
|
||||||
|
assert(size > 0 && "We should already have handled the size == 0 case.");
|
||||||
if (expected_members == 0)
|
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.");
|
SEMA_ERROR(elements[0], "Too many elements in initializer, it must be empty.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_union = assigned->decl_kind == DECL_UNION;
|
|
||||||
expected_members = is_union ? 1 : expected_members;
|
|
||||||
VECEACH(elements, i)
|
VECEACH(elements, i)
|
||||||
{
|
{
|
||||||
if (i >= expected_members)
|
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);
|
SEMA_ERROR(elements[i], "Too many elements in initializer, expected only %d.", expected_members);
|
||||||
return false;
|
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)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 7. Done!
|
||||||
return true;
|
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;
|
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.
|
// 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)
|
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.
|
// 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)
|
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_STRUCT:
|
||||||
case TYPE_UNION:
|
case TYPE_UNION:
|
||||||
return sema_expr_analyse_struct_initializer(context, assigned, expr);
|
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
TODO
|
return sema_expr_analyse_initializer(context, assigned, expr);
|
||||||
case TYPE_VARARRAY:
|
case TYPE_VARARRAY:
|
||||||
TODO
|
TODO
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user