diff options
| author | 2022-08-06 14:10:19 +0200 | |
|---|---|---|
| committer | 2022-08-06 14:10:29 +0200 | |
| commit | b8d9ad1f6636f46a832b0f949ce7525ae08f53bd (patch) | |
| tree | 037c7e0a86835b2e284df786e3ba2680b7677cc4 /bootstrap/parse.c | |
| parent | 1dd19e56fb81d1334bb21e4aa097f9593576feb7 (diff) | |
basic method calls & many bugfix
Diffstat (limited to 'bootstrap/parse.c')
| -rw-r--r-- | bootstrap/parse.c | 178 |
1 files changed, 147 insertions, 31 deletions
diff --git a/bootstrap/parse.c b/bootstrap/parse.c index 381cfcc..025e061 100644 --- a/bootstrap/parse.c +++ b/bootstrap/parse.c @@ -413,6 +413,7 @@ lex(struct parser *P) { case '-': if (chrmatch(P, '=')) tok.t = '-='; else if (chrmatch(P, '-')) tok.t = '--'; + else if (chrmatch(P, '>')) tok.t = '->'; else tok.t = '-'; return tok; case '&': @@ -511,13 +512,15 @@ popenv(struct parser *P) { assert(P->curenv); } -static void +static struct decl * putdecl(struct parser *P, struct span espan, const struct decl *decl) { + struct decl *ret; if (envfind(P->primenv, decl->name)) fatal(P, espan, "cannot shadow primitive `%s'", decl->name); - if (!envput(P->curenv, decl)) + if (!(ret = envput(P->curenv, decl))) fatal(P, decl->span, "cannot shadow earlier incompatible declaration of `%s'", decl->name); + return ret; } static const struct decl * @@ -652,6 +655,8 @@ islvalue(const struct expr *ex) { return 1; if (ex->t == Eprefix && ex->unop.op == '*') return 1; + if (ex->t == Eindex || ex->t == Eget) + return 1; return 0; } @@ -683,14 +688,22 @@ structidx2fld(const struct type *ty, int idx) { static int structfldnam2idx(const struct type *ty, const char *name) { - int i; assert(name); - for (i = 0; i < ty->agg.flds.n; ++i) + for (int i = 0; i < ty->agg.flds.n; ++i) if (!strcmp(name, ty->agg.flds.d[i].name)) return i; return -1; } +static struct decl * +findaggdecl(const struct type *ty, const char *name) { + assert(name); + for (int i = 0; i < ty->agg.decls.n; ++i) + if (!strcmp(name, ty->agg.decls.d[i].name)) + return &ty->agg.decls.d[i]; + return NULL; +} + static struct expr parsestructini(struct parser *P, const struct type *ty) { struct expr ex = {Eini}; @@ -788,6 +801,8 @@ parsearrini(struct parser *P, const struct type *ty) { static const struct type * fntype(const struct fn *fn) { struct type ty = { TYfn, 0, g_targ.sizesize }; + if (fn->selfty) + return fn->selfty; vec_t(const struct type *) params = {0}; ty.fn.retty = fn->retty; for (int i = 0; i < fn->params.n; ++i) @@ -946,6 +961,7 @@ static struct expr pexpostfix(struct parser *P) { struct expr ex = pexprimary(P); struct tok tok; + struct fn *met = NULL; if (P->used_targty) return ex; @@ -954,6 +970,12 @@ pexpostfix(struct parser *P) { const struct type *ty = ex.ty; int i = 0; + if (met) { + ++i; + ty = met->selfty = fntype(met); + vec_push(&args, ex); + } + if (ty->t == TYptr) ty = ty->child; @@ -979,11 +1001,17 @@ pexpostfix(struct parser *P) { break; } } - ex.call.callee = exprdup(ex); - ex.t = Ecall; - ex.span = tok.span; - ex.ty = ty->fn.retty; - vec_slice_cpy(&ex.call.args, &args); + if (met) { + ex.t = Emcall; + ex.mcall.met = met; + vec_slice_cpy(&ex.mcall.args, &args); + } else { + ex.call.callee = exprdup(ex); + ex.t = Ecall; + ex.span = tok.span; + ex.ty = ty->fn.retty; + vec_slice_cpy(&ex.call.args, &args); + } } else if (lexmatch(P, &tok, '[')) { struct expr lhs = ex, rhs = parseexpr(P); @@ -1023,7 +1051,7 @@ pexpostfix(struct parser *P) { int idx = structfldnam2idx(ty, fnam); struct aggfield *fld = &ty->agg.flds.d[idx]; if (idx < 0) - fatal(P, tok.span, "%t has no such field `%s'", ex.ty, fnam); + fatal(P, tok.span, "%t has no such field `%s'", ty, fnam); ex.get.lhs = exprdup(ex); ex.t = Eget; @@ -1034,6 +1062,62 @@ pexpostfix(struct parser *P) { fatal(P, tok.span, "cannot access `%s': left-hand-side is not an aggregate (%t)", fnam, ex.ty); } + } else if (lexmatch(P, &tok, '->')) { + const char *fnam = (tok = lexexpect(P, TKident)).str; + const struct type *ty = ex.ty; + bool exptr = 0, metptr = 0; + + if ((exptr = ty->t == TYptr)) + ty = ty->child; + if (ty->t == TYstruct || ty->t == TYunion) { + struct decl *decl = findaggdecl(ty, fnam); + if (!decl) + fatal(P, tok.span, "%t has no such method `%s'", ty, fnam); + if (decl->t != Dfn) + fatal(P, tok.span, "%t:%bs is not a function", ty, fnam); + met = &decl->fn; + if (met->params.n == 0) + fatal(P, tok.span, + "cannot call `->%s', it takes zero arguments", + fnam); + + const struct type *recv0 = met->params.d[0].ty, + *recv = recv0; + if ((metptr = recv->t == TYptr)) + recv = recv->child; + if (unconstify(ty) != unconstify(recv)) + fatal(P, tok.span, + "method receiver type mismatch for `->%s' (%t vs %t)", + fnam, ty, recv); + if (!exptr && !metptr) { + ; + } else if (exptr && !metptr) { + ex = (struct expr) { + Eprefix, ex.span, ty, .unop = { '*', exprdup(ex) } + }; + } else if (!exptr && metptr) { + struct type pty = {TYptr, g_targ.ptrsize, 0, 0, .child = ty}; + if (!islvalue(&ex)) + fatal(P, tok.span, "cannot call `->%s' by reference: left-hand-side is not" + "an lvalue", fnam); + else if (ty->konst && !recv->konst) + fatal(P, tok.span, "constness mismatch: method takes %t but subject is %t", + recv0, ex.ty); + ex = (struct expr) { + Eprefix, ex.span, interntype(pty), .unop = { '&', exprdup(ex) } + }; + } else if (exptr && metptr) { + if (ty->konst && !recv->konst) + fatal(P, tok.span, "constness mismatch: method takes %t but subject is %t", + recv0, ex.ty); + } + + if (lexpeek(P).t != '(') + lexexpect(P, '('); + } else { + fatal(P, tok.span, "cannot call `->%s': left-hand-side is not an aggregate (%t)", + fnam, ex.ty); + } } else { break; } @@ -2076,7 +2160,6 @@ parseenum(struct parser *P, const char *name) { if (min >= INT32_MIN && max <= INT32_MAX) ty.enu.intty = ty_int; if (min >= INT64_MIN && max <= INT64_MAX) ty.enu.intty = ty_int; } - assert(ty.enu.intty); } ty.size = ty.enu.intty->size; @@ -2088,18 +2171,24 @@ parseenum(struct parser *P, const char *name) { } static const struct type * -parseagg(struct parser *P, const char *name, int kind) { +parseagg(struct parser *P, const char *name, int kind, bool *put) { struct tok tok; struct type ty = {kind}; + const struct type *pty = NULL; static int id = 0; size_t size = 0, align = 1; vec_t(struct aggfield) flds = {0}; + *put = 1; + if (lexmatch(P, &tok, ';')) { ty.agg.fwd = 1; } else { lexexpect(P, '{'); while (!lexmatch(P, &tok, '}')) { + if (isdecltokt(lexpeek(P).t)) + goto decls; + const char *fnam = (tok = lexexpect(P, TKident)).str; const struct type *ty = parsetype(P); size_t off = kind == TYunion ? 0 : ALIGNUP(size, ty->align); @@ -2129,6 +2218,41 @@ parseagg(struct parser *P, const char *name, int kind) { } } } + if (0) +decls: { + vec_t(struct decl) decls = {0}; + struct env env = {.parent = P->curenv}; + struct decl *decl; + + ty.size = ALIGNUP(size, align); + ty.align = align; + ty.agg.name = name; + vec_slice_cpy(&ty.agg.flds, &flds); + ty.agg.id = id++; + pty = interntype(ty); + if (name) + decl = putdecl(P, tok.span, + &(struct decl){Dtype, name, .span = tok.span, .ty = pty}); + if (decl->ty != pty) + uninterntype(pty); + pty = decl->ty; + + pushenv(P, &env); + while (!lexmatch(P, &tok, '}')) + parsedecl(NULL, NULL, P, 0); + for (struct decls *ds = env.decls, *next; ds; ds = next) { + if (ds->decl.t == Dtype && ds->decl.ty == pty) + ; + else + vec_push(&decls, ds->decl); + next = ds->next; + free(ds); + } + vec_slice_cpy(&((struct type *)decl->ty)->agg.decls, &decls); + popenv(P); + *put = 0; + return decl->ty; + } ty.size = ALIGNUP(size, align); ty.align = align; @@ -2184,7 +2308,8 @@ staticvaryield(struct decl *decl, void *arg) { if (a->P->is_header && a->externp && decl->var.ini) fatal(a->P, decl->span, "cannot define extern variable in header"); - a->yield(decl, a->yarg); + if (a->yield) + a->yield(decl, a->yarg); } static void @@ -2234,25 +2359,13 @@ parsedecl(decl_yielder_t yield, void *yarg, struct parser *P, bool toplevel) { decl.name = lexexpects(P, TKident, "enum name").str; decl.ty = parseenum(P, decl.name); } else if (lexmatch(P, &tok, TKkw_struct)) { - struct decl *d2; + bool put; kind = TYstruct; if (externp) fatal(P, tok.span, "struct cannot be `extern'"); agg: decl.name = lexexpects(P, TKident, "struct name").str; - decl.ty = parseagg(P, decl.name, kind); - d2 = (struct decl *)finddecl(P, decl.name); - if (d2 && d2->t == Dtype && d2->ty->t == kind && d2->ty->agg.fwd) { - // modify existing forward declaration - *(size_t *)&d2->ty->size = decl.ty->size; - *(size_t *)&d2->ty->align = decl.ty->align; - *(bool *)&d2->ty->agg.fwd = 0; - memcpy((void *)&d2->ty->agg.flds, &decl.ty->agg.flds, - sizeof d2->ty->agg.flds); - uninterntype(decl.ty); - d2->span = tok.span; - envput(P->curenv, d2); - return; - } + decl.ty = parseagg(P, decl.name, kind, &put); + if (!put) goto noput; } else if (lexmatch(P, &tok, TKkw_union)) { if (externp) fatal(P, tok.span, "union cannot be `extern'"); kind = TYunion; @@ -2265,7 +2378,8 @@ parsedecl(decl_yielder_t yield, void *yarg, struct parser *P, bool toplevel) { cf = doimport(P, path); for (int i = 0; i < cf.decls.n; ++i) { putdecl(P, tok.span, &cf.decls.d[i]); - yield(&cf.decls.d[i], yarg); + if (yield) + yield(&cf.decls.d[i], yarg); } free(cf.decls.d); lexexpect(P, ';'); @@ -2276,8 +2390,10 @@ parsedecl(decl_yielder_t yield, void *yarg, struct parser *P, bool toplevel) { } decl.span = tok.span; - putdecl(P, tok.span, &decl); - yield(&decl, yarg); + decl = *putdecl(P, tok.span, &decl); +noput: + if (yield) + yield(&decl, yarg); } static void |