#include "im.h" #include "dbg.h" #include "errloc.h" #include "fn.h" #include "prv.h" #include "parse.h" #include "sym.h" #include #include #include #include #include void im_free(struct im *im) { ast_free(&im->ast); lex_free(&im->l); } static FILE *tryinc(const char *dir, const char *path, char **fullpath) { FILE *ret = NULL; size_t n = strlen(dir) + strlen(path) + 2; char *fp = malloc(n); if (!fp) { perror("malloc(3)"); goto end; } else if (snprintf(fp, n, "%s/%s", dir, path) < 0) { fprintf(stderr, "%s: snprintf(3) failed\n", __func__); goto end; } else if ((ret = fopen(fp, "rb"))) *fullpath = fp; end: if (!ret) free(fp); return ret; } static char *fpath(const char *cur, const char *path) { const char *sl = strrchr(cur, '/'); char *ret; /* '/' + '\0' */ size_t n = 2; int curlen; if (!sl) { cur = "."; curlen = 1; } else curlen = sl - cur; n += curlen + strlen(path); if ((ret = malloc(n))) snprintf(ret, n, "%.*s/%s", curlen, cur, path); else perror("malloc(3)"); return ret; } static int doim(const struct lex *l, const struct tk *tk, struct prv *p) { int ret = -1; FILE *f = NULL; struct im *im; struct fn *fn = fn_cur(p), *fns = NULL; struct ast *ast; const char *path = tk->s; size_t n = fn->nimps + 1; char *fp = NULL, *incfp; const struct loc *loc = &tk->loc; /* TODO: no protection against recursive imports */ if (!(fp = fpath(l->loc.f, path))) goto end; else if (!(f = fopen(fp, "rb"))) { const struct arg_input *incs = &l->args->incs; for (size_t i = 0; i < incs->n; i++) if ((f = tryinc(incs->v[i], path, &incfp))) { free(fp); fp = incfp; break; } } if (!f) { errloc(tk, "failed to open import \"%s\"", path); goto end; } else if (!(fns = malloc(sizeof *fns))) { perror("malloc(3)"); goto end; } *fns = (struct fn){.tk = tk}; if (!(im = realloc(fn->imps, n * sizeof *im))) { perror("realloc(3)"); goto end; } fn->imps = im; im = &fn->imps[fn->nimps++]; *im = (struct im){.l = {.loc.f = fp, .args = l->args}}; ast = &im->ast; ast->fns = fns; /* hack: treat imports as a function */ ast->nfns = 1; fp = NULL; dbg("start import %s (from %s:%d:%d)\n", im->l.loc.f, loc->f, loc->line, loc->col); if (lex(&im->l, f) || parse_im(&im->l, ast)) goto end; dbg("end import %s\n", im->l.loc.f); ret = 0; end: if (ret) free(fp); if (f && fclose(f)) { fprintf(stderr, "fclose(3) %s: %s\n", path, strerror(errno)); ret = -1; } return ret; } static int onsym(const struct lex *l, struct prv *p, const struct sym *s) { if (s->type != SYM_LIT) { errloc(s->tk, "expected literal"); return -1; } return doim(l, s->tk, p); } int im(const struct lex *l, struct prv *p) { struct fn *fn = fn_cur(p); if (fn->im) { const struct loc *loc = &fn->im->loc; errloc(p->stk, "imports section already defined at %s:%d:%d", loc->f, loc->line, loc->col); return -1; } fn->im = p->stk; p->stk = p->tk; return sym(p, onsym); }