diff options
| -rw-r--r-- | include/ek/ast.h | 5 | ||||
| -rw-r--r-- | include/ek/scope.h | 5 | ||||
| -rw-r--r-- | src/actualize.c | 148 | ||||
| -rw-r--r-- | src/ast.c | 7 | ||||
| -rw-r--r-- | src/scope.c | 164 | ||||
| -rw-r--r-- | tests/struct_cont/source.mk | 2 | ||||
| -rw-r--r-- | tests/struct_cont/struct_cont.ek | 11 |
7 files changed, 279 insertions, 63 deletions
diff --git a/include/ek/ast.h b/include/ek/ast.h index 9107e8a..f8ffd8b 100644 --- a/include/ek/ast.h +++ b/include/ek/ast.h @@ -238,6 +238,7 @@ struct ast { enum ast_flags f; struct ast *n; + struct ast *chain; struct src_loc loc; struct scope *scope; }; @@ -584,7 +585,7 @@ static inline bool is_primitive(struct type *t) #define struct_cont_id(x) return_s(x, AST_STRUCT_CONT_DEF) #define struct_cont_params(x) return_a0(x, AST_STRUCT_CONT_DEF) #define struct_cont_behav(x) return_t1(x, AST_STRUCT_CONT_DEF) -#define struct_cont_body(x) return_a2(x, AST_STRUCT_CONT_DEF) +#define struct_cont_body(x) return_a1(x, AST_STRUCT_CONT_DEF) #define gen_struct_cont(id, params, behav, body, loc) \ gen_ast(AST_STRUCT_CONT_DEF, params, body, NULL, NULL, behav, id, 0, \ loc) @@ -744,4 +745,6 @@ struct type *reverse_type_list(struct type *root); #define foreach_type(iter, nodes) \ for (struct type *iter = nodes; iter; iter = iter->n) +struct ast *chain_base(struct ast *node); + #endif /* AST_H */ diff --git a/include/ek/scope.h b/include/ek/scope.h index 3091388..e4c706a 100644 --- a/include/ek/scope.h +++ b/include/ek/scope.h @@ -178,6 +178,8 @@ int scope_add_var(struct scope *scope, struct ast *var); */ int scope_add_type(struct scope *scope, char *id, struct ast *type); +int scope_add_chain(struct scope *scope, char *id, struct ast *node); + /** * Add procedure to scope. * Propagates public procedures up the file scope chain as references. @@ -211,6 +213,9 @@ int scope_add_trait(struct scope *scope, struct ast *trait); int scope_add_expd_struct(struct scope *scope, struct ast *def, struct type *types, struct ast *expanded); +int scope_add_expd_chain(struct scope *scope, struct ast *def, + struct type *types, struct ast *expanded); + /** * Find a variable with ID in \p scope. * @note Only looks in the current scope, so doesn't see anything outside 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; @@ -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; diff --git a/tests/struct_cont/source.mk b/tests/struct_cont/source.mk index b986282..5e607c6 100644 --- a/tests/struct_cont/source.mk +++ b/tests/struct_cont/source.mk @@ -1 +1 @@ -SIMPLE_XFAIL += struct_cont,'unknown top element' +SIMPLE += struct_cont diff --git a/tests/struct_cont/struct_cont.ek b/tests/struct_cont/struct_cont.ek index f4799aa..6e01763 100644 --- a/tests/struct_cont/struct_cont.ek +++ b/tests/struct_cont/struct_cont.ek @@ -1,3 +1,12 @@ -typedef i27 {} +typedef i27 { + /* empty */ +} + continue i27 { + do_something() {} +} + +main() +{ + 29.do_something(); } |
