aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2025-01-10 22:59:41 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2025-01-10 23:01:35 +0200
commit2d90cea9adb9a3f73cd5b211a4ed9508b505729f (patch)
tree78f9cde6d162fbda9352d2c668ac00a298815b19 /src
parentdbf3ed3db10f9fa9157d661704e16ba5b73b0e84 (diff)
downloadek-2d90cea9adb9a3f73cd5b211a4ed9508b505729f.tar.gz
ek-2d90cea9adb9a3f73cd5b211a4ed9508b505729f.zip
initial struct continuations implemented
Diffstat (limited to 'src')
-rw-r--r--src/actualize.c148
-rw-r--r--src/ast.c7
-rw-r--r--src/scope.c164
3 files changed, 259 insertions, 60 deletions
diff --git a/src/actualize.c b/src/actualize.c
index ca9e31e..2409162 100644
--- a/src/actualize.c
+++ b/src/actualize.c
@@ -364,6 +364,12 @@ static int analyze_visibility(struct scope *scope, struct ast *node)
return scope_add_type(scope, struct_id(node), node);
}
+ case AST_STRUCT_CONT_DEF: {
+ node->scope = create_scope();
+ scope_add_scope(scope, node->scope);
+ return scope_add_chain(scope, struct_cont_id(node), node);
+ }
+
case AST_ENUM_DEF: {
node->scope = create_scope();
scope_add_scope(scope, node->scope);
@@ -2086,12 +2092,30 @@ static int actualize_trait(struct act_state *state, struct scope *scope,
return node->t == NULL;
}
-static int actualize_struct(struct act_state *state,
- struct scope *scope, struct ast *node)
+static struct ast *chain_lookup(struct act_state *state, struct ast *def,
+ char *id)
+{
+ if (!def)
+ return NULL;
+
+ struct ast *exists = actualized_scope_find_symbol(state, def->scope,
+ id);
+ if (exists)
+ return exists;
+
+ if (def->chain)
+ return chain_lookup(state, def->chain, id);
+
+ return NULL;
+}
+
+static int expand_struct_body(struct act_state *state,
+ struct scope *scope,
+ struct ast *node,
+ char *id,
+ struct ast *params,
+ struct ast *body)
{
- UNUSED(state);
- assert(node->k == AST_STRUCT_DEF);
- struct ast *params = struct_params(node);
struct scope *struct_scope = create_scope();
if (!struct_scope)
return -1;
@@ -2102,7 +2126,6 @@ static int actualize_struct(struct act_state *state,
ast_set_flags(node, AST_FLAG_GENERIC);
/* do type setting first to make sure body checking works */
- char *id = struct_id(node);
if (same_id(id, "i27"))
node->t = tgen_primitive(TYPE_I27, strdup(id), node, node->loc);
else if (same_id(id, "i9"))
@@ -2120,7 +2143,7 @@ static int actualize_struct(struct act_state *state,
/* iterate over types and make aliases to them */
struct type *types = NULL;
- foreach_node(n, struct_params(node)) {
+ foreach_node(n, params) {
char *id = var_id(n);
struct type *type = var_type(n);
struct act_state type_state = {0};
@@ -2142,11 +2165,19 @@ static int actualize_struct(struct act_state *state,
tstruct_params(node->t) = types;
struct ast *def = file_scope_find_type(scope, id);
- int ret = scope_add_expd_struct(scope, def, types, node);
- MAYBE_UNUSED(ret);
+ struct ast *base = chain_base(def);
+
+ int ret = 0;
+ if (node->k == AST_STRUCT_DEF)
+ ret = scope_add_expd_struct(scope, base, types, node);
+ else if (node->k == AST_STRUCT_CONT_DEF)
+ ret = scope_add_expd_chain(scope, base, types, node);
+ else
+ abort();
+
assert(ret == 0);
- foreach_node(n, struct_body(node)) {
+ foreach_node(n, body) {
if (n->k != AST_TYPE_EXPAND)
continue;
@@ -2160,12 +2191,12 @@ static int actualize_struct(struct act_state *state,
return -1;
}
- if (has_trait(struct_body(node), type_expand_id(n))) {
+ if (has_trait(body, type_expand_id(n))) {
n->k = AST_EMPTY;
continue;
}
- if (same_id(struct_id(node), type_expand_id(n))) {
+ if (same_id(id, type_expand_id(n))) {
semantic_error(scope->fctx, n,
"recursive trait implementations not allowed");
return -1;
@@ -2184,21 +2215,7 @@ static int actualize_struct(struct act_state *state,
n->n = body;
}
- /*
- foreach_node(n, struct_body(node)) {
- switch (n->k) {
- case AST_EMPTY: continue;
- case AST_ID: continue;
- case AST_PROC_DEF: if (!proc_body(n)) continue;
- default:
- }
-
- if (analyze_visibility(struct_scope, n))
- return -1;
- }
- */
-
- foreach_node(n, struct_body(node)) {
+ foreach_node(n, body) {
/* don't actually actualize type expansion for now, it's just
* sticking around to make it easier to check if a type
* implements a trait */
@@ -2210,11 +2227,22 @@ static int actualize_struct(struct act_state *state,
if (n->k == AST_PROC_DEF && !proc_body(n))
continue;
+ if (n->k == AST_PROC_DEF) {
+ struct ast *prev = chain_lookup(state, node->chain,
+ proc_id(n));
+ if (prev) {
+ /** @todo improve error messages */
+ semantic_error(scope->fctx, n, "redefinition");
+ semantic_info(scope->fctx, prev, "previous");
+ return -1;
+ }
+ }
+
if (analyze_visibility(struct_scope, n))
return -1;
}
- foreach_node(n, struct_body(node)) {
+ foreach_node(n, body) {
if (n->k == AST_TYPE_EXPAND)
continue;
@@ -2228,7 +2256,7 @@ static int actualize_struct(struct act_state *state,
}
/* check that all prototypes are implemented */
- foreach_node(n, struct_body(node)) {
+ foreach_node(n, body) {
if (n->k != AST_PROC_DEF)
continue;
@@ -2257,6 +2285,59 @@ static int actualize_struct(struct act_state *state,
return 0;
}
+static int actualize_struct(struct act_state *state,
+ struct scope *scope, struct ast *node)
+{
+ UNUSED(state);
+ assert(node->k == AST_STRUCT_DEF);
+ return expand_struct_body(state, scope, node,
+ struct_id(node), struct_params(node),
+ struct_body(node));
+}
+
+static int params_match(struct scope *scope, struct ast *base, struct ast *node)
+{
+ assert(base->k == AST_STRUCT_DEF);
+ assert(node->k == AST_STRUCT_CONT_DEF);
+
+ struct ast *base_params = struct_params(base);
+ struct ast *node_params = struct_cont_params(node);
+
+ if (ast_list_len(base_params) != ast_list_len(node_params)) {
+ semantic_error(scope->fctx, base_params,
+ "mismatch number of type params");
+ return -1;
+ }
+
+ /** @todo report more accurately what the issue is */
+ if (!equiv_nodes(base_params, node_params)) {
+ semantic_error(scope->fctx, base_params,
+ "mismatch type params");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int actualize_struct_cont(struct act_state *state,
+ struct scope *scope, struct ast *node)
+{
+ assert(node->k == AST_STRUCT_CONT_DEF);
+ struct ast *up = node->chain;
+ assert(up);
+
+ if (actualize(state, scope, up))
+ return -1;
+
+ if (params_match(scope, chain_base(node), node))
+ return -1;
+
+ return expand_struct_body(state, scope, node,
+ struct_cont_id(node),
+ struct_cont_params(node),
+ struct_cont_body(node));
+}
+
static int actualize_dot(struct act_state *state,
struct scope *scope, struct ast *node)
{
@@ -2295,9 +2376,8 @@ static int actualize_dot(struct act_state *state,
return -1;
}
- struct ast *exists = actualized_scope_find_symbol(state,
- def->scope,
- id);
+ struct ast *exists = chain_lookup(state, def, id);
+
if (exists) {
assert(exists->t);
set_type(node, exists->t);
@@ -2306,7 +2386,7 @@ static int actualize_dot(struct act_state *state,
char *tstr = type_str(type);
semantic_error(scope->fctx, node,
- "%s does not have have member",
+ "%s does not have member",
tstr);
free(tstr);
return -1;
@@ -2717,6 +2797,8 @@ static int actualize(struct act_state *state, struct scope *scope,
case AST_ALIAS_DEF: ret = actualize_alias(state, scope, node); break;
case AST_ENUM_DEF: ret = actualize_enum(state, scope, node); break;
case AST_STRUCT_DEF: ret = actualize_struct(state, scope, node); break;
+ case AST_STRUCT_CONT_DEF: ret = actualize_struct_cont(state, scope,
+ node); break;
case AST_VAR_DEF: ret = actualize_var(state, scope, node); break;
case AST_CALL: ret = actualize_call(state, scope, node); break;
case AST_BLOCK: ret = actualize_block(state, scope, node); break;
diff --git a/src/ast.c b/src/ast.c
index 528d30a..024cebf 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -777,3 +777,10 @@ struct type *reverse_type_list(struct type *root)
return new_root;
}
+struct ast *chain_base(struct ast *node)
+{
+ if (node->chain)
+ return chain_base(node->chain);
+
+ return node;
+}
diff --git a/src/scope.c b/src/scope.c
index f17b8ed..448c883 100644
--- a/src/scope.c
+++ b/src/scope.c
@@ -200,6 +200,64 @@ int scope_add_type(struct scope *scope, char *id, struct ast *type)
return 0;
}
+static struct visible *scope_find_visible(struct visible *v, char *id)
+{
+ if (!v)
+ return NULL;
+
+ foreach_visible(n, v) {
+ struct ast *node = n->node;
+ if (same_id(node->s, id))
+ return n;
+ }
+
+ return NULL;
+}
+
+static void insert_chain(struct scope *scope, char *id, struct ast *type)
+{
+ struct visible *v = scope_find_visible(scope->types, id);
+ assert(v);
+
+ struct ast *n = v->node;
+ assert(n);
+
+ if (ast_flags(n, AST_FLAG_PUBLIC)
+ || !ast_flags(type, AST_FLAG_PUBLIC)) {
+ type->chain = v->node;
+ v->node = type;
+ return;
+ }
+
+ /* find first public continuation in chain and insert just before it */
+ struct ast *next = n->chain;
+ while (next->k == AST_STRUCT_CONT_DEF && !ast_flags(next,
+ AST_FLAG_PUBLIC)) {
+ n = next;
+ next = n->chain;
+ }
+
+ n->chain = type;
+ type->chain = next;
+}
+
+int scope_add_chain(struct scope *scope, char *id, struct ast *type)
+{
+ struct ast *exists = file_scope_find_type(scope, id);
+ if (!exists) {
+ semantic_error(scope->fctx, type, "no previous definition");
+ return -1;
+ }
+
+ insert_chain(scope, id, type);
+
+ if (scope->parent &&
+ scope_flags(scope, SCOPE_FILE) && ast_flags(type, AST_FLAG_PUBLIC))
+ return scope_add_chain(scope->parent, id, type);
+
+ return 0;
+}
+
int scope_add_macro(struct scope *scope, struct ast *macro)
{
assert(macro->k == AST_MACRO_DEF);
@@ -262,6 +320,7 @@ int scope_add_expd_struct(struct scope *scope, struct ast *def,
struct type *types, struct ast *expd)
{
assert(def->k == AST_STRUCT_DEF);
+ assert(expd->k == AST_STRUCT_DEF);
assert(file_scope_find_expd_struct(scope, def, types) == NULL);
create_expanded(scope, def, types, expd);
@@ -272,40 +331,75 @@ int scope_add_expd_struct(struct scope *scope, struct ast *def,
return 0;
}
-static struct ast *scope_find_visible(struct visible *v, char *id)
+static struct expanded *scope_find_expanded(struct expanded *e, struct ast *def,
+ struct type *types)
{
- if (!v)
+ if (!e)
return NULL;
- foreach_visible(n, v) {
- struct ast *node = n->node;
- if (same_id(node->s, id))
- return node;
+ foreach_expanded(n, e) {
+ if (n->node != def)
+ continue;
+
+ if (type_lists_match(n->types, types))
+ return n;
}
return NULL;
}
-static struct ast *scope_find_expanded(struct expanded *e, struct ast *def,
- struct type *types)
+static void insert_expd_chain(struct scope *scope, struct ast *def,
+ struct type *types, struct ast *expd)
{
- if (!e)
- return NULL;
+ struct expanded *e = scope_find_expanded(scope->expanded, def, types);
+ assert(e);
- foreach_expanded(n, e) {
- if (n->node != def)
- continue;
+ struct ast *n = e->expd;
+ assert(n);
- if (type_lists_match(n->types, types))
- return n->expd;
+ if (ast_flags(n, AST_FLAG_PUBLIC)
+ || !ast_flags(expd, AST_FLAG_PUBLIC)) {
+ expd->chain = e->expd;
+ e->expd = expd;
+ /* types should be identical, we checked that earlier */
+ return;
}
- return NULL;
+ /* find first public continuation in chain and insert just before it */
+ struct ast *next = n->chain;
+ while (next->k == AST_STRUCT_CONT_DEF &&
+ !ast_flags(next, AST_FLAG_PUBLIC)) {
+ n = next;
+ next = n->chain;
+ }
+
+ n->chain = expd;
+ expd->chain = next;
+}
+
+int scope_add_expd_chain(struct scope *scope, struct ast *def,
+ struct type *types, struct ast *expd)
+{
+ assert(def->k == AST_STRUCT_DEF);
+ assert(expd->k == AST_STRUCT_CONT_DEF);
+ assert(file_scope_find_expd_struct(scope, def, types) != NULL);
+
+ insert_expd_chain(scope, def, types, expd);
+
+ if (scope->parent &&
+ scope_flags(scope, SCOPE_FILE) && ast_flags(def, AST_FLAG_PUBLIC))
+ return scope_add_expd_struct(scope->parent, def, types, expd);
+
+ return 0;
}
struct ast *scope_find_type(struct scope *scope, char *id)
{
- return scope_find_visible(scope->types, id);
+ struct visible *v = scope_find_visible(scope->types, id);
+ if (!v)
+ return NULL;
+
+ return v->node;
}
struct ast *file_scope_find_type(struct scope *scope, char *id)
@@ -325,7 +419,11 @@ struct ast *file_scope_find_type(struct scope *scope, char *id)
struct ast *scope_find_macro(struct scope *scope, char *id)
{
- return scope_find_visible(scope->macros, id);
+ struct visible *v = scope_find_visible(scope->macros, id);
+ if (!v)
+ return NULL;
+
+ return v->node;
}
struct ast *file_scope_find_macro(struct scope *scope, char *id)
@@ -345,10 +443,13 @@ struct ast *file_scope_find_macro(struct scope *scope, char *id)
struct ast *scope_find_proc(struct scope *scope, char *id)
{
- struct ast *n = scope_find_visible(scope->symbols, id);
- if (!n)
+ struct visible *v = scope_find_visible(scope->symbols, id);
+ if (!v)
return NULL;
+ struct ast *n = v->node;
+ assert(n);
+
if (n->k != AST_PROC_DEF)
return NULL;
@@ -369,7 +470,11 @@ struct ast *file_scope_find_proc(struct scope *scope, char *id)
struct ast *scope_find_symbol(struct scope *scope, char *id)
{
- return scope_find_visible(scope->symbols, id);
+ struct visible *v = scope_find_visible(scope->symbols, id);
+ if (!v)
+ return NULL;
+
+ return v->node;
}
struct ast *file_scope_find_symbol(struct scope *scope, char *id)
@@ -389,10 +494,13 @@ struct ast *file_scope_find_symbol(struct scope *scope, char *id)
struct ast *scope_find_var(struct scope *scope, char *id)
{
- struct ast *n = scope_find_visible(scope->symbols, id);
- if (!n)
+ struct visible *v = scope_find_visible(scope->symbols, id);
+ if (!v)
return NULL;
+ struct ast *n = v->node;
+ assert(n);
+
if (n->k != AST_VAR_DEF)
return NULL;
@@ -418,18 +526,20 @@ struct ast *scope_find_expd_struct(struct scope *scope, struct ast *def,
struct type *types)
{
assert(def->k == AST_STRUCT_DEF);
- struct ast *exists = scope_find_expanded(scope->expanded, def, types);
- if (!exists)
+ struct expanded *expd = scope_find_expanded(scope->expanded, def,
+ types);
+ if (!expd)
return NULL;
- assert(exists->k == AST_STRUCT_DEF);
+ struct ast *exists = expd->expd;
+ assert(exists->k == AST_STRUCT_DEF || exists->k == AST_STRUCT_CONT_DEF);
return exists;
}
struct ast *file_scope_find_expd_struct(struct scope *scope, struct ast *def,
struct type *types)
{
- assert(def->k == AST_STRUCT_DEF);
+ assert(def->k == AST_STRUCT_DEF || def->k == AST_STRUCT_CONT_DEF);
struct ast *found = scope_find_expd_struct(scope, def, types);
if (found)
return found;