Unions and structs, including setting them should now work.

This commit is contained in:
Christoffer Lerno
2020-04-08 21:17:03 +02:00
parent 96c8c77e89
commit bb806716e4
8 changed files with 159 additions and 206 deletions

View File

@@ -560,6 +560,10 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent)
fprint_expr_common(file, expr, indent + 1);
fprint_type_info_recursive(file, expr->type_expr.type, indent + 1);
break;
case EXPR_GROUP:
fprintf_indented(file, indent, "(group\n");
fprint_expr_recursive(file, expr->group_expr, indent + 1);
break;
case EXPR_CALL:
fprintf_indented(file, indent, "(call\n");
fprint_expr_common(file, expr, indent + 1);

View File

@@ -844,6 +844,7 @@ typedef struct _Context
Decl **ct_ifs;
Ast **defers;
Decl *active_function_for_analysis;
Decl *active_type_for_analysis;
Decl **last_local;
Ast **labels;
Ast **gotos;

View File

@@ -220,6 +220,7 @@ typedef enum
EXPR_IDENTIFIER,
EXPR_TYPE_ACCESS,
EXPR_CALL,
EXPR_GROUP,
EXPR_SIZEOF,
EXPR_SUBSCRIPT,
EXPR_ACCESS,
@@ -229,7 +230,6 @@ typedef enum
EXPR_SCOPED_EXPR,
EXPR_MACRO_EXPR,
EXPR_EXPR_BLOCK,
EXPR_DESIGNATED_INIT,
} ExprKind;

View File

