LFLAGS+=--header-file=scan.h
OBJECTS:=scan.o parse.o ast.o type.o util.o list.o sem.o genc.o \
- sem/scc.o\
- $(addprefix sem/hm, .o /gamma.o /subst.o /scheme.o)
+ $(addprefix sem,.o /scc.o $(addprefix /hm, .o /gamma.o /subst.o /scheme.o))
all: splc
splc: $(OBJECTS)
{
struct ast *res = safe_malloc(sizeof(struct ast));
res->loc = l;
- res->loc = l;
res->decls = (struct decl **)list_to_array(decls, &res->ndecls, true);
return res;
}
return res;
}
-static void set_fields(enum fieldspec **farray, int *n, struct list *fields)
-{
- void **els = list_to_array(fields, n, true);
- *farray = (enum fieldspec *)safe_malloc(*n*sizeof(enum fieldspec));
- for (int i = 0; i<*n; i++) {
- char *t = els[i];
- if (strcmp(t, "fst") == 0)
- (*farray)[i] = fst;
- else if (strcmp(t, "snd") == 0)
- (*farray)[i] = snd;
- else if (strcmp(t, "hd") == 0)
- (*farray)[i] = hd;
- else if (strcmp(t, "tl") == 0)
- (*farray)[i] = tl;
- free(t);
- }
- free(els);
+static bool is_valid_field(char *t)
+{
+ if (strcmp(t, "fst") == 0)
+ return true;
+ else if (strcmp(t, "snd") == 0)
+ return true;
+ else if (strcmp(t, "hd") == 0)
+ return true;
+ else if (strcmp(t, "tl") == 0)
+ return true;
+ return false;
}
-struct expr *expr_funcall(char *ident, struct list *args, struct list *fields, YYLTYPE l)
+bool is_builtin(char *t)
+{
+ return is_valid_field(t)
+ || strcmp(t, "isEmpty") == 0
+ || strcmp(t, "print") == 0;
+}
+
+struct expr *expr_funcall_real(char *ident, struct list *args, YYLTYPE l)
{
struct expr *res = safe_malloc(sizeof(struct expr));
res->loc = l;
res->data.efuncall.ident = ident;
res->data.efuncall.args = (struct expr **)
list_to_array(args, &res->data.efuncall.nargs, true);
- set_fields(&res->data.efuncall.fields,
- &res->data.efuncall.nfields, fields);
+ return res;
+}
+
+static struct expr *expr_apply_fields(struct expr *r, struct list *fields, YYLTYPE l)
+{
+ FOREACH(field, fields) {
+ if (is_valid_field(field->el)) {
+ struct list *as = list_cons(r, NULL);
+ r = expr_funcall_real(field->el, as, l);
+ }
+ }
+ list_free(fields, NULL);
+ return r;
+}
+
+struct expr *expr_funcall(char *ident, struct list *args, struct list *fields, YYLTYPE l)
+{
+ struct expr *res = expr_funcall_real(ident, args, l);
+ res = expr_apply_fields(res, fields, l);
return res;
}
struct expr *res = safe_malloc(sizeof(struct expr));
res->loc = l;
res->type = eident;
- res->data.eident.ident = ident;
- set_fields(&res->data.eident.fields, &res->data.eident.nfields, fields);
+ res->data.eident = ident;
+ res = expr_apply_fields(res, fields, l);
return res;
}
safe_fprintf(out, ", ");
}
safe_fprintf(out, ")");
- for (int i = 0; i<expr->data.efuncall.nfields; i++)
- fprintf(out, ".%s",
- fieldspec_str[expr->data.efuncall.fields[i]]);
break;
case eint:
safe_fprintf(out, "%d", expr->data.eint);
break;
case eident:
- fprintf(out, "%s", expr->data.eident.ident);
- for (int i = 0; i<expr->data.eident.nfields; i++)
- fprintf(out, ".%s",
- fieldspec_str[expr->data.eident.fields[i]]);
+ fprintf(out, "%s", expr->data.eident);
break;
case enil:
safe_fprintf(out, "[]");
free(expr->data.efuncall.ident);
for (int i = 0; i<expr->data.efuncall.nargs; i++)
expr_free(expr->data.efuncall.args[i]);
- free(expr->data.efuncall.fields);
free(expr->data.efuncall.args);
break;
case eint:
break;
case eident:
- free(expr->data.eident.ident);
- free(expr->data.eident.fields);
+ free(expr->data.eident);
break;
case enil:
break;
divide, modulo, power,
};
enum fieldspec {fst,snd,hd,tl};
+bool is_builtin(char *t);
enum unop {negate,inverse};
struct expr {
YYLTYPE loc;
char *ident;
int nargs;
struct expr **args;
- int nfields;
- enum fieldspec *fields;
} efuncall;
int eint;
- struct {
- char *ident;
- int nfields;
- enum fieldspec *fields;
- } eident;
+ char *eident;
struct {
struct expr *left;
struct expr *right;
safe_fprintf(cout, ", ");
}
safe_fprintf(cout, ")");
- for (int i = 0; i<expr->data.efuncall.nfields; i++)
- fprintf(cout, "->%s",
- fieldspec_str[expr->data.efuncall.fields[i]]);
break;
case eint:
safe_fprintf(cout, "%d", expr->data.eint);
break;
case eident:
- fprintf(cout, "%s", expr->data.eident.ident);
- for (int i = 0; i<expr->data.eident.nfields; i++)
- fprintf(cout, "->%s",
- fieldspec_str[expr->data.eident.fields[i]]);
+ fprintf(cout, "%s", expr->data.eident);
break;
case enil:
safe_fprintf(cout, "NULL");
D [0-9]
H [0-9a-fA-F]
+O [0-7]
E ([0\\abtnvfr]|x{H}?{H}|0[0-3]?{O}?{O})
I [a-zA-Z_]
-O [0-7]
%option noinput
%option nounput
%{
-#include <stdio.h>
#define YY_USER_ACTION \
yylloc.first_line = yylloc.last_line; \
yylloc.first_column = yylloc.last_column; \
else return ELSE;
while return WHILE;
var return VAR;
-true { yylval.expr = expr_bool(true, yylloc); return BOOL; }
-false { yylval.expr = expr_bool(false, yylloc); return BOOL; }
+True { yylval.expr = expr_bool(true, yylloc); return BOOL; }
+False { yylval.expr = expr_bool(false, yylloc); return BOOL; }
return return RETURN;
Int return TINT;
Bool return TBOOL;
}
<IN_COMMENT>{
\*\/ BEGIN(INITIAL);
-. ;
+.|\n {}
}
%%
? gamma_fresh(gamma) : vardecl->type;
struct subst *s = infer_expr(gamma, vardecl->expr, t);
- if (s == NULL)
- die("error inferring variable\n");
vardecl->type = subst_apply_t(s, t);
gamma_insert(gamma, vardecl->ident, scheme_create(vardecl->type));
//Create a fresh variable for every function in the component
struct type **fs = safe_malloc(ndecls*sizeof(struct type *));
for (int i = 0; i<ndecls; i++) {
- bool fresh = decl[i]->rtype == NULL || decl[i]->atypes == NULL;
- fs[i] = fresh ? gamma_fresh(gamma) : decl[i]->rtype;
+ fs[i] = gamma_fresh(gamma);
for (int j = 0; j<decl[i]->nargs; j++) {
- struct type *a = fresh ? gamma_fresh(gamma)
- : type_dup(decl[i]->atypes[j]);
+ struct type *a = gamma_fresh(gamma);
fs[i] = type_arrow(a, fs[i]);
}
gamma_insert(gamma, decl[i]->ident, scheme_create(fs[i]));
//Generalise all functions and put in gamma
for (int i = 0; i<ndecls; i++) {
struct type *t = subst_apply_t(s0, fs[i]);
- gamma_insert(gamma, decl[i]->ident, scheme_generalise(gamma, t));
- for (int j = 0; i<decl[i]->natypes; j++) {
- free(decl[i]->atypes[i]);
+ //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--)
+ 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);
}
- free(decl[i]->atypes);
+
+ 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]->natypes = decl[i]->nargs;
- for (int j = 0; j<decl[i]->nargs; j++) {
+ for (int j = 0; j<decl[i]->nargs; j++, t = t->data.tarrow.r)
decl[i]->atypes[j] = type_dup(t->data.tarrow.l);
- t = t->data.tarrow.r;
- }
decl[i]->rtype = type_dup(t);
}
subst_free(s0);
}
+void gamma_preamble(struct gamma *gamma)
+{
+ struct type *t = type_arrow(type_tuple(type_var(safe_strdup("a"))
+ , type_var(safe_strdup("b"))) ,type_var(safe_strdup("a")));
+ gamma_insert(gamma, "fst", scheme_generalise(gamma, t));
+ type_free(t);
+
+ t = type_arrow(type_tuple(type_var(safe_strdup("a"))
+ , type_var(safe_strdup("b"))) ,type_var(safe_strdup("b")));
+ gamma_insert(gamma, "snd", scheme_generalise(gamma, t));
+ type_free(t);
+
+ t = type_arrow(type_list(type_var(safe_strdup("a"))),
+ type_var(safe_strdup("a")));
+ gamma_insert(gamma, "hd", scheme_generalise(gamma, t));
+ type_free(t);
+
+ t = type_arrow(type_list(type_var(safe_strdup("a"))),
+ type_list(type_var(safe_strdup("a"))));
+ gamma_insert(gamma, "tl", scheme_generalise(gamma, t));
+ type_free(t);
+
+ t = type_arrow(type_list(type_var(safe_strdup("a"))),
+ type_basic(btbool));
+ gamma_insert(gamma, "isEmpty", scheme_generalise(gamma, t));
+ type_free(t);
+
+ t = type_arrow(type_var(safe_strdup("a")), type_basic(btvoid));
+ gamma_insert(gamma, "print", scheme_generalise(gamma, t));
+ type_free(t);
+}
+
+bool check_return_stmt(struct stmt *stmt);
+bool check_return_body(int nbody, struct stmt **body)
+{
+ for (int i = 0; i<nbody; i++)
+ if (check_return_stmt(body[i]))
+ return true;
+ return false;
+}
+
+
+bool check_return_stmt(struct stmt *stmt)
+{
+ switch (stmt->type) {
+ case sassign:
+ return false;
+ case sif:
+ return check_return_body(stmt->data.sif.nthen, stmt->data.sif.then)
+ && check_return_body(stmt->data.sif.nels, stmt->data.sif.els);
+ case swhile:
+ return check_return_body(stmt->data.swhile.nbody,
+ stmt->data.swhile.body);
+ case sreturn:
+ return true;
+ default:
+ return false;
+ }
+}
+
+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)
+ continue;
+ if (!check_return_body(decls[i]->nbody, decls[i]->body))
+ type_error(decls[i]->loc, true,
+ "%s doesn't return properly", decls[i]->ident);
+ }
+}
+
struct ast *sem(struct ast *ast)
{
+ //Break up into strongly connected components
ast = ast_scc(ast);
struct gamma *gamma = gamma_init();
+ gamma_preamble(gamma);
//Check all vardecls
for (int i = 0; i<ast->ndecls; i++) {
- switch(ast->decls[i]->type) {
+ struct decl *decl = ast->decls[i];
+ switch(decl->type) {
case dvardecl:
//Check if constant
- check_expr_constant(ast->decls[i]->data.dvar->expr);
+ check_expr_constant(decl->data.dvar->expr);
//Infer if necessary
- type_vardecl(gamma, ast->decls[i]->data.dvar);
+ type_vardecl(gamma, decl->data.dvar);
break;
case dfundecl:
//Infer function as singleton component
- type_comp(gamma, 1, &ast->decls[i]->data.dfun);
+ type_comp(gamma, 1, &decl->data.dfun);
+// check_return_comp(1, &decl->data.dfun);
break;
case dcomp:
//Infer function as singleton component
- type_comp(gamma, ast->decls[i]->data.dcomp.ndecls,
- ast->decls[i]->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);
break;
}
}
struct subst *s1, *s2;
if (l->type == tarrow && r->type == tarrow) {
s1 = unify(loc, l->data.tarrow.l, r->data.tarrow.l);
- s2 = unify(loc, subst_apply_t(s1, l->data.tarrow.l),
- subst_apply_t(s1, r->data.tarrow.l));
+ s2 = unify(loc, subst_apply_t(s1, l->data.tarrow.r),
+ subst_apply_t(s1, r->data.tarrow.r));
return subst_union(s2, s1);
} else if (l->type == tbasic && r->type == tbasic
&& l->data.tbasic == r->data.tbasic) {
return NULL;
}
-struct subst *unifyfree(YYLTYPE loc,
- struct type *l, struct type *r, bool freel, bool freer)
-{
- struct subst *s = unify(loc, l, r);
- if (freel)
- type_free(l);
- if (freer)
- type_free(r);
- return s;
-}
-
struct subst *infer_binop(struct gamma *gamma, struct expr *l, struct expr *r,
struct type *a1, struct type *a2, struct type *rt, struct type *sigma)
{
return subst_union(s2, s1);
}
+static struct type tyvoid = {.type=tbasic, .data={.tbasic=btvoid}};
static struct type tybool = {.type=tbasic, .data={.tbasic=btbool}};
static struct type tychar = {.type=tbasic, .data={.tbasic=btchar}};
static struct type tyint = {.type=tbasic, .data={.tbasic=btint}};
return unify(expr->loc, &tychar, type);
case efuncall:
if ((s = gamma_lookup(gamma, expr->data.efuncall.ident)) == NULL)
- type_error(expr->loc, "Unbound function: %s\n"
+ type_error(expr->loc, true, "Unbound function: %s\n"
, expr->data.efuncall.ident);
struct type *ft = scheme_instantiate(gamma, s);
struct type *t = ft;
s1 = unify(expr->loc, t, type);
s0 = subst_union(s1, s0);
type_free(ft);
- //TODO fields
return s0;
case eint:
return unify(expr->loc, &tyint, type);
case eident:
- if ((s = gamma_lookup(gamma, expr->data.eident.ident)) == NULL)
+ if ((s = gamma_lookup(gamma, expr->data.eident)) == NULL)
type_error(expr->loc, true, "Unbound variable: %s\n"
- , expr->data.eident.ident);
+ , expr->data.eident);
f1 = scheme_instantiate(gamma, s);
s0 = unify(expr->loc, f1, type);
type_free(f1);
- //TODO field
return s0;
case enil:
- f1 = gamma_fresh(gamma);
- return unifyfree(expr->loc, type_list(f1), type, true, false);
+ f1 = type_list(gamma_fresh(gamma));
+ s0 = unify(expr->loc, f1, type);
+ type_free(f1);
+ return s0;
case etuple:
f1 = gamma_fresh(gamma);
f2 = gamma_fresh(gamma);
}
return s0;
case sreturn:
- return infer_expr(gamma, stmt->data.sreturn, type);
+ return stmt->data.sreturn == NULL
+ ? unify(stmt->loc, &tyvoid, type)
+ : infer_expr(gamma, stmt->data.sreturn, type);
case sexpr:
f1 = gamma_fresh(gamma);
s0 = infer_expr(gamma, stmt->data.sexpr, f1);
type_free(f1);
return s0;
case svardecl:
- break;
+ f1 = gamma_fresh(gamma);
+ s0 = infer_expr(gamma, stmt->data.svardecl->expr, f1);
+ if (stmt->data.svardecl->type != NULL)
+ s1 = unify(stmt->loc, f1, stmt->data.svardecl->type);
+ else
+ s1 = subst_id();
+ s0 = subst_union(s1, s0);
+ //TODO fielsd
+ //TODO
+ gamma_insert(gamma, stmt->data.svardecl->ident, scheme_create(subst_apply_t(s0, f1)));
+ return s0;
case swhile:
s0 = infer_expr(gamma, stmt->data.swhile.pred, &tybool);
subst_apply_g(s0, gamma);
struct subst *s = subst_id();
for (int i = 0; i<fundecl->nbody; i++) {
- struct subst *s1 = infer_stmt(gamma,
- fundecl->body[i], at);
+ struct subst *s1 = infer_stmt(gamma, fundecl->body[i], at);
s = subst_union(s1, s);
subst_apply_g(s, gamma);
}
+ // 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;
+ }
return s;
}
#include "hm/scheme.h"
struct ast *infer(struct ast *ast);
+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);
struct subst *infer_fundecl(struct gamma *gamma, struct fundecl *fundecl, struct type *ftype);
#include "../hm.h"
+#define IN_CAP 25
+
struct gamma *gamma_init()
{
struct gamma *gamma = safe_malloc(sizeof(struct gamma));
+ gamma->capacity = IN_CAP;
gamma->fresh = 0;
gamma->nschemes = 0;
- gamma->vars = NULL;
- gamma->schemes = NULL;
+ gamma->vars = safe_malloc(IN_CAP*sizeof(char *));
+ gamma->schemes = safe_malloc(IN_CAP*sizeof(struct scheme *));
return gamma;
}
}
}
gamma->nschemes++;
- gamma->vars = safe_realloc(gamma->vars,
- gamma->nschemes*sizeof(char *));
- gamma->schemes = safe_realloc(gamma->schemes,
- gamma->nschemes*sizeof(struct scheme *));
+ if (gamma->nschemes >= 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->vars[gamma->nschemes-1] = safe_strdup(ident);
gamma->schemes[gamma->nschemes-1] = scheme;
}
+void gamma_remove(struct gamma *gamma, char *ident)
+{
+ 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;
+ }
+ }
+ for (i++; i<gamma->nschemes; i++) {
+ gamma->vars[i-1] = gamma->vars[i];
+ gamma->schemes[i-1] = gamma->schemes[i];
+ }
+ gamma->nschemes--;
+}
+
struct scheme *gamma_lookup(struct gamma *gamma, char *ident)
{
for (int i = 0; i<gamma->nschemes; i++)
#include "../hm.h"
struct gamma {
+ int capacity;
int fresh;
int nschemes;
char **vars;
struct gamma *gamma_init();
void gamma_insert(struct gamma *gamma, char *ident, struct scheme *scheme);
+void gamma_remove(struct gamma *gamma, char *ident);
struct scheme *gamma_lookup(struct gamma *gamma, char *ident);
struct type *gamma_fresh(struct gamma *gamma);
struct type *scheme_instantiate(struct gamma *gamma, struct scheme *sch)
{
struct subst *s = subst_id();
- for (int i = 0; i<sch->nvar; i++)
- subst_insert(s, safe_strdup(sch->var[i]), gamma_fresh(gamma));
+ struct type *t;
+ for (int i = 0; i<sch->nvar; i++) {
+ t = gamma_fresh(gamma);
+ subst_insert(s, sch->var[i], t);
+ type_free(t);
+ }
- struct type *t = subst_apply_t(s, type_dup(sch->type));
+ t = subst_apply_t(s, type_dup(sch->type));
subst_free(s);
return t;
}
#include "../hm.h"
-#define INCAP 10
+#define INCAP 25
struct subst *subst_id()
{
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) {
}
i++;
}
- s->nvar++;
- if (s->nvar > s->capacity) {
+ if (s->nvar >= s->capacity) {
s->capacity += s->capacity;
s->vars = safe_realloc(s->vars, s->capacity*sizeof(char *));
- s->types = safe_realloc(s->vars, s->capacity*sizeof(struct type *));
+ s->types = safe_realloc(s->types, s->capacity*sizeof(struct type *));
}
+ s->nvar ++;
s->vars[i] = safe_strdup(ident);
s->types[i] = type_dup(t);
return s;
struct subst *subst_singleton(char *ident, struct type *t)
{
- struct subst *res = subst_id();
- subst_insert(res, ident, t);
- return res;
+ return subst_insert(subst_id(), ident, t);
}
struct subst *subst_union(struct subst *s1, struct subst *s2)
void subst_print(struct subst *s, FILE *out)
{
if (s == NULL) {
- fprintf(out, "no subst\n");
+ fprintf(out, "(nil)");
} else {
fprintf(out, "[");
for (int i = 0; i<s->nvar; i++) {
if (i + 1 < s->nvar)
fprintf(out, ", ");
}
- fprintf(out, "]\n");
+ fprintf(out, "]");
}
}
#include "../ast.h"
#include "../list.h"
+#include "../sem.h"
#ifndef min
#define min(x, y) ((x)<(y) ? (x) : (y))
found = true;
}
}
- if (!found)
- die("Malformed function call\n");
+ if (!found && !is_builtin(expr->data.efuncall.ident))
+ type_error(expr->loc, true, "Unbound function: %s\n",
+ expr->data.efuncall.ident);
break;
case eint:
break;