log-e-sappho/src/spho/scope.c

258 lines
4.4 KiB
C

#include <sys/queue.h>
#include <stdlib.h>
#include <string.h>
#include "spho/spho.h"
#include "spho/ctx.h"
#include "spho/scope.h"
#include "spho/bind.h"
static void spho_nom_term(struct spho_nom *);
static int scope_nom_lookup_str_local(struct spho_scope *, const char *,
size_t, struct spho_nom **);
static int scope_nom_in_local(struct spho_scope *, struct spho_nom *);
int
spho_scope_init(struct spho_scope *sc, struct spho_ctx *ctx,
struct spho_scope *p)
{
sc->ctx = ctx;
sc->parent = p;
SLIST_INIT(&sc->subs);
SLIST_INIT(&sc->noms);
sc->n_noms = 0;
TAILQ_INIT(&sc->tps);
sc->bind_loc = NULL;
return (0);
}
void
spho_scope_term(struct spho_scope *sc)
{
SPHO_UTIL_SLIST_DESTROY(&sc->subs, spho_scope, next, spho_scope_term);
SPHO_UTIL_SLIST_DESTROY(&sc->noms, spho_nom, next, spho_nom_term);
sc->parent = NULL;
if (sc->bind_loc == NULL)
spho_prebind_free(sc->bind_loc);
sc->bind_loc = NULL;
}
struct spho_scope *
spho_scope_global(struct spho_ctx *ctx)
{
SPHO_PRECOND(ctx != NULL);
return (&ctx->glob);
}
struct spho_scope *
spho_scope_create(struct spho_scope *sc)
{
struct spho_scope *sub;
if ((sub = malloc(sizeof(struct spho_scope))) == NULL) {
SPHO_ERR(sc->ctx, SPHO_ERR_SYS);
return (NULL);
}
if (spho_scope_init(sub, sc->ctx, sc) == -1) {
free(sub);
return (NULL);
}
SLIST_INSERT_HEAD(&sc->subs, sub, next);
return (sub);
}
static void
spho_nom_term(__attribute__((unused)) struct spho_nom *nom)
{
return;
}
void
spho_scope_destroy(struct spho_scope *sc)
{
struct spho_scope *p;
p = sc->parent;
SLIST_REMOVE(&p->subs, sc, spho_scope, next);
spho_scope_term(sc);
free(sc);
}
struct spho_nom *
spho_scope_nom_add(struct spho_scope *sc, const char *nomstr, size_t sz)
{
size_t res;
struct spho_nom *nom;
nom = NULL;
if (scope_nom_lookup_str_local(sc, nomstr, sz, &nom) == -1)
return (NULL);
if (nom != NULL) {
SPHO_SC_ERR(sc, SPHO_ERR_NOM_INUSE);
return (NULL);
}
if ((nom = malloc(sizeof(struct spho_nom))) == NULL) {
SPHO_SC_ERR(sc, SPHO_ERR_SYS);
return (NULL);
}
res = strlcpy(nom->s, nomstr, sizeof(nom->s));
if (res >= sizeof(nom->s)) {
SPHO_SC_ERR(sc, SPHO_ERR_TOOBIG);
goto err;
}
SLIST_INSERT_HEAD(&sc->noms, nom, next);
sc->n_noms++;
return (nom);
err:
free(nom);
return (NULL);
}
int
spho_scope_nom_lookup_str(struct spho_scope *sc, const char *nomstr, size_t sz,
struct spho_nom **out)
{
struct spho_nom *nom;
nom = NULL;
if (sz > sizeof(nom->s)) {
SPHO_ERR(sc->ctx, SPHO_ERR_TOOBIG);
return (-1);
}
*out = NULL;
while (*out == NULL && sc != NULL) {
SLIST_FOREACH(nom, &sc->noms, next) {
if (strncmp(nom->s, nomstr, sz) == 0) {
*out = nom;
break;
}
}
sc = sc->parent;
}
return (0);
}
int
spho_scope_nom_lookup_str_strict(struct spho_scope *sc, const char *nomstr,
size_t sz, struct spho_nom **out)
{
if (spho_scope_nom_lookup_str(sc, nomstr, sz, out) == -1)
return (-1);
if (*out == NULL) {
SPHO_SC_ERR(sc, SPHO_ERR_NOM_NOTINSCOPE);
return (-1);
}
return (0);
}
int
spho_scope_prebind_init(struct spho_scope *sc)
{
if ((sc->bind_loc = spho_prebind_create(sc))
== NULL) {
return (-1);
}
return (0);
}
int
spho_scope_prebind_tp(struct spho_scope *sc, struct spho_nom *nom,
struct spho_tp *tp)
{
if (! scope_nom_in_local(sc, nom)) {
SPHO_ERR(sc->ctx, SPHO_ERR_NOM_NOTINSCOPE);
return (-1);
}
return (spho_prebind_tp(sc->bind_loc, nom, tp));
}
int
spho_scope_prebind_tp_op(struct spho_scope *sc, struct spho_nom *nom,
struct spho_tp_op *tp_op)
{
if (! scope_nom_in_local(sc, nom)) {
SPHO_ERR(sc->ctx, SPHO_ERR_NOM_NOTINSCOPE);
return (-1);
}
return (spho_prebind_tp_op(sc->bind_loc, nom, tp_op));
}
int
spho_scope_prebind_undef(struct spho_scope *sc, struct spho_nom *nom)
{
if (! scope_nom_in_local(sc, nom)) {
SPHO_ERR(sc->ctx, SPHO_ERR_NOM_NOTINSCOPE);
return (-1);
}
return (spho_prebind_undef(sc->bind_loc, nom));
}
static int
scope_nom_lookup_str_local(struct spho_scope *sc, const char *nomstr,
size_t sz, struct spho_nom **out)
{
struct spho_nom *nom;
nom = NULL;
if (sz > sizeof(nom->s)) {
SPHO_ERR(sc->ctx, SPHO_ERR_TOOBIG);
return (-1);
}
*out = NULL;
SLIST_FOREACH(nom, &sc->noms, next) {
if (strncmp(nom->s, nomstr, sz) == 0) {
*out = nom;
break;
}
}
return (0);
}
static int
scope_nom_in_local(struct spho_scope *sc, struct spho_nom *nom)
{
struct spho_nom *sc_nom;
SLIST_FOREACH(sc_nom, &sc->noms, next) {
if (sc_nom == nom)
return (1);
}
return (0);
}