aboutsummaryrefslogtreecommitdiff
path: root/src/actualize.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2023-04-03 16:00:34 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2023-04-03 16:00:34 +0300
commit2ca159fb5c2a52f33c499eef1fa50a98a863b0f0 (patch)
treec9497ad8372a047bcff366c189c8969ed84f0406 /src/actualize.c
parent4642bedb436981e92e3312f06bfcb2eb34074596 (diff)
downloadek-2ca159fb5c2a52f33c499eef1fa50a98a863b0f0.tar.gz
ek-2ca159fb5c2a52f33c499eef1fa50a98a863b0f0.zip
initial union testing
Diffstat (limited to 'src/actualize.c')
-rw-r--r--src/actualize.c212
1 files changed, 178 insertions, 34 deletions
diff --git a/src/actualize.c b/src/actualize.c
index 4d1d449..b25968f 100644
--- a/src/actualize.c
+++ b/src/actualize.c
@@ -337,6 +337,11 @@ static int analyze_file_visibility(struct scope *scope, struct ast_node *node)
break;
}
+ case AST_UNION: {
+ ret |= scope_add_type(scope, node);
+ break;
+ }
+
case AST_ENUM: {
ret |= scope_add_type(scope, node);
break;
@@ -1251,6 +1256,11 @@ static int actualize_type(struct act_state *state,
EXIT_ACT(-1);
}
+ /* this could be more clear, maybe add into the parser some kind
+ * of meta class for templated types? */
+ if (exists->node_type == AST_UNION)
+ type->_type.kind = AST_TYPE_UNION;
+
/* nothing to do, except maybe check that types are actually
* identical? */
if (exists->node_type == AST_TYPE)
@@ -1300,6 +1310,9 @@ static int actualize_type(struct act_state *state,
type->_type.unio.impls = NULL;
}
+ if (ast_flags(exists, AST_FLAG_GENERIC))
+ ast_set_flags(type, AST_FLAG_GENERIC);
+
break;
}
@@ -1344,11 +1357,24 @@ static int actualize_type(struct act_state *state,
break;
}
+ case AST_TYPE_UNION:
case AST_TYPE_STRUCT: {
- struct ast_node *id = type->_type.struc.id;
+ assert(ast_flags(type, AST_FLAG_ACTUAL));
+ break;
+ }
+
+ case AST_TYPE_GENERIC: {
+ struct ast_node *id = type->_type.generic.id;
struct ast_node *exists = file_scope_resolve_type(scope, id);
- if (!exists || exists->node_type != AST_STRUCT) {
- semantic_error(scope->fctx, type, "no such struct");
+ if (!exists) {
+ semantic_error(scope->fctx, type, "no such type");
+ EXIT_ACT(-1);
+ }
+
+ if (exists->node_type != AST_UNION &&
+ exists->node_type != AST_STRUCT) {
+ semantic_error(scope->fctx, type,
+ "type not struct or union");
EXIT_ACT(-1);
}
@@ -1356,7 +1382,7 @@ static int actualize_type(struct act_state *state,
if (actualize(state, exists->scope, exists))
EXIT_ACT(-1);
- struct ast_node *types = type->_type.struc.impls;
+ struct ast_node *types = type->_type.generic.args;
if (actualize(state, scope, types))
EXIT_ACT(-1);
@@ -1377,14 +1403,17 @@ static int actualize_type(struct act_state *state,
types = types->next;
}
- break;
- }
+ if (exists->node_type == AST_UNION)
+ type->_type.kind = AST_TYPE_UNION;
+ else
+ type->_type.kind = AST_TYPE_STRUCT;
- case AST_TYPE_MEMBER: {
- /* TODO */
break;
}
+ default:
+ semantic_error(scope->fctx, type, "unimplemented type");
+ EXIT_ACT(-1);
}
ast_set_flags(type, AST_FLAG_ACTUAL);
@@ -1494,16 +1523,16 @@ static size_t member_count(struct ast_node *exists)
return ast_list_len(body);
}
-static struct ast_node *lookup_struct_member_idx(struct ast_node *struc,
- struct ast_node *find,
- size_t *idx)
+static struct ast_node *lookup_member_idx(struct ast_node *body,
+ struct ast_node *find,
+ size_t *idx)
{
/* micro-optimisation, likely way premature but speeds up selection
* between lookup_struct_member_idx and *_name by a tiny amount */
(void)(find);
-
+ assert(idx);
size_t i = *idx;
- struct ast_node *m = struc->_struct.body;
+ struct ast_node *m = body;
while (i != 0 && m) {
m = m->next;
i--;
@@ -1512,12 +1541,13 @@ static struct ast_node *lookup_struct_member_idx(struct ast_node *struc,
return m;
}
-static struct ast_node *lookup_struct_member_name(struct ast_node *struc,
- struct ast_node *find,
- size_t *idx)
+static struct ast_node *lookup_member_name(struct ast_node *body,
+ struct ast_node *find,
+ size_t *idx)
{
+ assert(find->node_type == AST_ID);
size_t i = 0;
- struct ast_node *m = struc->_struct.body;
+ struct ast_node *m = body;
while (m) {
assert(m->node_type == AST_VAR);
if (identical_ast_nodes(0, find, m->_var.id))
@@ -1526,7 +1556,9 @@ static struct ast_node *lookup_struct_member_name(struct ast_node *struc,
i++;
}
- *idx = i;
+ if (idx)
+ *idx = i;
+
return m;
}
@@ -1534,9 +1566,19 @@ static struct ast_node *lookup_struct_member(struct ast_node *struc,
struct ast_node *find, size_t *idx)
{
if (find)
- return lookup_struct_member_name(struc, find, idx);
+ return lookup_member_name(struc->_struct.body, find, idx);
+
+ return lookup_member_idx(struc->_struct.body, find, idx);
+}
+
+static struct ast_node *lookup_union_member(struct ast_node *unio,
+ struct ast_node *find)
+{
+ if (find)
+ return lookup_member_name(unio->_union.body, find, NULL);
- return lookup_struct_member_idx(struc, find, idx);
+ size_t idx = 0;
+ return lookup_member_idx(unio->_union.body, find, &idx);
}
static struct ast_node *lookup_enum_member(struct ast_node *enu,
@@ -1555,11 +1597,53 @@ static struct ast_node *lookup_enum_member(struct ast_node *enu,
return m;
}
+static int init_union(struct act_state *state, struct scope *scope,
+ struct ast_node *exists, struct ast_node *init)
+{
+ struct ast_node *arg = init->_init.body;
+ if (arg->next) {
+ semantic_error(scope->fctx, arg->next,
+ "multiple arguments in union initialization not allowed");
+ return -1;
+ }
+
+ if (actualize(state, scope, arg))
+ return -1;
+
+ struct ast_node *member = NULL;
+ if (ast_flags(arg, AST_FLAG_MEMBER)) {
+ member = lookup_union_member(exists, arg->_var.id);
+ }
+ else {
+ /* pick first element in body */
+ member = exists->_union.body;
+ }
+
+ if (!member) {
+ char *sstr = type_str(exists->type);
+ semantic_error(scope->fctx, arg,
+ "no such member in %s",
+ sstr);
+ free(sstr);
+ return -1;
+ }
+
+ if (!implements(0, scope, arg->type, member->type)) {
+ char *mstr = type_str(member->type);
+ char *astr = type_str(arg->type);
+ semantic_error(scope->fctx, arg, "%s does not implement %s",
+ astr, mstr);
+ free(mstr);
+ free(astr);
+ return -1;
+ }
+
+ return 0;
+}
+
static int init_struct(struct act_state *state, struct scope *scope,
struct ast_node *exists, struct ast_node *init)
{
- assert(ast_flags(exists, AST_FLAG_ACTUAL));
-
size_t i = 0;
size_t mcount = member_count(exists);
@@ -1653,24 +1737,48 @@ struct ast_node *actual_type(struct ast_node *type)
return type;
}
-static int actualize_struct_init(struct act_state *state,
- struct scope *scope, struct ast_node *init,
- struct ast_node *struct_type)
+static int actualize_struct_init_cast(struct act_state *state,
+ struct scope *scope,
+ struct ast_node *init,
+ struct ast_node *actual)
{
- struct ast_node *actual = actual_type(struct_type);
- if (actual->_type.kind != AST_TYPE_STRUCT) {
- semantic_error(scope->fctx, struct_type,
- "type is not a structure");
- return -1;
- }
-
struct ast_node *id = actual->_type.struc.id;
struct ast_node *exists = file_scope_resolve_type(scope, id);
assert(exists);
+ assert(ast_flags(exists, AST_FLAG_ACTUAL));
return init_struct(state, scope, exists, init);
}
+static int actualize_union_init_cast(struct act_state *state,
+ struct scope *scope,
+ struct ast_node *init,
+ struct ast_node *actual)
+{
+ struct ast_node *id = actual->_type.unio.id;
+ struct ast_node *exists = file_scope_resolve_type(scope, id);
+ assert(exists);
+ assert(ast_flags(exists, AST_FLAG_ACTUAL));
+
+ return init_union(state, scope, exists, init);
+}
+
+static int actualize_init_cast(struct act_state *state,
+ struct scope *scope, struct ast_node *init,
+ struct ast_node *type)
+{
+ struct ast_node *actual = actual_type(type);
+ if (actual->_type.kind == AST_TYPE_STRUCT)
+ return actualize_struct_init_cast(state, scope, init, actual);
+ if (actual->_type.kind == AST_TYPE_UNION)
+ return actualize_union_init_cast(state, scope, init, actual);
+
+ semantic_error(scope->fctx, type,
+ "type is not a struct or union");
+ return -1;
+
+}
+
static int proc_pointer(struct ast_node *type)
{
if (type->_type.kind != AST_TYPE_POINTER)
@@ -1698,6 +1806,7 @@ static int proc_choice(struct ast_node *expr, struct ast_node *type)
static int match_proc(struct act_state *state, struct scope *scope,
struct ast_node *cast)
{
+ (void)(state);
semantic_error(scope->fctx, cast,
"procedure signature casts not yet implemented");
return -1;
@@ -1723,7 +1832,7 @@ static int actualize_cast(struct act_state *state,
if (expr->node_type == AST_INIT) {
cast->type = type;
- return actualize_struct_init(state, scope, expr, type);
+ return actualize_init_cast(state, scope, expr, type);
}
if (types_match(expr->type, type)) {
@@ -2068,6 +2177,8 @@ static int actualize_struct(struct act_state *state,
return -1;
scope_add_scope(node->scope, struct_scope);
+ if (generics)
+ ast_set_flags(node, AST_FLAG_GENERIC);
/* TODO: some IDs should be handles as just placeholders, I think? */
if (actualize(state, struct_scope, generics))
@@ -2086,6 +2197,36 @@ static int actualize_struct(struct act_state *state,
return 0;
}
+static int actualize_union(struct act_state *state,
+ struct scope *scope, struct ast_node *node)
+{
+ assert(node->node_type == AST_UNION);
+ ast_set_flags(node, AST_FLAG_INIT);
+ struct ast_node *generics = node->_union.generics;
+ struct scope *union_scope = create_scope();
+ if (!union_scope)
+ return -1;
+
+ scope_add_scope(node->scope, union_scope);
+ if (generics)
+ ast_set_flags(node, AST_FLAG_GENERIC);
+
+ if (actualize(state, union_scope, generics))
+ return -1;
+
+ struct ast_node *body = node->_union.body;
+ if (actualize(state, union_scope, body))
+ return -1;
+
+ /* cloning slightly odd, but I guess it's fine? */
+ struct ast_node *clone_id = clone_ast_node(node->_union.id);
+ node->type = gen_type(AST_TYPE_UNION, clone_id, NULL, NULL);
+ scope_add_scratch(scope, node->type);
+
+ ast_set_flags(node, AST_FLAG_ACTUAL);
+ return 0;
+}
+
/* could maybe be renamed, but essentially dot in copper works as either
* -> or . in C, so allow structures or templates and single level pointers to
* structures or templates. */
@@ -2165,7 +2306,7 @@ static int actualize_assign(struct act_state *state, struct scope *scope,
if (from->node_type == AST_INIT) {
node->type = to->type;
- return actualize_struct_init(state, scope, from, to->type);
+ return actualize_init_cast(state, scope, from, to->type);
}
if (!types_match(to->type, from->type)) {
@@ -2298,6 +2439,7 @@ static int actualize(struct act_state *state, struct scope *scope,
case AST_UNOP: ret |= actualize_unop(state, scope, node); break;
case AST_AS: ret |= actualize_as(state, scope, node); break;
case AST_STRUCT: ret |= actualize_struct(state, scope, node); break;
+ case AST_UNION: ret |= actualize_union(state, scope, node); break;
case AST_DOT: ret |= actualize_dot(state, scope, node); break;
case AST_INIT: ret |= actualize_init(state, scope, node); break;
case AST_ASSIGN: ret |= actualize_assign(state, scope, node); break;
@@ -2378,6 +2520,8 @@ void replace_type(struct ast_node *type, struct ast_node *from,
case AST_TYPE_TYPEOF:
destroy_ast_node(type->_type.typeo.expr);
break;
+
+ default:
}
*type = *clone;
free(clone);