aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/actualize.c137
-rw-r--r--src/ast.c27
-rw-r--r--src/debug.c2
-rw-r--r--src/lower.c73
-rw-r--r--src/parser.y44
-rw-r--r--src/scope.c17
6 files changed, 221 insertions, 79 deletions
diff --git a/src/actualize.c b/src/actualize.c
index 591333a..3837d00 100644
--- a/src/actualize.c
+++ b/src/actualize.c
@@ -35,6 +35,7 @@ struct act_state {
struct ast *cur_proc;
struct act_stack *defer_stack;
+ struct act_stack *loop_stack;
struct act_stack *goto_stack;
struct act_stack *label_stack;
};
@@ -436,6 +437,14 @@ static void replace_ast(struct ast *n, struct ast *t)
t->scope = scope;
}
+static void replace_slice_ast(struct ast *n, struct ast *t)
+{
+ struct ast *next = n->n;
+ replace_ast(n, t);
+ n->n = next;
+ /** @todo scope as well? */
+}
+
static struct ast *analyze_type_expand(struct scope *scope,
struct ast *n)
{
@@ -549,7 +558,7 @@ int types_match(struct type *a, struct type *b)
if (a->k == TYPE_CALLABLE)
return types_match(callable_rtype(a), callable_rtype(b))
- && types_match(callable_ptypes(a), callable_ptypes(b));
+ && types_match(callable_ptypes(a), callable_ptypes(b));
if (is_primitive(a) && is_primitive(b))
return 1;
@@ -595,7 +604,7 @@ static int _replace_id(struct ast *node, void *data)
clone->n = node->n;
clone->scope = node->scope;
- replace_ast(node, clone);
+ replace_slice_ast(node, clone);
/* a succesful replacement needs no futher replacements, I think */
return 0;
@@ -638,7 +647,8 @@ static int implements(struct type *trait, struct type *type)
return 0;
}
-static int should_implement_list(struct scope *scope, struct ast *params, struct src_loc loc, struct type *types)
+static int should_implement_list(struct scope *scope, struct ast *params,
+ struct src_loc loc, struct type *types)
{
while (params && types) {
assert(params->k == AST_VAR_DEF);
@@ -647,9 +657,9 @@ static int should_implement_list(struct scope *scope, struct ast *params, struct
char *type1 = type_str(types);
char *type2 = type_str(t);
type_error(scope->fctx, types,
- "%s does not implement %s",
- type1,
- type2);
+ "%s does not implement %s",
+ type1,
+ type2);
free(type1);
free(type2);
return 0;
@@ -664,13 +674,13 @@ static int should_implement_list(struct scope *scope, struct ast *params, struct
if (params != NULL) {
loc_error(scope->fctx, loc,
- "too few type params");
+ "too few type params");
return 0;
}
if (types != NULL) {
loc_error(scope->fctx, loc,
- "too many type params");
+ "too many type params");
return 0;
}
@@ -704,7 +714,7 @@ static int expand_type(struct ast *expd, struct ast *params, struct type *types)
struct scope *p = expd->scope->parent;
reset(expd);
-
+
foreach_node(n, params) {
struct ast *p = clone_ast(n);
var_type(p) = clone_type(types);
@@ -726,7 +736,8 @@ static int expand_type(struct ast *expd, struct ast *params, struct type *types)
return ret;
}
-static struct ast *maybe_expand_struct(struct scope *scope, struct ast *def, struct src_loc loc, struct type *args)
+static struct ast *maybe_expand_struct(struct scope *scope, struct ast *def,
+ struct src_loc loc, struct type *args)
{
assert(def->k == AST_STRUCT_DEF);
if (struct_params(def) == NULL) {
@@ -734,8 +745,8 @@ static struct ast *maybe_expand_struct(struct scope *scope, struct ast *def, str
return def;
loc_error(scope->fctx, loc,
- "passing types to non-generic struct %s",
- struct_id(def));
+ "passing types to non-generic struct %s",
+ struct_id(def));
return NULL;
}
@@ -754,14 +765,15 @@ static struct ast *maybe_expand_struct(struct scope *scope, struct ast *def, str
return expd;
}
-static struct ast *maybe_expand_trait(struct scope *scope, struct ast *def, struct src_loc loc, struct type *args)
+static struct ast *maybe_expand_trait(struct scope *scope, struct ast *def,
+ struct src_loc loc, struct type *args)
{
assert(def->k == AST_TRAIT_DEF);
if (trait_params(def) == NULL) {
if (args != NULL) {
loc_error(scope->fctx, loc,
- "passing types to non-generic trait %s",
- trait_id(def));
+ "passing types to non-generic trait %s",
+ trait_id(def));
return NULL;
}
@@ -772,7 +784,8 @@ static struct ast *maybe_expand_trait(struct scope *scope, struct ast *def, stru
return NULL;
}
-static struct ast *maybe_expand_type(struct scope *scope, struct ast *def, struct src_loc loc, struct type *args)
+static struct ast *maybe_expand_type(struct scope *scope, struct ast *def,
+ struct src_loc loc, struct type *args)
{
assert(def->k == AST_STRUCT_DEF || def->k == AST_TRAIT_DEF);
if (def->k == AST_STRUCT_DEF)
@@ -842,8 +855,7 @@ static int actualize_macro_expand(struct act_state *state,
arg = arg->n = next_arg;
}
- free(macro_expand_id(macro_expand));
- replace_ast(macro_expand, body);
+ replace_slice_ast(macro_expand, body);
/* actualize the new content */
if (actualize(state, scope, macro_expand)) {
@@ -863,18 +875,19 @@ static int simplify_refderef(struct act_state *state, struct scope *scope,
struct ast *e = unop_expr(n);
if (n->k == AST_REF && e->k == AST_DEREF) {
- replace_ast(n, unop_expr(e));
+ replace_slice_ast(n, unop_expr(e));
return simplify_refderef(state, scope, n);
}
if (n->k == AST_DEREF && e->k == AST_REF) {
- replace_ast(n, unop_expr(e));
+ replace_slice_ast(n, unop_expr(e));
return simplify_refderef(state, scope, n);
}
return 0;
}
+/* not really ufcs at the moment */
static int maybe_ufcs(struct act_state *state, struct scope *scope,
struct ast *call)
{
@@ -883,6 +896,11 @@ static int maybe_ufcs(struct act_state *state, struct scope *scope,
if (dot->k != AST_DOT)
return 0;
+ struct type *ptypes = callable_ptypes(dot->t);
+ if (!ptypes)
+ /* no ufcs */
+ return 0;
+
struct ast *expr = dot_expr(dot);
char *id = strdup(dot_id(dot));
call_expr(call) = gen_fetch(id, clone_type(expr->t), dot->loc);
@@ -890,7 +908,7 @@ static int maybe_ufcs(struct act_state *state, struct scope *scope,
(call_expr(call))->scope = scope;
struct ast *ref = NULL;
- struct type *ptypes = callable_ptypes(dot->t);
+
if (ptypes->k == TYPE_PTR) {
/* is ufcs expects reference to member, try to take address */
ref = gen_unop(AST_REF, expr, dot->loc);
@@ -1057,11 +1075,12 @@ static int actualize_proc(struct act_state *state,
return -1;
}
- /* add 'implicit' return */
+ /* add 'implicit' return as the last defer statement to be executed in a block*/
struct ast *body = proc_body(proc);
struct ast *r = gen_return(NULL, NULL, NULL_LOC());
r->scope = body->scope;
- ast_append(&block_body(body), r);
+ r->n = block_defers(body);
+ block_defers(body) = r;
}
else if (ast_block_last(proc_body(proc))->k != AST_RETURN) {
/* TODO: something more sophisticated than this */
@@ -1151,6 +1170,10 @@ static int actualize_block(struct act_state *state,
/* TODO: currently defers are sort of duplicated after a return, unsure
* if they should be handled here or somewhere else */
if (state->defer_stack) {
+ /* no new defers, no need to clone anything */
+ if (state->defer_stack == defers)
+ return 0;
+
block_defers(node) = clone_defers(state, defers);
if (!block_defers(node)) {
internal_error("failed cloning defers");
@@ -1369,7 +1392,7 @@ static int actualize_tstruct(struct act_state *state, struct scope *scope,
}
static int actualize_ttrait(struct act_state *state, struct scope *scope,
- struct type *t)
+ struct type *t)
{
UNUSED(state);
/* not much to do */
@@ -1387,8 +1410,8 @@ static int actualize_ttrait(struct act_state *state, struct scope *scope,
}
static int actualize_tconstruct(struct act_state *state,
- struct scope *scope,
- struct type *t)
+ struct scope *scope,
+ struct type *t)
{
assert(t->k == TYPE_CONSTRUCT);
struct ast *d = file_scope_find_type(scope, construct_id(t));
@@ -1604,8 +1627,6 @@ static int actualize_defer(struct act_state *state,
struct scope *scope, struct ast *node)
{
struct ast *expr = defer_expr(node);
- /* TODO: should the actualization only happen when the defers are
- * called? */
if (actualize(state, scope, expr))
return -1;
@@ -1655,6 +1676,8 @@ static int actualize_return(struct act_state *state, struct scope *scope,
* nonetheless. */
static void actualize_goto_defer(struct ast *got, struct ast *label)
{
+ goto_label_ref(got) = label;
+
struct ast *goto_defers = goto_defers(got);
struct ast *label_defers = label_defers(label);
/* since we're dealing with singly linked lists, keep a reference to one
@@ -1884,7 +1907,7 @@ static int _replace_type_id(struct type *type, void *data)
return 0;
}
-static int _replace_ast_type_id(struct ast *node, void *data)
+static int _replace_slice_ast_type_id(struct ast *node, void *data)
{
if (!node)
return 0;
@@ -1902,7 +1925,7 @@ static int replace_type_id(struct ast *nodes, char *id,
struct type *replacement)
{
struct replace_data pair = {id, replacement};
- return ast_visit_list(_replace_ast_type_id, NULL, nodes, &pair);
+ return ast_visit_list(_replace_slice_ast_type_id, NULL, nodes, &pair);
}
static int _clear_scope(struct ast *node, void *data)
@@ -2054,7 +2077,8 @@ static int actualize_struct(struct act_state *state,
type_append(&tstruct_params(node->t), type);
- struct ast *alias = gen_alias(strdup(id), clone_type(type), n->loc);
+ struct ast *alias = gen_alias(strdup(id), clone_type(type),
+ n->loc);
if (analyze_visibility(struct_scope, alias))
return -1;
@@ -2346,7 +2370,7 @@ static int actualize_enum_fetch(struct act_state *state, struct scope *scope,
return -1;
}
- replace_ast(fetch, val_val(member));
+ replace_slice_ast(fetch, val_val(member));
set_type(fetch, def->t);
return 0;
}
@@ -2465,19 +2489,60 @@ static int actualize_for(struct act_state *state, struct scope *scope,
struct ast *node)
{
assert(node->k == AST_FOR);
+ struct act_stack *prev = state->loop_stack;
+ enum act_flags flags = state->flags;
+ node->t = void_type();
+
if (actualize_list(state, scope, for_pre(node)))
- return -1;
+ goto err;
if (actualize_list(state, scope, for_post(node)))
- return -1;
+ goto err;
if (actualize_list(state, scope, for_cond(node)))
- return -1;
+ goto err;
+ state->flags |= ACT_IN_LOOP;
if (actualize_list(state, scope, for_body(node)))
+ goto err;
+
+ state->loop_stack = prev;
+ state->flags = flags;
+ return 0;
+
+err:
+ state->loop_stack = prev;
+ state->flags = flags;
+ return -1;
+}
+
+static int actualize_continue(struct act_state *state, struct scope *scope,
+ struct ast *node)
+{
+ UNUSED(scope);
+ node->t = void_type();
+ if (!state->flags & ACT_IN_LOOP) {
+ semantic_error(scope->fctx, node,
+ "continue outside of loop");
return -1;
+ }
+
+ continue_defers(node) = clone_defers(state, state->loop_stack);
+ return 0;
+}
+static int actualize_break(struct act_state *state, struct scope *scope,
+ struct ast *node)
+{
+ UNUSED(scope);
node->t = void_type();
+ if (!state->flags & ACT_IN_LOOP) {
+ semantic_error(scope->fctx, node,
+ "break outside of loop");
+ return -1;
+ }
+
+ break_defers(node) = clone_defers(state, state->loop_stack);
return 0;
}
@@ -2579,6 +2644,8 @@ static int actualize(struct act_state *state, struct scope *scope,
case AST_FETCH: ret = actualize_fetch(state, scope, node); break;
case AST_IF: ret = actualize_if(state, scope, node); break;
case AST_FOR: ret = actualize_for(state, scope, node); break;
+ case AST_CONTINUE: ret = actualize_continue(state, scope, node); break;
+ case AST_BREAK: ret = actualize_break(state, scope, node); break;
case AST_MACRO_EXPAND: ret = actualize_macro_expand(state, scope, node);
break;
case AST_MACRO_DEF: ret = actualize_macro_def(state, scope, node);
diff --git a/src/ast.c b/src/ast.c
index 890196b..c36d7a7 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -753,3 +753,30 @@ size_t type_offsetof(struct type *t, char *m)
return offset;
}
+
+struct ast *reverse_ast_list(struct ast *root)
+{
+ struct ast *new_root = NULL;
+ while (root) {
+ struct ast *next = root->n;
+ root->n = new_root;
+ new_root = root;
+ root = next;
+ }
+
+ return new_root;
+}
+
+struct type *reverse_type_list(struct type *root)
+{
+ struct type *new_root = NULL;
+ while (root) {
+ struct type *next = root->n;
+ root->n = new_root;
+ new_root = root;
+ root = next;
+ }
+
+ return new_root;
+}
+
diff --git a/src/debug.c b/src/debug.c
index 0d11473..47e53f2 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -147,7 +147,7 @@ void type_error(struct file_ctx fctx, struct type *node,
}
void loc_error(struct file_ctx fctx, struct src_loc loc,
- const char *fmt, ...)
+ const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
diff --git a/src/lower.c b/src/lower.c
index 630cb1d..18d0576 100644
--- a/src/lower.c
+++ b/src/lower.c
@@ -226,6 +226,7 @@ static ssize_t visit_struct(struct lower_state *s, struct ast *def, size_t base,
static int lower_expr(struct lower_state *s, struct ast *e,
struct retval *retval);
+
static int lower_statement(struct lower_state *s, struct ast *n);
static void output_ast_id(struct ast *id)
@@ -502,6 +503,7 @@ static int lower_assign(struct lower_state *s, struct ast *a,
}
printf("i27 %s = %s;\n", loc.s, retval->s);
+ retval_destroy(&loc);
return 0;
}
@@ -546,16 +548,29 @@ static int lower_struct_return(struct lower_state *s, struct ast *n, size_t o,
return 0;
}
+static int lower_deferred(struct lower_state *s, struct ast *d)
+{
+ struct ast *t = reverse_ast_list(d);
+ foreach_node(n, t) {
+ if (lower_statement(s, n))
+ return -1;
+ }
+
+ return 0;
+}
+
static int lower_return(struct lower_state *s, struct ast *r,
struct retval *retval)
{
assert(r->k == AST_RETURN);
+ if (lower_deferred(s, return_defers(r)))
+ return -1;
+
if (!return_expr(r)) {
printf("=> ();\n");
return 0;
}
- /** @todo defers, should they be handled here or in ast? */
if (lower_expr(s, return_expr(r), retval))
return -1;
@@ -1131,6 +1146,9 @@ static int lower_block(struct lower_state *s, struct ast *block)
return -1;
}
+ if (lower_deferred(s, block_defers(block)))
+ return -1;
+
assert(deallocs_top <= vec_len(&s->dealloc));
s->deallocs = deallocs_parent;
@@ -1150,6 +1168,54 @@ static int lower_block(struct lower_state *s, struct ast *block)
return 0;
}
+static int lower_continue(struct lower_state *s, struct ast *n)
+{
+ assert(n->k == AST_CONTINUE);
+ if (lower_deferred(s, continue_defers(n)))
+ return -1;
+
+ char *bottom = label_peek(s->bottom);
+ printf("-> %s\n", bottom);
+ return 0;
+}
+
+static int lower_break(struct lower_state *s, struct ast *n)
+{
+ assert(n->k == AST_BREAK);
+ if (lower_deferred(s, break_defers(n)))
+ return -1;
+
+ char *out = label_peek(s->out);
+ printf("-> %s;\n", out);
+ return 0;
+}
+
+static int lower_goto(struct lower_state *s, struct ast *n)
+{
+ assert(n->k == AST_GOTO);
+ if (lower_deferred(s, goto_defers(n)))
+ return -1;
+
+ struct ast *label = goto_label_ref(n);
+ assert(label);
+
+ char *out = mangle_scope(label, label->scope);
+ printf("-> %s;\n", out);
+ free(out);
+ return 0;
+}
+
+static int lower_label(struct lower_state *s, struct ast *n)
+{
+ UNUSED(s);
+
+ assert(n->k == AST_LABEL);
+ char *out = mangle_scope(n, n->scope);
+ printf("-> %s\n", out);
+ free(out);
+ return 0;
+}
+
static int lower_statement(struct lower_state *s, struct ast *n)
{
struct retval retval = retval_create();
@@ -1160,6 +1226,11 @@ static int lower_statement(struct lower_state *s, struct ast *n)
case AST_IF: ret = lower_if(s, n, &retval); break;
case AST_FOR: ret = lower_for(s, n, &retval); break;
case AST_BLOCK: ret = lower_block(s, n); break;
+ case AST_CONTINUE: ret = lower_continue(s, n); break;
+ case AST_BREAK: ret = lower_break(s, n); break;
+ case AST_GOTO: ret = lower_goto(s, n); break;
+ case AST_LABEL: ret = lower_label(s, n); break;
+ case AST_DEFER: break;
case AST_EMPTY: break;
default: ret = lower_expr(s, n, &retval); break;
}
diff --git a/src/parser.y b/src/parser.y
index a51eb9a..62afcac 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -134,7 +134,7 @@
%nterm <node> var_init proc
%nterm <node> alias trait enum_val enums enum top unit id
%nterm <node> embed param_decl members
-%nterm <node> top_if const_if const_for defer goto assign
+%nterm <node> top_if const_if const_for goto assign
%nterm <node> construct construct_args construct_arg
%nterm <node> statelet
@@ -157,6 +157,7 @@
%nterm <type> opt_types opt_sign_decls sign_decls sign_decl sign_var_decl
%nterm <node> opt_construct_args
%nterm <node> opt_behaviours behaviours behaviour
+%nterm <node> opt_deferred_statement
/* reverse lists */
%nterm <type> rev_sign_decls;
@@ -241,9 +242,6 @@ static char match_escape(char c);
*/
static char *strip(const char *s);
-static struct ast *reverse_ast_list(struct ast *root);
-static struct type *reverse_type_list(struct type *root);
-
%}
%start input;
@@ -344,9 +342,6 @@ opt_decls
: decls
| {$$ = NULL;}
-defer
- : "defer" body { $$ = gen_defer($2, src_loc(@$)); }
-
const_binop
: const_expr "+" const_expr {
$$ = gen_binop(AST_ADD, $1, $3, src_loc(@$));
@@ -480,16 +475,19 @@ statement
| struct
| struct_cont
| for
- | defer
| if
| const
| enum
| macro
| ID ":" { $$ = gen_label($[ID], NULL, src_loc(@$)); }
+opt_deferred_statement
+ : statement
+ | "defer" statement { $$ = gen_defer($2, src_loc(@$)); }
+
rev_statements
- : rev_statements statement { $$ = $2; $2->n = $1; }
- | statement
+ : rev_statements opt_deferred_statement { $$ = $2; $2->n = $1; }
+ | opt_deferred_statement
statements
: rev_statements { $$ = reverse_ast_list($1); }
@@ -1002,32 +1000,6 @@ static char *strip(const char *str)
}
-static struct ast *reverse_ast_list(struct ast *root)
-{
- struct ast *new_root = NULL;
- while (root) {
- struct ast *next = root->n;
- root->n = new_root;
- new_root = root;
- root = next;
- }
-
- return new_root;
-}
-
-static struct type *reverse_type_list(struct type *root)
-{
- struct type *new_root = NULL;
- while (root) {
- struct type *next = root->n;
- root->n = new_root;
- new_root = root;
- root = next;
- }
-
- return new_root;
-}
-
struct parser *create_parser()
{
return calloc(1, sizeof(struct parser));
diff --git a/src/scope.c b/src/scope.c
index 5cd7075..f17b8ed 100644
--- a/src/scope.c
+++ b/src/scope.c
@@ -113,7 +113,8 @@ struct visible *create_type(struct scope *scope, char *id, struct ast *type)
return n;
}
-struct expanded *create_expanded(struct scope *scope, struct ast *def, struct type *types, struct ast *expd)
+struct expanded *create_expanded(struct scope *scope, struct ast *def,
+ struct type *types, struct ast *expd)
{
struct expanded *n = calloc(1, sizeof(struct expanded));
if (!n)
@@ -257,14 +258,15 @@ int scope_add_trait(struct scope *scope, struct ast *trait)
return 0;
}
-int scope_add_expd_struct(struct scope *scope, struct ast *def, struct type *types, struct ast *expd)
+int scope_add_expd_struct(struct scope *scope, struct ast *def,
+ struct type *types, struct ast *expd)
{
assert(def->k == AST_STRUCT_DEF);
assert(file_scope_find_expd_struct(scope, def, types) == NULL);
create_expanded(scope, def, types, expd);
if (scope->parent &&
- scope_flags(scope, SCOPE_FILE) && ast_flags(def, AST_FLAG_PUBLIC))
+ scope_flags(scope, SCOPE_FILE) && ast_flags(def, AST_FLAG_PUBLIC))
return scope_add_expd_struct(scope->parent, def, types, expd);
return 0;
@@ -284,7 +286,8 @@ static struct ast *scope_find_visible(struct visible *v, char *id)
return NULL;
}
-static struct ast *scope_find_expanded(struct expanded *e, struct ast *def, struct type *types)
+static struct ast *scope_find_expanded(struct expanded *e, struct ast *def,
+ struct type *types)
{
if (!e)
return NULL;
@@ -411,7 +414,8 @@ struct ast *file_scope_find_var(struct scope *scope, char *id)
return NULL;
}
-struct ast *scope_find_expd_struct(struct scope *scope, struct ast *def, struct type *types)
+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);
@@ -422,7 +426,8 @@ struct ast *scope_find_expd_struct(struct scope *scope, struct ast *def, struct
return exists;
}
-struct ast *file_scope_find_expd_struct(struct scope *scope, struct ast *def, struct type *types)
+struct ast *file_scope_find_expd_struct(struct scope *scope, struct ast *def,
+ struct type *types)
{
assert(def->k == AST_STRUCT_DEF);
struct ast *found = scope_find_expd_struct(scope, def, types);