@@ -31,20 +31,17 @@ static inline LLVMValueRef gencontext_emit_sub_int(GenContext *context, Type *ty
? LLVMBuildNUWSub(context->builder, left, right, "usub")
: LLVMBuildNSWSub(context->builder, left, right, "sub");
}
static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, Expr *expr)
static inline LLVMValueRef gencontext_emit_subscript_addr_from_value(GenContext *context, LLVMValueRef parent, Type *parent_type, Expr *index_expr)
{
LLVMValueRef index = gencontext_emit_expr(context, expr->subscript_expr.index);
Type *type = expr->subscript_expr.expr->type->canonical;
switch (type->type_kind)
assert(parent_type->canonical == parent_type);
LLVMValueRef index = gencontext_emit_expr(context, index_expr);
switch (parent_type->type_kind)
{
case TYPE_ARRAY:
TODO
case TYPE_POINTER:
return LLVMBuildGEP2(context->builder,
llvm_type(type->pointer),
gencontext_emit_expr(context, expr->subscript_expr.expr),
&index, 1, "[]");
llvm_type(parent_type->pointer),
parent, &index, 1, "[]");
case TYPE_ARRAY:
case TYPE_VARARRAY:
case TYPE_SUBARRAY:
case TYPE_STRING:
@@ -52,6 +49,12 @@ static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, E
default:
UNREACHABLE
}
}
static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, Expr *expr)
{
LLVMValueRef parent = gencontext_emit_expr(context, expr->subscript_expr.expr);
return gencontext_emit_subscript_addr_from_value(context, parent, expr->subscript_expr.expr->type->canonical, expr->subscript_expr.index);
}
static LLVMValueRef gencontext_emit_member_addr(GenContext *context, LLVMValueRef value, Decl *parent, Decl *member)
@@ -76,10 +79,12 @@ static LLVMValueRef gencontext_emit_member_addr(GenContext *context, LLVMValueRe
if (current_parent->decl_kind == DECL_UNION)
{
return LLVMBuildBitCast(context->builder, value, LLVMPointerType(llvm_type(member->type), 0), "");
return LLVMBuildBitCast(context->builder, value, LLVMPointerType(llvm_type(member->type), 0), "unionref");
}
return LLVMBuildStructGEP2(context->builder, llvm_type(current_parent->type), value, index, "");
return LLVMBuildStructGEP2(context->builder, llvm_type(current_parent->type), value, index, "structref");
}
static inline LLVMValueRef gencontext_emit_access_addr(GenContext *context, Expr *expr)
{
Expr *parent = expr->access_expr.parent;
@@ -119,6 +124,8 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
return gencontext_emit_subscript_addr(context, expr);
case EXPR_SCOPED_EXPR:
return gencontext_emit_scoped_expr_address(context, expr);
case EXPR_GROUP:
return gencontext_emit_address(context, expr->group_expr);
case EXPR_CONST:
case EXPR_TYPE:
case EXPR_POISONED:
@@ -204,6 +211,28 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *
LLVMValueRef rhs = gencontext_emit_expr(context, expr->cast_expr.expr);
return gencontext_emit_cast(context, expr->cast_expr.kind, rhs, expr->type->canonical, expr->cast_expr.expr->type->canonical);
}
static inline LLVMValueRef gencontext_emit_designated_initializer(GenContext *context, Type *parent_type, LLVMValueRef parent, Expr *expr)
{
assert(parent_type == parent_type->canonical);
switch (expr->expr_kind)
{
case EXPR_SUBSCRIPT:
if (expr->subscript_expr.expr)
{
parent = gencontext_emit_designated_initializer(context, parent_type, parent, expr->subscript_expr.expr);
parent_type = expr->subscript_expr.expr->type->canonical;
}
return gencontext_emit_subscript_addr_from_value(context, parent, parent_type, expr->subscript_expr.index);
case EXPR_ACCESS:
parent = gencontext_emit_designated_initializer(context, parent_type, parent, expr->access_expr.parent);
parent_type = expr->subscript_expr.expr->type->canonical;
return gencontext_emit_member_addr(context, parent, parent_type->decl, expr->access_expr.ref);
case EXPR_IDENTIFIER:
return gencontext_emit_member_addr(context, parent, parent_type->decl, expr->identifier_expr.decl);
default:
UNREACHABLE
}
}
static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *context, Expr *expr)
{
@@ -225,7 +254,14 @@ static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *con
bool is_union = expr->type->canonical->type_kind == TYPE_UNION;
if (expr->expr_initializer.init_type == INITIALIZER_NORMAL)
{
assert(!is_union);
if (is_union)
{
assert(vec_size(elements) == 1);
LLVMValueRef init_value = gencontext_emit_expr(context, elements[0]);
LLVMValueRef u = LLVMBuildBitCast(context->builder, ref, LLVMPointerType(llvm_type(elements[0]->type->canonical), 0), "");
LLVMBuildStore(context->builder, init_value, u);
return ref;
}
VECEACH(elements, i)
{
Expr *element = elements[i];
@@ -245,27 +281,10 @@ static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *con
VECEACH(elements, i)
{
Expr *element = elements[i];
LLVMValueRef sub_value = gencontext_emit_expr(context, element->designated_init_expr.value);
Decl *parent = expr->type->decl;
DesignatedInitPath *path = &element->designated_init_expr.path;
LLVMValueRef subref = ref;
assert(element->expr_kind == EXPR_DESIGNATED_INIT);
// If this is a union, we down a step to begin with.
if (is_union)
{
subref = LLVMBuildBitCast(context->builder, ref, LLVMPointerType(llvm_type(path->decl->type), 0), "unioncast");
parent = path->decl;
path = path->sub_path;
}
while (path)
{
subref = LLVMBuildStructGEP2(context->builder, llvm_type(parent->type), subref, path->decl->var.id, "access");
parent = path->decl;
path = path->sub_path;
}
LLVMBuildStore(context->builder, sub_value, subref);
LLVMValueRef sub_value = gencontext_emit_expr(context, element->binary_expr.right);
LLVMValueRef sub_ref = gencontext_emit_designated_initializer(context, expr->type->canonical, ref, element->binary_expr.left);
LLVMBuildStore(context->builder, sub_value, sub_ref);
}
return ref;
}
@@ -828,8 +847,6 @@ static inline LLVMValueRef gencontext_emit_expression_list_expr(GenContext *cont
}
static inline LLVMValueRef gencontext_emit_expr_block(GenContext *context, Expr *expr)
{
LLVMValueRef old_ret_out = context->return_out;
@@ -896,6 +913,8 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
return gencontext_load_expr(context, gencontext_emit_address(context, expr));
case EXPR_CALL:
return gencontext_emit_call_expr(context, expr);
case EXPR_GROUP:
return gencontext_emit_expr(context, expr->group_expr);
case EXPR_ACCESS:
return gencontext_emit_access_expr(context, expr);
case EXPR_INITIALIZER_LIST:

View File

@@ -208,10 +208,12 @@ static Expr *parse_ternary_expr(Context *context, Expr *left_side)
static Expr *parse_grouping_expr(Context *context, Expr *left)
{
assert(!left && "Unexpected left hand side");
Expr *expr = expr_new(EXPR_GROUP, context->tok.span);
advance_and_verify(context, TOKEN_LPAREN);
Expr *right = TRY_EXPR_OR(parse_expr(context), &poisoned_expr);
expr->group_expr = TRY_EXPR_OR(parse_expr(context), &poisoned_expr);
CONSUME_OR(TOKEN_RPAREN, &poisoned_expr);
return right;
RANGE_EXTEND_PREV(expr);
return expr;
}
/**

View File

@@ -49,6 +49,8 @@ static bool expr_is_ltype(Expr *expr)
return expr->unary_expr.operator == UNARYOP_DEREF;
case EXPR_ACCESS:
return expr_is_ltype(expr->access_expr.parent);
case EXPR_GROUP:
return expr_is_ltype(expr->group_expr);
case EXPR_SUBSCRIPT:
return true;
default:
@@ -172,7 +174,6 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr
Decl *ambiguous_decl;
Decl *decl = sema_resolve_symbol(context, expr->identifier_expr.identifier, expr->identifier_expr.path, &ambiguous_decl);
if (!decl && !expr->identifier_expr.path && to)
{
if (find_possible_inferred_identifier(to, expr)) return true;
@@ -353,6 +354,13 @@ static Decl *strukt_recursive_search_member(Decl *strukt, const char *name)
return NULL;
}
static inline bool sema_expr_analyse_group(Context *context, Type *to, Expr *expr)
{
if (!sema_analyse_expr(context, to, expr->group_expr)) return false;
*expr = *expr->group_expr;
return true;
}
static inline bool sema_expr_analyse_access(Context *context, Type *to, Expr *expr)
{
@@ -482,10 +490,12 @@ static Decl *sema_analyse_init_identifier(Context *context, Decl *strukt, Expr *
{
assert(expr->resolve_status == RESOLVE_NOT_DONE);
expr->resolve_status = RESOLVE_RUNNING;
expr->identifier_expr.decl = sema_analyse_init_identifier_string(context, strukt, expr->identifier_expr.identifier);
Decl *res = sema_analyse_init_identifier_string(context, strukt, expr->identifier_expr.identifier);
if (!res) return NULL;
expr->identifier_expr.decl = res;
expr->resolve_status = RESOLVE_DONE;
expr->type = expr->identifier_expr.decl->type;
return expr->identifier_expr.decl;
expr->type = res->type;
return res;
}
static Decl *sema_analyse_init_access(Context *context, Decl *strukt, Expr *access_expr)
@@ -528,190 +538,92 @@ static Decl *sema_analyse_init_path(Context *context, Decl *strukt, Expr *expr)
}
}
static bool sema_expr_analyse_designated_init(Context *context, DesignatedInitPath *path, Decl *top, Expr *path_expr);
static bool sema_expr_analyse_designated_init_ident(Context *context, DesignatedInitPath *path, Decl *top, const char *name)
static bool sema_expr_analyse_struct_designated_initializer(Context *context, Decl *assigned, Expr *initializer)
{
// 3. Loop through the members.
Decl **members = top->strukt.members;
VECEACH(members, i)
Expr **init_expressions = initializer->expr_initializer.initializer_expr;
VECEACH(init_expressions, i)
{
Decl *member = members[i];
if (member->name == name)
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)
{
// 4. If found, set this to the current path.
(*path) = (DesignatedInitPath) { .decl = member, .sub_path = NULL };
// 5. And we're done!
return true;
}
// 6. We might encounter anonymous members. Treat this as a possible "match"
if (!member->name)
{
DesignatedInitPath anon_path;
bool found = sema_expr_analyse_designated_init_ident(context, &anon_path, member, name);
if (found)
{
// 7. If found, create a copy path.
DesignatedInitPath *path_copy = malloc_arena(sizeof(DesignatedInitPath));
*path_copy = anon_path;
(*path) = (DesignatedInitPath) { .decl = member, .sub_path = path_copy };
return true;
}
}
}
return false;
}
static bool sema_expr_analyse_designated_init(Context *context, DesignatedInitPath *path, Decl *top, Expr *path_expr)
{
// Our expression will look like this for a.b[3].c = ...
// access(subscript(access(identifier))), now we need to reverse that.
switch (path_expr->expr_kind)
{
case EXPR_IDENTIFIER:
// Resolving for an identifier:
// 1. Can't be a path attached.
if (path_expr->identifier_expr.path) return false;
// 2. Ensure it's a union or struct
if (!decl_is_struct_type(top)) return false;
return sema_expr_analyse_designated_init_ident(context, path, top, path_expr->identifier_expr.identifier);
case EXPR_ACCESS:
// Resolve for access:
// 1. Resolve the parent path:
if (!sema_expr_analyse_designated_init(context, path, top, path_expr->access_expr.parent)) return false;
// 2. Our new top is now lowest init path.
while (path->sub_path)
{
path = path->sub_path;
}
top = path->decl;
// 3. Do an analysis with the identifier:
path->sub_path = malloc_arena(sizeof(DesignatedInitPath));
return sema_expr_analyse_designated_init_ident(context,
path->sub_path,
top->type->decl,
path_expr->access_expr.sub_element.string);
case EXPR_SUBSCRIPT:
// Resolve for subscript:
// 1. Resolve the parent path:
if (!sema_expr_analyse_designated_init(context, path, top, path_expr->subscript_expr.expr)) return false;
// 2. Our new top is now lowest init path.
while (path->sub_path)
{
path = path->sub_path;
}
top = path->decl;
TODO // Analyse index etc.
default:
SEMA_ERROR(expr, "Expected an initializer on the format 'foo = 123' here.");
return false;
}
Expr *path = expr->binary_expr.left;
if (!sema_analyse_init_path(context, assigned, path))
{
SEMA_ERROR(path, "This is not a valid member of '%s'.", type_to_error_string(assigned->type));
return false;
}
}
static bool sema_expr_analyse_struct_designated_initializer_list(Context *context, Decl *assigned, Expr *expr_list)
{
assert(expr_list->expr_initializer.init_type == INITIALIZER_UNKNOWN);
VECEACH(expr_list->expr_initializer.initializer_expr, i)
{
Expr *expr = expr_list->expr_initializer.initializer_expr[i];
if (expr->expr_kind != EXPR_BINARY && expr->binary_expr.operator != BINARYOP_ASSIGN)
{
if (i != 0)
{
SEMA_ERROR(expr, "Named and non-named initializers are not allowed together, please choose one or the other.");
return false;
}
// If there is an unexpected expression and no previous element then this is a normal initializer list.
expr_list->expr_initializer.init_type = INITIALIZER_NORMAL;
return true;
}
Expr *path_expr = expr->binary_expr.left;
Expr *value = expr->binary_expr.right;
DesignatedInitPath path;
if (!sema_expr_analyse_designated_init(context, &path, assigned, path_expr))
{
if (i != 0)
{
SEMA_ERROR(path_expr, "Unexpected element when initializing '%s', did you get the name right?", assigned->name);
return false;
}
expr_list->expr_initializer.init_type = INITIALIZER_NORMAL;
return true;
}
// Walk down to the last decl.
DesignatedInitPath *init_path = &path;
while (init_path->sub_path) init_path = init_path->sub_path;
if (!sema_analyse_expr_of_required_type(context, init_path->decl->type, value)) return false;
// Destruct the expression and replace.
expr->designated_init_expr.value = value; // Do this first!
expr->resolve_status = RESOLVE_DONE;
expr->designated_init_expr.path = path;
expr->expr_kind = EXPR_DESIGNATED_INIT;
expr->type = init_path->decl->type;
if (!sema_analyse_expr_of_required_type(context, path->type, value)) return false;
expr->type = path->type;
}
expr_list->expr_initializer.init_type = INITIALIZER_DESIGNATED;
initializer->expr_initializer.init_type = INITIALIZER_DESIGNATED;
return true;
}
static inline bool sema_expr_analyse_struct_initializer_list(Context *context, Type *assigned, Expr *expr)
static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, Decl *assigned, Expr *initializer)
{
Expr **elements = initializer->expr_initializer.initializer_expr;
Decl **members = assigned->strukt.members;
initializer->expr_initializer.init_type = INITIALIZER_NORMAL;
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);
if (expected_members == 0)
{
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)
{
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 (expected_members > size)
{
SEMA_ERROR(elements[size - 1], "Few elements in initializer, there should be elements after this one.");
return false;
}
return true;
}
static inline bool sema_expr_analyse_struct_initializer(Context *context, Type *assigned, Expr *expr)
{
expr->type = assigned;
Decl **members = assigned->decl->strukt.members;
unsigned size = vec_size(members);
Expr **init_expressions = expr->expr_initializer.initializer_expr;
// Zero size init will initialize to empty.
if (size == 0)
// 1. Zero size init will initialize to empty.
if (vec_size(init_expressions) == 0)
{
expr->expr_initializer.init_type = INITIALIZER_ZERO;
return true;
}
if (!sema_expr_analyse_struct_designated_initializer_list(context, assigned->decl, expr)) return false;
// If we already parsed this.
if (expr->expr_initializer.init_type == INITIALIZER_DESIGNATED) return true;
Expr **elements = expr->expr_initializer.initializer_expr;
assert(expr->expr_initializer.init_type == INITIALIZER_NORMAL);
if (assigned->type_kind == TYPE_UNION)
// 2. Check if we might have a designated initializer
// 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)
{
SEMA_ERROR(elements[0], "Initializer list for unions must use named initializers, e.g. { a = 4 }");
return false;
return sema_expr_analyse_struct_designated_initializer(context, assigned->decl, expr);
}
VECEACH(elements, i)
{
if (i >= size)
{
SEMA_ERROR(elements[size], "Too many elements in initializer, expected only %d.", size);
return false;
}
if (!sema_analyse_expr_of_required_type(context, members[i]->type, elements[i])) return false;
}
if (size > vec_size(elements))
{
SEMA_ERROR(elements[vec_size(elements) - 1], "Too few elements in initializer, expected %d.", size);
return false;
}
return true;
// 3. Otherwise use the plain initializer.
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)
@@ -723,7 +635,9 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to
{
case TYPE_STRUCT:
case TYPE_UNION:
if (decl_is_struct_type(assigned->decl)) return sema_expr_analyse_struct_initializer_list(context, assigned, expr);
if (decl_is_struct_type(assigned->decl)) return sema_expr_analyse_struct_initializer(context,
assigned,
expr);
break;
case TYPE_ARRAY:
TODO
@@ -2127,6 +2041,9 @@ static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_ex
EXPR_COPY(expr->subscript_expr.expr);
EXPR_COPY(expr->subscript_expr.index);
return expr;
case EXPR_GROUP:
EXPR_COPY(expr->group_expr->group_expr);
return expr;
case EXPR_ACCESS:
EXPR_COPY(expr->access_expr.parent);
return expr;
@@ -2562,6 +2479,8 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *
return sema_expr_analyse_sizeof(context, to, expr);
case EXPR_SUBSCRIPT:
return sema_expr_analyse_subscript(context, to, expr);
case EXPR_GROUP:
return sema_expr_analyse_group(context, to, expr);
case EXPR_ACCESS:
return sema_expr_analyse_access(context, to, expr);
case EXPR_INITIALIZER_LIST:

View File

@@ -20,7 +20,7 @@ void context_push_scope_with_flags(Context *context, ScopeFlags flags)
context->current_scope->local_decl_start = context->last_local;
context->current_scope->defers.start = parent_defer;
context->current_scope->defers.end = parent_defer;
if (flags & (SCOPE_DEFER | SCOPE_EXPR_BLOCK))
if (flags & (SCOPE_DEFER | SCOPE_EXPR_BLOCK | SCOPE_NEXT))
{
context->current_scope->flags = flags;
}