{
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
}
}
-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) {
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
//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; j<decl[i]->natypes; 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; j<decl[i]->nargs; j++, t = t->data.tarrow.r)
decl[i]->atypes[j] = type_dup(t->data.tarrow.l);
void check_return_comp(int ndecl, struct fundecl **decls)
{
for (int i = 0; i<ndecl; i++) {
- if (decls[i]->rtype->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,
}
}
+void add_return_if_none(int ndecl, struct fundecl **decl)
+{
+ for (int i = 0; i<ndecl; i++) {
+ if (decl[i]->rtype == 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
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; i<ast->ndecls; i++) {
//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;
}
}
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; i<nstmt; i++) {
+ s1 = infer_stmt(gamma, stmts[i], type);
+ s0 = subst_union(s1, s0);
+ subst_apply_g(s0, gamma);
+ }
+ gamma_decrement_scope(gamma);
+ return s0;
+}
+
struct subst *infer_stmt(struct gamma *gamma, struct stmt *stmt, struct type *type)
{
struct subst *s0, *s1;
break;
case sif:
s0 = infer_expr(gamma, stmt->data.sif.pred, &tybool);
- subst_apply_g(s0, gamma);
+ //subst_apply_g(s0, gamma);
- for (int i = 0; i<stmt->data.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; i<stmt->data.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
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; i<stmt->data.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;
}
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; i<fundecl->nargs; i++) {
if (at->type != tarrow)
}
// Remove arguments from gamma
- at = ftype;
- for (int i = 0; i<fundecl->nargs; i++) {
- gamma_remove(gamma, fundecl->args[i]);
- at = at->data.tarrow.r;
- }
+ gamma_decrement_scope(gamma);
return s;
}
#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);
#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; i<gamma->nschemes; i++) {
- if(strcmp(gamma->vars[i], ident) == 0) {
- scheme_free(gamma->schemes[i]);
- gamma->schemes[i] = scheme;
+ for (int i = 0; i<gamma->nentries; 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; i<gamma->nschemes; i++) {
- if (strcmp(gamma->vars[i], ident) == 0) {
- scheme_free(gamma->schemes[i]);
- free(gamma->vars[i]);
- break;
+ while (i<gamma->nentries) {
+ if (gamma->entries[i].scope == gamma->scope) {
+ scheme_free(gamma->entries[i].scheme);
+ free(gamma->entries[i].var);
+ for (int j = i+1; j<gamma->nentries; j++)
+ gamma->entries[j-1] = gamma->entries[j];
+ gamma->nentries--;
+ } else {
+ i++;
}
}
- for (i++; i<gamma->nschemes; 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; i<gamma->nschemes; 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; i<gamma->nentries; 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)
void gamma_print(struct gamma *gamma, FILE *out)
{
fprintf(out, "{");
- for (int i = 0; i<gamma->nschemes; i++) {
- fprintf(out, "%s=", gamma->vars[i]);
- scheme_print(gamma->schemes[i], out);
- if (i + 1 < gamma->nschemes)
+ for (int i = 0; i<gamma->nentries; 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, "}");
void gamma_free(struct gamma *gamma)
{
- for (int i = 0; i<gamma->nschemes; i++) {
- free(gamma->vars[i]);
- scheme_free(gamma->schemes[i]);
+ for (int i = 0; i<gamma->nentries; i++) {
+ free(gamma->entries[i].var);
+ scheme_free(gamma->entries[i].scheme);
}
- free(gamma->vars);
- free(gamma->schemes);
+ free(gamma->entries);
free(gamma);
}
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);
s->var = safe_malloc(nftv*sizeof(char *));
for (int i = 0; i<nftv; i++) {
bool skip = false;
- for (int j = 0; j<gamma->nschemes; j++)
- if (strcmp(gamma->vars[j], ftv[i]) == 0)
+ for (int j = 0; j<gamma->nentries; j++)
+ if (strcmp(gamma->entries[j].var, ftv[i]) == 0)
skip = true;
if (skip)
continue;
#include <string.h>
#include <stdlib.h>
+#include <search.h>
+
#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;
}
{
//Apply s1 on s2
for (int i = 0; i<s2->nvar; 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; i<s1->nvar; 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;
}
break;
case tvar:
for (int i = 0; i<subst->nvar; 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;
for (int j = 0; j<subst->nvar; j++) {
bool found = false;
for (int i = 0; i<scheme->nvar; 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);
struct gamma *subst_apply_g(struct subst *subst, struct gamma *gamma)
{
- for (int i = 0; i<gamma->nschemes; i++)
- subst_apply_s(subst, gamma->schemes[i]);
+ for (int i = 0; i<gamma->nentries; i++)
+ subst_apply_s(subst, gamma->entries[i].scheme);
return gamma;
}
} else {
fprintf(out, "[");
for (int i = 0; i<s->nvar; 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, ", ");
}
{
if (s != NULL) {
for (int i = 0; i<s->nvar; 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);
}
}
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();
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; i<c->nnodes; 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; j<c->nnodes; j++)
+ d->data.dcomp.decls[j] =
+ ((struct decl *)c->nodes[j])->data.dfun;
ast->decls[i++] = d;
}
ast->ndecls = i;
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;
}