239 lines
4.1 KiB
C
239 lines
4.1 KiB
C
/*
|
|
* Subtyping
|
|
*/
|
|
#include <stdlib.h>
|
|
|
|
#include "spho/bind.h"
|
|
#include "spho/bind.h"
|
|
#include "spho/spho.h"
|
|
|
|
#include "spho/subt.h"
|
|
|
|
/* bound type */
|
|
struct bound {
|
|
struct spho_bind *bind;
|
|
const struct spho_tp *tp;
|
|
};
|
|
|
|
/* sequent */
|
|
struct sqnt {
|
|
struct spho_ctx *ctx;
|
|
|
|
size_t sz;
|
|
size_t filled;
|
|
struct bound *elms;
|
|
};
|
|
|
|
/* sequent turnstile */
|
|
struct tstl {
|
|
struct sqnt left;
|
|
struct sqnt right;
|
|
};
|
|
|
|
|
|
static struct bound *bound_tp(const struct spho_tp *);
|
|
|
|
|
|
/* read scopes and create bound type */
|
|
struct bound *
|
|
bound_tp(const struct spho_tp *tp)
|
|
{
|
|
struct spho_scope *sc;
|
|
struct spho_bind *bind, *more_bind;
|
|
|
|
struct bound *ret;
|
|
|
|
SPHO_PRECOND(tp != NULL);
|
|
SPHO_PRECOND(tp->sc != NULL);
|
|
SPHO_PRECOND(tp->sc->bind_loc != NULL);
|
|
|
|
sc = tp->sc;
|
|
bind = NULL;
|
|
|
|
if ((ret = calloc(1, sizeof(*ret))) == NULL) {
|
|
SPHO_ERR(sc->ctx, SPHO_ERR_SYS);
|
|
return (NULL);
|
|
}
|
|
ret->tp = tp;
|
|
|
|
|
|
if ((ret->bind = calloc(1, sizeof(*ret->bind))) == NULL) {
|
|
SPHO_ERR(sc->ctx, SPHO_ERR_SYS);
|
|
goto err;
|
|
}
|
|
|
|
/* initialize parent and duplicate scope-local bindings */
|
|
ret->bind->parent = NULL;
|
|
if ((ret->bind->loc = spho_prebind_dupl(sc->bind_loc)) == NULL) {
|
|
goto err;
|
|
}
|
|
|
|
/* iterate up through parent scopes and gather their local bindings */
|
|
bind = ret->bind;
|
|
while ((sc = sc->parent) != NULL) {
|
|
if ((more_bind = calloc(1, sizeof(*more_bind))) == NULL) {
|
|
SPHO_ERR(sc->ctx, SPHO_ERR_SYS);
|
|
goto err;
|
|
}
|
|
more_bind->parent = NULL;
|
|
if ((more_bind->loc = spho_prebind_dupl(sc->bind_loc))
|
|
== NULL) {
|
|
goto err;
|
|
}
|
|
bind->parent = more_bind;
|
|
bind = bind->parent;
|
|
}
|
|
|
|
return (ret);
|
|
|
|
err:
|
|
while (ret->bind != NULL) {
|
|
bind = ret->bind;
|
|
ret->bind = ret->bind->parent;
|
|
|
|
spho_prebind_free(bind->loc);
|
|
free(bind);
|
|
}
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
static int
|
|
sqnt_init(struct spho_ctx *ctx, size_t initsz, struct sqnt *seq)
|
|
{
|
|
if (initsz == 0)
|
|
initsz = 0x10; /* just feels good */
|
|
|
|
seq->ctx = ctx;
|
|
|
|
if ((seq->elms = calloc(initsz, sizeof(*seq->elms))) == NULL) {
|
|
SPHO_ERR(seq->ctx, SPHO_ERR_SYS);
|
|
goto err;
|
|
}
|
|
|
|
seq->sz = initsz;
|
|
seq->filled = 0;
|
|
|
|
return (0);
|
|
err:
|
|
if (seq->elms != NULL)
|
|
free(seq->elms);
|
|
seq->elms = NULL;
|
|
|
|
return (-1);
|
|
}
|
|
|
|
static int
|
|
sqnt_makebig(struct sqnt *seq)
|
|
{
|
|
size_t new_sz;
|
|
struct bound *new_elms;
|
|
|
|
SPHO_PRECOND(seq != NULL);
|
|
SPHO_PRECOND(seq->sz > 0);
|
|
SPHO_PRECOND(seq->sz <= (SIZE_MAX >> 1));
|
|
SPHO_PRECOND(seq->elms != NULL);
|
|
|
|
new_sz = seq->sz << 1;
|
|
|
|
if ((new_elms = realloc(seq->elms, new_sz)) == NULL) {
|
|
SPHO_ERR(seq->ctx, SPHO_ERR_SYS);
|
|
return (-1);
|
|
}
|
|
|
|
seq->sz = new_sz;
|
|
seq->elms = new_elms;
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
sqnt_add_bound(struct sqnt *seq, struct bound *elm)
|
|
{
|
|
SPHO_PRECOND(seq->filled <= seq->sz);
|
|
|
|
if (seq->filled >= seq->sz && (sqnt_makebig(seq) == -1))
|
|
return (-1);
|
|
|
|
seq->elms[seq->filled++] = *elm;
|
|
|
|
SPHO_POSTCOND(seq->filled <= seq->sz);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
tstl_init(struct spho_ctx *ctx, size_t lsz, size_t rsz,
|
|
struct tstl *ts)
|
|
{
|
|
if (sqnt_init(ctx, lsz, &ts->left) == -1)
|
|
return (-1);
|
|
if (sqnt_init(ctx, rsz, &ts->right) == -1)
|
|
return (-1);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static struct tstl *
|
|
tstl_alloc(struct spho_ctx *ctx)
|
|
{
|
|
struct tstl *ts;
|
|
|
|
if ((ts = calloc(1, sizeof(*ts))) == NULL) {
|
|
SPHO_ERR(ctx, SPHO_ERR_SYS);
|
|
return (NULL);
|
|
}
|
|
if (tstl_init(ctx, 0, 0, ts) == -1) {
|
|
free(ts);
|
|
return (NULL);
|
|
}
|
|
|
|
return (ts);
|
|
}
|
|
|
|
static int
|
|
tstl_add_left(struct tstl *ts, struct bound *tp)
|
|
{
|
|
return (sqnt_add_bound(&ts->left, tp));
|
|
}
|
|
|
|
static int
|
|
tstl_add_right(struct tstl *ts, struct bound *tp)
|
|
{
|
|
return (sqnt_add_bound(&ts->right, tp));
|
|
}
|
|
|
|
static int
|
|
tstl_decide(struct tstl *ts)
|
|
{
|
|
SPHO_RIP("implement");
|
|
}
|
|
|
|
int
|
|
spho_is_subt(struct spho_ctx *ctx, const struct spho_tp *tp_left,
|
|
const struct spho_tp *tp_right)
|
|
{
|
|
struct tstl ts;
|
|
struct bound *left, *right;
|
|
|
|
if ((left = bound_tp(tp_left)) == NULL)
|
|
return (-1);
|
|
if ((right = bound_tp(tp_right)) == NULL)
|
|
return (-1);
|
|
|
|
// TODO check well-definedness of types (e.g. no undefs)
|
|
|
|
if ((tstl_init(ctx, 0, 0, &ts)) == -1)
|
|
return (-1);
|
|
|
|
if (tstl_add_left(&ts, left) == -1)
|
|
return (-1);
|
|
if (tstl_add_right(&ts, right) == -1)
|
|
return (-1);
|
|
|
|
if (tstl_decide(&ts) == -1)
|
|
return (-1);
|
|
|
|
return (-1);
|
|
}
|
|
|