From: Mart Lubbers Date: Tue, 2 Mar 2021 14:23:36 +0000 (+0100) Subject: scoping X-Git-Url: https://git.martlubbers.net/?a=commitdiff_plain;h=1b093afed22457c344f0bf0183dcb109989a96f1;p=ccc.git scoping --- diff --git a/ast.c b/ast.c index 3f1c97d..e4c45a3 100644 --- a/ast.c +++ b/ast.c @@ -22,7 +22,7 @@ struct ast *ast(struct list *decls, YYLTYPE l) { struct ast *res = safe_malloc(sizeof(struct ast)); res->loc = l; - res->decls = (struct decl **)list_to_array(decls, &res->ndecls, true); + res->decls = (struct decl **)list_to_array(decls, &res->ndecls, true, 0); return res; } @@ -41,10 +41,11 @@ struct fundecl *fundecl(char *ident, struct list *args, struct list *atypes, struct fundecl *res = safe_malloc(sizeof(struct fundecl)); res->loc = l; res->ident = ident; - res->args = (char **)list_to_array(args, &res->nargs, true); - res->atypes = (struct type **)list_to_array(atypes, &res->natypes, true); + res->args = (char **)list_to_array(args, &res->nargs, true, 0); + res->atypes = (struct type **)list_to_array(atypes, &res->natypes, true, 0); res->rtype = rtype; - res->body = (struct stmt **)list_to_array(body, &res->nbody, true); + //Reserve room for an optional extra return inserted by the compiler + res->body = (struct stmt **)list_to_array(body, &res->nbody, true, 1); return res; } @@ -75,7 +76,7 @@ struct stmt *stmt_assign(char *ident, struct list *fields, struct expr *expr, YY res->type = sassign; res->data.sassign.ident = ident; res->data.sassign.fields = (char **) - list_to_array(fields, &res->data.sassign.nfields, true); + list_to_array(fields, &res->data.sassign.nfields, true, 0); res->data.sassign.expr = expr; return res; } @@ -87,9 +88,9 @@ struct stmt *stmt_if(struct expr *pred, struct list *then, struct list *els, YYL res->type = sif; res->data.sif.pred = pred; res->data.sif.then = (struct stmt **) - list_to_array(then, &res->data.sif.nthen, true); + list_to_array(then, &res->data.sif.nthen, true, 0); res->data.sif.els = (struct stmt **) - list_to_array(els, &res->data.sif.nels, true); + list_to_array(els, &res->data.sif.nels, true, 0); return res; } @@ -127,7 +128,7 @@ struct stmt *stmt_while(struct expr *pred, struct list *body, YYLTYPE l) res->type = swhile; res->data.swhile.pred = pred; res->data.swhile.body = (struct stmt **) - list_to_array(body, &res->data.swhile.nbody, true); + list_to_array(body, &res->data.swhile.nbody, true, 0); return res; } @@ -187,7 +188,7 @@ struct expr *expr_funcall_real(char *ident, struct list *args, YYLTYPE l) res->type = efuncall; res->data.efuncall.ident = ident; res->data.efuncall.args = (struct expr **) - list_to_array(args, &res->data.efuncall.nargs, true); + list_to_array(args, &res->data.efuncall.nargs, true, 0); return res; } diff --git a/list.c b/list.c index 62af95e..a18850b 100644 --- a/list.c +++ b/list.c @@ -34,11 +34,11 @@ void list_free(struct list *head, void (*freefun)(void *)) } } -void **list_to_array(struct list *list, int *num, bool reverse) +void **list_to_array(struct list *list, int *num, bool reverse, int extra) { int i = list_length(list); *num = i; - void **ptr = safe_malloc(i*sizeof(void *)); + void **ptr = safe_malloc((i+extra)*sizeof(void *)); struct list *r = list; while(i > 0) { diff --git a/list.h b/list.h index 1cc3fb2..979e101 100644 --- a/list.h +++ b/list.h @@ -13,7 +13,7 @@ struct list { struct list *list_append(void *el, struct list *head); struct list *list_cons(void *el, struct list *tail); void list_free(struct list *head, void (*freefun)(void *)); -void **list_to_array(struct list *list, int *num, bool reverse); +void **list_to_array(struct list *list, int *num, bool reverse, int extra); int list_length(struct list *head); #endif diff --git a/sem.c b/sem.c index f856b97..6fe9385 100644 --- a/sem.c +++ b/sem.c @@ -91,21 +91,20 @@ void type_comp(struct gamma *gamma, int ndecls, struct fundecl **decl) //unify against given type specification if (decl[i]->rtype != NULL) { struct type *dt = decl[i]->rtype; - for (int j = decl[i]->natypes-1; j>=0; j--) + for (int j = decl[i]->natypes-1; j>=0; j--) { dt = type_arrow(decl[i]->atypes[j], dt); - unify(decl[i]->loc, dt, t); - //Free the old types if there were any - for (int j = 0; jnatypes; j++) - type_free(decl[i]->atypes[j]); - free(decl[i]->atypes); - type_free(decl[i]->rtype); + } + struct subst *s1 = unify(decl[i]->loc, dt, t); + subst_apply_t(s1, fs[i]); + subst_free(s1); + type_free(dt); } gamma_insert(gamma, decl[i]->ident, scheme_generalise(gamma, t)); - //Put the type in the ast - decl[i]->atypes = safe_malloc(decl[i]->nargs*sizeof(struct type *)); + decl[i]->atypes = safe_realloc(decl[i]->atypes, + decl[i]->nargs*sizeof(struct type *)); decl[i]->natypes = decl[i]->nargs; for (int j = 0; jnargs; j++, t = t->data.tarrow.r) decl[i]->atypes[j] = type_dup(t->data.tarrow.l); @@ -182,7 +181,8 @@ bool check_return_stmt(struct stmt *stmt) void check_return_comp(int ndecl, struct fundecl **decls) { for (int i = 0; irtype->type == tbasic && decls[i]->rtype->data.tbasic == btvoid) + if (decls[i]->rtype->type == tbasic && + decls[i]->rtype->data.tbasic == btvoid) continue; if (!check_return_body(decls[i]->nbody, decls[i]->body)) type_error(decls[i]->loc, true, @@ -190,6 +190,18 @@ void check_return_comp(int ndecl, struct fundecl **decls) } } +void add_return_if_none(int ndecl, struct fundecl **decl) +{ + for (int i = 0; irtype == NULL && !check_return_body( + decl[i]->nbody, decl[i]->body)) { + //Room for this was reserved in ast.c + decl[i]->body[decl[i]->nbody++] = + stmt_return(NULL, decl[i]->loc); + } + } +} + struct ast *sem(struct ast *ast) { //Break up into strongly connected components @@ -197,6 +209,9 @@ struct ast *sem(struct ast *ast) struct gamma *gamma = gamma_init(); gamma_preamble(gamma); + fprintf(stderr, "start with gamma: "); + gamma_print(gamma, stderr); + fprintf(stderr, "\n"); //Check all vardecls for (int i = 0; indecls; i++) { @@ -208,17 +223,17 @@ struct ast *sem(struct ast *ast) //Infer if necessary type_vardecl(gamma, decl->data.dvar); break; - case dfundecl: - //Infer function as singleton component - type_comp(gamma, 1, &decl->data.dfun); -// check_return_comp(1, &decl->data.dfun); - break; case dcomp: //Infer function as singleton component + add_return_if_none(decl->data.dcomp.ndecls, + decl->data.dcomp.decls); type_comp(gamma, decl->data.dcomp.ndecls, decl->data.dcomp.decls); -// check_return_comp(decl->data.dcomp.ndecls, -// decl->data.dcomp.decls); + check_return_comp(decl->data.dcomp.ndecls, + decl->data.dcomp.decls); + break; + case dfundecl: + die("fundecls should be gone by now\n"); break; } } diff --git a/sem/hm.c b/sem/hm.c index 6e4ca9d..d81902a 100644 --- a/sem/hm.c +++ b/sem/hm.c @@ -196,6 +196,19 @@ struct subst *infer_expr(struct gamma *gamma, struct expr *expr, struct type *ty return NULL; } +struct subst *infer_body(struct gamma *gamma, int nstmt, struct stmt **stmts, struct type *type) +{ + gamma_increment_scope(gamma); + struct subst *s0 = subst_id(), *s1; + for (int i = 0; idata.sif.pred, &tybool); - subst_apply_g(s0, gamma); + //subst_apply_g(s0, gamma); - for (int i = 0; idata.sif.nthen; i++) { - s1 = infer_stmt(gamma, stmt->data.sif.then[i], type); - s0 = subst_union(s1, s0); - subst_apply_g(s0, gamma); - } + s0 = subst_union(s0, infer_body(gamma, + stmt->data.sif.nthen, stmt->data.sif.then, type)); - for (int i = 0; idata.sif.nels; i++) { - s1 = infer_stmt(gamma, stmt->data.sif.els[i], type); - s0 = subst_union(s1, s0); - subst_apply_g(s0, gamma); - } + s0 = subst_union(s0, infer_body(gamma, + stmt->data.sif.nels, stmt->data.sif.els, type)); return s0; case sreturn: return stmt->data.sreturn == NULL @@ -238,17 +245,16 @@ struct subst *infer_stmt(struct gamma *gamma, struct stmt *stmt, struct type *ty s0 = subst_union(s1, s0); //TODO fielsd //TODO - gamma_insert(gamma, stmt->data.svardecl->ident, scheme_create(subst_apply_t(s0, f1))); + gamma_insert(gamma, stmt->data.svardecl->ident, + scheme_create(subst_apply_t(s0, f1))); + type_free(f1); return s0; case swhile: s0 = infer_expr(gamma, stmt->data.swhile.pred, &tybool); - subst_apply_g(s0, gamma); + //subst_apply_g(s0, gamma); - for (int i = 0; idata.swhile.nbody; i++) { - s1 = infer_stmt(gamma, stmt->data.swhile.body[i], type); - s0 = subst_union(s1, s0); - subst_apply_g(s0, gamma); - } + s0 = subst_union(s0, infer_body(gamma, + stmt->data.swhile.nbody, stmt->data.swhile.body, type)); return s0; } @@ -258,6 +264,7 @@ struct subst *infer_stmt(struct gamma *gamma, struct stmt *stmt, struct type *ty struct subst *infer_fundecl(struct gamma *gamma, struct fundecl *fundecl, struct type *ftype) { // Put arguments in gamma + gamma_increment_scope(gamma); struct type *at = ftype; for (int i = 0; inargs; i++) { if (at->type != tarrow) @@ -277,10 +284,6 @@ struct subst *infer_fundecl(struct gamma *gamma, struct fundecl *fundecl, struct } // Remove arguments from gamma - at = ftype; - for (int i = 0; inargs; i++) { - gamma_remove(gamma, fundecl->args[i]); - at = at->data.tarrow.r; - } + gamma_decrement_scope(gamma); return s; } diff --git a/sem/hm.h b/sem/hm.h index 0a92475..932e508 100644 --- a/sem/hm.h +++ b/sem/hm.h @@ -7,6 +7,8 @@ #include "hm/scheme.h" struct ast *infer(struct ast *ast); + +bool occurs_check(char *var, struct type *r); struct subst *unify(YYLTYPE loc, struct type *l, struct type *r); struct subst *infer_expr(struct gamma *gamma, struct expr *expr, struct type *type); struct subst *infer_stmt(struct gamma *gamma, struct stmt *stmt, struct type *type); diff --git a/sem/hm/gamma.c b/sem/hm/gamma.c index c5ad9eb..93de4ec 100644 --- a/sem/hm/gamma.c +++ b/sem/hm/gamma.c @@ -3,63 +3,78 @@ #include "../hm.h" -#define IN_CAP 25 +#define IN_CAP 50 struct gamma *gamma_init() { struct gamma *gamma = safe_malloc(sizeof(struct gamma)); gamma->capacity = IN_CAP; gamma->fresh = 0; - gamma->nschemes = 0; - gamma->vars = safe_malloc(IN_CAP*sizeof(char *)); - gamma->schemes = safe_malloc(IN_CAP*sizeof(struct scheme *)); + gamma->nentries = 0; + gamma->scope = 0; + gamma->entries = safe_malloc(IN_CAP*sizeof(struct gamma_entry)); return gamma; } void gamma_insert(struct gamma *gamma, char *ident, struct scheme *scheme) { - for (int i = 0; inschemes; i++) { - if(strcmp(gamma->vars[i], ident) == 0) { - scheme_free(gamma->schemes[i]); - gamma->schemes[i] = scheme; + for (int i = 0; inentries; i++) { + if(strcmp(gamma->entries[i].var, ident) == 0 + && gamma->entries[i].scope == gamma->scope) { + scheme_free(gamma->entries[i].scheme); + gamma->entries[i].scheme = scheme; return; } } - gamma->nschemes++; - if (gamma->nschemes >= gamma->capacity) { + gamma->nentries++; + if (gamma->nentries >= gamma->capacity) { gamma->capacity += gamma->capacity; - gamma->vars = safe_realloc(gamma->vars, - gamma->capacity*sizeof(char *)); - gamma->schemes = safe_realloc(gamma->schemes, - gamma->capacity*sizeof(struct scheme *)); + gamma->entries = safe_realloc(gamma->entries, + gamma->capacity*sizeof(struct gamma_entry)); } - gamma->vars[gamma->nschemes-1] = safe_strdup(ident); - gamma->schemes[gamma->nschemes-1] = scheme; + gamma->entries[gamma->nentries-1].scope = gamma->scope; + gamma->entries[gamma->nentries-1].var = safe_strdup(ident); + gamma->entries[gamma->nentries-1].scheme = scheme; } -void gamma_remove(struct gamma *gamma, char *ident) +void gamma_increment_scope(struct gamma *gamma) { + gamma->scope++; +} + +void gamma_decrement_scope(struct gamma *gamma) +{ + if (gamma->scope == 0) + die("scope cannot be decrement to a negative scope\n"); + int i = 0; - for (i = 0; inschemes; i++) { - if (strcmp(gamma->vars[i], ident) == 0) { - scheme_free(gamma->schemes[i]); - free(gamma->vars[i]); - break; + while (inentries) { + if (gamma->entries[i].scope == gamma->scope) { + scheme_free(gamma->entries[i].scheme); + free(gamma->entries[i].var); + for (int j = i+1; jnentries; j++) + gamma->entries[j-1] = gamma->entries[j]; + gamma->nentries--; + } else { + i++; } } - for (i++; inschemes; i++) { - gamma->vars[i-1] = gamma->vars[i]; - gamma->schemes[i-1] = gamma->schemes[i]; - } - gamma->nschemes--; + gamma->scope--; } struct scheme *gamma_lookup(struct gamma *gamma, char *ident) { - for (int i = 0; inschemes; i++) - if (strcmp(ident, gamma->vars[i]) == 0) - return gamma->schemes[i]; - return NULL; + struct scheme *res = NULL; + int maxscope = 0; + for (int i = 0; inentries; i++) { + if (strcmp(ident, gamma->entries[i].var) == 0) { + if (gamma->entries[i].scope >= maxscope) { + maxscope = gamma->entries[i].scope; + res = gamma->entries[i].scheme; + } + } + } + return res; } struct type *gamma_fresh(struct gamma *gamma) @@ -72,10 +87,11 @@ struct type *gamma_fresh(struct gamma *gamma) void gamma_print(struct gamma *gamma, FILE *out) { fprintf(out, "{"); - for (int i = 0; inschemes; i++) { - fprintf(out, "%s=", gamma->vars[i]); - scheme_print(gamma->schemes[i], out); - if (i + 1 < gamma->nschemes) + for (int i = 0; inentries; i++) { + fprintf(out, "%s(%d) = ", gamma->entries[i].var, + gamma->entries[i].scope); + scheme_print(gamma->entries[i].scheme, out); + if (i + 1 < gamma->nentries) fprintf(out, ", "); } fprintf(out, "}"); @@ -83,11 +99,10 @@ void gamma_print(struct gamma *gamma, FILE *out) void gamma_free(struct gamma *gamma) { - for (int i = 0; inschemes; i++) { - free(gamma->vars[i]); - scheme_free(gamma->schemes[i]); + for (int i = 0; inentries; i++) { + free(gamma->entries[i].var); + scheme_free(gamma->entries[i].scheme); } - free(gamma->vars); - free(gamma->schemes); + free(gamma->entries); free(gamma); } diff --git a/sem/hm/gamma.h b/sem/hm/gamma.h index f146621..9641dcc 100644 --- a/sem/hm/gamma.h +++ b/sem/hm/gamma.h @@ -8,14 +8,19 @@ struct gamma { int capacity; int fresh; - int nschemes; - char **vars; - struct scheme **schemes; + int scope; + int nentries; + struct gamma_entry { + int scope; + char *var; + struct scheme *scheme; + } *entries; }; struct gamma *gamma_init(); void gamma_insert(struct gamma *gamma, char *ident, struct scheme *scheme); -void gamma_remove(struct gamma *gamma, char *ident); +void gamma_increment_scope(struct gamma *gamma); +void gamma_decrement_scope(struct gamma *gamma); struct scheme *gamma_lookup(struct gamma *gamma, char *ident); struct type *gamma_fresh(struct gamma *gamma); diff --git a/sem/hm/scheme.c b/sem/hm/scheme.c index b9b9861..5715837 100644 --- a/sem/hm/scheme.c +++ b/sem/hm/scheme.c @@ -39,8 +39,8 @@ struct scheme *scheme_generalise(struct gamma *gamma, struct type *t) s->var = safe_malloc(nftv*sizeof(char *)); for (int i = 0; inschemes; j++) - if (strcmp(gamma->vars[j], ftv[i]) == 0) + for (int j = 0; jnentries; j++) + if (strcmp(gamma->entries[j].var, ftv[i]) == 0) skip = true; if (skip) continue; diff --git a/sem/hm/subst.c b/sem/hm/subst.c index 1fcfbbc..6725fc7 100644 --- a/sem/hm/subst.c +++ b/sem/hm/subst.c @@ -1,42 +1,42 @@ #include #include +#include + #include "../hm.h" -#define INCAP 25 +#define INCAP 50 struct subst *subst_id() { struct subst *res = safe_malloc(sizeof(struct subst)); - res->nvar = 0; res->capacity = INCAP; - res->vars = safe_malloc(INCAP*sizeof(char *)); - res->types = safe_malloc(INCAP*sizeof(struct type *)); + res->nvar = 0; + res->entries = safe_malloc(INCAP*sizeof(struct subst_entry)); return res; } struct subst *subst_insert(struct subst *s, char *ident, struct type *t) { - int i = 0; while (i < s->nvar) { - if (strcmp(s->vars[i], ident) == 0) { - free(s->vars[i]); - s->vars[i] = safe_strdup(ident); - type_free(s->types[i]); - s->types[i] = type_dup(t); + if (strcmp(s->entries[i].var, ident) == 0) { + // free(s->entries[i].var); + // s->entries[i].var = safe_strdup(ident); + type_free(s->entries[i].type); + s->entries[i].type = type_dup(t); return s; } i++; } if (s->nvar >= s->capacity) { s->capacity += s->capacity; - s->vars = safe_realloc(s->vars, s->capacity*sizeof(char *)); - s->types = safe_realloc(s->types, s->capacity*sizeof(struct type *)); + s->entries = safe_realloc(s->entries, + s->capacity*sizeof(struct subst_entry)); } - s->nvar ++; - s->vars[i] = safe_strdup(ident); - s->types[i] = type_dup(t); + s->nvar++; + s->entries[i].var = safe_strdup(ident); + s->entries[i].type = type_dup(t); return s; } @@ -49,10 +49,10 @@ struct subst *subst_union(struct subst *s1, struct subst *s2) { //Apply s1 on s2 for (int i = 0; invar; i++) - s2->types[i] = subst_apply_t(s1, s2->types[i]); + s2->entries[i].type = subst_apply_t(s1, s2->entries[i].type); //Insert s1 into s2 for (int i = 0; invar; i++) - subst_insert(s2, s1->vars[i], s1->types[i]); + subst_insert(s2, s1->entries[i].var, s1->entries[i].type); subst_free(s1); return s2; } @@ -77,9 +77,10 @@ struct type *subst_apply_t(struct subst *subst, struct type *l) break; case tvar: for (int i = 0; invar; i++) { - if (strcmp(subst->vars[i], l->data.tvar) == 0) { + if (strcmp(subst->entries[i].var, l->data.tvar) == 0) { free(l->data.tvar); - struct type *r = type_dup(subst->types[i]); + struct type *r = + type_dup(subst->entries[i].type); *l = *r; free(r); break; @@ -97,12 +98,13 @@ struct scheme *subst_apply_s(struct subst *subst, struct scheme *scheme) for (int j = 0; jnvar; j++) { bool found = false; for (int i = 0; invar; i++) { - if (strcmp(scheme->var[i], subst->vars[j]) == 0) { + if (strcmp(scheme->var[i], subst->entries[j].var) == 0) { found = true; } } if (!found) - subst_insert(s, subst->vars[j], subst->types[j]); + subst_insert(s, subst->entries[j].var, + subst->entries[j].type); } scheme->type = subst_apply_t(s, scheme->type); subst_free(s); @@ -111,8 +113,8 @@ struct scheme *subst_apply_s(struct subst *subst, struct scheme *scheme) struct gamma *subst_apply_g(struct subst *subst, struct gamma *gamma) { - for (int i = 0; inschemes; i++) - subst_apply_s(subst, gamma->schemes[i]); + for (int i = 0; inentries; i++) + subst_apply_s(subst, gamma->entries[i].scheme); return gamma; } @@ -123,8 +125,8 @@ void subst_print(struct subst *s, FILE *out) } else { fprintf(out, "["); for (int i = 0; invar; i++) { - fprintf(out, "%s->", s->vars[i]); - type_print(s->types[i], out); + fprintf(out, "%s->", s->entries[i].var); + type_print(s->entries[i].type, out); if (i + 1 < s->nvar) fprintf(out, ", "); } @@ -136,11 +138,10 @@ void subst_free(struct subst *s) { if (s != NULL) { for (int i = 0; invar; i++) { - free(s->vars[i]); - type_free(s->types[i]); + free(s->entries[i].var); + type_free(s->entries[i].type); } - free(s->vars); - free(s->types); + free(s->entries); free(s); } } diff --git a/sem/hm/subst.h b/sem/hm/subst.h index ff9e71f..d3661c2 100644 --- a/sem/hm/subst.h +++ b/sem/hm/subst.h @@ -7,8 +7,11 @@ struct subst { int nvar; int capacity; - char **vars; - struct type **types; + struct subst_entry *entries; +}; +struct subst_entry { + char *var; + struct type *type; }; struct subst *subst_id(); diff --git a/sem/scc.c b/sem/scc.c index 29a3bee..dd25ee7 100644 --- a/sem/scc.c +++ b/sem/scc.c @@ -274,28 +274,21 @@ struct ast *ast_scc(struct ast *ast) fundecls[i]->data.dfun->body[j], edges); int nedges; struct edge **edata = (struct edge **) - list_to_array(edges, &nedges, false); + list_to_array(edges, &nedges, false, 0); // Do tarjan's and convert back into the declaration list struct components *cs = tarjans(nfun, (void **)fundecls, nedges, edata); -// if (cs == NULL) -// die("malformed edges in tarjan's????"); int i = ffun; for (struct components *c = cs; c != NULL; c = c->next) { struct decl *d = safe_malloc(sizeof(struct decl)); - if (c->nnodes > 1) { - d->type = dcomp; - d->data.dcomp.ndecls = c->nnodes; - d->data.dcomp.decls = safe_malloc( - c->nnodes*sizeof(struct fundecl *)); - for (int i = 0; innodes; i++) - d->data.dcomp.decls[i] = - ((struct decl *)c->nodes[i])->data.dfun; - } else { - d->type = dfundecl; - d->data.dfun = ((struct decl *)c->nodes[0])->data.dfun; - } + d->type = dcomp; + d->data.dcomp.ndecls = c->nnodes; + d->data.dcomp.decls = safe_malloc( + c->nnodes*sizeof(struct fundecl *)); + for (int j = 0; jnnodes; j++) + d->data.dcomp.decls[j] = + ((struct decl *)c->nodes[j])->data.dfun; ast->decls[i++] = d; } ast->ndecls = i; diff --git a/util.c b/util.c index 6c70c63..1653cad 100644 --- a/util.c +++ b/util.c @@ -155,7 +155,7 @@ void *safe_malloc(size_t size) void *safe_realloc(void *ptr, size_t size) { void *res = realloc(ptr, size); - if (res == NULL) + if (size > 0 && res == NULL) pdie("realloc"); return res; }