#include "call.h" #include "dbg.h" #include "errloc.h" #include "fn.h" #include "lex.h" #include "lit.h" #include "parse.h" #include "pr.h" #include "prv.h" #include "stmt.h" #include "sym.h" #include "type.h" #include #include #include #include static int using(const struct lex *, struct prv *); static int s_returning(const struct lex *, struct prv *); static const struct seq returning = {(struct step[]){{ID, "returning"}, {0}}, .fn = s_returning}; static const struct seq seqs[] = { {(struct step[]){{ID, "using"}, {0}}, .fn = using}, returning, {0} }; static const struct seq useqs[] = { returning, {0} }; static int param(const struct lex *l, struct prv *p, const struct sym *s) { struct stmt *stmt = stmt_cur(p); struct call *c = &stmt->u.call; size_t n = c->nparams + 1; struct callparam *params = realloc(c->params, n * sizeof *params); if (!params) { perror("realloc(3)"); return -1; } params[c->nparams++] = (struct callparam){.s = s}; c->params = params; return 0; } static int using(const struct lex *l, struct prv *p) { struct pos init = { .name = __func__, .seq = useqs }; struct stmt *stmt = stmt_cur(p); struct call *c = &stmt->u.call; const struct tk *tk = c->pr->tk, *u = c->using; if (u) { const struct loc *loc = &u->loc; errloc(p->stk, "\"using\" for \"%s\" already set at %d:%d", tk->s, loc->line, loc->col); return -1; } else if (push(&init, p)) return -1; c->using = p->stk; return sym(p, param); } static int setret(const struct lex *l, struct prv *p, const struct sym *s) { struct stmt *stmt = stmt_cur(p); struct call *c = &stmt->u.call; c->ret = s; return pop(l, p); } static int s_returning(const struct lex *l, struct prv *p) { struct pos init = { .name = __func__, .seq = useqs }; struct stmt *stmt = stmt_cur(p); struct call *c = &stmt->u.call; const struct tk *tk = c->pr->tk, *r = c->returning; if (r) { const struct loc *loc = &r->loc; errloc(p->stk, "\"returning\" for \"%s\" already set at %d:%d", tk->s, loc->line, loc->col); return -1; } if (push(&init, p)) return -1; c->returning = p->stk; return sym(p, setret); } static int endcall(const struct lex *l, struct prv *p) { const struct stmt *stmt = stmt_cur(p); const struct call *c = &stmt->u.call; const struct pr *pr = c->pr; const struct tk *tk = c->id->tk; size_t n = c->nparams; if (!pr) { errloc(p->stk - 1, "incomplete \"call\" statement"); return -1; } else if (c->using && !n) { errloc(c->using, "\"using\" without arguments"); return -1; } else if (c->returning && !c->ret) { errloc(c->using, "\"returning\" without return variable"); return -1; } else if (pr->variadic) { if (n < pr->nparams) { errloc(tk, "\"%s\" expects at least %zu parameters, " "but %zu were given", tk->s, pr->nparams, n); return -1; } } else if (n != pr->nparams) { errloc(tk, "\"%s\" expects %zu parameters, but %zu were given", tk->s, pr->nparams, n); return -1; } if (!pr->ret && c->ret) { errloc(tk, "function \"%s\" does not expect any return variable", tk->s); return -1; } fprintf(stderr, "%s: TODO\n", __func__); return -1; } void call_free(struct call *c) { if (c) free(c->params); } static const struct pr *find(const struct ast *ast, const char *s) { for (size_t i = 0; i < ast->nfns; i++) { const struct fn *fn = &ast->fns[i]; if (!strcmp(fn->tk->s, s)) return fn->pr; } return NULL; } static int onsym(const struct lex *l, struct prv *p, const struct sym *s) { const struct fn *fn = fn_cur(p); struct stmt *stmt = stmt_cur(p); struct call *c = &stmt->u.call; const struct tk *tk = s->tk; const struct pr *pr = find(p->ast, tk->s); const struct stentry *e; if (pr) c->pr = pr; else if (!(e = fn_var(fn, tk))) { errloc(tk, "undefined reference to \"%s\"", tk->s); return -1; } else if (e->t->type != P) { char *tn = type_name(e->t); if (tn) errloc(tk, "cannot call \"%s\" with type \"%s\"", tk->s, tn); free(tn); return -1; } else c->pr = e->t->u.p.fn->pr; c->id = s; return pop(l, p); } int call(const struct lex *l, struct prv *p) { struct pos init = { .name = __func__, .seq = seqs, .end = endcall, }; struct fn *fn = fn_cur(p); size_t n = fn->nstmts + 1; struct stmt *stmts = realloc(fn->stmts, n * sizeof *stmts); if (!stmts) { perror("realloc(3)"); return -1; } stmts[fn->nstmts++] = (struct stmt){.type = CALL, .u.call.tk = p->stk}; fn->stmts = stmts; if (push(&init, p)) return -1; return sym(p, onsym); }